vizia_core/context/
proxy.rs

1use std::any::Any;
2use std::fmt::Formatter;
3use std::sync::Mutex;
4
5use super::InternalEvent;
6
7use crate::prelude::*;
8
9/// A bundle of data representing a snapshot of the context when a thread was spawned.
10///
11/// It supports a small subset of context operations. You will get one of these passed to you when
12/// you create a new thread with the [`spawn`](crate::context::Context::spawn) method on [`Context`].
13pub struct ContextProxy {
14    /// The current entity when the proxy context was created.
15    pub current: Entity,
16    /// An event proxy used to send events back to the main thread.
17    pub event_proxy: Option<Box<dyn EventProxy>>,
18}
19
20/// Errors that might occur when emitting an event via a ContextProxy.
21#[derive(Debug)]
22pub enum ProxyEmitError {
23    /// The current runtime does not support proxying events.
24    Unsupported,
25    /// The event loop has been closed; the application is exiting.
26    EventLoopClosed,
27}
28
29impl std::fmt::Display for ProxyEmitError {
30    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31        match self {
32            ProxyEmitError::Unsupported => {
33                f.write_str("The current runtime does not support proxying events")
34            }
35            ProxyEmitError::EventLoopClosed => {
36                f.write_str("Sending an event to an event loop which has been closed")
37            }
38        }
39    }
40}
41
42impl std::error::Error for ProxyEmitError {}
43
44impl ContextProxy {
45    pub fn emit<M: Any + Send>(&mut self, message: M) -> Result<(), ProxyEmitError> {
46        if let Some(proxy) = &self.event_proxy {
47            let event = Event::new(message)
48                .target(self.current)
49                .origin(self.current)
50                .propagate(Propagation::Up);
51
52            proxy.send(event).map_err(|_| ProxyEmitError::EventLoopClosed)
53        } else {
54            Err(ProxyEmitError::Unsupported)
55        }
56    }
57
58    pub fn emit_to<M: Any + Send>(
59        &mut self,
60        target: Entity,
61        message: M,
62    ) -> Result<(), ProxyEmitError> {
63        if let Some(proxy) = &self.event_proxy {
64            let event = Event::new(message)
65                .target(target)
66                .origin(self.current)
67                .propagate(Propagation::Direct);
68
69            proxy.send(event).map_err(|_| ProxyEmitError::EventLoopClosed)
70        } else {
71            Err(ProxyEmitError::Unsupported)
72        }
73    }
74
75    pub fn redraw(&mut self) -> Result<(), ProxyEmitError> {
76        self.emit(InternalEvent::Redraw)
77    }
78
79    pub fn load_image(
80        &mut self,
81        path: String,
82        data: &[u8],
83        policy: ImageRetentionPolicy,
84    ) -> Result<(), ProxyEmitError> {
85        if let Some(image) = skia_safe::Image::from_encoded(skia_safe::Data::new_copy(data)) {
86            self.emit(InternalEvent::LoadImage { path, image: Mutex::new(Some(image)), policy })?
87        }
88
89        Ok(())
90    }
91
92    pub fn spawn<F>(&self, target: F)
93    where
94        F: 'static + Send + FnOnce(&mut ContextProxy),
95    {
96        let mut cxp = self.clone();
97        std::thread::spawn(move || target(&mut cxp));
98    }
99}
100
101impl Clone for ContextProxy {
102    fn clone(&self) -> Self {
103        Self {
104            current: self.current,
105            event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
106        }
107    }
108}
109
110pub trait EventProxy: Send {
111    #[allow(clippy::result_unit_err)]
112    fn send(&self, event: Event) -> Result<(), ()>;
113    fn make_clone(&self) -> Box<dyn EventProxy>;
114}