diff --git a/Cargo.toml b/Cargo.toml index f86da44d0..85dc5c30d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,8 +79,9 @@ x11rb = { version = "0.13.0", default-features = false } xkbcommon-dl = "0.4.2" # Orbital dependencies. +libredox = "0.1.12" orbclient = { version = "0.3.47", default-features = false } -redox_syscall = "0.5.7" +redox_event = { package = "redox_event", version = "0.4.5" } # Web dependencies. atomic-waker = "1" diff --git a/winit-orbital/Cargo.toml b/winit-orbital/Cargo.toml index 1d1e20a85..f3178d87f 100644 --- a/winit-orbital/Cargo.toml +++ b/winit-orbital/Cargo.toml @@ -21,5 +21,6 @@ tracing.workspace = true winit-core.workspace = true # Platform-specific +libredox.workspace = true orbclient.workspace = true -redox_syscall.workspace = true +redox_event.workspace = true diff --git a/winit-orbital/src/event_loop.rs b/winit-orbital/src/event_loop.rs index 2247e5ec3..0c4f962d5 100644 --- a/winit-orbital/src/event_loop.rs +++ b/winit-orbital/src/event_loop.rs @@ -10,6 +10,7 @@ use orbclient::{ ButtonEvent, EventOption, FocusEvent, HoverEvent, KeyEvent, MouseEvent, MouseRelativeEvent, MoveEvent, QuitEvent, ResizeEvent, ScrollEvent, TextInputEvent, }; +use redox_event::{EventFlags, EventQueue}; use smol_str::SmolStr; use winit_core::application::ApplicationHandler; use winit_core::cursor::{CustomCursor, CustomCursorSource}; @@ -288,16 +289,12 @@ impl EventLoop { let (user_events_sender, user_events_receiver) = mpsc::sync_channel(1); let event_socket = - Arc::new(RedoxSocket::event().map_err(|error| os_error!(format!("{error}")))?); + Arc::new(EventQueue::new().map_err(|error| os_error!(format!("{error}")))?); let wake_socket = TimeSocket::open().map_err(|error| os_error!(format!("{error}")))?; event_socket - .write(&syscall::Event { - id: wake_socket.0.fd, - flags: syscall::EventFlags::EVENT_READ, - data: wake_socket.0.fd, - }) + .subscribe(wake_socket.0.fd(), EventSource::Time, EventFlags::READ) .map_err(|error| os_error!(format!("{error}")))?; Ok(Self { @@ -498,7 +495,7 @@ impl EventLoop { let mut creates = self.window_target.creates.lock().unwrap(); creates.pop_front() } { - let window_id = WindowId::from_raw(window.fd); + let window_id = WindowId::from_raw(window.fd()); let mut buf: [u8; 4096] = [0; 4096]; let path = window.fpath(&mut buf).expect("failed to read properties"); @@ -522,18 +519,18 @@ impl EventLoop { } { app.window_event(&self.window_target, destroy_id, event::WindowEvent::Destroyed); self.windows - .retain(|(window, _event_state)| WindowId::from_raw(window.fd) != destroy_id); + .retain(|(window, _event_state)| WindowId::from_raw(window.fd()) != destroy_id); } // Handle window events. let mut i = 0; // While loop is used here because the same window may be processed more than once. while let Some((window, event_state)) = self.windows.get_mut(i) { - let window_id = WindowId::from_raw(window.fd); + let window_id = WindowId::from_raw(window.fd()); let mut event_buf = [0u8; 16 * mem::size_of::()]; - let count = - syscall::read(window.fd, &mut event_buf).expect("failed to read window events"); + let count = libredox::call::read(window.fd(), &mut event_buf) + .expect("failed to read window events"); // Safety: orbclient::Event is a packed struct designed to be transferred over a // socket. let events = unsafe { @@ -613,11 +610,7 @@ impl EventLoop { self.window_target .event_socket - .write(&syscall::Event { - id: timeout_socket.0.fd, - flags: syscall::EventFlags::EVENT_READ, - data: 0, - }) + .subscribe(timeout_socket.0.fd(), EventSource::Time, EventFlags::READ) .unwrap(); let start = Instant::now(); @@ -626,7 +619,7 @@ impl EventLoop { if let Some(duration) = instant.checked_duration_since(start) { time.tv_sec += duration.as_secs() as i64; - time.tv_nsec += duration.subsec_nanos() as i32; + time.tv_nsec += duration.subsec_nanos() as i64; // Normalize timespec so tv_nsec is not greater than one second. while time.tv_nsec >= 1_000_000_000 { time.tv_sec += 1; @@ -638,20 +631,22 @@ impl EventLoop { } // Wait for event if needed. - let mut event = syscall::Event::default(); - loop { - match self.window_target.event_socket.read(&mut event) { - Ok(_) => break, - Err(syscall::Error { errno: syscall::EINTR }) => continue, + let event = loop { + match self.window_target.event_socket.next_event() { + Ok(event) => break event, + Err(err) if err.is_interrupt() => continue, Err(err) => { return Err(os_error!(format!("failed to read event: {err}")).into()); }, } - } + }; // TODO: handle spurious wakeups (redraw caused wakeup but redraw already handled) match requested_resume { - Some(requested_resume) if event.id == timeout_socket.0.fd => { + Some(requested_resume) + if event.fd == timeout_socket.0.fd() + && matches!(event.user_data, EventSource::Time) => + { // If the event is from the special timeout socket, report that resume // time was reached. start_cause = StartCause::ResumeTimeReached { start, requested_resume }; @@ -689,6 +684,13 @@ impl EventLoopProxyProvider for EventLoopProxy { impl Unpin for EventLoopProxy {} +redox_event::user_data! { + pub enum EventSource { + Orbital, + Time, + } +} + #[derive(Debug)] pub struct ActiveEventLoop { control_flow: Cell, @@ -696,7 +698,7 @@ pub struct ActiveEventLoop { pub(super) creates: Mutex>>, pub(super) redraws: Arc>>, pub(super) destroys: Arc>>, - pub(super) event_socket: Arc, + pub(super) event_socket: Arc>, pub(super) event_loop_proxy: Arc, } diff --git a/winit-orbital/src/lib.rs b/winit-orbital/src/lib.rs index 71efc8218..25ae16dba 100644 --- a/winit-orbital/src/lib.rs +++ b/winit-orbital/src/lib.rs @@ -3,7 +3,12 @@ //! Redox OS has some functionality not yet present that will be implemented //! when its orbital display server provides it. -use std::{fmt, str}; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Result, Write}; +use std::os::fd::AsRawFd; +use std::{fmt, mem, slice, str}; + +use libredox::data::TimeSpec; pub use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes}; @@ -16,15 +21,11 @@ pub mod window; #[derive(Debug)] struct RedoxSocket { - fd: usize, + fd: File, } impl RedoxSocket { - fn event() -> syscall::Result { - Self::open_raw("/scheme/event") - } - - fn orbital(properties: &WindowProperties<'_>) -> syscall::Result { + fn orbital(properties: &WindowProperties<'_>) -> Result { Self::open_raw(&format!("{properties}")) } @@ -32,30 +33,27 @@ impl RedoxSocket { // non-socket path is used, it could cause read and write to not function as expected. For // example, the seek would change in a potentially unpredictable way if either read or write // were called at the same time by multiple threads. - fn open_raw(path: &str) -> syscall::Result { - let fd = syscall::open(path, syscall::O_RDWR | syscall::O_CLOEXEC)?; + fn open_raw(path: &str) -> Result { + let fd = OpenOptions::new().read(true).write(true).open(path)?; Ok(Self { fd }) } - fn read(&self, buf: &mut [u8]) -> syscall::Result<()> { - let count = syscall::read(self.fd, buf)?; - if count == buf.len() { Ok(()) } else { Err(syscall::Error::new(syscall::EINVAL)) } + fn fd(&self) -> usize { + self.fd.as_raw_fd() as usize } - fn write(&self, buf: &[u8]) -> syscall::Result<()> { - let count = syscall::write(self.fd, buf)?; - if count == buf.len() { Ok(()) } else { Err(syscall::Error::new(syscall::EINVAL)) } + fn read(&self, buf: &mut [u8]) -> Result<()> { + (&self.fd).read_exact(buf) } - fn fpath<'a>(&self, buf: &'a mut [u8]) -> syscall::Result<&'a str> { - let count = syscall::fpath(self.fd, buf)?; - str::from_utf8(&buf[..count]).map_err(|_err| syscall::Error::new(syscall::EINVAL)) + fn write(&self, buf: &[u8]) -> Result<()> { + (&self.fd).write_all(buf) } -} -impl Drop for RedoxSocket { - fn drop(&mut self) { - let _ = syscall::close(self.fd); + fn fpath<'a>(&self, buf: &'a mut [u8]) -> Result<&'a str> { + let count = libredox::call::fpath(self.fd(), buf)?; + str::from_utf8(&buf[..count]) + .map_err(|_| std::io::Error::from(std::io::ErrorKind::InvalidData)) } } @@ -63,26 +61,36 @@ impl Drop for RedoxSocket { struct TimeSocket(RedoxSocket); impl TimeSocket { - fn open() -> syscall::Result { + fn open() -> Result { RedoxSocket::open_raw("/scheme/time/4").map(Self) } // Read current time. - fn current_time(&self) -> syscall::Result { - let mut timespec = syscall::TimeSpec::default(); - self.0.read(&mut timespec)?; + fn current_time(&self) -> Result { + let mut timespec: libredox::data::TimeSpec = unsafe { mem::zeroed() }; + let timespec_bytes = unsafe { + slice::from_raw_parts_mut( + &mut timespec as *mut _ as *mut u8, + mem::size_of::(), + ) + }; + self.0.read(timespec_bytes)?; Ok(timespec) } // Write a timeout. - fn timeout(&self, timespec: &syscall::TimeSpec) -> syscall::Result<()> { - self.0.write(timespec) + fn timeout(&self, timespec: &TimeSpec) -> Result<()> { + let timespec_bytes = unsafe { + slice::from_raw_parts(timespec as *const _ as *const u8, mem::size_of::()) + }; + self.0.write(timespec_bytes) } // Wake immediately. - fn wake(&self) -> syscall::Result<()> { + fn wake(&self) -> Result<()> { // Writing a default TimeSpec will always trigger a time event. - self.timeout(&syscall::TimeSpec::default()) + let timespec: TimeSpec = unsafe { mem::zeroed() }; + self.timeout(×pec) } } @@ -97,7 +105,7 @@ struct WindowProperties<'a> { impl<'a> WindowProperties<'a> { fn new(path: &'a str) -> Self { - // orbital:flags/x/y/w/h/t + // /scheme/orbital/flags/x/y/w/h/t let mut parts = path.splitn(6, '/'); let flags = parts.next().unwrap_or(""); let x = parts.next().map_or(0, |part| part.parse::().unwrap_or(0)); diff --git a/winit-orbital/src/window.rs b/winit-orbital/src/window.rs index 4858b29b3..728c262a7 100644 --- a/winit-orbital/src/window.rs +++ b/winit-orbital/src/window.rs @@ -3,12 +3,13 @@ use std::iter; use std::sync::{Arc, Mutex}; use dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; +use redox_event::EventFlags; use winit_core::cursor::Cursor; use winit_core::error::{NotSupportedError, RequestError}; use winit_core::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; use winit_core::window::{self, Window as CoreWindow, WindowId}; -use crate::event_loop::{ActiveEventLoop, EventLoopProxy}; +use crate::event_loop::{ActiveEventLoop, EventLoopProxy, EventSource}; use crate::{RedoxSocket, WindowProperties}; // These values match the values uses in the `window_new` function in orbital: @@ -103,13 +104,7 @@ impl Window { .expect("failed to open window"); // Add to event socket. - el.event_socket - .write(&syscall::Event { - id: window.fd, - flags: syscall::EventFlags::EVENT_READ, - data: window.fd, - }) - .unwrap(); + el.event_socket.subscribe(window.fd(), EventSource::Orbital, EventFlags::READ).unwrap(); let window_socket = Arc::new(window); @@ -146,7 +141,7 @@ impl Window { #[inline] fn raw_window_handle_rwh_06(&self) -> Result { let handle = rwh_06::OrbitalWindowHandle::new({ - let window = self.window_socket.fd as *mut _; + let window = self.window_socket.fd() as *mut _; std::ptr::NonNull::new(window).expect("orbital fd should never be null") }); Ok(rwh_06::RawWindowHandle::Orbital(handle)) @@ -160,7 +155,7 @@ impl Window { impl CoreWindow for Window { fn id(&self) -> WindowId { - WindowId::from_raw(self.window_socket.fd) + WindowId::from_raw(self.window_socket.fd()) } fn ime_capabilities(&self) -> Option {