Skip to main content

blit_compositor/
lib.rs

1#[cfg(target_os = "linux")]
2mod imp;
3#[cfg(target_os = "linux")]
4mod render;
5#[cfg(target_os = "linux")]
6pub use imp::*;
7
8#[cfg(not(target_os = "linux"))]
9mod stub {
10    use std::sync::Arc;
11    use std::sync::atomic::AtomicBool;
12    use std::sync::mpsc;
13
14    pub mod drm_fourcc {
15        pub const ARGB8888: u32 = u32::from_le_bytes(*b"AR24");
16        pub const XRGB8888: u32 = u32::from_le_bytes(*b"XR24");
17        pub const ABGR8888: u32 = u32::from_le_bytes(*b"AB24");
18        pub const XBGR8888: u32 = u32::from_le_bytes(*b"XB24");
19        pub const NV12: u32 = u32::from_le_bytes(*b"NV12");
20    }
21
22    /// Placeholder for `std::os::fd::OwnedFd` on non-Unix platforms.
23    #[derive(Debug)]
24    pub struct OwnedFd(());
25
26    #[derive(Clone)]
27    pub enum PixelData {
28        Bgra(Arc<Vec<u8>>),
29        Rgba(Arc<Vec<u8>>),
30        Nv12 {
31            data: Arc<Vec<u8>>,
32            y_stride: usize,
33            uv_stride: usize,
34        },
35        DmaBuf {
36            fd: Arc<OwnedFd>,
37            fourcc: u32,
38            modifier: u64,
39            stride: u32,
40            offset: u32,
41        },
42    }
43
44    #[derive(Clone)]
45    pub struct PixelLayer {
46        pub x: i32,
47        pub y: i32,
48        pub width: u32,
49        pub height: u32,
50        pub pixels: PixelData,
51    }
52
53    impl PixelData {
54        pub fn to_rgba(&self, _width: u32, _height: u32) -> Vec<u8> {
55            match self {
56                PixelData::Rgba(data) => data.as_ref().clone(),
57                PixelData::Bgra(data) => {
58                    let mut rgba = Vec::with_capacity(data.len());
59                    for px in data.chunks_exact(4) {
60                        rgba.extend_from_slice(&[px[2], px[1], px[0], px[3]]);
61                    }
62                    rgba
63                }
64                PixelData::Nv12 { .. } | PixelData::DmaBuf { .. } => Vec::new(),
65            }
66        }
67
68        pub fn is_empty(&self) -> bool {
69            match self {
70                PixelData::Bgra(v) | PixelData::Rgba(v) => v.is_empty(),
71                PixelData::Nv12 { data, .. } => data.is_empty(),
72                PixelData::DmaBuf { .. } => false,
73            }
74        }
75
76        pub fn is_dmabuf(&self) -> bool {
77            matches!(self, PixelData::DmaBuf { .. })
78        }
79    }
80
81    pub enum CompositorEvent {
82        SurfaceCreated {
83            surface_id: u16,
84            title: String,
85            app_id: String,
86            parent_id: u16,
87            width: u16,
88            height: u16,
89        },
90        SurfaceDestroyed {
91            surface_id: u16,
92        },
93        SurfaceCommit {
94            surface_id: u16,
95            width: u32,
96            height: u32,
97            pixels: PixelData,
98        },
99        SurfaceTitle {
100            surface_id: u16,
101            title: String,
102        },
103        SurfaceAppId {
104            surface_id: u16,
105            app_id: String,
106        },
107        SurfaceResized {
108            surface_id: u16,
109            width: u16,
110            height: u16,
111        },
112        ClipboardContent {
113            surface_id: u16,
114            mime_type: String,
115            data: Vec<u8>,
116        },
117    }
118
119    pub enum CompositorCommand {
120        KeyInput {
121            surface_id: u16,
122            keycode: u32,
123            pressed: bool,
124        },
125        PointerMotion {
126            surface_id: u16,
127            x: f64,
128            y: f64,
129        },
130        PointerButton {
131            surface_id: u16,
132            button: u32,
133            pressed: bool,
134        },
135        PointerAxis {
136            surface_id: u16,
137            axis: u8,
138            value: f64,
139        },
140        SurfaceResize {
141            surface_id: u16,
142            width: u16,
143            height: u16,
144            scale_120: u16,
145        },
146        SurfaceFocus {
147            surface_id: u16,
148        },
149        SurfaceClose {
150            surface_id: u16,
151        },
152        ClipboardOffer {
153            surface_id: u16,
154            mime_type: String,
155            data: Vec<u8>,
156        },
157        ReleaseKeys {
158            keycodes: Vec<u32>,
159        },
160        Capture {
161            surface_id: u16,
162            reply: mpsc::SyncSender<Option<(u32, u32, Vec<u8>)>>,
163        },
164        /// Fire pending wl_surface.frame callbacks for a surface so the
165        /// client will paint and commit its next frame.  Send this when
166        /// the server is ready to consume a new frame (streaming or capture).
167        RequestFrame {
168            surface_id: u16,
169        },
170        Shutdown,
171    }
172
173    pub struct CompositorHandle {
174        pub event_rx: mpsc::Receiver<CompositorEvent>,
175        pub command_tx: mpsc::Sender<CompositorCommand>,
176        pub socket_name: String,
177        pub thread: std::thread::JoinHandle<()>,
178        pub shutdown: Arc<AtomicBool>,
179    }
180
181    impl CompositorHandle {
182        /// Wake the compositor event loop immediately.
183        pub fn wake(&self) {}
184    }
185
186    pub fn spawn_compositor(
187        _verbose: bool,
188        _event_notify: Arc<dyn Fn() + Send + Sync>,
189        _gpu_device: &str,
190    ) -> CompositorHandle {
191        let (event_tx, event_rx) = mpsc::channel();
192        let (command_tx, _command_rx) = mpsc::channel();
193        let shutdown = Arc::new(AtomicBool::new(false));
194        // Drop the sender immediately so event_rx.recv() returns Err.
195        drop(event_tx);
196        CompositorHandle {
197            event_rx,
198            command_tx,
199            socket_name: String::new(),
200            thread: std::thread::spawn(|| {}),
201            shutdown,
202        }
203    }
204}
205
206#[cfg(not(target_os = "linux"))]
207pub use stub::*;