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