client.rs

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