2015-04-24 09:51:23 +02:00
#![ cfg(target_os = " android " ) ]
2022-06-08 11:50:26 -07:00
use std ::{
collections ::VecDeque ,
2022-07-20 14:52:36 -03:00
sync ::{ mpsc , RwLock } ,
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
2020-05-06 15:27:49 +02:00
use ndk ::{
configuration ::Configuration ,
2022-04-01 18:16:59 +02:00
event ::{ InputEvent , KeyAction , Keycode , MotionAction } ,
2020-05-06 15:27:49 +02:00
looper ::{ ForeignLooper , Poll , ThreadLooper } ,
2022-07-14 12:35:49 +02:00
native_window ::NativeWindow ,
2020-05-06 15:27:49 +02:00
} ;
2022-07-14 12:35:49 +02:00
use ndk_glue ::{ Event , LockReadGuard , Rect } ;
2022-06-08 11:50:26 -07: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 ,
event ::{ self , VirtualKeyCode } ,
event_loop ::{ self , ControlFlow } ,
2022-06-13 09:43:14 +03:00
monitor ,
window ::{ self , CursorGrabMode } ,
2019-06-21 11:33:15 -04:00
} ;
2022-06-08 11:50:26 -07:00
static CONFIG : Lazy < RwLock < Configuration > > = Lazy ::new ( | | {
RwLock ::new ( Configuration ::from_asset_manager (
2022-02-17 18:50:18 +01:00
#[ allow(deprecated) ] // TODO: rust-windowing/winit#2196
2022-06-08 11:50:26 -07:00
& ndk_glue ::native_activity ( ) . asset_manager ( ) ,
) )
} ) ;
// If this is `Some()` a `Poll::Wake` is considered an `EventSource::Internal` with the event
// contained in the `Option`. The event is moved outside of the `Option` replacing it with a
// `None`.
//
// This allows us to inject event into the event loop without going through `ndk-glue` and
// calling unsafe function that should only be called by Android.
static INTERNAL_EVENT : Lazy < RwLock < Option < InternalEvent > > > = Lazy ::new ( | | RwLock ::new ( None ) ) ;
2021-06-05 12:47:08 +02:00
enum InternalEvent {
RedrawRequested ,
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
enum EventSource {
Callback ,
InputQueue ,
User ,
2021-06-05 12:47:08 +02:00
Internal ( InternalEvent ) ,
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
2022-04-01 18:16:59 +02:00
fn ndk_keycode_to_virtualkeycode ( keycode : Keycode ) -> Option < event ::VirtualKeyCode > {
match keycode {
Keycode ::A = > Some ( VirtualKeyCode ::A ) ,
Keycode ::B = > Some ( VirtualKeyCode ::B ) ,
Keycode ::C = > Some ( VirtualKeyCode ::C ) ,
Keycode ::D = > Some ( VirtualKeyCode ::D ) ,
Keycode ::E = > Some ( VirtualKeyCode ::E ) ,
Keycode ::F = > Some ( VirtualKeyCode ::F ) ,
Keycode ::G = > Some ( VirtualKeyCode ::G ) ,
Keycode ::H = > Some ( VirtualKeyCode ::H ) ,
Keycode ::I = > Some ( VirtualKeyCode ::I ) ,
Keycode ::J = > Some ( VirtualKeyCode ::J ) ,
Keycode ::K = > Some ( VirtualKeyCode ::K ) ,
Keycode ::L = > Some ( VirtualKeyCode ::L ) ,
Keycode ::M = > Some ( VirtualKeyCode ::M ) ,
Keycode ::N = > Some ( VirtualKeyCode ::N ) ,
Keycode ::O = > Some ( VirtualKeyCode ::O ) ,
Keycode ::P = > Some ( VirtualKeyCode ::P ) ,
Keycode ::Q = > Some ( VirtualKeyCode ::Q ) ,
Keycode ::R = > Some ( VirtualKeyCode ::R ) ,
Keycode ::S = > Some ( VirtualKeyCode ::S ) ,
Keycode ::T = > Some ( VirtualKeyCode ::T ) ,
Keycode ::U = > Some ( VirtualKeyCode ::U ) ,
Keycode ::V = > Some ( VirtualKeyCode ::V ) ,
Keycode ::W = > Some ( VirtualKeyCode ::W ) ,
Keycode ::X = > Some ( VirtualKeyCode ::X ) ,
Keycode ::Y = > Some ( VirtualKeyCode ::Y ) ,
Keycode ::Z = > Some ( VirtualKeyCode ::Z ) ,
Keycode ::Keycode0 = > Some ( VirtualKeyCode ::Key0 ) ,
Keycode ::Keycode1 = > Some ( VirtualKeyCode ::Key1 ) ,
Keycode ::Keycode2 = > Some ( VirtualKeyCode ::Key2 ) ,
Keycode ::Keycode3 = > Some ( VirtualKeyCode ::Key3 ) ,
Keycode ::Keycode4 = > Some ( VirtualKeyCode ::Key4 ) ,
Keycode ::Keycode5 = > Some ( VirtualKeyCode ::Key5 ) ,
Keycode ::Keycode6 = > Some ( VirtualKeyCode ::Key6 ) ,
Keycode ::Keycode7 = > Some ( VirtualKeyCode ::Key7 ) ,
Keycode ::Keycode8 = > Some ( VirtualKeyCode ::Key8 ) ,
Keycode ::Keycode9 = > Some ( VirtualKeyCode ::Key9 ) ,
Keycode ::Numpad0 = > Some ( VirtualKeyCode ::Numpad0 ) ,
Keycode ::Numpad1 = > Some ( VirtualKeyCode ::Numpad1 ) ,
Keycode ::Numpad2 = > Some ( VirtualKeyCode ::Numpad2 ) ,
Keycode ::Numpad3 = > Some ( VirtualKeyCode ::Numpad3 ) ,
Keycode ::Numpad4 = > Some ( VirtualKeyCode ::Numpad4 ) ,
Keycode ::Numpad5 = > Some ( VirtualKeyCode ::Numpad5 ) ,
Keycode ::Numpad6 = > Some ( VirtualKeyCode ::Numpad6 ) ,
Keycode ::Numpad7 = > Some ( VirtualKeyCode ::Numpad7 ) ,
Keycode ::Numpad8 = > Some ( VirtualKeyCode ::Numpad8 ) ,
Keycode ::Numpad9 = > Some ( VirtualKeyCode ::Numpad9 ) ,
Keycode ::NumpadAdd = > Some ( VirtualKeyCode ::NumpadAdd ) ,
Keycode ::NumpadSubtract = > Some ( VirtualKeyCode ::NumpadSubtract ) ,
Keycode ::NumpadMultiply = > Some ( VirtualKeyCode ::NumpadMultiply ) ,
Keycode ::NumpadDivide = > Some ( VirtualKeyCode ::NumpadDivide ) ,
Keycode ::NumpadEnter = > Some ( VirtualKeyCode ::NumpadEnter ) ,
Keycode ::NumpadEquals = > Some ( VirtualKeyCode ::NumpadEquals ) ,
Keycode ::NumpadComma = > Some ( VirtualKeyCode ::NumpadComma ) ,
Keycode ::NumpadDot = > Some ( VirtualKeyCode ::NumpadDecimal ) ,
Keycode ::NumLock = > Some ( VirtualKeyCode ::Numlock ) ,
Keycode ::DpadLeft = > Some ( VirtualKeyCode ::Left ) ,
Keycode ::DpadRight = > Some ( VirtualKeyCode ::Right ) ,
Keycode ::DpadUp = > Some ( VirtualKeyCode ::Up ) ,
Keycode ::DpadDown = > Some ( VirtualKeyCode ::Down ) ,
Keycode ::F1 = > Some ( VirtualKeyCode ::F1 ) ,
Keycode ::F2 = > Some ( VirtualKeyCode ::F2 ) ,
Keycode ::F3 = > Some ( VirtualKeyCode ::F3 ) ,
Keycode ::F4 = > Some ( VirtualKeyCode ::F4 ) ,
Keycode ::F5 = > Some ( VirtualKeyCode ::F5 ) ,
Keycode ::F6 = > Some ( VirtualKeyCode ::F6 ) ,
Keycode ::F7 = > Some ( VirtualKeyCode ::F7 ) ,
Keycode ::F8 = > Some ( VirtualKeyCode ::F8 ) ,
Keycode ::F9 = > Some ( VirtualKeyCode ::F9 ) ,
Keycode ::F10 = > Some ( VirtualKeyCode ::F10 ) ,
Keycode ::F11 = > Some ( VirtualKeyCode ::F11 ) ,
Keycode ::F12 = > Some ( VirtualKeyCode ::F12 ) ,
Keycode ::Space = > Some ( VirtualKeyCode ::Space ) ,
Keycode ::Escape = > Some ( VirtualKeyCode ::Escape ) ,
Keycode ::Enter = > Some ( VirtualKeyCode ::Return ) , // not on the Numpad
Keycode ::Tab = > Some ( VirtualKeyCode ::Tab ) ,
Keycode ::PageUp = > Some ( VirtualKeyCode ::PageUp ) ,
Keycode ::PageDown = > Some ( VirtualKeyCode ::PageDown ) ,
Keycode ::MoveHome = > Some ( VirtualKeyCode ::Home ) ,
Keycode ::MoveEnd = > Some ( VirtualKeyCode ::End ) ,
Keycode ::Insert = > Some ( VirtualKeyCode ::Insert ) ,
Keycode ::Del = > Some ( VirtualKeyCode ::Back ) , // Backspace (above Enter)
Keycode ::ForwardDel = > Some ( VirtualKeyCode ::Delete ) , // Delete (below Insert)
Keycode ::Copy = > Some ( VirtualKeyCode ::Copy ) ,
Keycode ::Paste = > Some ( VirtualKeyCode ::Paste ) ,
Keycode ::Cut = > Some ( VirtualKeyCode ::Cut ) ,
Keycode ::VolumeUp = > Some ( VirtualKeyCode ::VolumeUp ) ,
Keycode ::VolumeDown = > Some ( VirtualKeyCode ::VolumeDown ) ,
Keycode ::VolumeMute = > Some ( VirtualKeyCode ::Mute ) , // ???
Keycode ::Mute = > Some ( VirtualKeyCode ::Mute ) , // ???
Keycode ::MediaPlayPause = > Some ( VirtualKeyCode ::PlayPause ) ,
Keycode ::MediaStop = > Some ( VirtualKeyCode ::MediaStop ) , // ??? simple "Stop"?
Keycode ::MediaNext = > Some ( VirtualKeyCode ::NextTrack ) ,
Keycode ::MediaPrevious = > Some ( VirtualKeyCode ::PrevTrack ) ,
Keycode ::Plus = > Some ( VirtualKeyCode ::Plus ) ,
Keycode ::Minus = > Some ( VirtualKeyCode ::Minus ) ,
Keycode ::Equals = > Some ( VirtualKeyCode ::Equals ) ,
Keycode ::Semicolon = > Some ( VirtualKeyCode ::Semicolon ) ,
Keycode ::Slash = > Some ( VirtualKeyCode ::Slash ) ,
Keycode ::Backslash = > Some ( VirtualKeyCode ::Backslash ) ,
Keycode ::Comma = > Some ( VirtualKeyCode ::Comma ) ,
Keycode ::Period = > Some ( VirtualKeyCode ::Period ) ,
Keycode ::Apostrophe = > Some ( VirtualKeyCode ::Apostrophe ) ,
Keycode ::Grave = > Some ( VirtualKeyCode ::Grave ) ,
Keycode ::At = > Some ( VirtualKeyCode ::At ) ,
// TODO: Maybe mapping this to Snapshot makes more sense? See: "PrtScr/SysRq"
Keycode ::Sysrq = > Some ( VirtualKeyCode ::Sysrq ) ,
// These are usually the same (Pause/Break)
Keycode ::Break = > Some ( VirtualKeyCode ::Pause ) ,
// These are exactly the same
Keycode ::ScrollLock = > Some ( VirtualKeyCode ::Scroll ) ,
Keycode ::Yen = > Some ( VirtualKeyCode ::Yen ) ,
Keycode ::Kana = > Some ( VirtualKeyCode ::Kana ) ,
Keycode ::CtrlLeft = > Some ( VirtualKeyCode ::LControl ) ,
Keycode ::CtrlRight = > Some ( VirtualKeyCode ::RControl ) ,
Keycode ::ShiftLeft = > Some ( VirtualKeyCode ::LShift ) ,
Keycode ::ShiftRight = > Some ( VirtualKeyCode ::RShift ) ,
Keycode ::AltLeft = > Some ( VirtualKeyCode ::LAlt ) ,
Keycode ::AltRight = > Some ( VirtualKeyCode ::RAlt ) ,
// Different names for the same keys
Keycode ::MetaLeft = > Some ( VirtualKeyCode ::LWin ) ,
Keycode ::MetaRight = > Some ( VirtualKeyCode ::RWin ) ,
Keycode ::LeftBracket = > Some ( VirtualKeyCode ::LBracket ) ,
Keycode ::RightBracket = > Some ( VirtualKeyCode ::RBracket ) ,
Keycode ::Power = > Some ( VirtualKeyCode ::Power ) ,
Keycode ::Sleep = > Some ( VirtualKeyCode ::Sleep ) , // what about SoftSleep?
Keycode ::Wakeup = > Some ( VirtualKeyCode ::Wake ) ,
Keycode ::NavigateNext = > Some ( VirtualKeyCode ::NavigateForward ) ,
Keycode ::NavigatePrevious = > Some ( VirtualKeyCode ::NavigateBackward ) ,
Keycode ::Calculator = > Some ( VirtualKeyCode ::Calculator ) ,
Keycode ::Explorer = > Some ( VirtualKeyCode ::MyComputer ) , // "close enough"
Keycode ::Envelope = > Some ( VirtualKeyCode ::Mail ) , // "close enough"
Keycode ::Star = > Some ( VirtualKeyCode ::Asterisk ) , // ???
Keycode ::AllApps = > Some ( VirtualKeyCode ::Apps ) , // ???
Keycode ::AppSwitch = > Some ( VirtualKeyCode ::Apps ) , // ???
Keycode ::Refresh = > Some ( VirtualKeyCode ::WebRefresh ) , // ???
_ = > None ,
}
}
2020-05-06 15:27:49 +02:00
fn poll ( poll : Poll ) -> Option < EventSource > {
match poll {
2021-01-13 23:02:55 +01:00
Poll ::Event { ident , .. } = > match ident {
2021-01-30 19:43:26 +01:00
ndk_glue ::NDK_GLUE_LOOPER_EVENT_PIPE_IDENT = > Some ( EventSource ::Callback ) ,
ndk_glue ::NDK_GLUE_LOOPER_INPUT_QUEUE_IDENT = > Some ( EventSource ::InputQueue ) ,
2020-05-06 15:27:49 +02:00
_ = > unreachable! ( ) ,
} ,
Poll ::Timeout = > None ,
2021-06-05 12:47:08 +02:00
Poll ::Wake = > Some (
INTERNAL_EVENT
. write ( )
. unwrap ( )
. take ( )
. map_or ( EventSource ::User , EventSource ::Internal ) ,
) ,
2020-05-06 15:27:49 +02:00
Poll ::Callback = > unreachable! ( ) ,
2017-09-04 12:41:02 +02:00
}
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub struct EventLoop < T : 'static > {
window_target : event_loop ::EventLoopWindowTarget < T > ,
2022-07-20 14:52:36 -03:00
user_events_sender : mpsc ::Sender < T > ,
user_events_receiver : mpsc ::Receiver < T > ,
2020-06-17 15:55:52 +02:00
first_event : Option < EventSource > ,
start_cause : event ::StartCause ,
looper : ThreadLooper ,
running : bool ,
2022-07-14 12:35:49 +02:00
window_lock : Option < LockReadGuard < NativeWindow > > ,
2020-06-17 15:55:52 +02:00
}
2022-06-10 13:43:33 +03:00
#[ derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash) ]
2022-02-16 22:09:03 +01:00
pub ( crate ) struct PlatformSpecificEventLoopAttributes { }
2020-06-17 15:55:52 +02:00
macro_rules ! call_event_handler {
( $event_handler :expr , $window_target :expr , $cf :expr , $event :expr ) = > { {
2022-01-11 01:23:20 +01:00
if let ControlFlow ::ExitWithCode ( code ) = $cf {
$event_handler ( $event , $window_target , & mut ControlFlow ::ExitWithCode ( code ) ) ;
2020-06-17 15:55:52 +02:00
} else {
2022-01-11 01:23:20 +01:00
$event_handler ( $event , $window_target , & mut $cf ) ;
2020-06-17 15:55:52 +02:00
}
} } ;
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
impl < T : 'static > EventLoop < T > {
2022-02-16 22:09:03 +01:00
pub ( crate ) fn new ( _ : & PlatformSpecificEventLoopAttributes ) -> Self {
2022-07-20 14:52:36 -03:00
let ( user_events_sender , user_events_receiver ) = mpsc ::channel ( ) ;
2020-05-06 15:27:49 +02:00
Self {
window_target : event_loop ::EventLoopWindowTarget {
p : EventLoopWindowTarget {
_marker : std ::marker ::PhantomData ,
} ,
_marker : std ::marker ::PhantomData ,
} ,
2022-07-20 14:52:36 -03:00
user_events_sender ,
user_events_receiver ,
2020-06-17 15:55:52 +02:00
first_event : None ,
start_cause : event ::StartCause ::Init ,
looper : ThreadLooper ::for_thread ( ) . unwrap ( ) ,
running : false ,
2022-07-14 12:35:49 +02:00
window_lock : None ,
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
}
2020-06-17 15:55:52 +02:00
pub fn run < F > ( mut self , event_handler : F ) -> !
2019-06-21 11:33:15 -04:00
where
2020-05-06 15:27:49 +02:00
F : 'static
+ FnMut ( event ::Event < '_ , T > , & event_loop ::EventLoopWindowTarget < T > , & mut ControlFlow ) ,
2017-09-04 12:41:02 +02:00
{
2022-01-11 01:23:20 +01:00
let exit_code = self . run_return ( event_handler ) ;
::std ::process ::exit ( exit_code ) ;
2020-06-17 15:55:52 +02:00
}
2022-01-11 01:23:20 +01:00
pub fn run_return < F > ( & mut self , mut event_handler : F ) -> i32
2020-06-17 15:55:52 +02:00
where
F : FnMut ( event ::Event < '_ , T > , & event_loop ::EventLoopWindowTarget < T > , & mut ControlFlow ) ,
{
let mut control_flow = ControlFlow ::default ( ) ;
' event_loop : loop {
call_event_handler! (
event_handler ,
2020-05-06 15:27:49 +02:00
self . window_target ( ) ,
2020-06-17 15:55:52 +02:00
control_flow ,
event ::Event ::NewEvents ( self . start_cause )
2020-05-06 15:27:49 +02:00
) ;
let mut redraw = false ;
let mut resized = false ;
2020-06-17 15:55:52 +02:00
match self . first_event . take ( ) {
2020-05-06 15:27:49 +02:00
Some ( EventSource ::Callback ) = > match ndk_glue ::poll_events ( ) . unwrap ( ) {
Event ::WindowCreated = > {
2022-07-14 12:35:49 +02:00
// Acquire a lock on the window to prevent Android from destroying
// it until we've notified and waited for the user in Event::Suspended.
// WARNING: ndk-glue is inherently racy (https://github.com/rust-windowing/winit/issues/2293)
// and may have already received onNativeWindowDestroyed while this thread hasn't yet processed
// the event, and would see a `None` lock+window in that case.
if let Some ( next_window_lock ) = ndk_glue ::native_window ( ) {
assert! (
self . window_lock . replace ( next_window_lock ) . is_none ( ) ,
" Received `Event::WindowCreated` while we were already holding a lock "
) ;
call_event_handler! (
event_handler ,
self . window_target ( ) ,
control_flow ,
event ::Event ::Resumed
) ;
} else {
warn! ( " Received `Event::WindowCreated` while `ndk_glue::native_window()` provides no window " ) ;
}
2020-05-06 15:27:49 +02:00
}
Event ::WindowResized = > resized = true ,
Event ::WindowRedrawNeeded = > redraw = true ,
Event ::WindowDestroyed = > {
2022-07-14 12:35:49 +02:00
// Release the lock, allowing Android to clean up this surface
// WARNING: See above - if ndk-glue is racy, this event may be called
// without having a `self.window_lock` in place.
if self . window_lock . take ( ) . is_some ( ) {
call_event_handler! (
event_handler ,
self . window_target ( ) ,
control_flow ,
event ::Event ::Suspended
) ;
} else {
warn! ( " Received `Event::WindowDestroyed` while we were not holding a window lock " ) ;
}
2020-05-06 15:27:49 +02:00
}
2020-06-17 15:55:52 +02:00
Event ::Pause = > self . running = false ,
Event ::Resume = > self . running = true ,
2020-05-06 15:27:49 +02:00
Event ::ConfigChanged = > {
2022-02-17 18:50:18 +01:00
#[ allow(deprecated) ] // TODO: rust-windowing/winit#2196
2020-05-06 15:27:49 +02:00
let am = ndk_glue ::native_activity ( ) . asset_manager ( ) ;
let config = Configuration ::from_asset_manager ( & am ) ;
let old_scale_factor = MonitorHandle . scale_factor ( ) ;
* CONFIG . write ( ) . unwrap ( ) = config ;
let scale_factor = MonitorHandle . scale_factor ( ) ;
if ( scale_factor - old_scale_factor ) . abs ( ) < f64 ::EPSILON {
let mut size = MonitorHandle . size ( ) ;
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::ScaleFactorChanged {
new_inner_size : & mut size ,
scale_factor ,
} ,
} ;
2020-06-17 15:55:52 +02:00
call_event_handler! (
event_handler ,
self . window_target ( ) ,
control_flow ,
event
) ;
2020-05-06 15:27:49 +02:00
}
}
2020-10-08 19:44:41 +02:00
Event ::WindowHasFocus = > {
call_event_handler! (
event_handler ,
self . window_target ( ) ,
control_flow ,
event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Focused ( true ) ,
}
) ;
}
Event ::WindowLostFocus = > {
call_event_handler! (
event_handler ,
self . window_target ( ) ,
control_flow ,
event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Focused ( false ) ,
}
) ;
}
2020-05-06 15:27:49 +02:00
_ = > { }
} ,
Some ( EventSource ::InputQueue ) = > {
if let Some ( input_queue ) = ndk_glue ::input_queue ( ) . as_ref ( ) {
2022-07-14 12:35:49 +02:00
while let Some ( event ) = input_queue . get_event ( ) . expect ( " get_event " ) {
2020-05-06 15:27:49 +02:00
if let Some ( event ) = input_queue . pre_dispatch ( event ) {
2021-01-12 08:25:56 +01:00
let mut handled = true ;
2020-05-06 15:27:49 +02:00
let window_id = window ::WindowId ( WindowId ) ;
let device_id = event ::DeviceId ( DeviceId ) ;
match & event {
InputEvent ::MotionEvent ( motion_event ) = > {
let phase = match motion_event . action ( ) {
2020-11-28 17:41:11 +01:00
MotionAction ::Down | MotionAction ::PointerDown = > {
Some ( event ::TouchPhase ::Started )
}
MotionAction ::Up | MotionAction ::PointerUp = > {
Some ( event ::TouchPhase ::Ended )
}
2020-05-06 15:27:49 +02:00
MotionAction ::Move = > Some ( event ::TouchPhase ::Moved ) ,
MotionAction ::Cancel = > {
Some ( event ::TouchPhase ::Cancelled )
}
2021-01-12 08:25:56 +01:00
_ = > {
handled = false ;
None // TODO mouse events
}
2020-05-06 15:27:49 +02:00
} ;
if let Some ( phase ) = phase {
2020-12-02 21:13:42 +01:00
let pointers : Box <
dyn Iterator < Item = ndk ::event ::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 {
2020-11-28 17:41:11 +01:00
let location = PhysicalPosition {
x : pointer . x ( ) as _ ,
y : pointer . y ( ) as _ ,
} ;
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 ,
} ,
) ,
} ;
call_event_handler! (
event_handler ,
self . window_target ( ) ,
control_flow ,
event
) ;
}
2020-05-06 15:27:49 +02:00
}
}
2021-02-23 18:35:38 -03:00
InputEvent ::KeyEvent ( key ) = > {
let state = match key . action ( ) {
KeyAction ::Down = > event ::ElementState ::Pressed ,
KeyAction ::Up = > event ::ElementState ::Released ,
_ = > event ::ElementState ::Released ,
} ;
2021-03-30 21:27:32 +02:00
#[ allow(deprecated) ]
2021-02-23 18:35:38 -03:00
let event = event ::Event ::WindowEvent {
window_id ,
event : event ::WindowEvent ::KeyboardInput {
device_id ,
input : event ::KeyboardInput {
scancode : key . scan_code ( ) as u32 ,
state ,
2022-04-01 18:16:59 +02:00
virtual_keycode : ndk_keycode_to_virtualkeycode (
key . key_code ( ) ,
) ,
2021-02-23 18:35:38 -03:00
modifiers : event ::ModifiersState ::default ( ) ,
} ,
is_synthetic : false ,
} ,
} ;
call_event_handler! (
event_handler ,
self . window_target ( ) ,
control_flow ,
event
) ;
2021-01-12 08:25:56 +01:00
}
2020-05-06 15:27:49 +02:00
} ;
2021-01-12 08:25:56 +01:00
input_queue . finish_event ( event , handled ) ;
2020-05-06 15:27:49 +02:00
}
}
}
2019-06-24 12:14:55 -04:00
}
2020-05-06 15:27:49 +02:00
Some ( EventSource ::User ) = > {
2022-07-20 14:52:36 -03:00
// try_recv only errors when empty (expected) or disconnect. But because Self
// contains a Sender it will never disconnect, so no error handling need.
while let Ok ( event ) = self . user_events_receiver . try_recv ( ) {
2020-06-17 15:55:52 +02:00
call_event_handler! (
event_handler ,
2020-05-06 15:27:49 +02:00
self . window_target ( ) ,
2020-06-17 15:55:52 +02:00
control_flow ,
event ::Event ::UserEvent ( event )
2020-05-06 15:27:49 +02:00
) ;
2018-02-15 14:09:14 +01:00
}
2019-06-24 12:14:55 -04:00
}
2021-06-05 12:47:08 +02:00
Some ( EventSource ::Internal ( internal ) ) = > match internal {
InternalEvent ::RedrawRequested = > redraw = true ,
} ,
2020-08-12 20:56:28 +02:00
None = > { }
2020-05-06 15:27:49 +02:00
}
2020-06-17 15:55:52 +02:00
call_event_handler! (
event_handler ,
2020-05-06 15:27:49 +02:00
self . window_target ( ) ,
2020-06-17 15:55:52 +02:00
control_flow ,
event ::Event ::MainEventsCleared
2020-05-06 15:27:49 +02:00
) ;
2020-06-17 15:55:52 +02:00
if resized & & self . running {
2020-05-06 15:27:49 +02:00
let size = MonitorHandle . size ( ) ;
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Resized ( size ) ,
} ;
2020-06-17 15:55:52 +02:00
call_event_handler! ( event_handler , self . window_target ( ) , control_flow , event ) ;
2020-05-06 15:27:49 +02:00
}
2020-06-17 15:55:52 +02:00
if redraw & & self . running {
2020-05-06 15:27:49 +02:00
let event = event ::Event ::RedrawRequested ( window ::WindowId ( WindowId ) ) ;
2020-06-17 15:55:52 +02:00
call_event_handler! ( event_handler , self . window_target ( ) , control_flow , event ) ;
2020-05-06 15:27:49 +02:00
}
2020-06-17 15:55:52 +02:00
call_event_handler! (
event_handler ,
2020-05-06 15:27:49 +02:00
self . window_target ( ) ,
2020-06-17 15:55:52 +02:00
control_flow ,
event ::Event ::RedrawEventsCleared
2020-05-06 15:27:49 +02:00
) ;
2020-06-17 15:55:52 +02:00
match control_flow {
2022-01-11 01:23:20 +01:00
ControlFlow ::ExitWithCode ( code ) = > {
2020-06-17 15:55:52 +02:00
self . first_event = poll (
self . looper
. poll_once_timeout ( Duration ::from_millis ( 0 ) )
. unwrap ( ) ,
) ;
self . start_cause = event ::StartCause ::WaitCancelled {
start : Instant ::now ( ) ,
requested_resume : None ,
} ;
2022-01-11 01:23:20 +01:00
break 'event_loop code ;
2020-06-17 15:55:52 +02:00
}
2020-05-06 15:27:49 +02:00
ControlFlow ::Poll = > {
2020-08-12 20:56:28 +02:00
self . first_event = poll (
self . looper
. poll_all_timeout ( Duration ::from_millis ( 0 ) )
. unwrap ( ) ,
) ;
2020-06-17 15:55:52 +02:00
self . start_cause = event ::StartCause ::Poll ;
2020-05-06 15:27:49 +02:00
}
ControlFlow ::Wait = > {
2020-06-17 15:55:52 +02:00
self . first_event = poll ( self . looper . poll_all ( ) . unwrap ( ) ) ;
self . start_cause = event ::StartCause ::WaitCancelled {
2020-05-06 15:27:49 +02:00
start : Instant ::now ( ) ,
requested_resume : None ,
2018-02-15 14:09:14 +01:00
}
2019-06-24 12:14:55 -04:00
}
2020-05-06 15:27:49 +02:00
ControlFlow ::WaitUntil ( instant ) = > {
let start = Instant ::now ( ) ;
let duration = if instant < = start {
Duration ::default ( )
2017-10-29 02:02:57 -04:00
} else {
2020-05-06 15:27:49 +02:00
instant - start
} ;
2020-06-17 15:55:52 +02:00
self . first_event = poll ( self . looper . poll_all_timeout ( duration ) . unwrap ( ) ) ;
self . start_cause = if self . first_event . is_some ( ) {
2020-05-06 15:27:49 +02:00
event ::StartCause ::WaitCancelled {
start ,
requested_resume : Some ( instant ) ,
}
} else {
event ::StartCause ::ResumeTimeReached {
start ,
requested_resume : instant ,
}
2017-10-29 02:02:57 -04:00
}
2019-06-24 12:14:55 -04:00
}
2016-10-31 17:08:55 +01:00
}
2019-06-21 11:33:15 -04:00
}
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 ( ) ,
2020-05-06 15:27:49 +02:00
looper : ForeignLooper ::for_thread ( ) . expect ( " called from event loop thread " ) ,
}
}
}
pub struct EventLoopProxy < T : 'static > {
2022-07-20 14:52:36 -03:00
user_events_sender : mpsc ::Sender < T > ,
2020-05-06 15:27:49 +02:00
looper : ForeignLooper ,
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 )
. map_err ( | mpsc ::SendError ( x ) | event_loop ::EventLoopClosed ( x ) ) ? ;
2020-05-06 15:27:49 +02:00
self . looper . 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
impl < T > Clone for EventLoopProxy < T > {
fn clone ( & self ) -> Self {
EventLoopProxy {
2022-07-20 14:52:36 -03:00
user_events_sender : self . user_events_sender . clone ( ) ,
2020-05-06 15:27:49 +02:00
looper : self . looper . clone ( ) ,
}
}
}
pub struct EventLoopWindowTarget < T : 'static > {
_marker : std ::marker ::PhantomData < T > ,
}
2020-07-04 15:46:41 -04:00
impl < T : 'static > EventLoopWindowTarget < T > {
2020-09-07 20:20:47 +03:00
pub fn primary_monitor ( & self ) -> Option < monitor ::MonitorHandle > {
Some ( monitor ::MonitorHandle {
inner : MonitorHandle ,
} )
2020-07-04 15:46:41 -04:00
}
pub fn available_monitors ( & self ) -> VecDeque < MonitorHandle > {
let mut v = VecDeque ::with_capacity ( 1 ) ;
2020-09-07 20:20:47 +03:00
v . push_back ( MonitorHandle ) ;
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) ]
2017-09-04 12:41:02 +02:00
pub struct WindowId ;
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
2020-05-06 15:27:49 +02:00
pub struct Window ;
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 > (
2020-05-06 15:27:49 +02:00
_el : & EventLoopWindowTarget < T > ,
_window_attrs : window ::WindowAttributes ,
_ : PlatformSpecificWindowBuilderAttributes ,
) -> Result < Self , error ::OsError > {
// FIXME this ignores requested window attributes
Ok ( Self )
}
2018-06-14 19:42:18 -04:00
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
2020-09-07 20:20:47 +03:00
pub fn primary_monitor ( & self ) -> Option < monitor ::MonitorHandle > {
Some ( monitor ::MonitorHandle {
inner : MonitorHandle ,
} )
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 ) ;
v . push_back ( MonitorHandle ) ;
v
2016-10-31 17:08:55 +01:00
}
2017-09-07 09:33:46 +01:00
2020-09-07 20:09:24 +03:00
pub fn current_monitor ( & self ) -> Option < monitor ::MonitorHandle > {
Some ( monitor ::MonitorHandle {
2020-05-06 15:27:49 +02:00
inner : MonitorHandle ,
2020-09-07 20:09:24 +03:00
} )
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 {
2020-05-06 15:27:49 +02:00
MonitorHandle . 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 ) {
2021-06-05 12:47:08 +02:00
* INTERNAL_EVENT . write ( ) . unwrap ( ) = Some ( InternalEvent ::RedrawRequested ) ;
ForeignLooper ::for_thread ( ) . unwrap ( ) . wake ( ) ;
2016-10-31 17:08:55 +01:00
}
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
}
2020-05-06 15:27:49 +02:00
pub fn set_inner_size ( & self , _size : Size ) {
2020-07-26 21:13:17 +00:00
warn! ( " Cannot set window size on Android " ) ;
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn outer_size ( & self ) -> PhysicalSize < u32 > {
MonitorHandle . 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
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
}
2020-05-06 15:27:49 +02:00
pub fn set_minimized ( & self , _minimized : bool ) { }
2016-10-31 17:08:55 +01:00
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
}
2020-05-06 15:27:49 +02:00
pub fn set_fullscreen ( & self , _monitor : Option < window ::Fullscreen > ) {
2020-07-26 21:13:17 +00:00
warn! ( " Cannot set fullscreen on Android " ) ;
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn fullscreen ( & self ) -> Option < window ::Fullscreen > {
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
}
2020-05-06 15:27:49 +02:00
pub fn set_always_on_top ( & self , _always_on_top : bool ) { }
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
2020-05-06 15:27:49 +02:00
pub fn set_ime_position ( & self , _position : Position ) { }
2022-05-07 05:29:25 +03:00
pub fn set_ime_allowed ( & self , _allowed : bool ) { }
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 ( ) ,
) )
}
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-07-14 12:35:49 +02:00
if let Some ( native_window ) = ndk_glue ::native_window ( ) {
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 ( ) )
}
2020-05-06 15:27:49 +02:00
pub fn config ( & self ) -> Configuration {
CONFIG . read ( ) . unwrap ( ) . clone ( )
2017-12-22 07:50:46 -05:00
}
2020-05-06 15:27:49 +02:00
pub fn content_rect ( & self ) -> Rect {
ndk_glue ::content_rect ( )
2018-05-20 10:24:05 -04:00
}
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 ;
#[ derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd) ]
pub struct MonitorHandle ;
impl MonitorHandle {
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 > {
if let Some ( native_window ) = ndk_glue ::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 )
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 {
let config = CONFIG . read ( ) . unwrap ( ) ;
config
. 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
}
2020-05-06 15:27:49 +02:00
pub fn video_modes ( & self ) -> impl Iterator < Item = monitor ::VideoMode > {
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)
std ::iter ::once ( monitor ::VideoMode {
2020-05-06 15:27:49 +02:00
video_mode : VideoMode {
size ,
bit_depth : 32 ,
2022-07-08 13:25:56 +03:00
refresh_rate_millihertz : 60000 ,
2020-05-06 15:27:49 +02:00
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
2020-05-06 15:27:49 +02:00
pub fn monitor ( & self ) -> monitor ::MonitorHandle {
monitor ::MonitorHandle {
inner : self . monitor . clone ( ) ,
}
}
}