use super::CustomEvent; use crate::ipc::{new_listener, Connection, Data}; #[cfg(any(target_os = "windows", target_os = "macos"))] use hbb_common::tokio::sync::mpsc::unbounded_channel; #[cfg(any(target_os = "windows", target_os = "linux"))] use hbb_common::ResultType; use hbb_common::{ allow_err, log, tokio::{self, sync::mpsc::UnboundedReceiver}, }; use lazy_static::lazy_static; use std::sync::RwLock; use std::time::{Duration, Instant}; #[cfg(any(target_os = "windows", target_os = "macos"))] use tao::event_loop::EventLoopProxy; #[cfg(target_os = "linux")] use winit::event_loop::EventLoopProxy; lazy_static! { pub(super) static ref EVENT_PROXY: RwLock>> = RwLock::new(None); } const RIPPLE_DURATION: Duration = Duration::from_millis(500); #[cfg(target_os = "macos")] type RippleFloat = f64; #[cfg(any(target_os = "windows", target_os = "linux"))] type RippleFloat = f32; #[cfg(target_os = "linux")] pub use super::linux::run; #[cfg(any(target_os = "windows", target_os = "macos"))] pub fn run() { let (tx_exit, rx_exit) = unbounded_channel(); std::thread::spawn(move || { start_ipc(rx_exit); }); if let Err(e) = super::create_event_loop() { log::error!("Failed to create event loop: {}", e); tx_exit.send(()).ok(); return; } } #[tokio::main(flavor = "current_thread")] pub(super) async fn start_ipc(mut rx_exit: UnboundedReceiver<()>) { match new_listener("_whiteboard").await { Ok(mut incoming) => loop { tokio::select! { _ = rx_exit.recv() => { log::info!("Exiting IPC"); break; } res = incoming.next() => match res { Some(result) => match result { Ok(stream) => { log::debug!("Got new connection"); tokio::spawn(handle_new_stream(Connection::new(stream))); } Err(err) => { log::error!("Couldn't get whiteboard client: {:?}", err); } }, None => { log::error!("Failed to get whiteboard client"); } } } }, Err(err) => { log::error!("Failed to start whiteboard ipc server: {}", err); } } } async fn handle_new_stream(mut conn: Connection) { loop { tokio::select! { res = conn.next() => { match res { Err(err) => { log::info!("whiteboard ipc connection closed: {}", err); break; } Ok(Some(data)) => { match data { Data::Whiteboard((k, evt)) => { if matches!(evt, CustomEvent::Exit) { log::info!("whiteboard ipc connection closed"); break; } else { EVENT_PROXY.read().unwrap().as_ref().map(|ep| { allow_err!(ep.send_event((k, evt))); }); } } _ => {} } } Ok(None) => { log::info!("whiteboard ipc connection closed"); break; } } } } } EVENT_PROXY.read().unwrap().as_ref().map(|ep| { allow_err!(ep.send_event(("".to_string(), CustomEvent::Exit))); }); } #[cfg(any(target_os = "windows", target_os = "linux"))] pub(super) fn get_displays_rect() -> ResultType<(i32, i32, u32, u32)> { let displays = crate::server::display_service::try_get_displays()?; let mut min_x = i32::MAX; let mut min_y = i32::MAX; let mut max_x = i32::MIN; let mut max_y = i32::MIN; for display in displays { let (x, y) = (display.origin().0 as i32, display.origin().1 as i32); let (w, h) = (display.width() as i32, display.height() as i32); min_x = min_x.min(x); min_y = min_y.min(y); max_x = max_x.max(x + w); max_y = max_y.max(y + h); } let (x, y) = (min_x, min_y); let (w, h) = ((max_x - min_x) as u32, (max_y - min_y) as u32); Ok((x, y, w, h)) } #[inline] pub(super) fn argb_to_rgba(argb: u32) -> (u8, u8, u8, u8) { ( (argb >> 16 & 0xFF) as u8, (argb >> 8 & 0xFF) as u8, (argb & 0xFF) as u8, (argb >> 24 & 0xFF) as u8, ) } pub(super) struct Ripple { pub x: RippleFloat, pub y: RippleFloat, pub start_time: Instant, } impl Ripple { #[inline] pub fn retain_active(ripples: &mut Vec) { ripples.retain(|r| r.start_time.elapsed() < RIPPLE_DURATION); } pub fn get_radius_alpha(&self) -> (RippleFloat, RippleFloat) { let elapsed = self.start_time.elapsed(); #[cfg(target_os = "macos")] let progress = (elapsed.as_secs_f64() / RIPPLE_DURATION.as_secs_f64()).min(1.0); #[cfg(any(target_os = "windows", target_os = "linux"))] let progress = (elapsed.as_secs_f32() / RIPPLE_DURATION.as_secs_f32()).min(1.0); #[cfg(target_os = "macos")] let radius = 25.0 * progress; #[cfg(any(target_os = "windows", target_os = "linux"))] let radius = 45.0 * progress; let alpha = 1.0 - progress; (radius, alpha) } }