diff --git a/Cargo.toml b/Cargo.toml index 1dde01de..f5164687 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,9 +79,9 @@ x11rb = { version = "0.13.0", default-features = false } xkbcommon-dl = "0.4.2" # Orbital dependencies. -orbclient = { version = "0.3.47", default-features = false } -redox_syscall = "0.7" libredox = "0.1.12" +orbclient = { version = "0.3.47", default-features = false } +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 330bd520..f3178d87 100644 --- a/winit-orbital/Cargo.toml +++ b/winit-orbital/Cargo.toml @@ -21,6 +21,6 @@ tracing.workspace = true winit-core.workspace = true # Platform-specific -orbclient.workspace = true -redox_syscall.workspace = true libredox.workspace = true +orbclient.workspace = true +redox_event.workspace = true diff --git a/winit-orbital/src/event_loop.rs b/winit-orbital/src/event_loop.rs index 7db55f14..9c9b1adc 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}; @@ -100,6 +101,7 @@ fn convert_scancode(scancode: u8) -> (PhysicalKey, Option) { orbclient::K_LEFT => (KeyCode::ArrowLeft, Some(NamedKey::ArrowLeft)), orbclient::K_LEFT_SHIFT => (KeyCode::ShiftLeft, Some(NamedKey::Shift)), orbclient::K_MINUS => (KeyCode::Minus, None), + orbclient::K_NUM_0 => (KeyCode::Numpad0, None), orbclient::K_NUM_1 => (KeyCode::Numpad1, None), orbclient::K_NUM_2 => (KeyCode::Numpad2, None), @@ -110,12 +112,20 @@ fn convert_scancode(scancode: u8) -> (PhysicalKey, Option) { orbclient::K_NUM_7 => (KeyCode::Numpad7, None), orbclient::K_NUM_8 => (KeyCode::Numpad8, None), orbclient::K_NUM_9 => (KeyCode::Numpad9, None), + orbclient::K_NUM_ASTERISK => (KeyCode::NumpadMultiply, None), + orbclient::K_NUM_ENTER => (KeyCode::NumpadEnter, Some(NamedKey::Enter)), + orbclient::K_NUM_MINUS => (KeyCode::NumpadSubtract, None), + orbclient::K_NUM_PLUS => (KeyCode::NumpadAdd, None), + orbclient::K_NUM_SLASH => (KeyCode::NumpadDivide, None), + orbclient::K_NUM_PERIOD => (KeyCode::NumpadDecimal, None), + orbclient::K_PERIOD => (KeyCode::Period, None), orbclient::K_PGDN => (KeyCode::PageDown, Some(NamedKey::PageDown)), orbclient::K_PGUP => (KeyCode::PageUp, Some(NamedKey::PageUp)), orbclient::K_QUOTE => (KeyCode::Quote, None), orbclient::K_RIGHT => (KeyCode::ArrowRight, Some(NamedKey::ArrowRight)), orbclient::K_RIGHT_SHIFT => (KeyCode::ShiftRight, Some(NamedKey::Shift)), + orbclient::K_RIGHT_SUPER => (KeyCode::MetaRight, Some(NamedKey::Meta)), orbclient::K_SEMICOLON => (KeyCode::Semicolon, None), orbclient::K_SLASH => (KeyCode::Slash, None), orbclient::K_SPACE => (KeyCode::Space, None), @@ -127,6 +137,20 @@ fn convert_scancode(scancode: u8) -> (PhysicalKey, Option) { orbclient::K_VOLUME_TOGGLE => (KeyCode::AudioVolumeMute, Some(NamedKey::AudioVolumeMute)), orbclient::K_VOLUME_UP => (KeyCode::AudioVolumeUp, Some(NamedKey::AudioVolumeUp)), + orbclient::K_INS => (KeyCode::Insert, Some(NamedKey::Insert)), + orbclient::K_PRTSC => (KeyCode::PrintScreen, Some(NamedKey::PrintScreen)), + orbclient::K_NUM => (KeyCode::NumLock, Some(NamedKey::NumLock)), + orbclient::K_SCROLL => (KeyCode::ScrollLock, Some(NamedKey::ScrollLock)), + orbclient::K_APP => (KeyCode::ContextMenu, Some(NamedKey::ContextMenu)), + + orbclient::K_MEDIA_FAST_FORWARD => { + (KeyCode::MediaFastForward, Some(NamedKey::MediaFastForward)) + }, + orbclient::K_MEDIA_REWIND => (KeyCode::MediaRewind, Some(NamedKey::MediaRewind)), + orbclient::K_MEDIA_STOP => (KeyCode::MediaStop, Some(NamedKey::MediaStop)), + + orbclient::K_POWER => (KeyCode::Power, Some(NamedKey::Power)), + _ => return (PhysicalKey::Unidentified(NativeKeyCode::Unidentified), None), }; (PhysicalKey::Code(key_code), named_key_opt) @@ -288,16 +312,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 +518,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 +542,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 +633,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 +642,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,18 +654,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, - Err(err) => unreachable!("failed to read event: {}", err), + 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 }; @@ -687,6 +707,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, @@ -694,7 +721,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 0a41dd0e..25ae16db 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 = libredox::call::open(path, libredox::flag::O_RDWR | libredox::flag::O_CLOEXEC, 0)?; + 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) } } diff --git a/winit-orbital/src/window.rs b/winit-orbital/src/window.rs index 4858b29b..728c262a 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 {