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-11-10 16:55:19 +00:00
hash ::Hash ,
sync ::{
atomic ::{ AtomicBool , Ordering } ,
mpsc , Arc ,
} ,
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
2022-11-10 16:55:19 +00:00
use android_activity ::input ::{ InputEvent , KeyAction , Keycode , MotionAction } ;
use android_activity ::{
AndroidApp , AndroidAppWaker , ConfigurationRef , InputStatus , MainEvent , Rect ,
2020-05-06 15:27:49 +02:00
} ;
2022-07-21 22:22:36 +03:00
use raw_window_handle ::{
AndroidDisplayHandle , HasRawWindowHandle , RawDisplayHandle , RawWindowHandle ,
} ;
2022-06-08 11:50:26 -07:00
2022-09-21 10:04:28 +02:00
use crate ::platform_impl ::Fullscreen ;
2022-06-08 11:50:26 -07:00
use crate ::{
dpi ::{ PhysicalPosition , PhysicalSize , Position , Size } ,
error ,
2022-11-10 16:55:19 +00:00
event ::{ self , StartCause , VirtualKeyCode } ,
event_loop ::{ self , ControlFlow , EventLoopWindowTarget as RootELW } ,
2022-11-26 03:50:58 +02:00
window ::{ self , CursorGrabMode , Theme , WindowLevel } ,
2019-06-21 11:33:15 -04: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 ,
}
}
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
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
2020-06-17 15:55:52 +02:00
running : bool ,
}
2022-11-10 16:55:19 +00:00
#[ derive(Default, Debug, Clone, PartialEq) ]
pub ( crate ) struct PlatformSpecificEventLoopAttributes {
pub ( crate ) android_app : Option < AndroidApp > ,
}
2022-02-16 22:09:03 +01:00
2022-11-10 16:55:19 +00:00
fn sticky_exit_callback < T , F > (
evt : event ::Event < '_ , T > ,
target : & RootELW < T > ,
control_flow : & mut ControlFlow ,
callback : & mut F ,
) where
F : FnMut ( event ::Event < '_ , T > , & RootELW < T > , & mut ControlFlow ) ,
{
// 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 )
}
}
struct IterationResult {
deadline : Option < Instant > ,
timeout : Option < Duration > ,
wait_start : Instant ,
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-11-10 16:55:19 +00:00
pub ( crate ) fn new ( attributes : & PlatformSpecificEventLoopAttributes ) -> Self {
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 ( ) ;
2020-05-06 15:27:49 +02:00
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 ) ,
2020-06-17 15:55:52 +02:00
running : false ,
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
}
2022-11-10 16:55:19 +00:00
fn single_iteration < ' a , F > (
& mut self ,
control_flow : & mut ControlFlow ,
main_event : Option < MainEvent < ' a > > ,
pending_redraw : & mut bool ,
cause : & mut StartCause ,
callback : & mut F ,
) -> IterationResult
2019-06-21 11:33:15 -04:00
where
2022-11-10 16:55:19 +00: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 " ) ;
sticky_exit_callback (
event ::Event ::NewEvents ( * cause ) ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
let mut resized = false ;
if let Some ( event ) = main_event {
trace! ( " Handling main event {:?} " , event ) ;
match event {
MainEvent ::InitWindow { .. } = > {
sticky_exit_callback (
event ::Event ::Resumed ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
}
MainEvent ::TerminateWindow { .. } = > {
sticky_exit_callback (
event ::Event ::Suspended ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
}
MainEvent ::WindowResized { .. } = > resized = true ,
MainEvent ::RedrawNeeded { .. } = > * pending_redraw = true ,
MainEvent ::ContentRectChanged { .. } = > {
warn! ( " TODO: find a way to notify application of content rect change " ) ;
}
MainEvent ::GainedFocus = > {
sticky_exit_callback (
event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Focused ( true ) ,
} ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
}
MainEvent ::LostFocus = > {
sticky_exit_callback (
event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Focused ( false ) ,
} ,
self . window_target ( ) ,
control_flow ,
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 {
let mut size = MonitorHandle ::new ( self . android_app . clone ( ) ) . size ( ) ;
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::ScaleFactorChanged {
new_inner_size : & mut size ,
scale_factor ,
} ,
} ;
sticky_exit_callback ( event , self . window_target ( ) , control_flow , callback ) ;
}
}
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
2022-11-10 16:55:19 +00:00
// Process input events
2020-06-17 15:55:52 +02:00
2022-11-10 16:55:19 +00:00
self . android_app . input_events ( | event | {
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 )
2022-07-14 12:35:49 +02:00
}
2022-11-10 16:55:19 +00:00
MotionAction ::Up | MotionAction ::PointerUp = > {
Some ( event ::TouchPhase ::Ended )
2022-07-14 12:35:49 +02:00
}
2022-11-10 16:55:19 +00:00
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:?} " ) ;
2020-05-06 15:27:49 +02:00
let event = event ::Event ::WindowEvent {
2022-11-10 16:55:19 +00:00
window_id ,
event : event ::WindowEvent ::Touch (
event ::Touch {
device_id ,
phase ,
location ,
id : pointer . pointer_id ( ) as u64 ,
force : None ,
} ,
) ,
2020-05-06 15:27:49 +02:00
} ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ,
2020-06-17 15:55:52 +02:00
self . window_target ( ) ,
control_flow ,
2022-11-10 16:55:19 +00:00
callback
2020-06-17 15:55:52 +02:00
) ;
2020-05-06 15:27:49 +02:00
}
}
2019-06-24 12:14:55 -04:00
}
2022-11-10 16:55:19 +00:00
InputEvent ::KeyEvent ( key ) = > {
let device_id = event ::DeviceId ( DeviceId ) ;
let state = match key . action ( ) {
KeyAction ::Down = > event ::ElementState ::Pressed ,
KeyAction ::Up = > event ::ElementState ::Released ,
_ = > event ::ElementState ::Released ,
} ;
#[ allow(deprecated) ]
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::KeyboardInput {
device_id ,
input : event ::KeyboardInput {
scancode : key . scan_code ( ) as u32 ,
state ,
virtual_keycode : ndk_keycode_to_virtualkeycode (
key . key_code ( ) ,
) ,
modifiers : event ::ModifiersState ::default ( ) ,
} ,
is_synthetic : false ,
} ,
} ;
sticky_exit_callback (
event ,
self . window_target ( ) ,
control_flow ,
callback
) ;
}
_ = > {
warn! ( " Unknown android_activity input event {event:?} " )
2019-06-24 12:14:55 -04:00
}
2020-05-06 15:27:49 +02:00
}
2022-11-10 16:55:19 +00:00
// Assume all events are handled, while Winit doesn't currently give a way for
// applications to report whether they handled an input event.
InputStatus ::Handled
} ) ;
// 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 ( ) ,
control_flow ,
callback ,
) ;
}
}
2020-05-06 15:27:49 +02:00
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ::Event ::MainEventsCleared ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
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 ) ,
} ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback ( event , self . window_target ( ) , control_flow , callback ) ;
2020-05-06 15:27:49 +02:00
}
2022-11-10 16:55:19 +00: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 ) ) ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback ( event , self . window_target ( ) , 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
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ::Event ::RedrawEventsCleared ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
let start = Instant ::now ( ) ;
let ( deadline , timeout ) ;
match control_flow {
ControlFlow ::ExitWithCode ( _ ) = > {
deadline = None ;
timeout = None ;
}
ControlFlow ::Poll = > {
* cause = StartCause ::Poll ;
deadline = None ;
timeout = Some ( Duration ::from_millis ( 0 ) ) ;
}
ControlFlow ::Wait = > {
* cause = StartCause ::WaitCancelled {
start ,
requested_resume : None ,
} ;
deadline = None ;
timeout = None ;
}
ControlFlow ::WaitUntil ( wait_deadline ) = > {
* cause = StartCause ::ResumeTimeReached {
start ,
requested_resume : * wait_deadline ,
} ;
timeout = if * wait_deadline > start {
Some ( * wait_deadline - start )
} else {
Some ( Duration ::from_millis ( 0 ) )
} ;
deadline = Some ( * wait_deadline ) ;
}
}
IterationResult {
wait_start : start ,
deadline ,
timeout ,
}
}
pub fn run < F > ( mut self , event_handler : F ) -> !
where
F : 'static
+ FnMut ( event ::Event < '_ , T > , & event_loop ::EventLoopWindowTarget < T > , & mut ControlFlow ) ,
{
let exit_code = self . run_return ( event_handler ) ;
::std ::process ::exit ( exit_code ) ;
}
pub fn run_return < F > ( & mut self , mut callback : F ) -> i32
where
F : FnMut ( event ::Event < '_ , T > , & RootELW < T > , & mut ControlFlow ) ,
{
let mut control_flow = ControlFlow ::default ( ) ;
let mut cause = StartCause ::Init ;
let mut pending_redraw = false ;
// run the initial loop iteration
let mut iter_result = self . single_iteration (
& mut control_flow ,
None ,
& mut pending_redraw ,
& mut cause ,
& mut callback ,
) ;
let exit_code = loop {
if let ControlFlow ::ExitWithCode ( code ) = control_flow {
break code ;
}
let mut timeout = iter_result . timeout ;
// If we already have work to do then we don't want to block on the next poll...
pending_redraw | = self . redraw_flag . get_and_reset ( ) ;
if self . running & & ( pending_redraw | | self . user_events_receiver . has_incoming ( ) ) {
timeout = Some ( Duration ::from_millis ( 0 ) )
}
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.
pending_redraw | = self . redraw_flag . get_and_reset ( ) ;
if ! self . running
| | ( ! pending_redraw & & ! self . user_events_receiver . has_incoming ( ) )
{
return ;
}
}
android_activity ::PollEvent ::Timeout = > { }
android_activity ::PollEvent ::Main ( event ) = > {
main_event = Some ( event ) ;
}
unknown_event = > {
warn! ( " Unknown poll event {unknown_event:?} (ignored) " ) ;
2018-02-15 14:09:14 +01:00
}
2019-06-24 12:14:55 -04:00
}
2022-11-10 16:55:19 +00:00
let wait_cancelled = iter_result
. deadline
. map_or ( false , | deadline | Instant ::now ( ) < deadline ) ;
if wait_cancelled {
cause = StartCause ::WaitCancelled {
start : iter_result . wait_start ,
requested_resume : iter_result . deadline ,
2020-05-06 15:27:49 +02:00
} ;
2019-06-24 12:14:55 -04:00
}
2022-11-10 16:55:19 +00:00
iter_result = self . single_iteration (
& mut control_flow ,
main_event ,
& mut pending_redraw ,
& mut cause ,
& mut callback ,
) ;
} ) ;
} ;
sticky_exit_callback (
event ::Event ::LoopDestroyed ,
self . window_target ( ) ,
& mut control_flow ,
& mut callback ,
) ;
exit_code
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
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
}
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 > {
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
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
}
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
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-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
pub fn title ( & self ) -> String {
String ::new ( )
}
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 {
fn partial_cmp ( & self , _other : & Self ) -> Option < std ::cmp ::Ordering > {
Some ( std ::cmp ::Ordering ::Equal )
}
}
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
}
}