Skip to main content

blit_compositor/
lib.rs

1mod positioner;
2
3#[cfg(target_os = "linux")]
4mod imp;
5#[cfg(target_os = "linux")]
6mod render;
7#[cfg(target_os = "linux")]
8mod vulkan_render;
9#[cfg(target_os = "linux")]
10pub use imp::*;
11
12#[cfg(not(target_os = "linux"))]
13mod stub {
14    use std::sync::Arc;
15    use std::sync::atomic::AtomicBool;
16    use std::sync::mpsc;
17
18    pub mod drm_fourcc {
19        pub const ARGB8888: u32 = u32::from_le_bytes(*b"AR24");
20        pub const XRGB8888: u32 = u32::from_le_bytes(*b"XR24");
21        pub const ABGR8888: u32 = u32::from_le_bytes(*b"AB24");
22        pub const XBGR8888: u32 = u32::from_le_bytes(*b"XB24");
23        pub const NV12: u32 = u32::from_le_bytes(*b"NV12");
24    }
25
26    /// Placeholder for `std::os::fd::OwnedFd` on non-Unix platforms.
27    #[derive(Debug)]
28    pub struct OwnedFd(());
29
30    #[derive(Clone)]
31    pub enum PixelData {
32        Bgra(Arc<Vec<u8>>),
33        Rgba(Arc<Vec<u8>>),
34        Nv12 {
35            data: Arc<Vec<u8>>,
36            y_stride: usize,
37            uv_stride: usize,
38        },
39        DmaBuf {
40            fd: Arc<OwnedFd>,
41            fourcc: u32,
42            modifier: u64,
43            stride: u32,
44            offset: u32,
45        },
46        VaSurface {
47            surface_id: u32,
48            va_display: usize,
49            _fd: Arc<OwnedFd>,
50        },
51    }
52
53    #[derive(Clone)]
54    pub struct PixelLayer {
55        pub x: i32,
56        pub y: i32,
57        pub width: u32,
58        pub height: u32,
59        pub pixels: PixelData,
60    }
61
62    impl PixelData {
63        pub fn to_rgba(&self, _width: u32, _height: u32) -> Vec<u8> {
64            match self {
65                PixelData::Rgba(data) => data.as_ref().clone(),
66                PixelData::Bgra(data) => {
67                    let mut rgba = Vec::with_capacity(data.len());
68                    for px in data.chunks_exact(4) {
69                        rgba.extend_from_slice(&[px[2], px[1], px[0], px[3]]);
70                    }
71                    rgba
72                }
73                _ => Vec::new(),
74            }
75        }
76
77        pub fn is_empty(&self) -> bool {
78            match self {
79                PixelData::Bgra(v) | PixelData::Rgba(v) => v.is_empty(),
80                PixelData::Nv12 { data, .. } => data.is_empty(),
81                PixelData::DmaBuf { .. } | PixelData::VaSurface { .. } => false,
82            }
83        }
84
85        pub fn is_dmabuf(&self) -> bool {
86            matches!(self, PixelData::DmaBuf { .. })
87        }
88
89        pub fn is_va_surface(&self) -> bool {
90            matches!(self, PixelData::VaSurface { .. })
91        }
92    }
93
94    #[derive(Clone)]
95    pub enum CursorImage {
96        Named(String),
97        Custom {
98            hotspot_x: u16,
99            hotspot_y: u16,
100            width: u16,
101            height: u16,
102            rgba: Vec<u8>,
103        },
104        Hidden,
105    }
106
107    pub enum CompositorEvent {
108        SurfaceCreated {
109            surface_id: u16,
110            title: String,
111            app_id: String,
112            parent_id: u16,
113            width: u16,
114            height: u16,
115        },
116        SurfaceDestroyed {
117            surface_id: u16,
118        },
119        SurfaceCommit {
120            surface_id: u16,
121            width: u32,
122            height: u32,
123            pixels: PixelData,
124        },
125        SurfaceTitle {
126            surface_id: u16,
127            title: String,
128        },
129        SurfaceAppId {
130            surface_id: u16,
131            app_id: String,
132        },
133        SurfaceResized {
134            surface_id: u16,
135            width: u16,
136            height: u16,
137        },
138        ClipboardContent {
139            surface_id: u16,
140            mime_type: String,
141            data: Vec<u8>,
142        },
143        SurfaceCursor {
144            surface_id: u16,
145            cursor: CursorImage,
146        },
147    }
148
149    pub enum CompositorCommand {
150        KeyInput {
151            surface_id: u16,
152            keycode: u32,
153            pressed: bool,
154        },
155        PointerMotion {
156            surface_id: u16,
157            x: f64,
158            y: f64,
159        },
160        PointerButton {
161            surface_id: u16,
162            button: u32,
163            pressed: bool,
164        },
165        PointerAxis {
166            surface_id: u16,
167            axis: u8,
168            value: f64,
169        },
170        SurfaceResize {
171            surface_id: u16,
172            width: u16,
173            height: u16,
174            scale_120: u16,
175        },
176        SurfaceFocus {
177            surface_id: u16,
178        },
179        SurfaceClose {
180            surface_id: u16,
181        },
182        ClipboardOffer {
183            mime_type: String,
184            data: Vec<u8>,
185        },
186        /// List available clipboard MIME types.
187        ClipboardListMimes {
188            reply: mpsc::SyncSender<Vec<String>>,
189        },
190        /// Read clipboard content for a specific MIME type.
191        ClipboardGet {
192            mime_type: String,
193            reply: mpsc::SyncSender<Option<Vec<u8>>>,
194        },
195        /// Composed text from the browser (e.g. IME or shifted characters
196        /// that don't match the compositor's US-QWERTY keymap).  The compositor
197        /// synthesises evdev key sequences for ASCII chars and uses
198        /// zwp_text_input_v3 commit_string for non-ASCII.
199        TextInput {
200            text: String,
201        },
202        ReleaseKeys {
203            keycodes: Vec<u32>,
204        },
205        Capture {
206            surface_id: u16,
207            /// Render scale in 120ths. 0 = current output scale.
208            scale_120: u16,
209            reply: mpsc::SyncSender<Option<(u32, u32, Vec<u8>)>>,
210        },
211        /// Fire pending wl_surface.frame callbacks for a surface so the
212        /// client will paint and commit its next frame.  Send this when
213        /// the server is ready to consume a new frame (streaming or capture).
214        RequestFrame {
215            surface_id: u16,
216        },
217        SetExternalOutputBuffers {
218            buffers: Vec<ExternalOutputBuffer>,
219        },
220        Shutdown,
221    }
222
223    pub struct ExternalOutputBuffer {
224        pub fd: Arc<OwnedFd>,
225        pub fourcc: u32,
226        pub modifier: u64,
227        pub stride: u32,
228        pub offset: u32,
229        pub width: u32,
230        pub height: u32,
231        pub va_surface_id: u32,
232        pub va_display: usize,
233    }
234
235    pub struct CompositorHandle {
236        pub event_rx: mpsc::Receiver<CompositorEvent>,
237        pub command_tx: mpsc::Sender<CompositorCommand>,
238        pub socket_name: String,
239        pub thread: std::thread::JoinHandle<()>,
240        pub shutdown: Arc<AtomicBool>,
241    }
242
243    impl CompositorHandle {
244        /// Wake the compositor event loop immediately.
245        pub fn wake(&self) {}
246    }
247
248    pub fn spawn_compositor(
249        _verbose: bool,
250        _event_notify: Arc<dyn Fn() + Send + Sync>,
251        _gpu_device: &str,
252    ) -> CompositorHandle {
253        let (event_tx, event_rx) = mpsc::channel();
254        let (command_tx, _command_rx) = mpsc::channel();
255        let shutdown = Arc::new(AtomicBool::new(false));
256        // Drop the sender immediately so event_rx.recv() returns Err.
257        drop(event_tx);
258        CompositorHandle {
259            event_rx,
260            command_tx,
261            socket_name: String::new(),
262            thread: std::thread::spawn(|| {}),
263            shutdown,
264        }
265    }
266}
267
268#[cfg(not(target_os = "linux"))]
269pub use stub::*;