Skip to main content

vizia_core/context/
proxy.rs

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