1#![allow(dead_code)]
2use {
3 std::cell::Cell,
4 std::collections::HashMap,
5 crate::{
6 cx::Cx,
7 cursor::MouseCursor,
8 makepad_micro_serde::*,
9 makepad_math::{dvec2,DVec2},
10 window::WindowId,
11 area::Area,
12 event::{
13 KeyModifiers,
14 Event,
15 TextInputEvent,
16 TimerEvent,
17 KeyEvent,
18 ScrollEvent,
19 MouseButton,
20 MouseDownEvent,
21 MouseUpEvent,
22 MouseMoveEvent,
23 }
24 }
25};
26
27fn ref_array_to_array_of_refs<T, const N: usize>(ref_array: &[T; N]) -> [&T; N] {
29 let mut out_refs = std::mem::MaybeUninit::<[&T; N]>::uninit();
30 for (i, ref_elem) in ref_array.iter().enumerate() {
31 unsafe { *out_refs.as_mut_ptr().cast::<&T>().add(i) = ref_elem; }
32 }
33 unsafe { out_refs.assume_init() }
34}
35
36pub const SWAPCHAIN_IMAGE_COUNT: usize = match () {
37 _ if cfg!(target_os = "linux") => 3,
39 _ if cfg!(target_os = "macos") => 1,
40 _ if cfg!(target_os = "windows") => 2,
41 _ => 2,
42};
43
44#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
52pub struct Swapchain<I>
53 where I: Sized
55{
56 pub window_id: usize,
57 pub alloc_width: u32,
58 pub alloc_height: u32,
59 pub presentable_images: [PresentableImage<I>; SWAPCHAIN_IMAGE_COUNT],
60}
61
62impl Swapchain<()> {
63 pub fn new(window_id: usize, alloc_width: u32, alloc_height: u32) -> Self {
64 let presentable_images = [(); SWAPCHAIN_IMAGE_COUNT].map(|()| PresentableImage {
65 id: PresentableImageId::alloc(),
66 image: (),
67 });
68 Self { window_id, alloc_width, alloc_height, presentable_images }
69 }
70}
71
72impl<I> Swapchain<I> {
73 pub fn get_image(&self, id: PresentableImageId) -> Option<&PresentableImage<I>> {
74 self.presentable_images.iter().find(|pi| pi.id == id)
75 }
76 pub fn images_as_ref(&self) -> Swapchain<&I> {
77 let Swapchain { window_id, alloc_width, alloc_height, ref presentable_images } = *self;
78 let presentable_images = ref_array_to_array_of_refs(presentable_images)
79 .map(|&PresentableImage { id, ref image }| PresentableImage { id, image });
80 Swapchain { window_id, alloc_width, alloc_height, presentable_images }
81 }
82 pub fn images_map<I2>(self, mut f: impl FnMut(PresentableImage<I>) -> I2) -> Swapchain<I2> {
83 let Swapchain { window_id, alloc_width, alloc_height, presentable_images } = self;
84 let presentable_images = presentable_images
85 .map(|pi| PresentableImage { id: pi.id, image: f(pi) });
86 Swapchain { window_id, alloc_width, alloc_height, presentable_images }
87 }
88}
89
90#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
92pub struct PresentableImage<I>
93 where I: Sized
95{
96 pub id: PresentableImageId,
97 pub image: I,
98}
99
100#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
104pub struct PresentableImageId {
105 origin_pid: u32,
107
108 per_origin_counter: u32,
113}
114
115impl PresentableImageId {
116 pub fn alloc() -> Self {
117 use std::sync::atomic::{AtomicU32, Ordering};
118
119 static COUNTER: AtomicU32 = AtomicU32::new(0);
120
121 Self {
122 origin_pid: std::process::id(),
123 per_origin_counter: COUNTER.fetch_add(1, Ordering::Relaxed),
124 }
125 }
126
127 pub fn as_u64(self) -> u64 {
128 let Self { origin_pid, per_origin_counter } = self;
129 (u64::from(origin_pid) << 32) | u64::from(per_origin_counter)
130 }
131
132 fn from_u64(pid_and_counter: u64) -> Self {
134 Self {
135 origin_pid: (pid_and_counter >> 32) as u32,
136 per_origin_counter: pid_and_counter as u32,
137 }
138 }
139}
140
141pub type SharedSwapchain = Swapchain<SharedPresentableImageOsHandle>;
142
143#[cfg(all(target_os = "linux", not(target_env="ohos")))]
147pub type SharedPresentableImageOsHandle =
148 crate::os::linux::dma_buf::Image<aux_chan::AuxChannedImageFd>;
149
150#[cfg(target_os = "macos")]
155#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
156pub struct SharedPresentableImageOsHandle {
157 pub _dummy_for_macos: Option<u32>,
159}
160
161#[cfg(target_os = "windows")]
163pub type SharedPresentableImageOsHandle = u64;
165
166#[cfg(not(any(all(target_os = "linux", not(target_env="ohos")), target_os = "macos", target_os = "windows")))]
168#[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
169pub struct SharedPresentableImageOsHandle {
170 pub _dummy_for_unsupported: Option<u32>,
172}
173
174#[cfg(all(target_os = "linux", not(target_env="ohos")))]
176pub mod aux_chan {
177 use super::*;
178 use crate::os::linux::ipc::{self as linux_ipc, FixedSizeEncoding};
179 use std::{io, os::fd::{AsFd, AsRawFd, FromRawFd, OwnedFd}};
180
181 fn io_error_other(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
183 io::Error::new(io::ErrorKind::Other, error)
184 }
185
186 pub type H2C = (PresentableImageId, OwnedFd);
188 pub type C2H = linux_ipc::Never;
189
190 impl FixedSizeEncoding<{u64::BYTE_LEN}, 0> for PresentableImageId {
191 fn encode(&self) -> ([u8; Self::BYTE_LEN], [std::os::fd::BorrowedFd<'_>; 0]) {
192 let (bytes, []) = self.as_u64().encode();
193 (bytes, [])
194 }
195 fn decode(bytes: [u8; Self::BYTE_LEN], fds: [OwnedFd; 0]) -> Self {
196 Self::from_u64(u64::decode(bytes, fds))
197 }
198 }
199
200 pub type HostEndpoint = linux_ipc::Channel<H2C, C2H>;
201 pub type ClientEndpoint = linux_ipc::Channel<C2H, H2C>;
202 pub fn make_host_and_client_endpoint_pair() -> io::Result<(HostEndpoint, ClientEndpoint)> {
203 linux_ipc::channel()
204 }
205
206 pub type InheritableClientEndpoint = linux_ipc::InheritableChannel<C2H, H2C>;
207 impl InheritableClientEndpoint {
208 pub fn extra_args_for_client_spawning(&self) -> [String; 1] {
209 [format!("--stdin-loop-aux-chan-fd={}", self.as_fd().as_raw_fd())]
210 }
211 pub fn from_process_args_in_client() -> io::Result<Self> {
212 for arg in std::env::args() {
213 if let Some(fd) = arg.strip_prefix("--stdin-loop-aux-chan-fd=") {
214 let raw_fd = fd.parse().map_err(io_error_other)?;
215 let owned_fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
216 return Ok(Self::from(owned_fd));
217 }
218 }
219 Err(io_error_other("missing --stdin-loop-aux-chan-fd argument"))
220 }
221 }
222
223 #[derive(Copy, Clone, Debug, PartialEq, SerBin, DeBin, SerJson, DeJson)]
228 pub struct AuxChannedImageFd {
229 _private: Option<u32>,
231 }
232 type PrDmaBufImg<FD> = PresentableImage<crate::os::linux::dma_buf::Image<FD>>;
233 impl PrDmaBufImg<OwnedFd> {
234 pub fn send_fds_to_aux_chan(self, host_endpoint: &HostEndpoint)
235 -> io::Result<PrDmaBufImg<AuxChannedImageFd>>
236 {
237 let Self { id, image } = self;
238 let mut plane_idx = 0;
239 let mut success = Ok(());
240 let image = image.planes_fd_map(|fd| {
241 assert_eq!(plane_idx, 0, "only images with one DMA-BUF plane are supported");
242 plane_idx += 1;
243 if success.is_ok() {
244 success = host_endpoint.send((self.id, fd));
245 }
246 AuxChannedImageFd { _private: None }
247 });
248 success?;
249 Ok(PresentableImage { id, image })
250 }
251 }
252 impl PrDmaBufImg<AuxChannedImageFd> {
253 pub fn recv_fds_from_aux_chan(self, client_endpoint: &ClientEndpoint)
254 -> io::Result<PrDmaBufImg<OwnedFd>>
255 {
256 let Self { id, image } = self;
257 let mut plane_idx = 0;
258 let mut success = Ok(());
259 let image = image.planes_fd_map(|_| {
260 assert_eq!(plane_idx, 0, "only images with one DMA-BUF plane are supported");
261 plane_idx += 1;
262
263 client_endpoint.recv().and_then(|(recv_id, recv_fd)|
264 if recv_id != id {
265 Err(io_error_other(format!(
266 "recv_fds_from_aux_chan: ID mismatch \
267 (expected {id:?}, got {recv_id:?}",
268 )))
269 } else {
270 Ok(recv_fd)
271 }).map_err(|err| if success.is_ok() { success = Err(err); })
272 });
273 success?;
274 Ok(PresentableImage {
275 id,
276 image: image.planes_fd_map(Result::unwrap)
277 })
278 }
279 }
280}
281#[cfg(not(all(target_os = "linux", not(target_env="ohos"))))]
282pub mod aux_chan {
283 use std::io;
284
285 #[derive(Clone)]
286 pub struct HostEndpoint { _private: () }
287 pub struct ClientEndpoint { _private: () }
288 pub fn make_host_and_client_endpoint_pair() -> io::Result<(HostEndpoint, ClientEndpoint)> {
289 Ok((HostEndpoint { _private: () }, ClientEndpoint { _private: () }))
290 }
291
292 pub struct InheritableClientEndpoint(ClientEndpoint);
293 impl ClientEndpoint {
294 pub fn into_child_process_inheritable(
295 self,
296 ) -> io::Result<InheritableClientEndpoint> {
297 Ok(InheritableClientEndpoint(self))
298 }
299 }
300 impl InheritableClientEndpoint {
301 pub fn into_uninheritable(self) -> io::Result<ClientEndpoint> {
302 Ok(self.0)
303 }
304 pub fn extra_args_for_client_spawning(&self) -> [String; 0] {
305 []
306 }
307 }
308}
309
310
311#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
312pub struct StdinKeyModifiers{
313 pub shift: bool,
314 pub control: bool,
315 pub alt: bool,
316 pub logo: bool
317}
318
319impl StdinKeyModifiers{
320 pub fn into_key_modifiers(&self)->KeyModifiers{
321 KeyModifiers{
322 shift: self.shift,
323 control: self.control,
324 alt: self.alt,
325 logo: self.logo,
326 }
327 }
328 pub fn from_key_modifiers(km:&KeyModifiers)->Self{
329 Self{
330 shift: km.shift,
331 control: km.control,
332 alt: km.alt,
333 logo: km.logo,
334 }
335 }
336}
337
338
339#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
340pub struct StdinMouseDown {
341 pub button_raw_bits: u32,
342 pub x: f64,
343 pub y: f64,
344 pub time: f64,
345 pub modifiers: StdinKeyModifiers
346}
347
348impl StdinMouseDown {
349 pub fn into_event(self, window_id: WindowId, pos: DVec2) -> MouseDownEvent {
350 MouseDownEvent {
351 abs: dvec2(self.x - pos.x, self.y - pos.y),
352 button: MouseButton::from_bits_retain(self.button_raw_bits),
353 window_id,
354 modifiers: self.modifiers.into_key_modifiers(),
355 time: self.time,
356 handled: Cell::new(Area::Empty),
357 }
358 }
359}
360
361#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
362pub struct StdinMouseMove{
363 pub time: f64,
364 pub x: f64,
365 pub y: f64,
366 pub modifiers: StdinKeyModifiers
367}
368
369impl StdinMouseMove {
370 pub fn into_event(self, window_id: WindowId, pos: DVec2) -> MouseMoveEvent {
371 MouseMoveEvent{
372 abs: dvec2(self.x - pos.x, self.y - pos.y),
373 window_id,
374 modifiers: self.modifiers.into_key_modifiers(),
375 time: self.time,
376 handled: Cell::new(Area::Empty),
377 }
378 }
379}
380
381#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
382pub struct StdinMouseUp {
383 pub time: f64,
384 pub button_raw_bits: u32,
385 pub x: f64,
386 pub y: f64,
387 pub modifiers: StdinKeyModifiers
388}
389
390#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
391pub struct StdinTextInput{
392 pub time: f64,
393 pub window_id: usize,
394 pub raw_button: usize,
395 pub x: f64,
396 pub y: f64
397}
398
399impl StdinMouseUp {
400 pub fn into_event(self, window_id: WindowId, pos: DVec2) -> MouseUpEvent {
401 MouseUpEvent {
402 abs: dvec2(self.x - pos.x, self.y - pos.y),
403 button: MouseButton::from_bits_retain(self.button_raw_bits),
404 window_id,
405 modifiers: self.modifiers.into_key_modifiers(),
406 time: self.time,
407 }
408 }
409}
410
411
412#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
413pub struct StdinScroll{
414 pub time: f64,
415 pub sx: f64,
416 pub sy: f64,
417 pub x: f64,
418 pub y: f64,
419 pub is_mouse: bool,
420 pub modifiers: StdinKeyModifiers
421}
422
423impl StdinScroll {
424 pub fn into_event(self, window_id: WindowId, pos: DVec2) -> ScrollEvent {
425 ScrollEvent{
426 abs: dvec2(self.x - pos.x, self.y - pos.y),
427 scroll: dvec2(self.sx, self.sy),
428 window_id,
429 modifiers: self.modifiers.into_key_modifiers(),
430 handled_x: Cell::new(false),
431 handled_y: Cell::new(false),
432 is_mouse: self.is_mouse,
433 time: self.time,
434 }
435 }
436}
437
438#[derive(Clone, Debug, SerBin, DeBin, SerJson, DeJson)]
439pub enum HostToStdin{
440 Swapchain(SharedSwapchain),
441 WindowGeomChange {
442 dpi_factor: f64,
443 window_id: usize,
444 left: f64,
447 top: f64,
448 width: f64,
449 height: f64,
450 },
451 Tick,
452 MouseDown(StdinMouseDown),
461 MouseUp(StdinMouseUp),
462 MouseMove(StdinMouseMove),
463 KeyDown(KeyEvent),
464 KeyUp(KeyEvent),
465 TextInput(TextInputEvent),
466 Scroll(StdinScroll),
467 }
472
473#[derive(Copy, Clone, Debug, SerBin, DeBin, SerJson, DeJson)]
478pub struct PresentableDraw {
479 pub window_id: usize,
480 pub target_id: PresentableImageId,
481 pub width: u32,
482 pub height: u32,
483}
484
485#[repr(usize)]
486pub enum WindowKindId{
487 Main = 0,
488 Design = 1,
489 Outline = 2
490}
491
492impl WindowKindId{
493 pub fn from_usize(d:usize)->Self{
494 match d{
495 0=>Self::Main,
496 1=>Self::Design,
497 2=>Self::Outline,
498 _=>panic!()
499 }
500 }
501}
502
503#[derive(Clone, Debug, SerBin, DeBin, SerJson, DeJson)]
504pub enum StdinToHost {
505 CreateWindow{window_id: usize, kind_id:usize},
506 ReadyToStart,
507 SetCursor(MouseCursor),
508 DrawCompleteAndFlip(PresentableDraw)
510}
511
512impl StdinToHost{
513 pub fn to_json(&self)->String{
514 let mut json = self.serialize_json();
515 json.push('\n');
516 json
517 }
518}
519
520impl HostToStdin{
521 pub fn to_json(&self)->String{
522 let mut json = self.serialize_json();
523 json.push('\n');
524 json
525 }
526}
527
528impl Cx {
529
530}
531
532
533use std::time::Instant;
534use std::time::Duration;
535
536pub struct PollTimer {
537 pub start_time: Instant,
538 pub interval: Duration,
539 pub repeats: bool,
540 pub step: u64,
541}
542
543impl PollTimer {
544 pub fn new(interval_s: f64, repeats: bool) -> Self {
545 Self {
546 start_time: Instant::now(),
547 interval: Duration::from_secs_f64(interval_s),
548 repeats,
549 step: 0,
550 }
551 }
552}
553
554pub struct PollTimers{
555 pub timers: HashMap<u64, PollTimer>,
556 pub time_start: Instant,
557 pub last_time: Instant,
558}
559impl Default for PollTimers{
560 fn default()->Self{
561 Self{
562 time_start: Instant::now(),
563 last_time: Instant::now(),
564 timers: Default::default()
565 }
566 }
567}
568impl PollTimers{
569
570 pub fn time_now(&self) -> f64 {
571 let time_now = Instant::now(); (time_now.duration_since(self.time_start)).as_secs_f64()
573 }
574
575 pub fn get_dispatch(&mut self)->Vec<Event>{
576 let mut to_be_dispatched = Vec::with_capacity(self.timers.len());
577 let mut to_be_removed = Vec::with_capacity(self.timers.len());
578 let now = Instant::now();
579 let time = self.time_now();
580 for (id, timer) in self.timers.iter_mut() {
581 let elapsed_time = now - timer.start_time;
582 let next_due_time = Duration::from_nanos(timer.interval.as_nanos() as u64 * (timer.step + 1));
583
584 if elapsed_time > next_due_time {
585
586 to_be_dispatched.push(Event::Timer(TimerEvent {timer_id: *id, time:Some(time)}));
587 if timer.repeats {
588 timer.step += 1;
589 } else {
590 to_be_removed.push(*id);
591 }
592 }
593 }
594
595 for id in to_be_removed {
596 self.timers.remove(&id);
597 }
598
599 self.last_time = now;
600 to_be_dispatched
601 }
602}