11use std:: cell:: Cell ;
22use std:: collections:: VecDeque ;
3- use std:: os:: raw:: c_long;
43use std:: sync:: atomic:: { AtomicBool , Ordering } ;
54use std:: sync:: { Arc , Mutex , mpsc} ;
6- use std:: time:: Instant ;
5+ use std:: time:: { Duration , Instant } ;
76use std:: { iter, mem, slice} ;
87
98use bitflags:: bitflags;
109use orbclient:: {
1110 ButtonEvent , EventOption , FocusEvent , HoverEvent , KeyEvent , MouseEvent , MouseRelativeEvent ,
1211 MoveEvent , QuitEvent , ResizeEvent , ScrollEvent , TextInputEvent ,
1312} ;
14- use redox_event:: { EventFlags , EventQueue } ;
13+ use redox_event:: { EventFlags , EventQueue , UserData } ;
1514use smol_str:: SmolStr ;
1615use winit_core:: application:: ApplicationHandler ;
1716use winit_core:: cursor:: { CustomCursor , CustomCursorSource } ;
1817use winit_core:: error:: { EventLoopError , NotSupportedError , RequestError } ;
1918use winit_core:: event:: { self , Ime , Modifiers , StartCause } ;
19+ use winit_core:: event_loop:: pump_events:: PumpStatus ;
2020use winit_core:: event_loop:: {
2121 ActiveEventLoop as RootActiveEventLoop , ControlFlow , DeviceEvents ,
2222 EventLoopProxy as CoreEventLoopProxy , EventLoopProxyProvider ,
@@ -31,6 +31,9 @@ use winit_core::window::{Theme, Window as CoreWindow, WindowId};
3131use crate :: window:: Window ;
3232use crate :: { RedoxSocket , TimeSocket , WindowProperties } ;
3333
34+ /// timeout from redox_syscall
35+ const EVENT_TIMEOUT_ID : usize = usize:: MAX - 2 ;
36+
3437fn convert_scancode ( scancode : u8 ) -> ( PhysicalKey , Option < NamedKey > ) {
3538 // Key constants from https://docs.rs/orbclient/latest/orbclient/event/index.html
3639 let ( key_code, named_key_opt) = match scancode {
@@ -157,6 +160,15 @@ fn convert_scancode(scancode: u8) -> (PhysicalKey, Option<NamedKey>) {
157160 ( PhysicalKey :: Code ( key_code) , named_key_opt)
158161}
159162
163+ pub fn scancode_to_physicalkey ( scancode : u32 ) -> PhysicalKey {
164+ convert_scancode ( scancode. try_into ( ) . unwrap_or_default ( ) ) . 0
165+ }
166+
167+ pub fn physicalkey_to_scancode ( _physical_key : PhysicalKey ) -> Option < u32 > {
168+ // TODO
169+ None
170+ }
171+
160172fn element_state ( pressed : bool ) -> event:: ElementState {
161173 if pressed { event:: ElementState :: Pressed } else { event:: ElementState :: Released }
162174}
@@ -296,6 +308,8 @@ impl EventState {
296308
297309#[ derive( Debug ) ]
298310pub struct EventLoop {
311+ /// Has `run` or `run_on_demand` been called or a call to `pump_events` that starts the loop
312+ loop_running : bool ,
299313 windows : Vec < ( Arc < RedoxSocket > , EventState ) > ,
300314 window_target : ActiveEventLoop ,
301315 user_events_receiver : mpsc:: Receiver < ( ) > ,
@@ -323,6 +337,7 @@ impl EventLoop {
323337 . map_err ( |error| os_error ! ( format!( "{error}" ) ) ) ?;
324338
325339 Ok ( Self {
340+ loop_running : false ,
326341 windows : Vec :: new ( ) ,
327342 window_target : ActiveEventLoop {
328343 control_flow : Cell :: new ( ControlFlow :: default ( ) ) ,
@@ -508,11 +523,28 @@ impl EventLoop {
508523 & mut self ,
509524 mut app : A ,
510525 ) -> Result < ( ) , EventLoopError > {
511- let mut start_cause = StartCause :: Init ;
512526 loop {
513- app. new_events ( & self . window_target , start_cause) ;
527+ match self . pump_app_events ( None , & mut app) {
528+ PumpStatus :: Exit ( 0 ) => {
529+ break Ok ( ( ) ) ;
530+ } ,
531+ PumpStatus :: Exit ( code) => {
532+ break Err ( EventLoopError :: ExitFailure ( code) ) ;
533+ } ,
534+ _ => {
535+ continue ;
536+ } ,
537+ }
538+ }
539+ }
540+
541+ fn single_iteration < A : ApplicationHandler > ( & mut self , app : & mut A , cause : StartCause ) {
542+ // TODO: Unindent
543+ {
544+ app. new_events ( & self . window_target , cause) ;
514545
515- if start_cause == StartCause :: Init {
546+ if cause == StartCause :: Init {
547+ // NB: For consistency all platforms must call `can_create_surfaces`
516548 app. can_create_surfaces ( & self . window_target ) ;
517549 }
518550
@@ -572,7 +604,7 @@ impl EventLoop {
572604 orbital_event. to_option ( ) ,
573605 event_state,
574606 & self . window_target ,
575- & mut app,
607+ app,
576608 ) ;
577609 }
578610
@@ -616,75 +648,82 @@ impl EventLoop {
616648 }
617649
618650 app. about_to_wait ( & self . window_target ) ;
651+ }
652+ }
619653
620- if self . window_target . exiting ( ) {
621- break ;
622- }
654+ pub fn pump_app_events < A : ApplicationHandler > (
655+ & mut self ,
656+ timeout : Option < Duration > ,
657+ mut app : A ,
658+ ) -> PumpStatus {
659+ if !self . loop_running {
660+ self . loop_running = true ;
661+
662+ // Run the initial loop iteration.
663+ self . single_iteration ( & mut app, StartCause :: Init ) ;
664+ }
665+
666+ if self . window_target . exit . get ( ) {
667+ self . loop_running = false ;
668+ // TODO: other exit codes
669+ return PumpStatus :: Exit ( 0 ) ;
670+ }
623671
672+ let start = Instant :: now ( ) ;
673+ let timeout = {
624674 let requested_resume = match self . window_target . control_flow ( ) {
625- ControlFlow :: Poll => {
626- start_cause = StartCause :: Poll ;
627- continue ;
628- } ,
675+ ControlFlow :: Poll => Some ( Duration :: ZERO ) ,
629676 ControlFlow :: Wait => None ,
630- ControlFlow :: WaitUntil ( instant) => Some ( instant) ,
677+ ControlFlow :: WaitUntil ( instant) => Some ( instant. saturating_duration_since ( start ) ) ,
631678 } ;
679+ min_timeout ( timeout, requested_resume)
680+ } ;
632681
633- // Re-using wake socket caused extra wake events before because there were leftover
634- // timeouts, and then new timeouts were added each time a spurious timeout expired.
635- let timeout_socket = TimeSocket :: open ( ) . unwrap ( ) ;
636-
682+ if let Some ( timeout) = timeout {
637683 self . window_target
638684 . event_socket
639- . subscribe ( timeout_socket. 0 . fd ( ) , EventSource :: Time , EventFlags :: READ )
640- . unwrap ( ) ;
641-
642- let start = Instant :: now ( ) ;
643- if let Some ( instant) = requested_resume {
644- let mut time = timeout_socket. current_time ( ) . unwrap ( ) ;
645-
646- if let Some ( duration) = instant. checked_duration_since ( start) {
647- time. tv_sec += duration. as_secs ( ) as i64 ;
648- time. tv_nsec += duration. subsec_nanos ( ) as c_long ;
649- // Normalize timespec so tv_nsec is not greater than one second.
650- while time. tv_nsec >= 1_000_000_000 {
651- time. tv_sec += 1 ;
652- time. tv_nsec -= 1_000_000_000 ;
653- }
654- }
685+ . subscribe (
686+ EVENT_TIMEOUT_ID ,
687+ UserData :: from_user_data ( timeout. as_millis ( ) as usize ) ,
688+ EventFlags :: READ ,
689+ )
690+ . expect ( "failed to register EVENT_TIMEOUT_ID" )
691+ }
655692
656- timeout_socket. timeout ( & time) . unwrap ( ) ;
693+ // Wait for event if needed.
694+ let event = loop {
695+ match self . window_target . event_socket . next_event ( ) {
696+ Ok ( event) => break event,
697+ Err ( err) if err. is_interrupt ( ) => continue ,
698+ Err ( err) => {
699+ panic ! ( "failed to read event: {err}" ) ;
700+ } ,
657701 }
702+ } ;
658703
659- // Wait for event if needed.
660- let event = loop {
661- match self . window_target . event_socket . next_event ( ) {
662- Ok ( event) => break event,
663- Err ( err) if err. is_interrupt ( ) => continue ,
664- Err ( err) => {
665- return Err ( os_error ! ( format!( "failed to read event: {err}" ) ) . into ( ) ) ;
666- } ,
704+ if timeout. is_some ( ) && event. fd == EVENT_TIMEOUT_ID {
705+ // NB: EVENT_TIMEOUT_ID is not a regular event ID.
706+ // Here nothing is happened yet.
707+ return PumpStatus :: Continue ;
708+ }
709+
710+ // Normal window event or spurious timeout.
711+ let cause = match self . window_target . control_flow ( ) {
712+ ControlFlow :: Poll => StartCause :: Poll ,
713+ ControlFlow :: Wait => StartCause :: WaitCancelled { start, requested_resume : None } ,
714+ ControlFlow :: WaitUntil ( deadline) => {
715+ if Instant :: now ( ) < deadline {
716+ StartCause :: WaitCancelled { start, requested_resume : Some ( deadline) }
717+ } else {
718+ StartCause :: ResumeTimeReached { start, requested_resume : deadline }
667719 }
668- } ;
720+ } ,
721+ } ;
669722
670- // TODO: handle spurious wakeups (redraw caused wakeup but redraw already handled)
671- match requested_resume {
672- Some ( requested_resume)
673- if event. fd == timeout_socket. 0 . fd ( )
674- && matches ! ( event. user_data, EventSource :: Time ) =>
675- {
676- // If the event is from the special timeout socket, report that resume
677- // time was reached.
678- start_cause = StartCause :: ResumeTimeReached { start, requested_resume } ;
679- } ,
680- _ => {
681- // Normal window event or spurious timeout.
682- start_cause = StartCause :: WaitCancelled { start, requested_resume } ;
683- } ,
684- }
685- }
723+ // Do actual event processing
724+ self . single_iteration ( & mut app, cause) ;
686725
687- Ok ( ( ) )
726+ PumpStatus :: Continue
688727 }
689728
690729 pub fn window_target ( & self ) -> & dyn RootActiveEventLoop {
@@ -802,3 +841,10 @@ impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
802841
803842#[ derive( Default , Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
804843pub struct PlatformSpecificEventLoopAttributes { }
844+
845+ /// Returns the minimum `Option<Duration>`, taking into account that `None`
846+ /// equates to an infinite timeout, not a zero timeout (so can't just use
847+ /// `Option::min`)
848+ fn min_timeout ( a : Option < Duration > , b : Option < Duration > ) -> Option < Duration > {
849+ a. map_or ( b, |a_timeout| b. map_or ( Some ( a_timeout) , |b_timeout| Some ( a_timeout. min ( b_timeout) ) ) )
850+ }
0 commit comments