use std::cell::RefCell; use std::rc::Rc; use anyhow::anyhow; use calloop::{EventLoop, LoopHandle}; use futures::channel::oneshot; use util::ResultExt; use crate::platform::linux::LinuxClient; use crate::platform::{LinuxCommon, PlatformWindow}; use crate::{ AnyWindowHandle, CursorStyle, DisplayId, PlatformDisplay, ScreenCaptureSource, WindowParams, }; pub struct HeadlessClientState { pub(crate) _loop_handle: LoopHandle<'static, HeadlessClient>, pub(crate) event_loop: Option>, pub(crate) common: LinuxCommon, } #[derive(Clone)] pub(crate) struct HeadlessClient(Rc>); impl HeadlessClient { pub(crate) fn new() -> Self { let event_loop = EventLoop::try_new().unwrap(); let (common, main_receiver) = LinuxCommon::new(event_loop.get_signal()); let handle = event_loop.handle(); handle .insert_source(main_receiver, |event, _, _: &mut HeadlessClient| { if let calloop::channel::Event::Msg(runnable) = event { runnable.run(); } }) .ok(); HeadlessClient(Rc::new(RefCell::new(HeadlessClientState { event_loop: Some(event_loop), _loop_handle: handle, common, }))) } } impl LinuxClient for HeadlessClient { fn with_common(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R { f(&mut self.0.borrow_mut().common) } fn keyboard_layout(&self) -> String { "unknown".to_string() } fn displays(&self) -> Vec> { vec![] } fn primary_display(&self) -> Option> { None } fn display(&self, _id: DisplayId) -> Option> { None } fn is_screen_capture_supported(&self) -> bool { false } fn screen_capture_sources( &self, ) -> oneshot::Receiver>>> { let (mut tx, rx) = oneshot::channel(); tx.send(Err(anyhow!( "Headless mode does not support screen capture." ))) .ok(); rx } fn active_window(&self) -> Option { None } fn window_stack(&self) -> Option> { None } fn open_window( &self, _handle: AnyWindowHandle, _params: WindowParams, ) -> anyhow::Result> { Err(anyhow::anyhow!( "neither DISPLAY nor WAYLAND_DISPLAY is set. You can run in headless mode" )) } fn compositor_name(&self) -> &'static str { "headless" } fn set_cursor_style(&self, _style: CursorStyle) {} fn open_uri(&self, _uri: &str) {} fn reveal_path(&self, _path: std::path::PathBuf) {} fn write_to_primary(&self, _item: crate::ClipboardItem) {} fn write_to_clipboard(&self, _item: crate::ClipboardItem) {} fn read_from_primary(&self) -> Option { None } fn read_from_clipboard(&self) -> Option { None } fn run(&self) { let mut event_loop = self .0 .borrow_mut() .event_loop .take() .expect("App is already running"); event_loop.run(None, &mut self.clone(), |_| {}).log_err(); } }