use crate::{_run_driver_step_run_frame_body, RunPhase, RunPresent, RunStep};
use crate::{Event, RunApp, RunBackend, RunControl, RunDriver, RunDriverFrameError, RunRender};
use crate::{XDisplay, XError, XImageMode, XPresent, XPresenter, XSurfaceFrame, XWindow};
use crate::{is, whilst};
#[doc = crate::_tags!(unix runtime)]
#[doc = crate::_doc_meta!{location("sys/device/display/x11")}]
pub(crate) struct XFrameCtx<'a> {
pub(crate) display: &'a mut XDisplay,
pub(crate) window: &'a mut XWindow,
}
#[doc = crate::_tags!(unix runtime)]
#[doc = crate::_doc_meta!{location("sys/device/display/x11")}]
#[derive(Debug)]
pub(crate) struct XBackend {
display: XDisplay,
window: XWindow,
}
impl XBackend {
pub fn open(x: i16, y: i16, width: u16, height: u16) -> Result<Self, XError> {
let mut display = XDisplay::open()?;
let window = XWindow::new(&mut display, x, y, width, height, 1)?;
Ok(Self { display, window })
}
}
impl RunBackend for XBackend {
type Event = Event;
type Error = XError;
type Context<'a>
= XFrameCtx<'a>
where
Self: 'a;
fn collect_events(&mut self, out: &mut [Self::Event]) -> Result<usize, Self::Error> {
whilst! { written in 0..out.len(); {
let ev = self.display.poll_event();
is! { ev.is_none(), break }
out[written] = ev;
}}
Ok(written)
}
fn context(&mut self) -> Self::Context<'_> {
XFrameCtx {
display: &mut self.display,
window: &mut self.window,
}
}
}
#[doc = crate::_tags!(unix runtime)]
#[doc = crate::_doc_meta!{location("sys/device/display/x11")}]
#[derive(Debug)]
pub struct XFrontend {
backend: XBackend,
presenter: XPresenter,
}
#[rustfmt::skip]
impl XFrontend {
const fn _new(backend: XBackend, presenter: XPresenter) -> Self { Self { backend, presenter } }
pub fn open(x: i16, y: i16, width: u16, height: u16) -> Result<Self, XError> {
Self::open_with(XImageMode::Auto, x, y, width, height)
}
pub fn open_with(mode: XImageMode, x: i16, y: i16, width: u16, height: u16)
-> Result<Self, XError> {
Ok(Self::_new(XBackend::open(x, y, width, height)?, XPresenter::new(mode)))
}
pub const fn display(&self) -> &XDisplay { &self.backend.display }
pub const fn display_mut(&mut self) -> &mut XDisplay { &mut self.backend.display }
#[cfg(ffi_xcb_shm··)]
pub const fn has_shm(&self) -> bool { self.backend.display.has_shm() }
pub const fn mode(&self) -> XImageMode { self.presenter.mode() }
pub fn active_mode(&self) -> Option<XImageMode> { self.presenter.active_mode() }
pub fn poll_event(&mut self) -> Event { self.backend.display.poll_event() }
pub fn wait_event(&mut self) -> Event { self.backend.display.wait_event() }
}
impl XFrontend {
#[allow(private_bounds, reason = "private XFrameCtx")]
pub fn step_frame<T, A, R, S, RE>(
&mut self,
driver: &mut RunDriver<T>,
app: &mut A,
renderer: &mut R,
scene: &S,
events: &mut [A::Event],
) -> Result<RunControl, RunDriverFrameError<XError, A::Error, RE, XError>>
where
A: RunApp<Event = Event>,
for<'a> R: RunRender<S, Event, XFrameCtx<'a>, Error = RE, Output<'a> = XPresent<'a>>,
{
_run_driver_step_run_frame_body!(@check
driver, self.backend, app, renderer, self.presenter, scene(scene), events, control,
driver.runtime_mut().tick_once(), driver.runtime_mut().transition(RunPhase::Stopped));
Ok(control)
}
#[allow(private_bounds, reason = "private XFrameCtx")]
pub fn run_frame<T, A, R, S, RE>(
&mut self,
driver: &mut RunDriver<T>,
app: &mut A,
renderer: &mut R,
scene: &S,
events: &mut [A::Event],
) -> Result<(), RunDriverFrameError<XError, A::Error, RE, XError>>
where
A: RunApp<Event = Event>,
for<'a> R: RunRender<S, Event, XFrameCtx<'a>, Error = RE, Output<'a> = XPresent<'a>>,
{
driver.start();
while driver.can_advance() {
_run_driver_step_run_frame_body!(
driver,
self.backend,
app,
renderer,
self.presenter,
scene(scene),
events,
control,
driver.runtime_mut().tick_once(),
driver.runtime_mut().transition(RunPhase::Stopped),
break
);
}
Ok(())
}
}
impl XFrontend {
pub fn with_surface_frame<F, T>(
&mut self,
width: u16,
height: u16,
depth: u8,
clear_redraw: bool,
render: F,
) -> Result<T, XError>
where
F: FnOnce(&mut XSurfaceFrame<'_>) -> Result<T, XError>,
{
let result = {
let mut frame =
self.presenter.surface_frame(&self.backend.display, width, height, depth)?;
render(&mut frame)?
};
self.presenter.present_surface(
&mut self.backend.display,
&mut self.backend.window,
clear_redraw,
)?;
Ok(result)
}
#[allow(clippy::too_many_arguments)]
#[allow(private_bounds, reason = "private XFrameCtx")]
pub fn step_frame_surface<R, A, F, RE>(
&mut self,
driver: &mut RunDriver<R>,
app: &mut A,
width: u16,
height: u16,
depth: u8,
clear_redraw: bool,
events: &mut [Event],
render: F,
) -> Result<RunControl, RunDriverFrameError<XError, A::Error, RE, XError>>
where
A: RunApp<Event = Event>,
F: FnOnce(&mut XSurfaceFrame<'_>) -> Result<(), RE>,
{
let written = self.backend.collect_events(events).map_err(RunDriverFrameError::Backend)?;
let events = &events[..written];
let step = RunStep::new(driver.runtime_mut().tick(), driver.phase(), events);
let control = app.run_step(step).map_err(RunDriverFrameError::App)?;
if matches!(control, RunControl::Stop) {
driver.runtime_mut().transition(RunPhase::Stopped);
return Ok(control);
}
let mut surface = self
.presenter
.surface_frame(&self.backend.display, width, height, depth)
.map_err(RunDriverFrameError::Present)?;
render(&mut surface).map_err(RunDriverFrameError::Render)?;
self.presenter
.present_surface(&mut self.backend.display, &mut self.backend.window, clear_redraw)
.map_err(RunDriverFrameError::Present)?;
driver.runtime_mut().tick_once();
Ok(control)
}
}