client.rs

  1use std::cell::RefCell;
  2use std::rc::Rc;
  3
  4use calloop::{EventLoop, LoopHandle};
  5
  6use util::ResultExt;
  7
  8use crate::platform::linux::LinuxClient;
  9use crate::platform::{LinuxCommon, PlatformWindow};
 10use crate::{AnyWindowHandle, CursorStyle, DisplayId, PlatformDisplay, WindowParams};
 11
 12pub struct HeadlessClientState {
 13    pub(crate) _loop_handle: LoopHandle<'static, HeadlessClient>,
 14    pub(crate) event_loop: Option<calloop::EventLoop<'static, HeadlessClient>>,
 15    pub(crate) common: LinuxCommon,
 16}
 17
 18#[derive(Clone)]
 19pub(crate) struct HeadlessClient(Rc<RefCell<HeadlessClientState>>);
 20
 21impl HeadlessClient {
 22    pub(crate) fn new() -> Self {
 23        let event_loop = EventLoop::try_new().unwrap();
 24
 25        let (common, main_receiver) = LinuxCommon::new(event_loop.get_signal());
 26
 27        let handle = event_loop.handle();
 28
 29        handle
 30            .insert_source(main_receiver, |event, _, _: &mut HeadlessClient| {
 31                if let calloop::channel::Event::Msg(runnable) = event {
 32                    runnable.run();
 33                }
 34            })
 35            .ok();
 36
 37        HeadlessClient(Rc::new(RefCell::new(HeadlessClientState {
 38            event_loop: Some(event_loop),
 39            _loop_handle: handle,
 40            common,
 41        })))
 42    }
 43}
 44
 45impl LinuxClient for HeadlessClient {
 46    fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R {
 47        f(&mut self.0.borrow_mut().common)
 48    }
 49
 50    fn keyboard_layout(&self) -> String {
 51        "unknown".to_string()
 52    }
 53
 54    fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
 55        vec![]
 56    }
 57
 58    fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
 59        None
 60    }
 61
 62    fn display(&self, _id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
 63        None
 64    }
 65
 66    fn active_window(&self) -> Option<AnyWindowHandle> {
 67        None
 68    }
 69
 70    fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
 71        None
 72    }
 73
 74    fn open_window(
 75        &self,
 76        _handle: AnyWindowHandle,
 77        _params: WindowParams,
 78    ) -> anyhow::Result<Box<dyn PlatformWindow>> {
 79        Err(anyhow::anyhow!(
 80            "neither DISPLAY nor WAYLAND_DISPLAY is set. You can run in headless mode"
 81        ))
 82    }
 83
 84    fn compositor_name(&self) -> &'static str {
 85        "headless"
 86    }
 87
 88    fn set_cursor_style(&self, _style: CursorStyle) {}
 89
 90    fn open_uri(&self, _uri: &str) {}
 91
 92    fn reveal_path(&self, _path: std::path::PathBuf) {}
 93
 94    fn write_to_primary(&self, _item: crate::ClipboardItem) {}
 95
 96    fn write_to_clipboard(&self, _item: crate::ClipboardItem) {}
 97
 98    fn read_from_primary(&self) -> Option<crate::ClipboardItem> {
 99        None
100    }
101
102    fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
103        None
104    }
105
106    fn run(&self) {
107        let mut event_loop = self
108            .0
109            .borrow_mut()
110            .event_loop
111            .take()
112            .expect("App is already running");
113
114        event_loop.run(None, &mut self.clone(), |_| {}).log_err();
115    }
116}