1#![allow(dead_code)]
2use {
3 std::cell::Cell,
4 crate::{
5 cx::Cx,
6 cursor::MouseCursor,
7 makepad_micro_serde::*,
8 makepad_math::dvec2,
9 window::CxWindowPool,
10 area::Area,
11 event::{
12 KeyEvent,
13 ScrollEvent,
14 MouseDownEvent,
15 MouseUpEvent,
16 MouseMoveEvent,
17 }
18 }
19};
20
21fn ref_array_to_array_of_refs<T, const N: usize>(ref_array: &[T; N]) -> [&T; N] {
23 let mut out_refs = std::mem::MaybeUninit::<[&T; N]>::uninit();
24 for (i, ref_elem) in ref_array.iter().enumerate() {
25 unsafe { *out_refs.as_mut_ptr().cast::<&T>().add(i) = ref_elem; }
26 }
27 unsafe { out_refs.assume_init() }
28}
29
30pub const SWAPCHAIN_IMAGE_COUNT: usize = match () {
31 _ if cfg!(target_os = "linux") => 3,
33 _ if cfg!(target_os = "macos") => 1,
34 _ if cfg!(target_os = "windows") => 2,
35 _ => 2,
36};
37
38#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
46pub struct Swapchain<I>
47 where I: Sized
49{
50 pub alloc_width: u32,
51 pub alloc_height: u32,
52 pub presentable_images: [PresentableImage<I>; SWAPCHAIN_IMAGE_COUNT],
53}
54
55impl Swapchain<()> {
56 pub fn new(alloc_width: u32, alloc_height: u32) -> Self {
57 let presentable_images = [(); SWAPCHAIN_IMAGE_COUNT].map(|()| PresentableImage {
58 id: PresentableImageId::alloc(),
59 image: (),
60 });
61 Self { alloc_width, alloc_height, presentable_images }
62 }
63}
64
65impl<I> Swapchain<I> {
66 pub fn get_image(&self, id: PresentableImageId) -> Option<&PresentableImage<I>> {
67 self.presentable_images.iter().find(|pi| pi.id == id)
68 }
69 pub fn images_as_ref(&self) -> Swapchain<&I> {
70 let Swapchain { alloc_width, alloc_height, ref presentable_images } = *self;
71 let presentable_images = ref_array_to_array_of_refs(presentable_images)
72 .map(|&PresentableImage { id, ref image }| PresentableImage { id, image });
73 Swapchain { alloc_width, alloc_height, presentable_images }
74 }
75 pub fn images_map<I2>(self, mut f: impl FnMut(PresentableImage<I>) -> I2) -> Swapchain<I2> {
76 let Swapchain { alloc_width, alloc_height, presentable_images } = self;
77 let presentable_images = presentable_images
78 .map(|pi| PresentableImage { id: pi.id, image: f(pi) });
79 Swapchain { alloc_width, alloc_height, presentable_images }
80 }
81}
82
83#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
85pub struct PresentableImage<I>
86 where I: Sized
88{
89 pub id: PresentableImageId,
90 pub image: I,
91}
92
93#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
97pub struct PresentableImageId {
98 origin_pid: u32,
100
101 per_origin_counter: u32,
106}
107
108impl PresentableImageId {
109 pub fn alloc() -> Self {
110 use std::sync::atomic::{AtomicU32, Ordering};
111
112 static COUNTER: AtomicU32 = AtomicU32::new(0);
113
114 Self {
115 origin_pid: std::process::id(),
116 per_origin_counter: COUNTER.fetch_add(1, Ordering::Relaxed),
117 }
118 }
119
120 pub fn as_u64(self) -> u64 {
121 let Self { origin_pid, per_origin_counter } = self;
122 (u64::from(origin_pid) << 32) | u64::from(per_origin_counter)
123 }
124
125 fn from_u64(pid_and_counter: u64) -> Self {
127 Self {
128 origin_pid: (pid_and_counter >> 32) as u32,
129 per_origin_counter: pid_and_counter as u32,
130 }
131 }
132}
133
134pub type SharedSwapchain = Swapchain<SharedPresentableImageOsHandle>;
135
136#[cfg(target_os = "linux")]
140pub type SharedPresentableImageOsHandle =
141 crate::os::linux::dma_buf::Image<aux_chan::AuxChannedImageFd>;
142
143#[cfg(target_os = "macos")]
148#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
149pub struct SharedPresentableImageOsHandle {
150 pub _dummy_for_macos: Option<u32>,
152}
153
154#[cfg(target_os = "windows")]
156pub type SharedPresentableImageOsHandle = u64;
158
159#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
161#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
162pub struct SharedPresentableImageOsHandle {
163 pub _dummy_for_unsupported: Option<u32>,
165}
166
167#[cfg(target_os = "linux")]
169pub mod aux_chan {
170 use super::*;
171 use crate::os::linux::ipc::{self as linux_ipc, FixedSizeEncoding};
172 use std::{io, os::fd::{AsFd, AsRawFd, FromRawFd, OwnedFd}};
173
174 fn io_error_other(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
176 io::Error::new(io::ErrorKind::Other, error)
177 }
178
179 pub type H2C = (PresentableImageId, OwnedFd);
181 pub type C2H = linux_ipc::Never;
182
183 impl FixedSizeEncoding<{u64::BYTE_LEN}, 0> for PresentableImageId {
184 fn encode(&self) -> ([u8; Self::BYTE_LEN], [std::os::fd::BorrowedFd<'_>; 0]) {
185 let (bytes, []) = self.as_u64().encode();
186 (bytes, [])
187 }
188 fn decode(bytes: [u8; Self::BYTE_LEN], fds: [OwnedFd; 0]) -> Self {
189 Self::from_u64(u64::decode(bytes, fds))
190 }
191 }
192
193 pub type HostEndpoint = linux_ipc::Channel<H2C, C2H>;
194 pub type ClientEndpoint = linux_ipc::Channel<C2H, H2C>;
195 pub fn make_host_and_client_endpoint_pair() -> io::Result<(HostEndpoint, ClientEndpoint)> {
196 linux_ipc::channel()
197 }
198
199 pub type InheritableClientEndpoint = linux_ipc::InheritableChannel<C2H, H2C>;
200 impl InheritableClientEndpoint {
201 pub fn extra_args_for_client_spawning(&self) -> [String; 1] {
202 [format!("--stdin-loop-aux-chan-fd={}", self.as_fd().as_raw_fd())]
203 }
204 pub fn from_process_args_in_client() -> io::Result<Self> {
205 for arg in std::env::args() {
206 if let Some(fd) = arg.strip_prefix("--stdin-loop-aux-chan-fd=") {
207 let raw_fd = fd.parse().map_err(io_error_other)?;
208 let owned_fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
209 return Ok(Self::from(owned_fd));
210 }
211 }
212 Err(io_error_other("missing --stdin-loop-aux-chan-fd argument"))
213 }
214 }
215
216 #[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
221 pub struct AuxChannedImageFd {
222 _private: Option<u32>,
224 }
225 type PrDmaBufImg<FD> = PresentableImage<crate::os::linux::dma_buf::Image<FD>>;
226 impl PrDmaBufImg<OwnedFd> {
227 pub fn send_fds_to_aux_chan(self, host_endpoint: &HostEndpoint)
228 -> io::Result<PrDmaBufImg<AuxChannedImageFd>>
229 {
230 let Self { id, image } = self;
231 let mut plane_idx = 0;
232 let mut success = Ok(());
233 let image = image.planes_fd_map(|fd| {
234 assert_eq!(plane_idx, 0, "only images with one DMA-BUF plane are supported");
235 plane_idx += 1;
236 if success.is_ok() {
237 success = host_endpoint.send((self.id, fd));
238 }
239 AuxChannedImageFd { _private: None }
240 });
241 success?;
242 Ok(PresentableImage { id, image })
243 }
244 }
245 impl PrDmaBufImg<AuxChannedImageFd> {
246 pub fn recv_fds_from_aux_chan(self, client_endpoint: &ClientEndpoint)
247 -> io::Result<PrDmaBufImg<OwnedFd>>
248 {
249 let Self { id, image } = self;
250 let mut plane_idx = 0;
251 let mut success = Ok(());
252 let image = image.planes_fd_map(|_| {
253 assert_eq!(plane_idx, 0, "only images with one DMA-BUF plane are supported");
254 plane_idx += 1;
255
256 client_endpoint.recv().and_then(|(recv_id, recv_fd)|
257 if recv_id != id {
258 Err(io_error_other(format!(
259 "recv_fds_from_aux_chan: ID mismatch \
260 (expected {id:?}, got {recv_id:?}",
261 )))
262 } else {
263 Ok(recv_fd)
264 }).map_err(|err| if success.is_ok() { success = Err(err); })
265 });
266 success?;
267 Ok(PresentableImage {
268 id,
269 image: image.planes_fd_map(Result::unwrap)
270 })
271 }
272 }
273}
274#[cfg(not(target_os = "linux"))]
275pub mod aux_chan {
276 use std::io;
277
278 #[derive(Clone)]
279 pub struct HostEndpoint { _private: () }
280 pub struct ClientEndpoint { _private: () }
281 pub fn make_host_and_client_endpoint_pair() -> io::Result<(HostEndpoint, ClientEndpoint)> {
282 Ok((HostEndpoint { _private: () }, ClientEndpoint { _private: () }))
283 }
284
285 pub struct InheritableClientEndpoint(ClientEndpoint);
286 impl ClientEndpoint {
287 pub fn into_child_process_inheritable(
288 self,
289 ) -> io::Result<InheritableClientEndpoint> {
290 Ok(InheritableClientEndpoint(self))
291 }
292 }
293 impl InheritableClientEndpoint {
294 pub fn into_uninheritable(self) -> io::Result<ClientEndpoint> {
295 Ok(self.0)
296 }
297 pub fn extra_args_for_client_spawning(&self) -> [String; 0] {
298 []
299 }
300 }
301}
302
303#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
304pub struct StdinMouseDown{
305 pub button: usize,
306 pub x: f64,
307 pub y: f64,
308 pub time: f64,
309}
310
311impl From<StdinMouseDown> for MouseDownEvent {
312 fn from(v: StdinMouseDown) -> Self {
313 Self{
314 abs: dvec2(v.x, v.y),
315 button: v.button,
316 window_id: CxWindowPool::id_zero(),
317 modifiers: Default::default(),
318 time: v.time,
319 handled: Cell::new(Area::Empty),
320 }
321 }
322}
323
324#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
325pub struct StdinMouseMove{
326 pub time: f64,
327 pub x: f64,
328 pub y: f64
329}
330
331impl From<StdinMouseMove> for MouseMoveEvent {
332 fn from(v: StdinMouseMove) -> Self {
333 Self{
334 abs: dvec2(v.x, v.y),
335 window_id: CxWindowPool::id_zero(),
336 modifiers: Default::default(),
337 time: v.time,
338 handled: Cell::new(Area::Empty),
339 }
340 }
341}
342
343#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
344pub struct StdinMouseUp{
345 pub time: f64,
346 pub button: usize,
347 pub x: f64,
348 pub y: f64
349}
350
351impl From<StdinMouseUp> for MouseUpEvent {
352 fn from(v: StdinMouseUp) -> Self {
353 Self{
354 abs: dvec2(v.x, v.y),
355 button: v.button,
356 window_id: CxWindowPool::id_zero(),
357 modifiers: Default::default(),
358 time: v.time,
359 }
360 }
361}
362
363
364#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
365pub struct StdinScroll{
366 pub time: f64,
367 pub sx: f64,
368 pub sy: f64,
369 pub x: f64,
370 pub y: f64,
371 pub is_mouse: bool,
372}
373
374impl From<StdinScroll> for ScrollEvent {
375 fn from(v: StdinScroll) -> Self {
376 Self{
377 abs: dvec2(v.x, v.y),
378 scroll: dvec2(v.sx, v.sy),
379 window_id: CxWindowPool::id_zero(),
380 modifiers: Default::default(),
381 handled_x: Cell::new(false),
382 handled_y: Cell::new(false),
383 is_mouse: v.is_mouse,
384 time: v.time,
385 }
386 }
387}
388
389#[derive(Clone, Debug, SerBin, DeBin, SerJson, DeJson)]
390pub enum HostToStdin{
391 Swapchain(SharedSwapchain),
392 WindowGeomChange {
393 dpi_factor: f64,
394 inner_width: f64,
397 inner_height: f64,
398 },
399 Tick{
400 buffer_id: u64,
401 frame: u64,
402 time: f64,
403 },
404 MouseDown(StdinMouseDown),
405 MouseUp(StdinMouseUp),
406 MouseMove(StdinMouseMove),
407 KeyDown(KeyEvent),
408 KeyUp(KeyEvent),
409 Scroll(StdinScroll),
410 ReloadFile{
411 file:String,
412 contents:String
413 },
414}
415
416#[derive(Copy, Clone, Debug, SerBin, DeBin, SerJson, DeJson)]
421pub struct PresentableDraw {
422 pub target_id: PresentableImageId,
423 pub width: u32,
424 pub height: u32,
425}
426
427#[derive(Clone, Debug, SerBin, DeBin, SerJson, DeJson)]
428pub enum StdinToHost {
429 ReadyToStart,
430 SetCursor(MouseCursor),
431 DrawCompleteAndFlip(PresentableDraw)
433}
434
435impl StdinToHost{
436 pub fn to_json(&self)->String{
437 let mut json = self.serialize_json();
438 json.push('\n');
439 json
440 }
441}
442
443impl HostToStdin{
444 pub fn to_json(&self)->String{
445 let mut json = self.serialize_json();
446 json.push('\n');
447 json
448 }
449}
450
451impl Cx {
452
453}