Files
RedBear-OS/inputd/src/lib.rs
T
bjorn3 273cbda872 inputd: Split ControlHandle and DisplayHandle
ControlHandle is used to switch the active vt, while DisplayHandle is
used by display drivers to register new vt's. There are entirely
unrelated tasks and the fact that they had been merged together has been
confusing me for a while.

Also changed activating a VT to no longer create a new vt when none
existed previously. The target graphics driver may not be able to handle
the new VT. inputd -A already didn't allow activating non-existent VT's
as it first tried to open a consumer handle for the target VT.
2024-12-22 16:46:02 +01:00

170 lines
4.2 KiB
Rust

#![feature(iter_next_chunk)]
use std::fs::File;
use std::io::{Error, Read, Write};
unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
::core::slice::from_raw_parts((p as *const T) as *const u8, ::core::mem::size_of::<T>())
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct VtActivate {
pub vt: usize,
}
pub struct DisplayHandle(File);
impl DisplayHandle {
pub fn new<S: Into<String>>(device_name: S) -> Result<Self, Error> {
let path = format!("/scheme/input/handle/display/{}", device_name.into());
Ok(Self(File::open(path)?))
}
// The return value is the display identifier. It will be used to uniquely
// identify the display on activation events.
pub fn register_vt(&mut self) -> Result<usize, Error> {
self.0.read(&mut [])
}
}
pub struct ControlHandle(File);
impl ControlHandle {
pub fn new() -> Result<Self, Error> {
let path = format!("/scheme/input/control");
Ok(Self(File::open(path)?))
}
pub fn activate_vt(&mut self, vt: usize) -> Result<usize, Error> {
let cmd = VtActivate { vt };
self.0.write(unsafe { any_as_u8_slice(&cmd) })
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(u8)]
enum CmdTy {
Unknown = 0,
Activate,
Deactivate,
Resize,
}
impl From<u8> for CmdTy {
fn from(value: u8) -> Self {
match value {
1 => CmdTy::Activate,
2 => CmdTy::Deactivate,
3 => CmdTy::Resize,
_ => CmdTy::Unknown,
}
}
}
#[derive(Debug)]
pub enum Cmd {
// TODO(andypython): #VT should really need to be a `u8`.
Activate {
vt: usize,
},
Deactivate(usize /* #VT */),
Resize {
// TODO(andypython): do we really need to pass the VT here?
vt: usize,
width: u32,
height: u32,
stride: u32,
},
}
impl Cmd {
fn ty(&self) -> CmdTy {
match self {
Cmd::Activate { .. } => CmdTy::Activate,
Cmd::Deactivate(_) => CmdTy::Deactivate,
Cmd::Resize { .. } => CmdTy::Resize,
}
}
}
pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), libredox::error::Error> {
use std::os::fd::AsRawFd;
let mut result = vec![];
result.push(command.ty() as u8);
match command {
Cmd::Activate { vt } => {
let cmd = VtActivate { vt };
let bytes = unsafe { any_as_u8_slice(&cmd) };
result.extend_from_slice(bytes);
}
Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()),
Cmd::Resize {
vt,
width,
height,
stride,
} => {
result.extend_from_slice(&vt.to_le_bytes());
result.extend(width.to_le_bytes());
result.extend(height.to_le_bytes());
result.extend(stride.to_le_bytes());
}
};
let written = libredox::call::write(file.as_raw_fd() as usize, &result)?;
// XXX: Ensure all of the data is written.
assert_eq!(written, result.len());
Ok(())
}
pub fn parse_command(buffer: &[u8]) -> Option<Cmd> {
const U32_SIZE: usize = core::mem::size_of::<u32>();
const USIZE_SIZE: usize = core::mem::size_of::<usize>();
let mut parser = buffer.iter().cloned();
let command = CmdTy::from(parser.next()?);
let vt = usize::from_le_bytes(parser.next_chunk::<USIZE_SIZE>().ok()?);
match command {
CmdTy::Activate => {
let cmd = unsafe { &*buffer.as_ptr().offset(1).cast::<VtActivate>() };
Some(Cmd::Activate { vt: cmd.vt })
}
CmdTy::Deactivate => Some(Cmd::Deactivate(vt)),
CmdTy::Resize => {
let width = parser.next_chunk::<U32_SIZE>().ok()?;
let height = parser.next_chunk::<U32_SIZE>().ok()?;
let stride = parser.next_chunk::<U32_SIZE>().ok()?;
Some(Cmd::Resize {
vt,
width: u32::from_le_bytes(width),
height: u32::from_le_bytes(height),
stride: u32::from_le_bytes(stride),
})
}
CmdTy::Unknown => None,
}
}
#[repr(packed)]
pub struct Damage {
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
}