Implicitly create a new VT for each consumer

Instead of requiring the graphics driver to create a fixed set of VTs in
advance. This fixes the graphical interface when there is a graphics
driver but no boot framebuffer. Previously in that case vesad would exit
before it creates any VT and thus no consumer could show anything as
their VT was missing. In the future creating new VTs on the fly could
also allow a display manager to use a separate VT for each user session.
This commit is contained in:
bjorn3
2025-03-01 20:39:03 +01:00
parent 2e82009412
commit e9d8d7ceaf
5 changed files with 31 additions and 46 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ pub struct Display {
impl Display {
pub fn open_first_vt() -> io::Result<Self> {
let input_handle = ConsumerHandle::for_vt(1)?;
let input_handle = ConsumerHandle::new_vt()?;
let map = match input_handle.open_display() {
Ok(display) => {
+1 -1
View File
@@ -14,7 +14,7 @@ pub struct DisplayMap {
impl Display {
pub fn open_vt(vt: usize) -> io::Result<Self> {
let input_handle = ConsumerHandle::for_vt(vt)?;
let input_handle = ConsumerHandle::new_vt()?;
if let Ok(display_handle) = Self::open_display(&input_handle) {
let map = display_handle
+2 -12
View File
@@ -15,12 +15,6 @@ mod framebuffer;
mod scheme;
fn main() {
let mut spec = Vec::new();
for _ in env::args().skip(1) {
spec.push(());
}
if env::var("FRAMEBUFFER_WIDTH").is_err() {
println!("vesad: No boot framebuffer");
return;
@@ -78,16 +72,12 @@ fn main() {
};
}
redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec))
redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers))
.expect("failed to create daemon");
}
fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>, spec: &[()]) -> ! {
fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>) -> ! {
let mut inputd_display_handle = DisplayHandle::new_early("vesa").unwrap();
for &() in spec.iter() {
inputd_display_handle.register_vt().unwrap();
}
let mut scheme = GraphicsScheme::new(FbAdapter { framebuffers }, "display.vesa".to_owned());
user_data! {
+2 -8
View File
@@ -17,11 +17,11 @@ unsafe fn any_as_u8_slice_mut<T: Sized>(p: &mut T) -> &mut [u8] {
pub struct ConsumerHandle(File);
impl ConsumerHandle {
pub fn for_vt(vt: usize) -> Result<Self, Error> {
pub fn new_vt() -> Result<Self, Error> {
let file = OpenOptions::new()
.read(true)
.custom_flags(O_NONBLOCK as i32)
.open(format!("/scheme/input/consumer/{vt}"))?;
.open(format!("/scheme/input/consumer"))?;
Ok(Self(file))
}
@@ -70,12 +70,6 @@ impl DisplayHandle {
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 fn read_vt_event(&mut self) -> Result<Option<VtEvent>, Error> {
let mut event = VtEvent {
kind: VtEventKind::Resize,
+25 -24
View File
@@ -131,17 +131,19 @@ impl Scheme for InputScheme {
let handle_ty = match command {
"producer" => Handle::Producer,
"consumer" => {
let target = path_parts
.next()
.and_then(|x| x.parse::<usize>().ok())
.ok_or(SysError::new(EINVAL))?;
let vt = self.next_vt_id.fetch_add(1, Ordering::Relaxed);
self.vts.insert(vt);
if self.active_vt.is_none() {
self.switch_vt(vt);
}
Handle::Consumer {
events: EventFlags::empty(),
pending: Vec::new(),
needs_handoff: false,
notified: false,
vt: target,
vt,
}
}
"handle" | "handle_early" => {
@@ -258,24 +260,8 @@ impl Scheme for InputScheme {
Ok(copy)
}
Handle::Display {
pending, device, ..
} => {
// FIXME Create new VT through a write instead and return a NewVt event on read
// This allows also returning events for VT (de)activation from the display handle
// rather than pushing them to the graphics driver.
if buf.is_empty() {
// Trying to do an empty read creates a new VT.
let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst);
log::info!("inputd: created VT #{vt} for {device}");
self.vts.insert(vt);
if self.active_vt.is_none() {
self.switch_vt(vt);
}
Ok(vt)
} else if buf.len() % size_of::<VtEvent>() == 0 {
Handle::Display { pending, .. } => {
if buf.len() % size_of::<VtEvent>() == 0 {
let copy = core::cmp::min(pending.len(), buf.len() / size_of::<VtEvent>());
for (i, event) in pending.drain(..copy).enumerate() {
@@ -472,7 +458,22 @@ impl Scheme for InputScheme {
}
}
fn close(&mut self, _id: usize) -> syscall::Result<usize> {
fn close(&mut self, id: usize) -> syscall::Result<usize> {
let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?;
match *handle {
Handle::Consumer { vt, .. } => {
self.vts.remove(&vt);
if self.active_vt == Some(vt) {
if let Some(&new_vt) = self.vts.last() {
self.switch_vt(new_vt);
} else {
self.active_vt = None;
}
}
}
_ => {}
}
Ok(0)
}
}