Merge branch 'fbbootlogd_improvements' into 'master'
Bunch of fbbootlogd and fbcond changes See merge request redox-os/drivers!256
This commit is contained in:
@@ -1,154 +0,0 @@
|
||||
use event::{user_data, EventQueue};
|
||||
use graphics_ipc::v1::{Damage, V1GraphicsHandle};
|
||||
use inputd::ConsumerHandle;
|
||||
use libredox::errno::ESTALE;
|
||||
use orbclient::Event;
|
||||
use std::mem;
|
||||
use std::os::fd::BorrowedFd;
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{io, os::unix::io::AsRawFd, slice};
|
||||
|
||||
fn read_to_slice<T: Copy>(
|
||||
file: BorrowedFd,
|
||||
buf: &mut [T],
|
||||
) -> Result<usize, libredox::error::Error> {
|
||||
unsafe {
|
||||
libredox::call::read(
|
||||
file.as_raw_fd() as usize,
|
||||
slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::<T>()),
|
||||
)
|
||||
.map(|count| count / mem::size_of::<T>())
|
||||
}
|
||||
}
|
||||
|
||||
fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result<DisplayMap> {
|
||||
let display_map = display_handle.map_display()?;
|
||||
Ok(DisplayMap {
|
||||
display_handle: Arc::new(display_handle),
|
||||
inner: display_map,
|
||||
})
|
||||
}
|
||||
|
||||
pub struct DisplayMap {
|
||||
display_handle: Arc<V1GraphicsHandle>,
|
||||
pub inner: graphics_ipc::v1::DisplayMap,
|
||||
}
|
||||
|
||||
enum DisplayCommand {
|
||||
SyncRects(Vec<Damage>),
|
||||
}
|
||||
|
||||
pub struct Display {
|
||||
cmd_tx: Sender<DisplayCommand>,
|
||||
pub map: Arc<Mutex<Option<DisplayMap>>>,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn open_first_vt() -> io::Result<Self> {
|
||||
let input_handle = ConsumerHandle::new_vt()?;
|
||||
|
||||
let map = match input_handle.open_display() {
|
||||
Ok(display) => {
|
||||
let display_handle = V1GraphicsHandle::from_file(display)?;
|
||||
Arc::new(Mutex::new(Some(
|
||||
display_fd_map(display_handle)
|
||||
.unwrap_or_else(|e| panic!("failed to map display: {e}")),
|
||||
)))
|
||||
}
|
||||
Err(err) => {
|
||||
println!("fbbootlogd: No display present yet: {err}");
|
||||
Arc::new(Mutex::new(None))
|
||||
}
|
||||
};
|
||||
|
||||
let map_clone = map.clone();
|
||||
std::thread::spawn(move || {
|
||||
Self::handle_input_events(map_clone, input_handle);
|
||||
});
|
||||
|
||||
let (cmd_tx, cmd_rx) = mpsc::channel();
|
||||
let map_clone = map.clone();
|
||||
std::thread::spawn(move || {
|
||||
Self::handle_sync_rect(map_clone, cmd_rx);
|
||||
});
|
||||
|
||||
Ok(Self { cmd_tx, map })
|
||||
}
|
||||
|
||||
fn handle_input_events(map: Arc<Mutex<Option<DisplayMap>>>, input_handle: ConsumerHandle) {
|
||||
let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue");
|
||||
|
||||
user_data! {
|
||||
enum Source {
|
||||
Input,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME listen for resize events from inputd and handle them
|
||||
|
||||
event_queue
|
||||
.subscribe(
|
||||
input_handle.inner().as_raw_fd() as usize,
|
||||
Source::Input,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.expect("fbbootlogd: failed to subscribe to scheme events");
|
||||
|
||||
let mut events = [Event::new(); 16];
|
||||
for Source::Input in event_queue.map(|event| event.unwrap().user_data) {
|
||||
match read_to_slice(input_handle.inner(), &mut events) {
|
||||
Err(err) if err.errno() == ESTALE => {
|
||||
eprintln!("fbbootlogd: handoff requested");
|
||||
|
||||
let new_display_handle = match input_handle.open_display() {
|
||||
Ok(display) => V1GraphicsHandle::from_file(display).unwrap(),
|
||||
Err(err) => {
|
||||
println!("fbbootlogd: No display present yet: {err}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match display_fd_map(new_display_handle) {
|
||||
Ok(ok) => {
|
||||
*map.lock().unwrap() = Some(ok);
|
||||
|
||||
eprintln!("fbbootlogd: handoff finished");
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("fbbootlogd: failed to open display: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(_count) => {}
|
||||
Err(err) => {
|
||||
panic!("fbbootlogd: error while reading events: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_sync_rect(map: Arc<Mutex<Option<DisplayMap>>>, cmd_rx: Receiver<DisplayCommand>) {
|
||||
while let Ok(cmd) = cmd_rx.recv() {
|
||||
match cmd {
|
||||
DisplayCommand::SyncRects(sync_rects) => {
|
||||
// We may not hold this lock across the write call to avoid deadlocking if the
|
||||
// graphics driver tries to write to the bootlog.
|
||||
let display_handle = if let Some(map) = &*map.lock().unwrap() {
|
||||
map.display_handle.clone()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
display_handle.sync_rects(&sync_rects).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sync_rects(&mut self, sync_rects: Vec<Damage>) {
|
||||
self.cmd_tx
|
||||
.send(DisplayCommand::SyncRects(sync_rects))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
@@ -1,60 +1,112 @@
|
||||
//! Fbbootlogd renders the boot log and presents it on VT1.
|
||||
//!
|
||||
//! While fbbootlogd is superficially similar to fbcond, there are two major differences:
|
||||
//! While fbbootlogd is superficially similar to fbcond, the major difference is:
|
||||
//!
|
||||
//! * Fbbootlogd doesn't accept input coming from the keyboard. It only allows getting written to.
|
||||
//! * Writing to fbbootlogd will never block. Not even on the graphics driver or inputd. This makes
|
||||
//! it safe for graphics drivers and inputd to write to the boot log without risking deadlocks.
|
||||
//! Fbcond will block on the graphics driver during handoff and will continously block on inputd
|
||||
//! to get new input. Fbbootlogd does all blocking operations in background threads such that the
|
||||
//! main thread will always keep accepting new input and writing it to the framebuffer.
|
||||
//!
|
||||
//! In the future fbbootlogd may also pull from logd as opposed to have logd push logs to it. And it
|
||||
//! it could display a boot splash like plymouth instead of a boot log when booting in quiet mode.
|
||||
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
use event::EventQueue;
|
||||
use inputd::ConsumerHandleEvent;
|
||||
use libredox::errno::EAGAIN;
|
||||
use orbclient::Event;
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
|
||||
use crate::scheme::FbbootlogScheme;
|
||||
|
||||
mod display;
|
||||
mod scheme;
|
||||
|
||||
fn main() {
|
||||
redox_daemon::Daemon::new(|daemon| inner(daemon)).expect("failed to create daemon");
|
||||
}
|
||||
fn inner(daemon: redox_daemon::Daemon) -> ! {
|
||||
let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue");
|
||||
|
||||
event::user_data! {
|
||||
enum Source {
|
||||
Scheme,
|
||||
Input,
|
||||
}
|
||||
}
|
||||
|
||||
let socket =
|
||||
Socket::create("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme");
|
||||
Socket::nonblock("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme");
|
||||
|
||||
event_queue
|
||||
.subscribe(
|
||||
socket.inner().raw(),
|
||||
Source::Scheme,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.expect("fbcond: failed to subscribe to scheme events");
|
||||
|
||||
let mut scheme = FbbootlogScheme::new();
|
||||
|
||||
event_queue
|
||||
.subscribe(
|
||||
scheme.input_handle.event_handle().as_raw_fd() as usize,
|
||||
Source::Input,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.expect("fbbootlogd: failed to subscribe to scheme events");
|
||||
|
||||
// This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics
|
||||
// driver handoff. In the future inputd may directly pass a handle to the display instead.
|
||||
//libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace");
|
||||
|
||||
daemon.ready().expect("failed to notify parent");
|
||||
|
||||
loop {
|
||||
let request = match socket
|
||||
.next_request(SignalBehavior::Restart)
|
||||
.expect("fbbootlogd: failed to read display scheme")
|
||||
{
|
||||
Some(request) => request,
|
||||
None => {
|
||||
// Scheme likely got unmounted
|
||||
std::process::exit(0);
|
||||
}
|
||||
};
|
||||
for event in event_queue {
|
||||
match event.expect("fbbootlogd: failed to get event").user_data {
|
||||
Source::Scheme => {
|
||||
loop {
|
||||
let request = match socket.next_request(SignalBehavior::Restart) {
|
||||
Ok(Some(request)) => request,
|
||||
Ok(None) => {
|
||||
// Scheme likely got unmounted
|
||||
std::process::exit(0);
|
||||
}
|
||||
Err(err) if err.errno == EAGAIN => break,
|
||||
Err(err) => panic!("fbbootlogd: failed to read display scheme: {err:?}"),
|
||||
};
|
||||
|
||||
match request.kind() {
|
||||
RequestKind::Call(call) => {
|
||||
let response = call.handle_scheme(&mut scheme);
|
||||
match request.kind() {
|
||||
RequestKind::Call(call) => {
|
||||
let response = call.handle_scheme(&mut scheme);
|
||||
|
||||
socket
|
||||
.write_responses(&[response], SignalBehavior::Restart)
|
||||
.expect("pcid: failed to write next scheme response");
|
||||
socket
|
||||
.write_responses(&[response], SignalBehavior::Restart)
|
||||
.expect("pcid: failed to write next scheme response");
|
||||
}
|
||||
RequestKind::OnClose { id } => {
|
||||
scheme.on_close(id);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
RequestKind::OnClose { id } => {
|
||||
scheme.on_close(id);
|
||||
Source::Input => {
|
||||
let mut events = [Event::new(); 16];
|
||||
loop {
|
||||
match scheme
|
||||
.input_handle
|
||||
.read_events(&mut events)
|
||||
.expect("fbbootlogd: error while reading events")
|
||||
{
|
||||
ConsumerHandleEvent::Events(&[]) => break,
|
||||
ConsumerHandleEvent::Events(_) => {}
|
||||
ConsumerHandleEvent::Handoff => {
|
||||
eprintln!("fbbootlogd: handoff requested");
|
||||
scheme.handle_handoff();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,55 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use graphics_ipc::v1::V1GraphicsHandle;
|
||||
use inputd::ConsumerHandle;
|
||||
use redox_scheme::Scheme;
|
||||
use syscall::{Error, Result, EINVAL, ENOENT};
|
||||
|
||||
use crate::display::Display;
|
||||
pub struct DisplayMap {
|
||||
display_handle: V1GraphicsHandle,
|
||||
inner: graphics_ipc::v1::DisplayMap,
|
||||
}
|
||||
|
||||
pub struct FbbootlogScheme {
|
||||
display: Display,
|
||||
pub input_handle: ConsumerHandle,
|
||||
display_map: Option<DisplayMap>,
|
||||
text_screen: console_draw::TextScreen,
|
||||
}
|
||||
|
||||
impl FbbootlogScheme {
|
||||
pub fn new() -> FbbootlogScheme {
|
||||
FbbootlogScheme {
|
||||
display: Display::open_first_vt().expect("Failed to open display for vt"),
|
||||
let mut scheme = FbbootlogScheme {
|
||||
input_handle: ConsumerHandle::new_vt().expect("fbbootlogd: Failed to open vt"),
|
||||
display_map: None,
|
||||
text_screen: console_draw::TextScreen::new(),
|
||||
};
|
||||
|
||||
scheme.handle_handoff();
|
||||
|
||||
scheme
|
||||
}
|
||||
|
||||
pub fn handle_handoff(&mut self) {
|
||||
let new_display_handle = match self.input_handle.open_display() {
|
||||
Ok(display) => V1GraphicsHandle::from_file(display).unwrap(),
|
||||
Err(err) => {
|
||||
eprintln!("fbbootlogd: No display present yet: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match new_display_handle.map_display() {
|
||||
Ok(display_map) => {
|
||||
self.display_map = Some(DisplayMap {
|
||||
display_handle: new_display_handle,
|
||||
inner: display_map,
|
||||
});
|
||||
|
||||
eprintln!("fbbootlogd: mapped display");
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("fbbootlogd: failed to open display: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,8 +90,7 @@ impl Scheme for FbbootlogScheme {
|
||||
}
|
||||
|
||||
fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result<usize> {
|
||||
let mut map_guard = self.display.map.lock().unwrap();
|
||||
if let Some(map) = &mut *map_guard {
|
||||
if let Some(map) = &mut self.display_map {
|
||||
let damage = self.text_screen.write(
|
||||
&mut console_draw::DisplayMap {
|
||||
offscreen: map.inner.ptr_mut(),
|
||||
@@ -66,9 +100,10 @@ impl Scheme for FbbootlogScheme {
|
||||
buf,
|
||||
&mut VecDeque::new(),
|
||||
);
|
||||
drop(map_guard);
|
||||
|
||||
self.display.sync_rects(damage);
|
||||
if let Some(map) = &self.display_map {
|
||||
map.display_handle.sync_rects(&damage).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
|
||||
@@ -13,33 +13,19 @@ pub struct DisplayMap {
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn open_vt(vt: usize) -> io::Result<Self> {
|
||||
let input_handle = ConsumerHandle::new_vt()?;
|
||||
pub fn open_new_vt() -> io::Result<Self> {
|
||||
let mut display = Self {
|
||||
input_handle: ConsumerHandle::new_vt()?,
|
||||
map: None,
|
||||
};
|
||||
|
||||
if let Ok(display_handle) = Self::open_display(&input_handle) {
|
||||
let map = display_handle
|
||||
.map_display()
|
||||
.unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}"));
|
||||
display.reopen_for_handoff();
|
||||
|
||||
Ok(Self {
|
||||
input_handle,
|
||||
map: Some(DisplayMap {
|
||||
display_handle,
|
||||
inner: map,
|
||||
}),
|
||||
})
|
||||
} else {
|
||||
Ok(Self {
|
||||
input_handle,
|
||||
map: None,
|
||||
})
|
||||
}
|
||||
Ok(display)
|
||||
}
|
||||
|
||||
/// Re-open the display after a handoff.
|
||||
pub fn reopen_for_handoff(&mut self) {
|
||||
eprintln!("fbcond: Performing handoff");
|
||||
|
||||
let new_display_handle = Self::open_display(&self.input_handle).unwrap();
|
||||
|
||||
eprintln!("fbcond: Opened new display");
|
||||
|
||||
+13
-28
@@ -1,9 +1,9 @@
|
||||
use event::EventQueue;
|
||||
use libredox::errno::{EAGAIN, EINTR, ESTALE};
|
||||
use inputd::ConsumerHandleEvent;
|
||||
use libredox::errno::{EAGAIN, EINTR};
|
||||
use orbclient::Event;
|
||||
use redox_scheme::{CallRequest, RequestKind, Response, SignalBehavior, Socket};
|
||||
use std::os::fd::{AsRawFd, BorrowedFd};
|
||||
use std::{env, mem, slice};
|
||||
use std::env;
|
||||
use syscall::EVENT_READ;
|
||||
|
||||
use crate::scheme::{FbconScheme, VtIndex};
|
||||
@@ -12,19 +12,6 @@ mod display;
|
||||
mod scheme;
|
||||
mod text;
|
||||
|
||||
fn read_to_slice<T: Copy>(
|
||||
file: BorrowedFd,
|
||||
buf: &mut [T],
|
||||
) -> Result<usize, libredox::error::Error> {
|
||||
unsafe {
|
||||
libredox::call::read(
|
||||
file.as_raw_fd() as usize,
|
||||
slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::<T>()),
|
||||
)
|
||||
.map(|count| count / mem::size_of::<T>())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let vt_ids = env::args()
|
||||
.skip(1)
|
||||
@@ -129,21 +116,19 @@ fn handle_event(
|
||||
|
||||
let mut events = [Event::new(); 16];
|
||||
loop {
|
||||
match read_to_slice(vt.display.input_handle.inner(), &mut events) {
|
||||
Ok(0) => break,
|
||||
Err(err) if err.errno() == ESTALE => {
|
||||
vt.handle_handoff();
|
||||
}
|
||||
|
||||
Ok(count) => {
|
||||
let events = &mut events[..count];
|
||||
for event in events.iter_mut() {
|
||||
match vt
|
||||
.display
|
||||
.input_handle
|
||||
.read_events(&mut events)
|
||||
.expect("fbcond: Error while reading events")
|
||||
{
|
||||
ConsumerHandleEvent::Events(&[]) => break,
|
||||
ConsumerHandleEvent::Events(events) => {
|
||||
for event in events {
|
||||
vt.input(event)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
panic!("fbcond: Error while reading events: {err}");
|
||||
}
|
||||
ConsumerHandleEvent::Handoff => vt.handle_handoff(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ impl FbconScheme {
|
||||
let mut vts = BTreeMap::new();
|
||||
|
||||
for &vt_i in vt_ids {
|
||||
let display = Display::open_vt(vt_i).expect("Failed to open display for vt");
|
||||
let display = Display::open_new_vt().expect("Failed to open display for vt");
|
||||
event_queue
|
||||
.subscribe(
|
||||
display.input_handle.inner().as_raw_fd() as usize,
|
||||
display.input_handle.event_handle().as_raw_fd() as usize,
|
||||
VtIndex(vt_i),
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
|
||||
@@ -23,6 +23,7 @@ impl TextScreen {
|
||||
}
|
||||
|
||||
pub fn handle_handoff(&mut self) {
|
||||
eprintln!("fbcond: Performing handoff");
|
||||
self.display.reopen_for_handoff();
|
||||
}
|
||||
|
||||
|
||||
+42
-13
@@ -1,23 +1,44 @@
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Error, Read, Write};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::mem::size_of;
|
||||
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::slice;
|
||||
|
||||
use libredox::flag::{O_CLOEXEC, O_NONBLOCK, O_RDWR};
|
||||
use orbclient::Event;
|
||||
use syscall::ESTALE;
|
||||
|
||||
fn read_to_slice<T: Copy>(
|
||||
file: BorrowedFd,
|
||||
buf: &mut [T],
|
||||
) -> Result<usize, libredox::error::Error> {
|
||||
unsafe {
|
||||
libredox::call::read(
|
||||
file.as_raw_fd() as usize,
|
||||
slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * size_of::<T>()),
|
||||
)
|
||||
.map(|count| count / size_of::<T>())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
|
||||
std::slice::from_raw_parts((p as *const T) as *const u8, size_of::<T>())
|
||||
slice::from_raw_parts((p as *const T) as *const u8, size_of::<T>())
|
||||
}
|
||||
|
||||
unsafe fn any_as_u8_slice_mut<T: Sized>(p: &mut T) -> &mut [u8] {
|
||||
std::slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::<T>())
|
||||
slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::<T>())
|
||||
}
|
||||
|
||||
pub struct ConsumerHandle(File);
|
||||
|
||||
pub enum ConsumerHandleEvent<'a> {
|
||||
Events(&'a [Event]),
|
||||
Handoff,
|
||||
}
|
||||
|
||||
impl ConsumerHandle {
|
||||
pub fn new_vt() -> Result<Self, Error> {
|
||||
pub fn new_vt() -> io::Result<Self> {
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.custom_flags(O_NONBLOCK as i32)
|
||||
@@ -25,11 +46,11 @@ impl ConsumerHandle {
|
||||
Ok(Self(file))
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> BorrowedFd<'_> {
|
||||
pub fn event_handle(&self) -> BorrowedFd<'_> {
|
||||
self.0.as_fd()
|
||||
}
|
||||
|
||||
pub fn open_display(&self) -> Result<File, Error> {
|
||||
pub fn open_display(&self) -> io::Result<File> {
|
||||
let mut buffer = [0; 1024];
|
||||
let fd = self.0.as_raw_fd();
|
||||
let written = libredox::call::fpath(fd as usize, &mut buffer)?;
|
||||
@@ -49,6 +70,14 @@ impl ConsumerHandle {
|
||||
|
||||
Ok(display_file)
|
||||
}
|
||||
|
||||
pub fn read_events<'a>(&self, events: &'a mut [Event]) -> io::Result<ConsumerHandleEvent<'a>> {
|
||||
match read_to_slice(self.0.as_fd(), events) {
|
||||
Ok(count) => Ok(ConsumerHandleEvent::Events(&events[..count])),
|
||||
Err(err) if err.errno() == ESTALE => Ok(ConsumerHandleEvent::Handoff),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -60,17 +89,17 @@ pub struct VtActivate {
|
||||
pub struct DisplayHandle(File);
|
||||
|
||||
impl DisplayHandle {
|
||||
pub fn new<S: Into<String>>(device_name: S) -> Result<Self, Error> {
|
||||
pub fn new<S: Into<String>>(device_name: S) -> io::Result<Self> {
|
||||
let path = format!("/scheme/input/handle/display/{}", device_name.into());
|
||||
Ok(Self(File::open(path)?))
|
||||
}
|
||||
|
||||
pub fn new_early<S: Into<String>>(device_name: S) -> Result<Self, Error> {
|
||||
pub fn new_early<S: Into<String>>(device_name: S) -> io::Result<Self> {
|
||||
let path = format!("/scheme/input/handle_early/display/{}", device_name.into());
|
||||
Ok(Self(File::open(path)?))
|
||||
}
|
||||
|
||||
pub fn read_vt_event(&mut self) -> Result<Option<VtEvent>, Error> {
|
||||
pub fn read_vt_event(&mut self) -> io::Result<Option<VtEvent>> {
|
||||
let mut event = VtEvent {
|
||||
kind: VtEventKind::Resize,
|
||||
vt: usize::MAX,
|
||||
@@ -97,12 +126,12 @@ impl DisplayHandle {
|
||||
pub struct ControlHandle(File);
|
||||
|
||||
impl ControlHandle {
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let path = format!("/scheme/input/control");
|
||||
Ok(Self(File::open(path)?))
|
||||
}
|
||||
|
||||
pub fn activate_vt(&mut self, vt: usize) -> Result<usize, Error> {
|
||||
pub fn activate_vt(&mut self, vt: usize) -> io::Result<usize> {
|
||||
let cmd = VtActivate { vt };
|
||||
self.0.write(unsafe { any_as_u8_slice(&cmd) })
|
||||
}
|
||||
@@ -129,11 +158,11 @@ pub struct VtEvent {
|
||||
pub struct ProducerHandle(File);
|
||||
|
||||
impl ProducerHandle {
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
File::open("/scheme/input/producer").map(ProducerHandle)
|
||||
}
|
||||
|
||||
pub fn write_event(&mut self, event: orbclient::Event) -> Result<(), Error> {
|
||||
pub fn write_event(&mut self, event: orbclient::Event) -> io::Result<()> {
|
||||
self.0.write(&event)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user