2022-12-25 09:57:27 +02:00
#![ cfg(android_platform) ]
2015-04-24 09:51:23 +02:00
2022-06-08 11:50:26 -07:00
use std ::{
collections ::VecDeque ,
2022-11-10 16:55:19 +00:00
hash ::Hash ,
sync ::{
atomic ::{ AtomicBool , Ordering } ,
2023-07-31 00:39:01 +04:00
mpsc , Arc , Mutex , RwLock ,
2022-11-10 16:55:19 +00:00
} ,
2022-06-08 11:50:26 -07:00
time ::{ Duration , Instant } ,
2020-05-06 15:27:49 +02:00
} ;
2022-06-08 11:50:26 -07:00
2023-06-21 18:49:44 +01:00
use android_activity ::input ::{ InputEvent , KeyAction , Keycode , MotionAction } ;
2022-11-10 16:55:19 +00:00
use android_activity ::{
AndroidApp , AndroidAppWaker , ConfigurationRef , InputStatus , MainEvent , Rect ,
2020-05-06 15:27:49 +02:00
} ;
2023-01-17 03:30:14 +02:00
use once_cell ::sync ::Lazy ;
2022-07-21 22:22:36 +03:00
use raw_window_handle ::{
AndroidDisplayHandle , HasRawWindowHandle , RawDisplayHandle , RawWindowHandle ,
} ;
2022-06-08 11:50:26 -07:00
use crate ::{
dpi ::{ PhysicalPosition , PhysicalSize , Position , Size } ,
error ,
2023-07-31 00:39:01 +04:00
event ::{ self , InnerSizeWriter , StartCause } ,
2022-11-10 16:55:19 +00:00
event_loop ::{ self , ControlFlow , EventLoopWindowTarget as RootELW } ,
2023-06-18 11:10:13 +01:00
platform ::pump_events ::PumpStatus ,
2023-01-29 16:46:46 +01:00
window ::{
self , CursorGrabMode , ImePurpose , ResizeDirection , Theme , WindowButtons , WindowLevel ,
} ,
2019-06-21 11:33:15 -04:00
} ;
2023-08-13 23:20:09 +04:00
use crate ::{ error ::EventLoopError , platform_impl ::Fullscreen } ;
2019-06-21 11:33:15 -04:00
2023-06-21 18:49:44 +01:00
mod keycodes ;
2023-01-17 03:30:14 +02:00
static HAS_FOCUS : Lazy < RwLock < bool > > = Lazy ::new ( | | RwLock ::new ( true ) ) ;
2023-06-18 11:10:13 +01:00
/// Returns the minimum `Option<Duration>`, taking into account that `None`
/// equates to an infinite timeout, not a zero timeout (so can't just use
/// `Option::min`)
fn min_timeout ( a : Option < Duration > , b : Option < Duration > ) -> Option < Duration > {
a . map_or ( b , | a_timeout | {
b . map_or ( Some ( a_timeout ) , | b_timeout | Some ( a_timeout . min ( b_timeout ) ) )
} )
}
2022-11-10 16:55:19 +00:00
struct PeekableReceiver < T > {
recv : mpsc ::Receiver < T > ,
first : Option < T > ,
}
impl < T > PeekableReceiver < T > {
pub fn from_recv ( recv : mpsc ::Receiver < T > ) -> Self {
Self { recv , first : None }
}
pub fn has_incoming ( & mut self ) -> bool {
if self . first . is_some ( ) {
return true ;
}
match self . recv . try_recv ( ) {
Ok ( v ) = > {
self . first = Some ( v ) ;
true
}
Err ( mpsc ::TryRecvError ::Empty ) = > false ,
Err ( mpsc ::TryRecvError ::Disconnected ) = > {
warn! ( " Channel was disconnected when checking incoming " ) ;
false
}
}
}
pub fn try_recv ( & mut self ) -> Result < T , mpsc ::TryRecvError > {
if let Some ( first ) = self . first . take ( ) {
return Ok ( first ) ;
}
self . recv . try_recv ( )
}
}
#[ derive(Clone) ]
struct SharedFlagSetter {
flag : Arc < AtomicBool > ,
}
impl SharedFlagSetter {
pub fn set ( & self ) -> bool {
self . flag
. compare_exchange ( false , true , Ordering ::AcqRel , Ordering ::Relaxed )
. is_ok ( )
}
}
struct SharedFlag {
flag : Arc < AtomicBool > ,
}
// Used for queuing redraws from arbitrary threads. We don't care how many
// times a redraw is requested (so don't actually need to queue any data,
// we just need to know at the start of a main loop iteration if a redraw
// was queued and be able to read and clear the state atomically)
impl SharedFlag {
pub fn new ( ) -> Self {
Self {
flag : Arc ::new ( AtomicBool ::new ( false ) ) ,
}
}
pub fn setter ( & self ) -> SharedFlagSetter {
SharedFlagSetter {
flag : self . flag . clone ( ) ,
}
}
pub fn get_and_reset ( & self ) -> bool {
self . flag . swap ( false , std ::sync ::atomic ::Ordering ::AcqRel )
}
}
#[ derive(Clone) ]
pub struct RedrawRequester {
flag : SharedFlagSetter ,
waker : AndroidAppWaker ,
}
impl RedrawRequester {
fn new ( flag : & SharedFlag , waker : AndroidAppWaker ) -> Self {
RedrawRequester {
flag : flag . setter ( ) ,
waker ,
}
}
pub fn request_redraw ( & self ) {
if self . flag . set ( ) {
// Only explicitly try to wake up the main loop when the flag
// value changes
self . waker . wake ( ) ;
}
2017-09-04 12:41:02 +02:00
}
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
2023-05-28 20:02:59 +02:00
#[ derive(Debug, Clone, Eq, PartialEq, Hash) ]
pub struct KeyEventExtra { }
2020-05-06 15:27:49 +02:00
pub struct EventLoop < T : 'static > {
2022-11-10 16:55:19 +00:00
android_app : AndroidApp ,
2020-05-06 15:27:49 +02:00
window_target : event_loop ::EventLoopWindowTarget < T > ,
2022-11-10 16:55:19 +00:00
redraw_flag : SharedFlag ,
2022-07-20 14:52:36 -03:00
user_events_sender : mpsc ::Sender < T > ,
2022-11-10 16:55:19 +00:00
user_events_receiver : PeekableReceiver < T > , //must wake looper whenever something gets sent
2023-06-18 11:10:13 +01:00
loop_running : bool , // Dispatched `NewEvents<Init>`
2020-06-17 15:55:52 +02:00
running : bool ,
2023-06-18 11:10:13 +01:00
pending_redraw : bool ,
control_flow : ControlFlow ,
cause : StartCause ,
2023-06-06 23:04:51 +02:00
ignore_volume_keys : bool ,
2023-08-07 23:56:42 +01:00
combining_accent : Option < char > ,
2020-06-17 15:55:52 +02:00
}
2023-06-06 23:04:51 +02:00
#[ derive(Debug, Clone, PartialEq) ]
2022-11-10 16:55:19 +00:00
pub ( crate ) struct PlatformSpecificEventLoopAttributes {
pub ( crate ) android_app : Option < AndroidApp > ,
2023-06-06 23:04:51 +02:00
pub ( crate ) ignore_volume_keys : bool ,
}
impl Default for PlatformSpecificEventLoopAttributes {
fn default ( ) -> Self {
Self {
android_app : Default ::default ( ) ,
ignore_volume_keys : true ,
}
}
2022-11-10 16:55:19 +00:00
}
2022-02-16 22:09:03 +01:00
2022-11-10 16:55:19 +00:00
fn sticky_exit_callback < T , F > (
2023-07-31 00:39:01 +04:00
evt : event ::Event < T > ,
2022-11-10 16:55:19 +00:00
target : & RootELW < T > ,
control_flow : & mut ControlFlow ,
callback : & mut F ,
) where
2023-07-31 00:39:01 +04:00
F : FnMut ( event ::Event < T > , & RootELW < T > , & mut ControlFlow ) ,
2022-11-10 16:55:19 +00:00
{
// make ControlFlow::ExitWithCode sticky by providing a dummy
// control flow reference if it is already ExitWithCode.
if let ControlFlow ::ExitWithCode ( code ) = * control_flow {
callback ( evt , target , & mut ControlFlow ::ExitWithCode ( code ) )
} else {
callback ( evt , target , control_flow )
}
}
2020-05-06 15:27:49 +02:00
impl < T : 'static > EventLoop < T > {
2023-08-13 23:20:09 +04:00
pub ( crate ) fn new (
attributes : & PlatformSpecificEventLoopAttributes ,
) -> Result < Self , EventLoopError > {
2022-07-20 14:52:36 -03:00
let ( user_events_sender , user_events_receiver ) = mpsc ::channel ( ) ;
2022-11-10 16:55:19 +00:00
let android_app = attributes . android_app . as_ref ( ) . expect ( " An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on Android " ) ;
let redraw_flag = SharedFlag ::new ( ) ;
2023-08-13 23:20:09 +04:00
Ok ( Self {
2022-11-10 16:55:19 +00:00
android_app : android_app . clone ( ) ,
2020-05-06 15:27:49 +02:00
window_target : event_loop ::EventLoopWindowTarget {
p : EventLoopWindowTarget {
2022-11-10 16:55:19 +00:00
app : android_app . clone ( ) ,
redraw_requester : RedrawRequester ::new (
& redraw_flag ,
android_app . create_waker ( ) ,
) ,
2020-05-06 15:27:49 +02:00
_marker : std ::marker ::PhantomData ,
} ,
_marker : std ::marker ::PhantomData ,
} ,
2022-11-10 16:55:19 +00:00
redraw_flag ,
2022-07-20 14:52:36 -03:00
user_events_sender ,
2022-11-10 16:55:19 +00:00
user_events_receiver : PeekableReceiver ::from_recv ( user_events_receiver ) ,
2023-06-18 11:10:13 +01:00
loop_running : false ,
2020-06-17 15:55:52 +02:00
running : false ,
2023-06-18 11:10:13 +01:00
pending_redraw : false ,
control_flow : Default ::default ( ) ,
cause : StartCause ::Init ,
2023-06-06 23:04:51 +02:00
ignore_volume_keys : attributes . ignore_volume_keys ,
2023-08-07 23:56:42 +01:00
combining_accent : None ,
2023-08-13 23:20:09 +04:00
} )
2016-10-31 17:08:55 +01:00
}
2023-06-18 11:10:13 +01:00
fn single_iteration < F > ( & mut self , main_event : Option < MainEvent < '_ > > , callback : & mut F )
2019-06-21 11:33:15 -04:00
where
2023-07-31 00:39:01 +04:00
F : FnMut ( event ::Event < T > , & RootELW < T > , & mut ControlFlow ) ,
2017-09-04 12:41:02 +02:00
{
2022-11-10 16:55:19 +00:00
trace! ( " Mainloop iteration " ) ;
2023-06-18 11:10:13 +01:00
let cause = self . cause ;
let mut control_flow = self . control_flow ;
let mut pending_redraw = self . pending_redraw ;
let mut resized = false ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
2023-06-18 11:10:13 +01:00
event ::Event ::NewEvents ( cause ) ,
2022-11-10 16:55:19 +00:00
self . window_target ( ) ,
2023-06-18 11:10:13 +01:00
& mut control_flow ,
2022-11-10 16:55:19 +00:00
callback ,
) ;
if let Some ( event ) = main_event {
trace! ( " Handling main event {:?} " , event ) ;
match event {
MainEvent ::InitWindow { .. } = > {
sticky_exit_callback (
event ::Event ::Resumed ,
self . window_target ( ) ,
2023-06-18 11:10:13 +01:00
& mut control_flow ,
2022-11-10 16:55:19 +00:00
callback ,
) ;
}
MainEvent ::TerminateWindow { .. } = > {
sticky_exit_callback (
event ::Event ::Suspended ,
self . window_target ( ) ,
2023-06-18 11:10:13 +01:00
& mut control_flow ,
2022-11-10 16:55:19 +00:00
callback ,
) ;
}
MainEvent ::WindowResized { .. } = > resized = true ,
2023-06-18 11:10:13 +01:00
MainEvent ::RedrawNeeded { .. } = > pending_redraw = true ,
2022-11-10 16:55:19 +00:00
MainEvent ::ContentRectChanged { .. } = > {
warn! ( " TODO: find a way to notify application of content rect change " ) ;
}
MainEvent ::GainedFocus = > {
2023-01-17 03:30:14 +02:00
* HAS_FOCUS . write ( ) . unwrap ( ) = true ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Focused ( true ) ,
} ,
self . window_target ( ) ,
2023-06-18 11:10:13 +01:00
& mut control_flow ,
2022-11-10 16:55:19 +00:00
callback ,
) ;
}
MainEvent ::LostFocus = > {
2023-01-17 03:30:14 +02:00
* HAS_FOCUS . write ( ) . unwrap ( ) = false ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Focused ( false ) ,
} ,
self . window_target ( ) ,
2023-06-18 11:10:13 +01:00
& mut control_flow ,
2022-11-10 16:55:19 +00:00
callback ,
) ;
}
MainEvent ::ConfigChanged { .. } = > {
let monitor = MonitorHandle ::new ( self . android_app . clone ( ) ) ;
let old_scale_factor = monitor . scale_factor ( ) ;
let scale_factor = monitor . scale_factor ( ) ;
if ( scale_factor - old_scale_factor ) . abs ( ) < f64 ::EPSILON {
2023-07-31 00:39:01 +04:00
let new_inner_size = Arc ::new ( Mutex ::new (
MonitorHandle ::new ( self . android_app . clone ( ) ) . size ( ) ,
) ) ;
2022-11-10 16:55:19 +00:00
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::ScaleFactorChanged {
2023-07-31 00:39:01 +04:00
inner_size_writer : InnerSizeWriter ::new ( Arc ::downgrade (
& new_inner_size ,
) ) ,
2022-11-10 16:55:19 +00:00
scale_factor ,
} ,
} ;
2023-06-18 11:10:13 +01:00
sticky_exit_callback (
event ,
self . window_target ( ) ,
& mut control_flow ,
callback ,
) ;
2022-11-10 16:55:19 +00:00
}
}
MainEvent ::LowMemory = > {
// XXX: how to forward this state to applications?
// It seems like ideally winit should support lifecycle and
// low-memory events, especially for mobile platforms.
warn! ( " TODO: handle Android LowMemory notification " ) ;
}
MainEvent ::Start = > {
// XXX: how to forward this state to applications?
warn! ( " TODO: forward onStart notification to application " ) ;
}
MainEvent ::Resume { .. } = > {
debug! ( " App Resumed - is running " ) ;
self . running = true ;
}
MainEvent ::SaveState { .. } = > {
// XXX: how to forward this state to applications?
// XXX: also how do we expose state restoration to apps?
warn! ( " TODO: forward saveState notification to application " ) ;
}
MainEvent ::Pause = > {
debug! ( " App Paused - stopped running " ) ;
self . running = false ;
}
MainEvent ::Stop = > {
// XXX: how to forward this state to applications?
warn! ( " TODO: forward onStop notification to application " ) ;
}
MainEvent ::Destroy = > {
// XXX: maybe exit mainloop to drop things before being
// killed by the OS?
warn! ( " TODO: forward onDestroy notification to application " ) ;
}
MainEvent ::InsetsChanged { .. } = > {
// XXX: how to forward this state to applications?
warn! ( " TODO: handle Android InsetsChanged notification " ) ;
}
unknown = > {
trace! ( " Unknown MainEvent {unknown:?} (ignored) " ) ;
}
}
} else {
trace! ( " No main event to handle " ) ;
}
2020-06-17 15:55:52 +02:00
2023-08-07 23:56:42 +01:00
// temporarily decouple `android_app` from `self` so we aren't holding
// a borrow of `self` while iterating
let android_app = self . android_app . clone ( ) ;
2022-11-10 16:55:19 +00:00
2023-08-07 23:56:42 +01:00
// Process input events
match android_app . input_events_iter ( ) {
Ok ( mut input_iter ) = > loop {
let read_event = input_iter . next ( | event | {
self . handle_input_event ( & android_app , event , & mut control_flow , callback )
} ) ;
if ! read_event {
break ;
2019-06-24 12:14:55 -04:00
}
2023-08-07 23:56:42 +01:00
} ,
Err ( err ) = > {
log ::warn! ( " Failed to get input events iterator: {err:?} " ) ;
2020-05-06 15:27:49 +02:00
}
2023-08-07 23:56:42 +01:00
}
2022-11-10 16:55:19 +00:00
// Empty the user event buffer
{
while let Ok ( event ) = self . user_events_receiver . try_recv ( ) {
sticky_exit_callback (
crate ::event ::Event ::UserEvent ( event ) ,
self . window_target ( ) ,
2023-06-18 11:10:13 +01:00
& mut control_flow ,
2022-11-10 16:55:19 +00:00
callback ,
) ;
}
}
2020-05-06 15:27:49 +02:00
2022-11-10 16:55:19 +00:00
if self . running {
if resized {
let size = if let Some ( native_window ) = self . android_app . native_window ( ) . as_ref ( ) {
let width = native_window . width ( ) as _ ;
let height = native_window . height ( ) as _ ;
PhysicalSize ::new ( width , height )
} else {
PhysicalSize ::new ( 0 , 0 )
} ;
2020-05-06 15:27:49 +02:00
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Resized ( size ) ,
} ;
2023-06-18 11:10:13 +01:00
sticky_exit_callback ( event , self . window_target ( ) , & mut control_flow , callback ) ;
2020-05-06 15:27:49 +02:00
}
2023-06-18 11:10:13 +01:00
pending_redraw | = self . redraw_flag . get_and_reset ( ) ;
if pending_redraw {
pending_redraw = false ;
2020-05-06 15:27:49 +02:00
let event = event ::Event ::RedrawRequested ( window ::WindowId ( WindowId ) ) ;
2023-06-18 11:10:13 +01:00
sticky_exit_callback ( event , self . window_target ( ) , & mut control_flow , callback ) ;
2020-05-06 15:27:49 +02:00
}
2022-11-10 16:55:19 +00:00
}
2020-05-06 15:27:49 +02:00
2023-07-28 17:37:56 +01:00
// This is always the last event we dispatch before poll again
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
2023-07-28 17:37:56 +01:00
event ::Event ::AboutToWait ,
2022-11-10 16:55:19 +00:00
self . window_target ( ) ,
2023-06-18 11:10:13 +01:00
& mut control_flow ,
2022-11-10 16:55:19 +00:00
callback ,
) ;
2023-06-18 11:10:13 +01:00
self . control_flow = control_flow ;
self . pending_redraw = pending_redraw ;
2022-11-10 16:55:19 +00:00
}
2023-08-07 23:56:42 +01:00
fn handle_input_event < F > (
& mut self ,
android_app : & AndroidApp ,
event : & InputEvent < '_ > ,
control_flow : & mut ControlFlow ,
callback : & mut F ,
) -> InputStatus
where
F : FnMut ( event ::Event < T > , & RootELW < T > , & mut ControlFlow ) ,
{
let mut input_status = InputStatus ::Handled ;
match event {
InputEvent ::MotionEvent ( motion_event ) = > {
let window_id = window ::WindowId ( WindowId ) ;
let device_id = event ::DeviceId ( DeviceId ) ;
let phase = match motion_event . action ( ) {
MotionAction ::Down | MotionAction ::PointerDown = > {
Some ( event ::TouchPhase ::Started )
}
MotionAction ::Up | MotionAction ::PointerUp = > Some ( event ::TouchPhase ::Ended ) ,
MotionAction ::Move = > Some ( event ::TouchPhase ::Moved ) ,
MotionAction ::Cancel = > Some ( event ::TouchPhase ::Cancelled ) ,
_ = > {
None // TODO mouse events
}
} ;
if let Some ( phase ) = phase {
let pointers : Box < dyn Iterator < Item = android_activity ::input ::Pointer < '_ > > > =
match phase {
event ::TouchPhase ::Started | event ::TouchPhase ::Ended = > {
Box ::new ( std ::iter ::once (
motion_event . pointer_at_index ( motion_event . pointer_index ( ) ) ,
) )
}
event ::TouchPhase ::Moved | event ::TouchPhase ::Cancelled = > {
Box ::new ( motion_event . pointers ( ) )
}
} ;
for pointer in pointers {
let location = PhysicalPosition {
x : pointer . x ( ) as _ ,
y : pointer . y ( ) as _ ,
} ;
trace! ( " Input event {device_id:?}, {phase:?}, loc={location:?}, pointer={pointer:?} " ) ;
let event = event ::Event ::WindowEvent {
window_id ,
event : event ::WindowEvent ::Touch ( event ::Touch {
device_id ,
phase ,
location ,
id : pointer . pointer_id ( ) as u64 ,
force : None ,
} ) ,
} ;
sticky_exit_callback ( event , self . window_target ( ) , control_flow , callback ) ;
}
}
}
InputEvent ::KeyEvent ( key ) = > {
match key . key_code ( ) {
// Flag keys related to volume as unhandled. While winit does not have a way for applications
// to configure what keys to flag as handled, this appears to be a good default until winit
// can be configured.
Keycode ::VolumeUp | Keycode ::VolumeDown | Keycode ::VolumeMute = > {
if self . ignore_volume_keys {
input_status = InputStatus ::Unhandled
}
}
keycode = > {
let state = match key . action ( ) {
KeyAction ::Down = > event ::ElementState ::Pressed ,
KeyAction ::Up = > event ::ElementState ::Released ,
_ = > event ::ElementState ::Released ,
} ;
let key_char = keycodes ::character_map_and_combine_key (
android_app ,
key ,
& mut self . combining_accent ,
) ;
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::KeyboardInput {
device_id : event ::DeviceId ( DeviceId ) ,
event : event ::KeyEvent {
state ,
physical_key : keycodes ::to_physical_keycode ( keycode ) ,
logical_key : keycodes ::to_logical ( key_char , keycode ) ,
location : keycodes ::to_location ( keycode ) ,
repeat : key . repeat_count ( ) > 0 ,
text : None ,
platform_specific : KeyEventExtra { } ,
} ,
is_synthetic : false ,
} ,
} ;
sticky_exit_callback ( event , self . window_target ( ) , control_flow , callback ) ;
}
}
}
_ = > {
warn! ( " Unknown android_activity input event {event:?} " )
}
}
input_status
}
2023-08-13 23:20:09 +04:00
pub fn run < F > ( mut self , event_handler : F ) -> Result < ( ) , EventLoopError >
2022-11-10 16:55:19 +00:00
where
2023-08-06 01:56:56 +04:00
F : FnMut ( event ::Event < T > , & event_loop ::EventLoopWindowTarget < T > , & mut ControlFlow ) ,
2022-11-10 16:55:19 +00:00
{
2023-04-11 12:50:52 +01:00
self . run_ondemand ( event_handler )
2022-11-10 16:55:19 +00:00
}
2023-08-13 23:20:09 +04:00
pub fn run_ondemand < F > ( & mut self , mut event_handler : F ) -> Result < ( ) , EventLoopError >
2023-06-18 11:10:13 +01:00
where
2023-07-31 00:39:01 +04:00
F : FnMut ( event ::Event < T > , & event_loop ::EventLoopWindowTarget < T > , & mut ControlFlow ) ,
2023-06-18 11:10:13 +01:00
{
if self . loop_running {
2023-08-13 23:20:09 +04:00
return Err ( EventLoopError ::AlreadyRunning ) ;
2023-06-18 11:10:13 +01:00
}
2022-11-10 16:55:19 +00:00
2023-06-18 11:10:13 +01:00
loop {
2023-07-24 00:37:51 +01:00
match self . pump_events ( None , & mut event_handler ) {
2023-06-18 11:10:13 +01:00
PumpStatus ::Exit ( 0 ) = > {
break Ok ( ( ) ) ;
}
PumpStatus ::Exit ( code ) = > {
2023-08-13 23:20:09 +04:00
break Err ( EventLoopError ::ExitFailure ( code ) ) ;
2023-06-18 11:10:13 +01:00
}
_ = > {
continue ;
}
2022-11-10 16:55:19 +00:00
}
2023-06-18 11:10:13 +01:00
}
}
2023-07-24 00:37:51 +01:00
pub fn pump_events < F > ( & mut self , timeout : Option < Duration > , mut callback : F ) -> PumpStatus
2023-06-18 11:10:13 +01:00
where
2023-07-31 00:39:01 +04:00
F : FnMut ( event ::Event < T > , & RootELW < T > , & mut ControlFlow ) ,
2023-06-18 11:10:13 +01:00
{
if ! self . loop_running {
self . loop_running = true ;
// Reset the internal state for the loop as we start running to
// ensure consistent behaviour in case the loop runs and exits more
// than once
self . pending_redraw = false ;
self . cause = StartCause ::Init ;
self . control_flow = ControlFlow ::Poll ;
// run the initial loop iteration
self . single_iteration ( None , & mut callback ) ;
}
2022-11-10 16:55:19 +00:00
2023-06-18 11:10:13 +01:00
// Consider the possibility that the `StartCause::Init` iteration could
// request to Exit
if ! matches! ( self . control_flow , ControlFlow ::ExitWithCode ( _ ) ) {
self . poll_events_with_timeout ( timeout , & mut callback ) ;
}
if let ControlFlow ::ExitWithCode ( code ) = self . control_flow {
self . loop_running = false ;
let mut dummy = self . control_flow ;
sticky_exit_callback (
2023-07-28 17:19:53 +01:00
event ::Event ::LoopExiting ,
2023-06-18 11:10:13 +01:00
self . window_target ( ) ,
& mut dummy ,
& mut callback ,
) ;
PumpStatus ::Exit ( code )
} else {
PumpStatus ::Continue
}
}
2022-11-10 16:55:19 +00:00
2023-06-18 11:10:13 +01:00
fn poll_events_with_timeout < F > ( & mut self , mut timeout : Option < Duration > , mut callback : F )
where
2023-07-31 00:39:01 +04:00
F : FnMut ( event ::Event < T > , & RootELW < T > , & mut ControlFlow ) ,
2023-06-18 11:10:13 +01:00
{
let start = Instant ::now ( ) ;
self . pending_redraw | = self . redraw_flag . get_and_reset ( ) ;
timeout =
if self . running & & ( self . pending_redraw | | self . user_events_receiver . has_incoming ( ) ) {
// If we already have work to do then we don't want to block on the next poll
Some ( Duration ::ZERO )
} else {
let control_flow_timeout = match self . control_flow {
ControlFlow ::Wait = > None ,
ControlFlow ::Poll = > Some ( Duration ::ZERO ) ,
ControlFlow ::WaitUntil ( wait_deadline ) = > {
Some ( wait_deadline . saturating_duration_since ( start ) )
2022-11-10 16:55:19 +00:00
}
2023-06-18 11:10:13 +01:00
// `ExitWithCode()` will be reset to `Poll` before polling
ControlFlow ::ExitWithCode ( _code ) = > unreachable! ( ) ,
} ;
min_timeout ( control_flow_timeout , timeout )
} ;
let app = self . android_app . clone ( ) ; // Don't borrow self as part of poll expression
app . poll_events ( timeout , | poll_event | {
let mut main_event = None ;
match poll_event {
android_activity ::PollEvent ::Wake = > {
// In the X11 backend it's noted that too many false-positive wake ups
// would cause the event loop to run continuously. They handle this by re-checking
// for pending events (assuming they cover all valid reasons for a wake up).
//
// For now, user_events and redraw_requests are the only reasons to expect
// a wake up here so we can ignore the wake up if there are no events/requests.
// We also ignore wake ups while suspended.
self . pending_redraw | = self . redraw_flag . get_and_reset ( ) ;
if ! self . running
| | ( ! self . pending_redraw & & ! self . user_events_receiver . has_incoming ( ) )
{
return ;
2018-02-15 14:09:14 +01:00
}
2019-06-24 12:14:55 -04:00
}
2023-06-18 11:10:13 +01:00
android_activity ::PollEvent ::Timeout = > { }
android_activity ::PollEvent ::Main ( event ) = > {
main_event = Some ( event ) ;
2019-06-24 12:14:55 -04:00
}
2023-06-18 11:10:13 +01:00
unknown_event = > {
warn! ( " Unknown poll event {unknown_event:?} (ignored) " ) ;
}
}
2022-11-10 16:55:19 +00:00
2023-06-18 11:10:13 +01:00
self . cause = match self . control_flow {
ControlFlow ::Poll = > StartCause ::Poll ,
ControlFlow ::Wait = > StartCause ::WaitCancelled {
start ,
requested_resume : None ,
} ,
ControlFlow ::WaitUntil ( deadline ) = > {
if Instant ::now ( ) < deadline {
StartCause ::WaitCancelled {
start ,
requested_resume : Some ( deadline ) ,
}
} else {
StartCause ::ResumeTimeReached {
start ,
requested_resume : deadline ,
}
}
}
// `ExitWithCode()` will be reset to `Poll` before polling
ControlFlow ::ExitWithCode ( _code ) = > unreachable! ( ) ,
} ;
2022-11-10 16:55:19 +00:00
2023-06-18 11:10:13 +01:00
self . single_iteration ( main_event , & mut callback ) ;
} ) ;
2017-09-04 12:41:02 +02:00
}
2020-05-06 15:27:49 +02:00
pub fn window_target ( & self ) -> & event_loop ::EventLoopWindowTarget < T > {
& self . window_target
2018-02-15 14:09:14 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn create_proxy ( & self ) -> EventLoopProxy < T > {
EventLoopProxy {
2022-07-20 14:52:36 -03:00
user_events_sender : self . user_events_sender . clone ( ) ,
2022-11-10 16:55:19 +00:00
waker : self . android_app . create_waker ( ) ,
2020-05-06 15:27:49 +02:00
}
}
}
pub struct EventLoopProxy < T : 'static > {
2022-07-20 14:52:36 -03:00
user_events_sender : mpsc ::Sender < T > ,
2022-11-10 16:55:19 +00:00
waker : AndroidAppWaker ,
}
impl < T : 'static > Clone for EventLoopProxy < T > {
fn clone ( & self ) -> Self {
EventLoopProxy {
user_events_sender : self . user_events_sender . clone ( ) ,
waker : self . waker . clone ( ) ,
}
}
2017-09-04 12:41:02 +02:00
}
2020-05-06 15:27:49 +02:00
impl < T > EventLoopProxy < T > {
pub fn send_event ( & self , event : T ) -> Result < ( ) , event_loop ::EventLoopClosed < T > > {
2022-07-20 14:52:36 -03:00
self . user_events_sender
. send ( event )
2022-11-10 16:55:19 +00:00
. map_err ( | err | event_loop ::EventLoopClosed ( err . 0 ) ) ? ;
self . waker . wake ( ) ;
2017-09-04 12:41:02 +02:00
Ok ( ( ) )
}
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub struct EventLoopWindowTarget < T : 'static > {
2022-11-10 16:55:19 +00:00
app : AndroidApp ,
redraw_requester : RedrawRequester ,
2020-05-06 15:27:49 +02:00
_marker : std ::marker ::PhantomData < T > ,
}
2020-07-04 15:46:41 -04:00
impl < T : 'static > EventLoopWindowTarget < T > {
2022-09-21 10:04:28 +02:00
pub fn primary_monitor ( & self ) -> Option < MonitorHandle > {
2022-11-10 16:55:19 +00:00
Some ( MonitorHandle ::new ( self . app . clone ( ) ) )
2020-07-04 15:46:41 -04:00
}
pub fn available_monitors ( & self ) -> VecDeque < MonitorHandle > {
let mut v = VecDeque ::with_capacity ( 1 ) ;
2022-11-10 16:55:19 +00:00
v . push_back ( MonitorHandle ::new ( self . app . clone ( ) ) ) ;
2020-07-04 15:46:41 -04:00
v
}
2022-07-21 22:22:36 +03:00
pub fn raw_display_handle ( & self ) -> RawDisplayHandle {
RawDisplayHandle ::Android ( AndroidDisplayHandle ::empty ( ) )
}
2020-07-04 15:46:41 -04:00
}
2020-05-06 15:27:49 +02:00
#[ derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd) ]
2022-11-10 16:55:19 +00:00
pub ( crate ) struct WindowId ;
2017-09-04 12:41:02 +02:00
2018-12-21 09:51:48 -07:00
impl WindowId {
2021-08-30 19:40:02 +02:00
pub const fn dummy ( ) -> Self {
2018-12-21 09:51:48 -07:00
WindowId
}
}
2022-07-02 14:27:19 +03:00
impl From < WindowId > for u64 {
fn from ( _ : WindowId ) -> Self {
0
}
}
impl From < u64 > for WindowId {
fn from ( _ : u64 ) -> Self {
Self
}
}
2020-05-06 15:27:49 +02:00
#[ derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd) ]
2017-09-04 12:41:02 +02:00
pub struct DeviceId ;
2018-12-21 09:51:48 -07:00
impl DeviceId {
2021-08-30 19:40:02 +02:00
pub const fn dummy ( ) -> Self {
2018-12-21 09:51:48 -07:00
DeviceId
}
}
2020-05-06 15:27:49 +02:00
#[ derive(Clone, Copy, Debug, Default, Eq, PartialEq) ]
pub struct PlatformSpecificWindowBuilderAttributes ;
2017-09-04 12:41:02 +02:00
2022-11-10 16:55:19 +00:00
pub ( crate ) struct Window {
app : AndroidApp ,
redraw_requester : RedrawRequester ,
}
2018-06-14 19:42:18 -04:00
2020-05-06 15:27:49 +02:00
impl Window {
2022-06-10 19:05:28 +02:00
pub ( crate ) fn new < T : 'static > (
2022-11-10 16:55:19 +00:00
el : & EventLoopWindowTarget < T > ,
2020-05-06 15:27:49 +02:00
_window_attrs : window ::WindowAttributes ,
_ : PlatformSpecificWindowBuilderAttributes ,
) -> Result < Self , error ::OsError > {
// FIXME this ignores requested window attributes
2022-11-10 16:55:19 +00:00
Ok ( Self {
app : el . app . clone ( ) ,
redraw_requester : el . redraw_requester . clone ( ) ,
} )
2020-05-06 15:27:49 +02:00
}
2018-06-14 19:42:18 -04:00
2023-08-14 21:19:57 +02:00
pub ( crate ) fn maybe_queue_on_main ( & self , f : impl FnOnce ( & Self ) + Send + 'static ) {
f ( self )
}
pub ( crate ) fn maybe_wait_on_main < R : Send > ( & self , f : impl FnOnce ( & Self ) -> R + Send ) -> R {
f ( self )
}
2020-05-06 15:27:49 +02:00
pub fn id ( & self ) -> WindowId {
WindowId
2018-06-14 19:42:18 -04:00
}
2016-10-31 17:08:55 +01:00
2022-09-21 10:04:28 +02:00
pub fn primary_monitor ( & self ) -> Option < MonitorHandle > {
2022-11-10 16:55:19 +00:00
Some ( MonitorHandle ::new ( self . app . clone ( ) ) )
2017-09-04 12:41:02 +02:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn available_monitors ( & self ) -> VecDeque < MonitorHandle > {
let mut v = VecDeque ::with_capacity ( 1 ) ;
2022-11-10 16:55:19 +00:00
v . push_back ( MonitorHandle ::new ( self . app . clone ( ) ) ) ;
2020-05-06 15:27:49 +02:00
v
2016-10-31 17:08:55 +01:00
}
2017-09-07 09:33:46 +01:00
2022-09-21 10:04:28 +02:00
pub fn current_monitor ( & self ) -> Option < MonitorHandle > {
2022-11-10 16:55:19 +00:00
Some ( MonitorHandle ::new ( self . app . clone ( ) ) )
2017-09-07 09:33:46 +01:00
}
2017-10-17 14:56:38 +03:00
2020-01-03 14:52:27 -05:00
pub fn scale_factor ( & self ) -> f64 {
2022-11-10 16:55:19 +00:00
MonitorHandle ::new ( self . app . clone ( ) ) . scale_factor ( )
2017-10-17 14:56:38 +03:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn request_redraw ( & self ) {
2022-11-10 16:55:19 +00:00
self . redraw_requester . request_redraw ( )
2016-10-31 17:08:55 +01:00
}
2023-06-22 08:08:53 +04:00
pub fn pre_present_notify ( & self ) { }
2020-05-06 15:27:49 +02:00
pub fn inner_position ( & self ) -> Result < PhysicalPosition < i32 > , error ::NotSupportedError > {
Err ( error ::NotSupportedError ::new ( ) )
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn outer_position ( & self ) -> Result < PhysicalPosition < i32 > , error ::NotSupportedError > {
Err ( error ::NotSupportedError ::new ( ) )
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn set_outer_position ( & self , _position : Position ) {
// no effect
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn inner_size ( & self ) -> PhysicalSize < u32 > {
self . outer_size ( )
2016-10-31 17:08:55 +01:00
}
2023-07-10 04:02:26 +00:00
pub fn request_inner_size ( & self , _size : Size ) -> Option < PhysicalSize < u32 > > {
Some ( self . inner_size ( ) )
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn outer_size ( & self ) -> PhysicalSize < u32 > {
2022-11-10 16:55:19 +00:00
MonitorHandle ::new ( self . app . clone ( ) ) . size ( )
2018-04-16 21:40:30 -04:00
}
2020-05-06 15:27:49 +02:00
pub fn set_min_inner_size ( & self , _ : Option < Size > ) { }
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn set_max_inner_size ( & self , _ : Option < Size > ) { }
2018-03-23 05:35:35 -04:00
2022-09-03 21:50:22 +03:00
pub fn resize_increments ( & self ) -> Option < PhysicalSize < u32 > > {
None
}
pub fn set_resize_increments ( & self , _increments : Option < Size > ) { }
2020-05-06 15:27:49 +02:00
pub fn set_title ( & self , _title : & str ) { }
2018-03-23 05:35:35 -04:00
2023-01-15 23:39:36 +03:00
pub fn set_transparent ( & self , _transparent : bool ) { }
2020-05-06 15:27:49 +02:00
pub fn set_visible ( & self , _visibility : bool ) { }
2018-06-14 19:42:18 -04:00
2022-02-17 20:44:14 +02:00
pub fn is_visible ( & self ) -> Option < bool > {
None
}
2020-05-06 15:27:49 +02:00
pub fn set_resizable ( & self , _resizeable : bool ) { }
2016-10-31 17:08:55 +01:00
2022-02-17 17:03:17 +02:00
pub fn is_resizable ( & self ) -> bool {
false
}
2022-11-29 12:03:51 +02:00
pub fn set_enabled_buttons ( & self , _buttons : WindowButtons ) { }
pub fn enabled_buttons ( & self ) -> WindowButtons {
WindowButtons ::all ( )
}
2020-05-06 15:27:49 +02:00
pub fn set_minimized ( & self , _minimized : bool ) { }
2016-10-31 17:08:55 +01:00
2023-01-19 23:39:04 +02:00
pub fn is_minimized ( & self ) -> Option < bool > {
None
}
2020-05-06 15:27:49 +02:00
pub fn set_maximized ( & self , _maximized : bool ) { }
2016-10-31 17:08:55 +01:00
2021-01-27 20:01:17 +02:00
pub fn is_maximized ( & self ) -> bool {
false
}
2022-09-21 10:04:28 +02:00
pub fn set_fullscreen ( & self , _monitor : Option < Fullscreen > ) {
2020-07-26 21:13:17 +00:00
warn! ( " Cannot set fullscreen on Android " ) ;
2016-10-31 17:08:55 +01:00
}
2022-09-21 10:04:28 +02:00
pub fn fullscreen ( & self ) -> Option < Fullscreen > {
2020-05-06 15:27:49 +02:00
None
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn set_decorations ( & self , _decorations : bool ) { }
2018-06-18 12:32:18 -04:00
2022-02-17 15:31:13 +02:00
pub fn is_decorated ( & self ) -> bool {
true
}
2022-11-26 03:50:58 +02:00
pub fn set_window_level ( & self , _level : WindowLevel ) { }
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn set_window_icon ( & self , _window_icon : Option < crate ::icon ::Icon > ) { }
2017-08-28 00:22:26 +01:00
2023-06-22 19:12:14 +00:00
pub fn set_ime_cursor_area ( & self , _position : Position , _size : Size ) { }
2020-05-06 15:27:49 +02:00
2022-05-07 05:29:25 +03:00
pub fn set_ime_allowed ( & self , _allowed : bool ) { }
2023-01-29 16:46:46 +01:00
pub fn set_ime_purpose ( & self , _purpose : ImePurpose ) { }
2021-05-19 18:39:53 +02:00
pub fn focus_window ( & self ) { }
2020-11-27 03:03:08 +01:00
pub fn request_user_attention ( & self , _request_type : Option < window ::UserAttentionType > ) { }
2020-05-06 15:27:49 +02:00
pub fn set_cursor_icon ( & self , _ : window ::CursorIcon ) { }
2019-12-22 01:04:11 -05:00
2020-05-06 15:27:49 +02:00
pub fn set_cursor_position ( & self , _ : Position ) -> Result < ( ) , error ::ExternalError > {
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
2017-09-07 09:33:46 +01:00
}
2022-06-13 09:43:14 +03:00
pub fn set_cursor_grab ( & self , _ : CursorGrabMode ) -> Result < ( ) , error ::ExternalError > {
2020-05-06 15:27:49 +02:00
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
2019-04-26 03:09:32 +10:00
}
2020-05-06 15:27:49 +02:00
pub fn set_cursor_visible ( & self , _ : bool ) { }
2021-03-07 10:43:23 +01:00
pub fn drag_window ( & self ) -> Result < ( ) , error ::ExternalError > {
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
}
2023-01-11 18:07:09 +01:00
pub fn drag_resize_window (
& self ,
_direction : ResizeDirection ,
) -> Result < ( ) , error ::ExternalError > {
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
}
2022-04-12 19:10:46 +02:00
pub fn set_cursor_hittest ( & self , _hittest : bool ) -> Result < ( ) , error ::ExternalError > {
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
}
2021-11-30 17:50:23 +01:00
pub fn raw_window_handle ( & self ) -> RawWindowHandle {
2022-11-10 16:55:19 +00:00
if let Some ( native_window ) = self . app . native_window ( ) . as_ref ( ) {
2022-06-10 11:37:06 +02:00
native_window . raw_window_handle ( )
2020-05-06 15:27:49 +02:00
} else {
2020-10-29 16:23:46 -05:00
panic! ( " Cannot get the native window, it's null and will always be null before Event::Resumed and after Event::Suspended. Make sure you only call this function between those events. " ) ;
2022-06-10 11:37:06 +02:00
}
2017-08-28 01:43:34 +01:00
}
2022-07-21 22:22:36 +03:00
pub fn raw_display_handle ( & self ) -> RawDisplayHandle {
RawDisplayHandle ::Android ( AndroidDisplayHandle ::empty ( ) )
}
2022-11-10 16:55:19 +00:00
pub fn config ( & self ) -> ConfigurationRef {
self . app . config ( )
2017-12-22 07:50:46 -05:00
}
2020-05-06 15:27:49 +02:00
pub fn content_rect ( & self ) -> Rect {
2022-11-10 16:55:19 +00:00
self . app . content_rect ( )
2018-05-20 10:24:05 -04:00
}
2022-10-19 03:34:36 +09:00
2022-11-29 11:05:51 +02:00
pub fn set_theme ( & self , _theme : Option < Theme > ) { }
2022-10-19 03:34:36 +09:00
pub fn theme ( & self ) -> Option < Theme > {
None
}
2022-11-03 10:11:37 -07:00
2023-01-17 03:30:14 +02:00
pub fn has_focus ( & self ) -> bool {
* HAS_FOCUS . read ( ) . unwrap ( )
}
2022-11-03 10:11:37 -07:00
pub fn title ( & self ) -> String {
String ::new ( )
}
2023-05-28 20:02:59 +02:00
pub fn reset_dead_keys ( & self ) { }
2020-05-06 15:27:49 +02:00
}
2018-05-20 10:24:05 -04:00
2020-05-06 15:27:49 +02:00
#[ derive(Default, Clone, Debug) ]
pub struct OsError ;
use std ::fmt ::{ self , Display , Formatter } ;
impl Display for OsError {
fn fmt ( & self , fmt : & mut Formatter < '_ > ) -> Result < ( ) , fmt ::Error > {
write! ( fmt , " Android OS Error " )
2018-05-07 17:36:21 -04:00
}
2020-05-06 15:27:49 +02:00
}
2018-05-07 17:36:21 -04:00
2020-05-06 15:27:49 +02:00
pub ( crate ) use crate ::icon ::NoIcon as PlatformIcon ;
2022-11-10 16:55:19 +00:00
#[ derive(Clone, Debug, PartialEq, Eq, Hash) ]
pub struct MonitorHandle {
app : AndroidApp ,
}
impl PartialOrd for MonitorHandle {
2023-07-31 00:39:01 +04:00
fn partial_cmp ( & self , other : & Self ) -> Option < std ::cmp ::Ordering > {
Some ( self . cmp ( other ) )
2022-11-10 16:55:19 +00:00
}
}
impl Ord for MonitorHandle {
fn cmp ( & self , _other : & Self ) -> std ::cmp ::Ordering {
std ::cmp ::Ordering ::Equal
}
}
2020-05-06 15:27:49 +02:00
impl MonitorHandle {
2022-11-10 16:55:19 +00:00
pub ( crate ) fn new ( app : AndroidApp ) -> Self {
Self { app }
}
2020-05-06 15:27:49 +02:00
pub fn name ( & self ) -> Option < String > {
Some ( " Android Device " . to_owned ( ) )
2018-05-17 21:28:30 -04:00
}
2020-05-06 15:27:49 +02:00
pub fn size ( & self ) -> PhysicalSize < u32 > {
2022-11-10 16:55:19 +00:00
if let Some ( native_window ) = self . app . native_window ( ) {
PhysicalSize ::new ( native_window . width ( ) as _ , native_window . height ( ) as _ )
2020-05-06 15:27:49 +02:00
} else {
PhysicalSize ::new ( 0 , 0 )
2019-06-21 11:33:15 -04:00
}
2017-08-28 00:22:26 +01:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn position ( & self ) -> PhysicalPosition < i32 > {
( 0 , 0 ) . into ( )
2018-06-16 10:14:12 -04:00
}
2020-05-06 15:27:49 +02:00
pub fn scale_factor ( & self ) -> f64 {
2022-11-10 16:55:19 +00:00
self . app
. config ( )
2020-05-06 15:27:49 +02:00
. density ( )
. map ( | dpi | dpi as f64 / 160.0 )
. unwrap_or ( 1.0 )
}
2022-07-08 13:25:56 +03:00
pub fn refresh_rate_millihertz ( & self ) -> Option < u32 > {
2022-07-15 14:02:12 -02:30
// FIXME no way to get real refresh rate for now.
2022-07-08 13:25:56 +03:00
None
}
2022-09-21 10:04:28 +02:00
pub fn video_modes ( & self ) -> impl Iterator < Item = VideoMode > {
2020-05-06 15:27:49 +02:00
let size = self . size ( ) . into ( ) ;
// FIXME this is not the real refresh rate
2022-06-10 13:43:33 +03:00
// (it is guaranteed to support 32 bit color though)
2022-09-21 10:04:28 +02:00
std ::iter ::once ( VideoMode {
size ,
bit_depth : 32 ,
refresh_rate_millihertz : 60000 ,
monitor : self . clone ( ) ,
2022-06-10 13:43:33 +03:00
} )
2018-06-16 10:14:12 -04:00
}
2020-05-06 15:27:49 +02:00
}
2018-06-16 10:14:12 -04:00
2020-05-06 15:27:49 +02:00
#[ derive(Clone, Debug, Eq, Hash, PartialEq) ]
pub struct VideoMode {
size : ( u32 , u32 ) ,
bit_depth : u16 ,
2022-07-08 13:25:56 +03:00
refresh_rate_millihertz : u32 ,
2020-05-06 15:27:49 +02:00
monitor : MonitorHandle ,
}
impl VideoMode {
pub fn size ( & self ) -> PhysicalSize < u32 > {
self . size . into ( )
2016-10-31 17:08:55 +01:00
}
2019-09-30 17:17:01 +02:00
2020-05-06 15:27:49 +02:00
pub fn bit_depth ( & self ) -> u16 {
self . bit_depth
2019-09-30 17:17:01 +02:00
}
2017-07-06 23:33:42 +02:00
2022-07-08 13:25:56 +03:00
pub fn refresh_rate_millihertz ( & self ) -> u32 {
self . refresh_rate_millihertz
2020-05-06 15:27:49 +02:00
}
2017-09-04 12:41:02 +02:00
2022-09-21 10:04:28 +02:00
pub fn monitor ( & self ) -> MonitorHandle {
self . monitor . clone ( )
2020-05-06 15:27:49 +02:00
}
}