use std::cell::RefCell;use std::rc::Rc; use calloop::{EventLoop, LoopHandle}; use util::ResultExt; use crate::platform::linux::LinuxClient;use crate::platform::{LinuxCommon, PlatformWindow};use crate::{AnyWindowHandle, CursorStyle, DisplayId, PlatformDisplay, WindowParams}; pub struct HeadlessClientState { pub(crate) _loop_handle: LoopHandle<'static, HeadlessClient>, pub(crate) event_loop: Option<calloop::EventLoop<'static, HeadlessClient>>, pub(crate) common: LinuxCommon,} #[derive(Clone)]pub(crate) struct HeadlessClient(Rc<RefCell<HeadlessClientState>>); 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<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R { f(&mut self.0.borrow_mut().common) } fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> { vec![] } fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> { None } fn display(&self, _id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> { None } fn active_window(&self) -> Option<AnyWindowHandle> { None } fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> { None } fn open_window( &self, _handle: AnyWindowHandle, _params: WindowParams, ) -> anyhow::Result<Box<dyn PlatformWindow>> { 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<crate::ClipboardItem> { None } fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> { 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(); }}
use std::cell::RefCell;
use std::rc::Rc;
use calloop::{EventLoop, LoopHandle};
use util::ResultExt;
use crate::platform::linux::LinuxClient;
use crate::platform::{LinuxCommon, PlatformWindow};
use crate::{AnyWindowHandle, CursorStyle, DisplayId, PlatformDisplay, WindowParams};
pub struct HeadlessClientState {
pub(crate) _loop_handle: LoopHandle<'static, HeadlessClient>,
pub(crate) event_loop: Option<calloop::EventLoop<'static, HeadlessClient>>,
pub(crate) common: LinuxCommon,
}
#[derive(Clone)]
pub(crate) struct HeadlessClient(Rc<RefCell<HeadlessClientState>>);
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<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R {
f(&mut self.0.borrow_mut().common)
}
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
vec![]
}
fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
None
}
fn display(&self, _id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
None
}
fn active_window(&self) -> Option<AnyWindowHandle> {
None
}
fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
None
}
fn open_window(
&self,
_handle: AnyWindowHandle,
_params: WindowParams,
) -> anyhow::Result<Box<dyn PlatformWindow>> {
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<crate::ClipboardItem> {
None
}
fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
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();
}
}