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(Box::new(event_loop.get_signal()), None);
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 displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
51 vec![]
52 }
53
54 fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
55 None
56 }
57
58 fn display(&self, _id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
59 None
60 }
61
62 fn active_window(&self) -> Option<AnyWindowHandle> {
63 None
64 }
65
66 fn open_window(
67 &self,
68 _handle: AnyWindowHandle,
69 _params: WindowParams,
70 ) -> anyhow::Result<Box<dyn PlatformWindow>> {
71 Err(anyhow::anyhow!(
72 "neither DISPLAY nor WAYLAND_DISPLAY is set. You can run in headless mode"
73 ))
74 }
75
76 fn compositor_name(&self) -> &'static str {
77 "headless"
78 }
79
80 fn set_cursor_style(&self, _style: CursorStyle) {}
81
82 fn open_uri(&self, _uri: &str) {}
83
84 fn write_to_primary(&self, _item: crate::ClipboardItem) {}
85
86 fn write_to_clipboard(&self, _item: crate::ClipboardItem) {}
87
88 fn read_from_primary(&self) -> Option<crate::ClipboardItem> {
89 None
90 }
91
92 fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
93 None
94 }
95
96 fn run(&self) {
97 let mut event_loop = self
98 .0
99 .borrow_mut()
100 .event_loop
101 .take()
102 .expect("App is already running");
103
104 event_loop.run(None, &mut self.clone(), |_| {}).log_err();
105 }
106}