From e9d8d7ceafad73278d6441acc5e931999a12266f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 20:39:03 +0100 Subject: [PATCH] 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. --- graphics/fbbootlogd/src/display.rs | 2 +- graphics/fbcond/src/display.rs | 2 +- graphics/vesad/src/main.rs | 14 ++------- inputd/src/lib.rs | 10 ++---- inputd/src/main.rs | 49 +++++++++++++++--------------- 5 files changed, 31 insertions(+), 46 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 4f736f8643..bd4d0c2e93 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -46,7 +46,7 @@ pub struct Display { impl Display { pub fn open_first_vt() -> io::Result { - let input_handle = ConsumerHandle::for_vt(1)?; + let input_handle = ConsumerHandle::new_vt()?; let map = match input_handle.open_display() { Ok(display) => { diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 5e613c76b0..b60b8e6674 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -14,7 +14,7 @@ pub struct DisplayMap { impl Display { pub fn open_vt(vt: usize) -> io::Result { - 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 diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 3a74ee42e9..dee3318404 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -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, spec: &[()]) -> ! { +fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { 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! { diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 239c5f1b52..b7ca196db6 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -17,11 +17,11 @@ unsafe fn any_as_u8_slice_mut(p: &mut T) -> &mut [u8] { pub struct ConsumerHandle(File); impl ConsumerHandle { - pub fn for_vt(vt: usize) -> Result { + pub fn new_vt() -> Result { 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 { - self.0.read(&mut []) - } - pub fn read_vt_event(&mut self) -> Result, Error> { let mut event = VtEvent { kind: VtEventKind::Resize, diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 83bf152367..d98fe35dd5 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -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::().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::() == 0 { + Handle::Display { pending, .. } => { + if buf.len() % size_of::() == 0 { let copy = core::cmp::min(pending.len(), buf.len() / size_of::()); for (i, event) in pending.drain(..copy).enumerate() { @@ -472,7 +458,22 @@ impl Scheme for InputScheme { } } - fn close(&mut self, _id: usize) -> syscall::Result { + fn close(&mut self, id: usize) -> syscall::Result { + 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) } }