ferroui_base/rendering/composition/
composition_custom_visual.rs1use super::generated::CompositionContainerVisualProps;
2use super::server::{ServerCompositionCustomVisual, ServerCompositionVisual};
3use super::visual::CompositionVisualKind;
4use super::{CompositionVisual, Compositor, ICompositionCustomVisualHandler};
5use std::any::Any;
6use std::cell::RefCell;
7use std::ops::Deref;
8use std::rc::Rc;
9
10pub(crate) struct CustomVisualData {
13 props: CompositionContainerVisualProps,
14 messages: RefCell<Option<Vec<std::sync::Arc<dyn Any + Send + Sync>>>>,
15}
16
17impl CustomVisualData {
18 pub(crate) fn props(&self) -> &CompositionContainerVisualProps {
19 &self.props
20 }
21}
22
23#[derive(Clone)]
25pub struct CompositionCustomVisual(Rc<CompositionVisual>);
26
27impl Deref for CompositionCustomVisual {
28 type Target = Rc<CompositionVisual>;
29
30 fn deref(&self) -> &Rc<CompositionVisual> {
31 &self.0
32 }
33}
34
35impl CompositionCustomVisual {
36 pub(crate) fn new(
37 compositor: &Rc<Compositor>,
38 handler: impl FnOnce() -> Rc<dyn ICompositionCustomVisualHandler> + Send + 'static,
39 ) -> CompositionCustomVisual {
40 let data = CustomVisualData { props: CompositionContainerVisualProps::new(), messages: RefCell::new(None) };
41 CompositionCustomVisual(CompositionVisual::create_with(
42 compositor,
43 CompositionVisualKind::Custom(data),
44 move || Box::new(ServerCompositionCustomVisual::new(handler())),
45 ServerCompositionCustomVisual::attach,
46 ))
47 }
48
49 pub fn from_visual(visual: &Rc<CompositionVisual>) -> Option<CompositionCustomVisual> {
51 matches!(visual.kind, CompositionVisualKind::Custom(_)).then(|| CompositionCustomVisual(visual.clone()))
52 }
53
54 fn data(&self) -> &CustomVisualData {
55 match &self.0.kind {
56 CompositionVisualKind::Custom(data) => data,
57 _ => unreachable!("a custom visual handle wraps a custom visual"),
58 }
59 }
60
61 pub fn send_handler_message(&self, message: std::sync::Arc<dyn Any + Send + Sync>) {
64 let first = self.data().messages.borrow().is_none();
65 if first {
66 *self.data().messages.borrow_mut() = Some(Vec::new());
67 let visual = Rc::downgrade(&self.0);
68 self.compositor().request_composition_update(move || {
69 if let Some(visual) = visual.upgrade() {
70 CompositionCustomVisual(visual).on_composition_update();
71 }
72 });
73 }
74 if let Some(messages) = self.data().messages.borrow_mut().as_mut() {
75 messages.push(message);
76 }
77 }
78
79 fn on_composition_update(&self) {
80 let Some(messages) = self.data().messages.borrow_mut().take() else { return };
81
82 let server = self.server();
83 self.compositor().post_server_job(
84 move |compositor| {
85 let visual = compositor.get::<ServerCompositionVisual>(server);
86 if let Some(content) = visual.as_ref().and_then(|v| v.content_as::<ServerCompositionCustomVisual>()) {
87 content.dispatch_messages(messages);
88 }
89 },
90 false,
91 );
92 }
93}