154 lines
4.5 KiB
Rust
154 lines
4.5 KiB
Rust
#![allow(clippy::borrow_as_ptr)]
|
|
|
|
mod framebuffer;
|
|
mod input;
|
|
|
|
use std::rc::Rc;
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use evdev::KeyCode;
|
|
use slint::platform::software_renderer::{MinimalSoftwareWindow, RepaintBufferType, Rgb565Pixel};
|
|
use slint::platform::{EventLoopProxy, Platform, WindowEvent};
|
|
use slint::{EventLoopError, LogicalPosition, PhysicalSize, PlatformError, WindowSize};
|
|
|
|
use self::framebuffer::Framebuffer;
|
|
use self::input::InputState;
|
|
|
|
pub struct Trekstor {
|
|
window: Rc<MinimalSoftwareWindow>,
|
|
queue: Queue,
|
|
quit_flag: Arc<AtomicBool>,
|
|
}
|
|
|
|
impl Trekstor {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
}
|
|
|
|
impl Default for Trekstor {
|
|
fn default() -> Self {
|
|
let window = MinimalSoftwareWindow::new(RepaintBufferType::NewBuffer);
|
|
|
|
Self {
|
|
window,
|
|
queue: Arc::new(Mutex::new(Vec::new())),
|
|
quit_flag: Arc::new(AtomicBool::new(false)),
|
|
}
|
|
}
|
|
}
|
|
|
|
type Closure = Box<dyn FnOnce() + Send>;
|
|
type Queue = Arc<Mutex<Vec<Closure>>>;
|
|
|
|
struct TrekstorEventProxy {
|
|
queue: Queue,
|
|
quit_flag: Arc<AtomicBool>,
|
|
}
|
|
|
|
impl EventLoopProxy for TrekstorEventProxy {
|
|
fn quit_event_loop(&self) -> Result<(), EventLoopError> {
|
|
self.quit_flag.store(true, Ordering::SeqCst);
|
|
Ok(())
|
|
}
|
|
|
|
fn invoke_from_event_loop(&self, event: Closure) -> Result<(), EventLoopError> {
|
|
// Don't queue if the loop is shutting down, the closure would never
|
|
// run, and any caller blocking on a channel send inside it would hang.
|
|
if self.quit_flag.load(Ordering::SeqCst) {
|
|
return Err(EventLoopError::EventLoopTerminated);
|
|
}
|
|
self.queue
|
|
.lock()
|
|
.expect("event loop closure queue poisoned")
|
|
.push(event);
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Platform for Trekstor {
|
|
fn create_window_adapter(
|
|
&self,
|
|
) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
|
Ok(self.window.clone())
|
|
}
|
|
|
|
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
|
let mut frame_buffer = Framebuffer::open()
|
|
.map_err(|e| PlatformError::Other(format!("failed to open /dev/fb0: {e}")))?;
|
|
|
|
let mut input = InputState::new(frame_buffer.width, frame_buffer.height);
|
|
|
|
#[allow(clippy::large_stack_arrays)] // causes stack overflow if rgba8
|
|
let mut buffer1 = [Rgb565Pixel(0); 614_400];
|
|
|
|
self.window.set_size(WindowSize::Physical(PhysicalSize::new(
|
|
frame_buffer.width,
|
|
frame_buffer.height,
|
|
)));
|
|
|
|
loop {
|
|
input.handle_event();
|
|
|
|
slint::platform::update_timers_and_animations();
|
|
|
|
if input.is_just_pressed(KeyCode::BTN_TOUCH) {
|
|
self.window
|
|
.try_dispatch_event(WindowEvent::PointerPressed {
|
|
position: LogicalPosition::new(input.x as f32, input.y as f32),
|
|
button: slint::platform::PointerEventButton::Left,
|
|
})
|
|
.ok();
|
|
}
|
|
|
|
if input.is_just_released(KeyCode::BTN_TOUCH) {
|
|
self.window
|
|
.try_dispatch_event(WindowEvent::PointerReleased {
|
|
position: LogicalPosition::new(input.x as f32, input.y as f32),
|
|
button: slint::platform::PointerEventButton::Left,
|
|
})
|
|
.ok();
|
|
}
|
|
|
|
if input.is_down(KeyCode::BTN_TOUCH) {
|
|
self.window
|
|
.try_dispatch_event(WindowEvent::PointerMoved {
|
|
position: LogicalPosition::new(input.x as f32, input.y as f32),
|
|
})
|
|
.ok();
|
|
}
|
|
|
|
if self.quit_flag.load(Ordering::SeqCst) {
|
|
break;
|
|
}
|
|
|
|
self.window.draw_if_needed(|renderer| {
|
|
renderer.render(&mut buffer1, frame_buffer.width as usize);
|
|
frame_buffer.write_buffer(&buffer1);
|
|
});
|
|
|
|
input.finish();
|
|
|
|
let pending: Vec<_> = self
|
|
.queue
|
|
.lock()
|
|
.expect("event loop closure queue poisoned")
|
|
.drain(..)
|
|
.collect();
|
|
for c in pending {
|
|
c();
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn new_event_loop_proxy(&self) -> Option<Box<dyn EventLoopProxy>> {
|
|
Some(Box::new(TrekstorEventProxy {
|
|
queue: self.queue.clone(),
|
|
quit_flag: self.quit_flag.clone(),
|
|
}))
|
|
}
|
|
}
|