|
| 1 | +use super::*; |
| 2 | +use crate::handler::WindowHandlerBuilder; |
| 3 | +use crate::platform::x11::event_loop::EventLoop; |
| 4 | +use crate::platform::x11::window_shared::WindowInner; |
| 5 | +use crate::{WindowContext, WindowOpenOptions}; |
| 6 | +use calloop::LoopSignal; |
| 7 | +use std::cell::Cell; |
| 8 | +use std::num::NonZeroU32; |
| 9 | +use std::panic::resume_unwind; |
| 10 | +use std::rc::Rc; |
| 11 | +use std::sync::mpsc; |
| 12 | +use std::thread; |
| 13 | +use std::thread::JoinHandle; |
| 14 | +use std::time::Duration; |
| 15 | + |
| 16 | +pub struct WindowThreadHandle { |
| 17 | + window_id: NonZeroU32, |
| 18 | + event_loop_handle: Cell<Option<JoinHandle<()>>>, |
| 19 | +} |
| 20 | + |
| 21 | +impl WindowThreadHandle { |
| 22 | + pub fn create_window( |
| 23 | + options: WindowOpenOptions, handler: WindowHandlerBuilder, |
| 24 | + ) -> Result<Self> { |
| 25 | + let (tx, rx) = result_channel(); |
| 26 | + |
| 27 | + let join_handle = thread::spawn(move || { |
| 28 | + let thread = match WindowThread::create(options, handler) { |
| 29 | + Err(e) => return tx.send_error(e), |
| 30 | + Ok(thread) => thread, |
| 31 | + }; |
| 32 | + |
| 33 | + if tx.send_success(&thread) { |
| 34 | + thread.run() |
| 35 | + } |
| 36 | + }); |
| 37 | + |
| 38 | + thread::sleep(Duration::from_millis(2000)); |
| 39 | + |
| 40 | + rx.receive(join_handle) |
| 41 | + } |
| 42 | + |
| 43 | + pub fn run_until_closed(self) { |
| 44 | + let Some(thread) = self.event_loop_handle.take() else { return }; |
| 45 | + |
| 46 | + if let Err(panic) = thread.join() { |
| 47 | + resume_unwind(panic); |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + pub fn is_open(&self) -> bool { |
| 52 | + todo!() |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +impl Drop for WindowThreadHandle { |
| 57 | + fn drop(&mut self) { |
| 58 | + // TODO: stop event loop |
| 59 | + if let Some(event_loop) = self.event_loop_handle.take() { |
| 60 | + let _ = event_loop.join(); |
| 61 | + } |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +enum WindowOpenResult { |
| 66 | + Success { window_id: NonZeroU32, loop_signal: LoopSignal }, |
| 67 | + Error(String), |
| 68 | +} |
| 69 | + |
| 70 | +struct WindowThread { |
| 71 | + event_loop: EventLoop, |
| 72 | + ev_loop: calloop::EventLoop<'static, EventLoop>, |
| 73 | +} |
| 74 | + |
| 75 | +impl WindowThread { |
| 76 | + pub fn create(options: WindowOpenOptions, handler: WindowHandlerBuilder) -> Result<Self> { |
| 77 | + let mut ev_loop = calloop::EventLoop::try_new()?; |
| 78 | + let inner = WindowInner::create(options)?; |
| 79 | + let handler = handler.build(WindowContext::new(Rc::clone(&inner)))?; |
| 80 | + let event_loop = EventLoop::new(inner, handler, &mut ev_loop)?; |
| 81 | + |
| 82 | + Ok(Self { event_loop, ev_loop }) |
| 83 | + } |
| 84 | + |
| 85 | + pub fn run(self) { |
| 86 | + self.event_loop.run(self.ev_loop).unwrap(); |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +fn result_channel() -> (WindowResultSender, WindowResultReceiver) { |
| 91 | + let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1); |
| 92 | + (WindowResultSender(tx), WindowResultReceiver(rx)) |
| 93 | +} |
| 94 | + |
| 95 | +struct WindowResultSender(mpsc::SyncSender<WindowOpenResult>); |
| 96 | +impl WindowResultSender { |
| 97 | + pub fn send_error(self, error: Error) { |
| 98 | + if let Err(err) = self.0.send(WindowOpenResult::Error(format!("{}", error))) { |
| 99 | + crate::error!("Window creation failed: {}", error); |
| 100 | + crate::warn!("Failed to send error to main thread: {err}"); |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + pub fn send_success(self, thread: &WindowThread) -> bool { |
| 105 | + let msg = WindowOpenResult::Success { |
| 106 | + loop_signal: thread.ev_loop.get_signal(), |
| 107 | + window_id: thread.event_loop.window_id(), |
| 108 | + }; |
| 109 | + |
| 110 | + if let Err(err) = self.0.send(msg) { |
| 111 | + crate::error!("Failed to send created window to main thread: {}. Aborting.", err); |
| 112 | + return false; |
| 113 | + } |
| 114 | + |
| 115 | + true |
| 116 | + } |
| 117 | +} |
| 118 | + |
| 119 | +struct WindowResultReceiver(mpsc::Receiver<WindowOpenResult>); |
| 120 | +impl WindowResultReceiver { |
| 121 | + pub fn receive(self, join_handle: JoinHandle<()>) -> Result<WindowThreadHandle> { |
| 122 | + let result = self.0.recv()?; |
| 123 | + match result { |
| 124 | + WindowOpenResult::Error(e) => Err(Error::CreationFailed(e)), |
| 125 | + WindowOpenResult::Success { window_id, loop_signal } => { |
| 126 | + Ok(WindowThreadHandle { event_loop_handle: Some(join_handle).into(), window_id }) |
| 127 | + } |
| 128 | + } |
| 129 | + } |
| 130 | +} |
0 commit comments