2022-06-08 11:50:26 -07:00
|
|
|
use std::cell::Cell;
|
2022-11-10 16:55:19 +00:00
|
|
|
use std::hash::Hash;
|
2024-07-23 19:59:37 +02:00
|
|
|
use std::num::{NonZeroU16, NonZeroU32};
|
2022-11-10 16:55:19 +00:00
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
2024-06-24 13:04:55 +03:00
|
|
|
use std::sync::{Arc, Mutex};
|
2022-06-08 11:50:26 -07:00
|
|
|
use std::time::{Duration, Instant};
|
|
|
|
|
|
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
|
|
|
};
|
2024-02-25 19:20:39 -08:00
|
|
|
use tracing::{debug, trace, warn};
|
2022-06-08 11:50:26 -07:00
|
|
|
|
2024-05-20 20:27:36 +04:00
|
|
|
use crate::application::ApplicationHandler;
|
2023-12-25 07:20:52 +01:00
|
|
|
use crate::cursor::Cursor;
|
2022-06-08 11:50:26 -07:00
|
|
|
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
2024-09-06 17:20:11 +03:00
|
|
|
use crate::error::{EventLoopError, NotSupportedError, RequestError};
|
2024-10-11 11:15:54 +03:00
|
|
|
use crate::event::{self, DeviceId, Force, StartCause, SurfaceSizeWriter};
|
2024-08-06 21:02:53 +03:00
|
|
|
use crate::event_loop::{
|
|
|
|
|
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
|
|
|
|
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle,
|
|
|
|
|
};
|
|
|
|
|
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
2023-06-18 11:10:13 +01:00
|
|
|
use crate::platform::pump_events::PumpStatus;
|
2023-01-29 16:46:46 +01:00
|
|
|
use crate::window::{
|
2024-08-23 23:40:27 +03:00
|
|
|
self, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, ImePurpose,
|
2024-10-08 15:29:40 +02:00
|
|
|
ResizeDirection, Theme, Window as CoreWindow, WindowAttributes, WindowButtons, WindowId,
|
|
|
|
|
WindowLevel,
|
2019-06-21 11:33:15 -04:00
|
|
|
};
|
|
|
|
|
|
2023-06-21 18:49:44 +01:00
|
|
|
mod keycodes;
|
|
|
|
|
|
2024-02-03 07:27:17 +04:00
|
|
|
pub(crate) use crate::cursor::{
|
|
|
|
|
NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource,
|
|
|
|
|
};
|
|
|
|
|
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
|
|
|
|
|
2024-02-28 12:28:26 +01:00
|
|
|
static HAS_FOCUS: AtomicBool = AtomicBool::new(true);
|
2023-01-17 03:30:14 +02:00
|
|
|
|
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
|
|
|
#[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)) }
|
|
|
|
|
}
|
2024-04-26 19:11:44 +04:00
|
|
|
|
2022-11-10 16:55:19 +00:00
|
|
|
pub fn setter(&self) -> SharedFlagSetter {
|
|
|
|
|
SharedFlagSetter { flag: self.flag.clone() }
|
|
|
|
|
}
|
2024-04-26 19:11:44 +04:00
|
|
|
|
2022-11-10 16:55:19 +00:00
|
|
|
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 }
|
|
|
|
|
}
|
2024-04-26 19:11:44 +04:00
|
|
|
|
2022-11-10 16:55:19 +00:00
|
|
|
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 {}
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
pub struct EventLoop {
|
2024-07-26 21:49:32 +03:00
|
|
|
pub(crate) android_app: AndroidApp,
|
2024-08-06 21:02:53 +03:00
|
|
|
window_target: ActiveEventLoop,
|
2022-11-10 16:55:19 +00:00
|
|
|
redraw_flag: SharedFlag,
|
2024-06-24 13:04:55 +03: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,
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2024-08-08 00:46:28 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
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
|
|
|
|
2024-10-08 15:29:40 +02:00
|
|
|
// Android currently only supports one window
|
|
|
|
|
const GLOBAL_WINDOW: WindowId = WindowId::from_raw(0);
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
impl EventLoop {
|
2023-08-13 23:20:09 +04:00
|
|
|
pub(crate) fn new(
|
|
|
|
|
attributes: &PlatformSpecificEventLoopAttributes,
|
|
|
|
|
) -> Result<Self, EventLoopError> {
|
2024-06-24 13:04:55 +03:00
|
|
|
let proxy_wake_up = Arc::new(AtomicBool::new(false));
|
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(),
|
2024-08-06 21:02:53 +03:00
|
|
|
window_target: ActiveEventLoop {
|
|
|
|
|
app: android_app.clone(),
|
|
|
|
|
control_flow: Cell::new(ControlFlow::default()),
|
|
|
|
|
exit: Cell::new(false),
|
|
|
|
|
redraw_requester: RedrawRequester::new(&redraw_flag, android_app.create_waker()),
|
|
|
|
|
proxy_wake_up,
|
2020-05-06 15:27:49 +02:00
|
|
|
},
|
2022-11-10 16:55:19 +00:00
|
|
|
redraw_flag,
|
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,
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
pub(crate) fn window_target(&self) -> &dyn RootActiveEventLoop {
|
|
|
|
|
&self.window_target
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
fn single_iteration<A: ApplicationHandler>(
|
2024-05-20 20:27:36 +04:00
|
|
|
&mut self,
|
|
|
|
|
main_event: Option<MainEvent<'_>>,
|
|
|
|
|
app: &mut A,
|
|
|
|
|
) {
|
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 pending_redraw = self.pending_redraw;
|
|
|
|
|
let mut resized = false;
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
app.new_events(&self.window_target, cause);
|
2022-11-10 16:55:19 +00:00
|
|
|
|
|
|
|
|
if let Some(event) = main_event {
|
|
|
|
|
trace!("Handling main event {:?}", event);
|
|
|
|
|
|
|
|
|
|
match event {
|
|
|
|
|
MainEvent::InitWindow { .. } => {
|
2024-08-06 21:02:53 +03:00
|
|
|
app.can_create_surfaces(&self.window_target);
|
2022-11-10 16:55:19 +00:00
|
|
|
},
|
|
|
|
|
MainEvent::TerminateWindow { .. } => {
|
2024-08-06 21:02:53 +03:00
|
|
|
app.destroy_surfaces(&self.window_target);
|
2022-11-10 16:55:19 +00:00
|
|
|
},
|
|
|
|
|
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 => {
|
2024-02-28 12:28:26 +01:00
|
|
|
HAS_FOCUS.store(true, Ordering::Relaxed);
|
2024-05-20 20:27:36 +04:00
|
|
|
let event = event::WindowEvent::Focused(true);
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2022-11-10 16:55:19 +00:00
|
|
|
},
|
|
|
|
|
MainEvent::LostFocus => {
|
2024-02-28 12:28:26 +01:00
|
|
|
HAS_FOCUS.store(false, Ordering::Relaxed);
|
2024-05-20 20:27:36 +04:00
|
|
|
let event = event::WindowEvent::Focused(false);
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2022-11-10 16:55:19 +00:00
|
|
|
},
|
|
|
|
|
MainEvent::ConfigChanged { .. } => {
|
2024-07-26 15:59:17 +02:00
|
|
|
let old_scale_factor = scale_factor(&self.android_app);
|
|
|
|
|
let scale_factor = scale_factor(&self.android_app);
|
2022-11-10 16:55:19 +00:00
|
|
|
if (scale_factor - old_scale_factor).abs() < f64::EPSILON {
|
2024-09-04 15:04:48 +02:00
|
|
|
let new_surface_size = Arc::new(Mutex::new(screen_size(&self.android_app)));
|
2024-05-20 20:27:36 +04:00
|
|
|
let event = event::WindowEvent::ScaleFactorChanged {
|
2024-09-04 15:04:48 +02:00
|
|
|
surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(
|
|
|
|
|
&new_surface_size,
|
2024-05-20 20:27:36 +04:00
|
|
|
)),
|
|
|
|
|
scale_factor,
|
2022-11-10 16:55:19 +00:00
|
|
|
};
|
2024-05-20 20:27:36 +04:00
|
|
|
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2022-11-10 16:55:19 +00:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
MainEvent::LowMemory => {
|
2024-08-06 21:02:53 +03:00
|
|
|
app.memory_warning(&self.window_target);
|
2022-11-10 16:55:19 +00:00
|
|
|
},
|
|
|
|
|
MainEvent::Start => {
|
2024-10-16 12:17:59 +02:00
|
|
|
app.resumed(self.window_target());
|
2022-11-10 16:55:19 +00:00
|
|
|
},
|
|
|
|
|
MainEvent::Resume { .. } => {
|
|
|
|
|
debug!("App Resumed - is running");
|
2024-10-16 12:17:59 +02:00
|
|
|
// TODO: This is incorrect - will be solved in https://github.com/rust-windowing/winit/pull/3897
|
2022-11-10 16:55:19 +00:00
|
|
|
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");
|
2024-10-16 12:17:59 +02:00
|
|
|
// TODO: This is incorrect - will be solved in https://github.com/rust-windowing/winit/pull/3897
|
2022-11-10 16:55:19 +00:00
|
|
|
self.running = false;
|
|
|
|
|
},
|
|
|
|
|
MainEvent::Stop => {
|
2024-10-16 12:17:59 +02:00
|
|
|
app.suspended(self.window_target());
|
2022-11-10 16:55:19 +00:00
|
|
|
},
|
|
|
|
|
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 {
|
2023-09-07 08:25:04 +02:00
|
|
|
let read_event =
|
2024-05-20 20:27:36 +04:00
|
|
|
input_iter.next(|event| self.handle_input_event(&android_app, event, app));
|
2023-08-07 23:56:42 +01:00
|
|
|
|
|
|
|
|
if !read_event {
|
|
|
|
|
break;
|
2019-06-24 12:14:55 -04:00
|
|
|
}
|
2023-08-07 23:56:42 +01:00
|
|
|
},
|
|
|
|
|
Err(err) => {
|
2024-02-25 19:20:39 -08:00
|
|
|
tracing::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
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
if self.window_target.proxy_wake_up.swap(false, Ordering::Relaxed) {
|
|
|
|
|
app.proxy_wake_up(&self.window_target);
|
2022-11-10 16:55:19 +00:00
|
|
|
}
|
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)
|
|
|
|
|
};
|
2024-09-04 15:04:48 +02:00
|
|
|
let event = event::WindowEvent::SurfaceResized(size);
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
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;
|
2024-05-20 20:27:36 +04:00
|
|
|
let event = event::WindowEvent::RedrawRequested;
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
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
|
2024-08-06 21:02:53 +03:00
|
|
|
app.about_to_wait(&self.window_target);
|
2023-09-07 08:25:04 +02:00
|
|
|
|
2023-06-18 11:10:13 +01:00
|
|
|
self.pending_redraw = pending_redraw;
|
2022-11-10 16:55:19 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
fn handle_input_event<A: ApplicationHandler>(
|
2023-08-07 23:56:42 +01:00
|
|
|
&mut self,
|
|
|
|
|
android_app: &AndroidApp,
|
|
|
|
|
event: &InputEvent<'_>,
|
2024-05-20 20:27:36 +04:00
|
|
|
app: &mut A,
|
|
|
|
|
) -> InputStatus {
|
2023-08-07 23:56:42 +01:00
|
|
|
let mut input_status = InputStatus::Handled;
|
|
|
|
|
match event {
|
|
|
|
|
InputEvent::MotionEvent(motion_event) => {
|
2024-10-11 11:15:54 +03:00
|
|
|
let device_id = Some(DeviceId::from_raw(motion_event.device_id() as i64));
|
2024-10-08 14:19:00 +02:00
|
|
|
let action = motion_event.action();
|
|
|
|
|
|
|
|
|
|
let pointers: Option<
|
|
|
|
|
Box<dyn Iterator<Item = android_activity::input::Pointer<'_>>>,
|
|
|
|
|
> = match action {
|
|
|
|
|
MotionAction::Down
|
|
|
|
|
| MotionAction::PointerDown
|
|
|
|
|
| MotionAction::Up
|
|
|
|
|
| MotionAction::PointerUp => Some(Box::new(std::iter::once(
|
|
|
|
|
motion_event.pointer_at_index(motion_event.pointer_index()),
|
|
|
|
|
))),
|
|
|
|
|
MotionAction::Move | MotionAction::Cancel => {
|
|
|
|
|
Some(Box::new(motion_event.pointers()))
|
2023-08-07 23:56:42 +01:00
|
|
|
},
|
2024-10-08 14:19:00 +02:00
|
|
|
// TODO mouse events
|
|
|
|
|
_ => None,
|
2023-08-07 23:56:42 +01:00
|
|
|
};
|
|
|
|
|
|
2024-10-08 14:19:00 +02:00
|
|
|
if let Some(pointers) = pointers {
|
2023-08-07 23:56:42 +01:00
|
|
|
for pointer in pointers {
|
2024-10-08 14:19:00 +02:00
|
|
|
let tool_type = pointer.tool_type();
|
|
|
|
|
let position =
|
2023-08-07 23:56:42 +01:00
|
|
|
PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ };
|
|
|
|
|
trace!(
|
2024-10-08 14:19:00 +02:00
|
|
|
"Input event {device_id:?}, {action:?}, loc={position:?}, \
|
|
|
|
|
pointer={pointer:?}, tool_type={tool_type:?}"
|
2023-08-07 23:56:42 +01:00
|
|
|
);
|
2024-10-08 14:19:00 +02:00
|
|
|
let finger_id = event::FingerId(FingerId(pointer.pointer_id()));
|
|
|
|
|
let force = Some(Force::Normalized(pointer.pressure() as f64));
|
|
|
|
|
|
|
|
|
|
match action {
|
|
|
|
|
MotionAction::Down | MotionAction::PointerDown => {
|
|
|
|
|
let event = event::WindowEvent::PointerEntered {
|
|
|
|
|
device_id,
|
|
|
|
|
position,
|
|
|
|
|
kind: match tool_type {
|
|
|
|
|
android_activity::input::ToolType::Finger => {
|
|
|
|
|
event::PointerKind::Touch(finger_id)
|
|
|
|
|
},
|
|
|
|
|
// TODO mouse events
|
|
|
|
|
android_activity::input::ToolType::Mouse => continue,
|
|
|
|
|
_ => event::PointerKind::Unknown,
|
|
|
|
|
},
|
|
|
|
|
};
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2024-10-08 14:19:00 +02:00
|
|
|
let event = event::WindowEvent::PointerButton {
|
|
|
|
|
device_id,
|
|
|
|
|
state: event::ElementState::Pressed,
|
|
|
|
|
position,
|
|
|
|
|
button: match tool_type {
|
|
|
|
|
android_activity::input::ToolType::Finger => {
|
|
|
|
|
event::ButtonSource::Touch { finger_id, force }
|
|
|
|
|
},
|
|
|
|
|
// TODO mouse events
|
|
|
|
|
android_activity::input::ToolType::Mouse => continue,
|
|
|
|
|
_ => event::ButtonSource::Unknown(0),
|
|
|
|
|
},
|
|
|
|
|
};
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2024-10-08 14:19:00 +02:00
|
|
|
},
|
|
|
|
|
MotionAction::Move => {
|
|
|
|
|
let event = event::WindowEvent::PointerMoved {
|
|
|
|
|
device_id,
|
|
|
|
|
position,
|
|
|
|
|
source: match tool_type {
|
|
|
|
|
android_activity::input::ToolType::Finger => {
|
|
|
|
|
event::PointerSource::Touch { finger_id, force }
|
|
|
|
|
},
|
|
|
|
|
// TODO mouse events
|
|
|
|
|
android_activity::input::ToolType::Mouse => continue,
|
|
|
|
|
_ => event::PointerSource::Unknown,
|
|
|
|
|
},
|
|
|
|
|
};
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2024-10-08 14:19:00 +02:00
|
|
|
},
|
|
|
|
|
MotionAction::Up | MotionAction::PointerUp | MotionAction::Cancel => {
|
|
|
|
|
if let MotionAction::Up | MotionAction::PointerUp = action {
|
|
|
|
|
let event = event::WindowEvent::PointerButton {
|
|
|
|
|
device_id,
|
|
|
|
|
state: event::ElementState::Released,
|
|
|
|
|
position,
|
|
|
|
|
button: match tool_type {
|
|
|
|
|
android_activity::input::ToolType::Finger => {
|
|
|
|
|
event::ButtonSource::Touch { finger_id, force }
|
|
|
|
|
},
|
|
|
|
|
// TODO mouse events
|
|
|
|
|
android_activity::input::ToolType::Mouse => continue,
|
|
|
|
|
_ => event::ButtonSource::Unknown(0),
|
|
|
|
|
},
|
|
|
|
|
};
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2024-10-08 14:19:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let event = event::WindowEvent::PointerLeft {
|
|
|
|
|
device_id,
|
|
|
|
|
position: Some(position),
|
|
|
|
|
kind: match tool_type {
|
|
|
|
|
android_activity::input::ToolType::Finger => {
|
|
|
|
|
event::PointerKind::Touch(finger_id)
|
|
|
|
|
},
|
|
|
|
|
// TODO mouse events
|
|
|
|
|
android_activity::input::ToolType::Mouse => continue,
|
|
|
|
|
_ => event::PointerKind::Unknown,
|
|
|
|
|
},
|
|
|
|
|
};
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2024-10-08 14:19:00 +02:00
|
|
|
},
|
|
|
|
|
_ => unreachable!(),
|
|
|
|
|
}
|
2023-08-07 23:56:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
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.
|
2024-04-23 19:51:23 +02:00
|
|
|
Keycode::VolumeUp | Keycode::VolumeDown | Keycode::VolumeMute
|
|
|
|
|
if self.ignore_volume_keys =>
|
|
|
|
|
{
|
|
|
|
|
input_status = InputStatus::Unhandled
|
2023-08-07 23:56:42 +01:00
|
|
|
},
|
|
|
|
|
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,
|
|
|
|
|
);
|
|
|
|
|
|
2024-05-20 20:27:36 +04:00
|
|
|
let event = event::WindowEvent::KeyboardInput {
|
2024-10-11 11:15:54 +03:00
|
|
|
device_id: Some(DeviceId::from_raw(key.device_id() as i64)),
|
2024-05-20 20:27:36 +04:00
|
|
|
event: event::KeyEvent {
|
|
|
|
|
state,
|
|
|
|
|
physical_key: keycodes::to_physical_key(keycode),
|
|
|
|
|
logical_key: keycodes::to_logical(key_char, keycode),
|
|
|
|
|
location: keycodes::to_location(keycode),
|
|
|
|
|
repeat: key.repeat_count() > 0,
|
|
|
|
|
text: None,
|
|
|
|
|
platform_specific: KeyEventExtra {},
|
2023-08-07 23:56:42 +01:00
|
|
|
},
|
2024-05-20 20:27:36 +04:00
|
|
|
is_synthetic: false,
|
2023-08-07 23:56:42 +01:00
|
|
|
};
|
2024-05-20 20:27:36 +04:00
|
|
|
|
2024-10-08 15:29:40 +02:00
|
|
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
2023-08-07 23:56:42 +01:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
warn!("Unknown android_activity input event {event:?}")
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
input_status
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-11 15:38:09 +02:00
|
|
|
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
2024-05-20 20:27:36 +04:00
|
|
|
self.run_app_on_demand(app)
|
2022-11-10 16:55:19 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
2024-05-20 20:27:36 +04:00
|
|
|
&mut self,
|
2024-07-11 15:38:09 +02:00
|
|
|
mut app: A,
|
2024-05-20 20:27:36 +04:00
|
|
|
) -> Result<(), EventLoopError> {
|
2024-08-06 21:02:53 +03:00
|
|
|
self.window_target.clear_exit();
|
2023-06-18 11:10:13 +01:00
|
|
|
loop {
|
2024-07-11 15:38:09 +02:00
|
|
|
match self.pump_app_events(None, &mut app) {
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
pub fn pump_app_events<A: ApplicationHandler>(
|
2024-05-20 20:27:36 +04:00
|
|
|
&mut self,
|
|
|
|
|
timeout: Option<Duration>,
|
2024-07-11 15:38:09 +02:00
|
|
|
mut app: A,
|
2024-05-20 20:27:36 +04:00
|
|
|
) -> PumpStatus {
|
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;
|
|
|
|
|
|
|
|
|
|
// run the initial loop iteration
|
2024-07-11 15:38:09 +02:00
|
|
|
self.single_iteration(None, &mut app);
|
2023-06-18 11:10:13 +01:00
|
|
|
}
|
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
|
2023-09-07 08:25:04 +02:00
|
|
|
if !self.exiting() {
|
2024-07-11 15:38:09 +02:00
|
|
|
self.poll_events_with_timeout(timeout, &mut app);
|
2023-06-18 11:10:13 +01:00
|
|
|
}
|
2023-09-07 08:25:04 +02:00
|
|
|
if self.exiting() {
|
2023-06-18 11:10:13 +01:00
|
|
|
self.loop_running = false;
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
app.exiting(&self.window_target);
|
2023-06-18 11:10:13 +01:00
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
PumpStatus::Exit(0)
|
2023-06-18 11:10:13 +01:00
|
|
|
} else {
|
|
|
|
|
PumpStatus::Continue
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 16:55:19 +00:00
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
fn poll_events_with_timeout<A: ApplicationHandler>(
|
2024-05-20 20:27:36 +04:00
|
|
|
&mut self,
|
|
|
|
|
mut timeout: Option<Duration>,
|
|
|
|
|
app: &mut A,
|
|
|
|
|
) {
|
2023-06-18 11:10:13 +01:00
|
|
|
let start = Instant::now();
|
|
|
|
|
|
|
|
|
|
self.pending_redraw |= self.redraw_flag.get_and_reset();
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
timeout = if self.running
|
2024-08-06 21:02:53 +03:00
|
|
|
&& (self.pending_redraw || self.window_target.proxy_wake_up.load(Ordering::Relaxed))
|
2024-06-24 13:04:55 +03:00
|
|
|
{
|
|
|
|
|
// 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))
|
|
|
|
|
},
|
2023-06-18 11:10:13 +01:00
|
|
|
};
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
min_timeout(control_flow_timeout, timeout)
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-20 20:27:36 +04:00
|
|
|
let android_app = self.android_app.clone(); // Don't borrow self as part of poll expression
|
|
|
|
|
android_app.poll_events(timeout, |poll_event| {
|
2023-06-18 11:10:13 +01:00
|
|
|
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
|
2024-06-29 17:19:09 +02:00
|
|
|
|| (!self.pending_redraw
|
2024-08-06 21:02:53 +03:00
|
|
|
&& !self.window_target.proxy_wake_up.load(Ordering::Relaxed))
|
2023-06-18 11:10:13 +01:00
|
|
|
{
|
|
|
|
|
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-09-07 08:25:04 +02:00
|
|
|
self.cause = match self.control_flow() {
|
2023-06-18 11:10:13 +01:00
|
|
|
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 }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
2022-11-10 16:55:19 +00:00
|
|
|
|
2024-05-20 20:27:36 +04:00
|
|
|
self.single_iteration(main_event, app);
|
2023-06-18 11:10:13 +01:00
|
|
|
});
|
2017-09-04 12:41:02 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
fn control_flow(&self) -> ControlFlow {
|
2024-08-06 21:02:53 +03:00
|
|
|
self.window_target.control_flow()
|
2023-09-07 08:25:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn exiting(&self) -> bool {
|
2024-08-06 21:02:53 +03:00
|
|
|
self.window_target.exiting()
|
2023-09-07 08:25:04 +02:00
|
|
|
}
|
2020-05-06 15:27:49 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct EventLoopProxy {
|
|
|
|
|
proxy_wake_up: Arc<AtomicBool>,
|
2022-11-10 16:55:19 +00:00
|
|
|
waker: AndroidAppWaker,
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
impl EventLoopProxy {
|
|
|
|
|
pub fn wake_up(&self) {
|
|
|
|
|
self.proxy_wake_up.store(true, Ordering::Relaxed);
|
2022-11-10 16:55:19 +00:00
|
|
|
self.waker.wake();
|
2017-09-04 12:41:02 +02:00
|
|
|
}
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-01-31 17:29:59 +04:00
|
|
|
pub struct ActiveEventLoop {
|
2024-07-26 21:49:32 +03:00
|
|
|
pub(crate) app: AndroidApp,
|
2023-09-07 08:25:04 +02:00
|
|
|
control_flow: Cell<ControlFlow>,
|
|
|
|
|
exit: Cell<bool>,
|
2022-11-10 16:55:19 +00:00
|
|
|
redraw_requester: RedrawRequester,
|
2024-06-29 17:19:09 +02:00
|
|
|
proxy_wake_up: Arc<AtomicBool>,
|
2020-05-06 15:27:49 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-31 17:29:59 +04:00
|
|
|
impl ActiveEventLoop {
|
2024-08-06 21:02:53 +03:00
|
|
|
fn clear_exit(&self) {
|
|
|
|
|
self.exit.set(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RootActiveEventLoop for ActiveEventLoop {
|
|
|
|
|
fn create_proxy(&self) -> RootEventLoopProxy {
|
|
|
|
|
let event_loop_proxy = EventLoopProxy {
|
|
|
|
|
proxy_wake_up: self.proxy_wake_up.clone(),
|
|
|
|
|
waker: self.app.create_waker(),
|
|
|
|
|
};
|
|
|
|
|
RootEventLoopProxy { event_loop_proxy }
|
2024-06-29 17:19:09 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn create_window(
|
|
|
|
|
&self,
|
|
|
|
|
window_attributes: WindowAttributes,
|
2024-09-06 17:20:11 +03:00
|
|
|
) -> Result<Box<dyn CoreWindow>, RequestError> {
|
2024-08-23 23:40:27 +03:00
|
|
|
Ok(Box::new(Window::new(self, window_attributes)?))
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn create_custom_cursor(
|
2024-08-06 18:57:03 +02:00
|
|
|
&self,
|
|
|
|
|
_source: CustomCursorSource,
|
2024-09-06 17:20:11 +03:00
|
|
|
) -> Result<CustomCursor, RequestError> {
|
|
|
|
|
Err(NotSupportedError::new("create_custom_cursor is not supported").into())
|
2024-02-03 07:27:17 +04:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn available_monitors(&self) -> Box<dyn Iterator<Item = RootMonitorHandle>> {
|
2024-07-26 15:59:17 +02:00
|
|
|
Box::new(std::iter::empty())
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
2022-07-21 22:22:36 +03:00
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn primary_monitor(&self) -> Option<RootMonitorHandle> {
|
2024-07-26 15:59:17 +02:00
|
|
|
None
|
2024-08-06 21:02:53 +03:00
|
|
|
}
|
2023-09-01 23:14:16 +02:00
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn system_theme(&self) -> Option<Theme> {
|
2024-08-05 20:51:38 +02:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn listen_device_events(&self, _allowed: DeviceEvents) {}
|
2023-09-07 08:25:04 +02:00
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn set_control_flow(&self, control_flow: ControlFlow) {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.control_flow.set(control_flow)
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn control_flow(&self) -> ControlFlow {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.control_flow.get()
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn exit(&self) {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.exit.set(true)
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn exiting(&self) -> bool {
|
|
|
|
|
self.exit.get()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn owned_display_handle(&self) -> RootOwnedDisplayHandle {
|
|
|
|
|
RootOwnedDisplayHandle { platform: OwnedDisplayHandle }
|
2023-12-22 20:00:20 +04:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
|
|
|
|
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
|
|
|
|
let raw = rwh_06::AndroidDisplayHandle::new();
|
|
|
|
|
Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw.into()) })
|
2024-01-15 11:58:11 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-08 00:46:28 +02:00
|
|
|
#[derive(Clone, PartialEq, Eq)]
|
2024-01-15 11:58:11 -08:00
|
|
|
pub(crate) struct OwnedDisplayHandle;
|
|
|
|
|
|
|
|
|
|
impl OwnedDisplayHandle {
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_display_handle_rwh_06(
|
|
|
|
|
&self,
|
|
|
|
|
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
|
|
|
|
Ok(rwh_06::AndroidDisplayHandle::new().into())
|
|
|
|
|
}
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-08 00:36:36 +02:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
|
|
|
|
pub struct FingerId(i32);
|
|
|
|
|
|
|
|
|
|
impl FingerId {
|
2024-09-29 15:49:45 +02:00
|
|
|
#[cfg(test)]
|
2024-08-08 00:36:36 +02:00
|
|
|
pub const fn dummy() -> Self {
|
|
|
|
|
FingerId(0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 15:27:49 +02:00
|
|
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
2024-01-31 17:29:59 +04:00
|
|
|
pub struct PlatformSpecificWindowAttributes;
|
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 {
|
2024-01-13 21:36:53 +01:00
|
|
|
pub(crate) fn new(
|
2024-01-31 17:29:59 +04:00
|
|
|
el: &ActiveEventLoop,
|
2020-05-06 15:27:49 +02:00
|
|
|
_window_attrs: window::WindowAttributes,
|
2024-09-06 17:20:11 +03:00
|
|
|
) -> Result<Self, RequestError> {
|
2020-05-06 15:27:49 +02:00
|
|
|
// 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
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
pub fn config(&self) -> ConfigurationRef {
|
|
|
|
|
self.app.config()
|
2023-08-14 21:19:57 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
pub fn content_rect(&self) -> Rect {
|
|
|
|
|
self.app.content_rect()
|
2023-08-14 21:19:57 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
// Allow the usage of HasRawWindowHandle inside this function
|
|
|
|
|
#[allow(deprecated)]
|
|
|
|
|
fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
|
|
|
|
|
use rwh_06::HasRawWindowHandle;
|
|
|
|
|
|
|
|
|
|
if let Some(native_window) = self.app.native_window().as_ref() {
|
|
|
|
|
native_window.raw_window_handle()
|
|
|
|
|
} else {
|
|
|
|
|
tracing::error!(
|
|
|
|
|
"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."
|
|
|
|
|
);
|
|
|
|
|
Err(rwh_06::HandleError::Unavailable)
|
|
|
|
|
}
|
2018-06-14 19:42:18 -04:00
|
|
|
}
|
2016-10-31 17:08:55 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
fn raw_display_handle_rwh_06(&self) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
|
|
|
|
Ok(rwh_06::RawDisplayHandle::Android(rwh_06::AndroidDisplayHandle::new()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
impl rwh_06::HasDisplayHandle for Window {
|
|
|
|
|
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
|
|
|
|
let raw = self.raw_display_handle_rwh_06()?;
|
|
|
|
|
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
impl rwh_06::HasWindowHandle for Window {
|
|
|
|
|
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
|
|
|
|
let raw = self.raw_window_handle_rwh_06()?;
|
|
|
|
|
unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) }
|
2017-09-04 12:41:02 +02:00
|
|
|
}
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
2016-10-31 17:08:55 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
impl CoreWindow for Window {
|
2024-10-08 15:29:40 +02:00
|
|
|
fn id(&self) -> WindowId {
|
|
|
|
|
GLOBAL_WINDOW
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn primary_monitor(&self) -> Option<RootMonitorHandle> {
|
2024-07-26 15:59:17 +02:00
|
|
|
None
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
2017-09-07 09:33:46 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn available_monitors(&self) -> Box<dyn Iterator<Item = RootMonitorHandle>> {
|
|
|
|
|
Box::new(std::iter::empty())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn current_monitor(&self) -> Option<RootMonitorHandle> {
|
2024-07-26 15:59:17 +02:00
|
|
|
None
|
2017-09-07 09:33:46 +01:00
|
|
|
}
|
2017-10-17 14:56:38 +03:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn scale_factor(&self) -> f64 {
|
2024-07-26 15:59:17 +02:00
|
|
|
scale_factor(&self.app)
|
2017-10-17 14:56:38 +03:00
|
|
|
}
|
2016-10-31 17:08:55 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn pre_present_notify(&self) {}
|
2023-06-22 08:08:53 +04:00
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
|
|
|
|
Err(NotSupportedError::new("inner_position is not supported").into())
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
|
|
|
|
Err(NotSupportedError::new("outer_position is not supported").into())
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_outer_position(&self, _position: Position) {
|
2020-05-06 15:27:49 +02:00
|
|
|
// no effect
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn surface_size(&self) -> PhysicalSize<u32> {
|
2020-05-06 15:27:49 +02:00
|
|
|
self.outer_size()
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn request_surface_size(&self, _size: Size) -> Option<PhysicalSize<u32>> {
|
|
|
|
|
Some(self.surface_size())
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn outer_size(&self) -> PhysicalSize<u32> {
|
2024-07-21 00:40:57 +02:00
|
|
|
screen_size(&self.app)
|
2018-04-16 21:40:30 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn set_min_surface_size(&self, _: Option<Size>) {}
|
2016-10-31 17:08:55 +01:00
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn set_max_surface_size(&self, _: Option<Size>) {}
|
2018-03-23 05:35:35 -04:00
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn surface_resize_increments(&self) -> Option<PhysicalSize<u32>> {
|
2022-09-03 21:50:22 +03:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn set_surface_resize_increments(&self, _increments: Option<Size>) {}
|
2022-09-03 21:50:22 +03:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_title(&self, _title: &str) {}
|
2018-03-23 05:35:35 -04:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_transparent(&self, _transparent: bool) {}
|
2023-01-15 23:39:36 +03:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_blur(&self, _blur: bool) {}
|
2023-10-08 22:53:15 +03:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_visible(&self, _visibility: bool) {}
|
2018-06-14 19:42:18 -04:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn is_visible(&self) -> Option<bool> {
|
2022-02-17 20:44:14 +02:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_resizable(&self, _resizeable: bool) {}
|
2016-10-31 17:08:55 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn is_resizable(&self) -> bool {
|
2022-02-17 17:03:17 +02:00
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_enabled_buttons(&self, _buttons: WindowButtons) {}
|
2022-11-29 12:03:51 +02:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn enabled_buttons(&self) -> WindowButtons {
|
2022-11-29 12:03:51 +02:00
|
|
|
WindowButtons::all()
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_minimized(&self, _minimized: bool) {}
|
2016-10-31 17:08:55 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn is_minimized(&self) -> Option<bool> {
|
2023-01-19 23:39:04 +02:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_maximized(&self, _maximized: bool) {}
|
2016-10-31 17:08:55 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn is_maximized(&self) -> bool {
|
2021-01-27 20:01:17 +02:00
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn fullscreen(&self) -> Option<Fullscreen> {
|
2020-05-06 15:27:49 +02:00
|
|
|
None
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_decorations(&self, _decorations: bool) {}
|
2018-06-18 12:32:18 -04:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn is_decorated(&self) -> bool {
|
2022-02-17 15:31:13 +02:00
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_window_level(&self, _level: WindowLevel) {}
|
2016-10-31 17:08:55 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {}
|
2017-08-28 00:22:26 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_ime_cursor_area(&self, _position: Position, _size: Size) {}
|
2020-05-06 15:27:49 +02:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_ime_allowed(&self, _allowed: bool) {}
|
2022-05-07 05:29:25 +03:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_ime_purpose(&self, _purpose: ImePurpose) {}
|
2023-01-29 16:46:46 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn focus_window(&self) {}
|
2021-05-19 18:39:53 +02:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}
|
2020-11-27 03:03:08 +01:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_cursor(&self, _: Cursor) {}
|
2023-12-16 22:02:17 +02:00
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn set_cursor_position(&self, _: Position) -> Result<(), RequestError> {
|
|
|
|
|
Err(NotSupportedError::new("set_cursor_position is not supported").into())
|
2017-09-07 09:33:46 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), RequestError> {
|
|
|
|
|
Err(NotSupportedError::new("set_cursor_grab is not supported").into())
|
2019-04-26 03:09:32 +10:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_cursor_visible(&self, _: bool) {}
|
2020-05-06 15:27:49 +02:00
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn drag_window(&self) -> Result<(), RequestError> {
|
|
|
|
|
Err(NotSupportedError::new("drag_window is not supported").into())
|
2021-03-07 10:43:23 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), RequestError> {
|
|
|
|
|
Err(NotSupportedError::new("drag_resize_window").into())
|
2023-01-11 18:07:09 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-11 01:16:16 +03:30
|
|
|
#[inline]
|
2024-08-23 23:40:27 +03:00
|
|
|
fn show_window_menu(&self, _position: Position) {}
|
2023-10-11 01:16:16 +03:30
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), RequestError> {
|
|
|
|
|
Err(NotSupportedError::new("set_cursor_hittest is not supported").into())
|
2022-04-12 19:10:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_theme(&self, _theme: Option<Theme>) {}
|
2023-10-14 19:07:39 -07:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn theme(&self) -> Option<Theme> {
|
|
|
|
|
None
|
2022-07-21 22:22:36 +03:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn set_content_protected(&self, _protected: bool) {}
|
2017-12-22 07:50:46 -05:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn has_focus(&self) -> bool {
|
|
|
|
|
HAS_FOCUS.load(Ordering::Relaxed)
|
2018-05-20 10:24:05 -04:00
|
|
|
}
|
2022-10-19 03:34:36 +09:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn title(&self) -> String {
|
|
|
|
|
String::new()
|
2022-10-19 03:34:36 +09:00
|
|
|
}
|
2022-11-03 10:11:37 -07:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
fn reset_dead_keys(&self) {}
|
2023-09-01 23:14:16 +02:00
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
|
|
|
|
self
|
2023-01-17 03:30:14 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
|
|
|
|
self
|
2022-11-03 10:11:37 -07: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
|
|
|
|
2024-07-26 15:59:17 +02:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
pub struct MonitorHandle;
|
2020-05-06 15:27:49 +02:00
|
|
|
|
|
|
|
|
impl MonitorHandle {
|
|
|
|
|
pub fn name(&self) -> Option<String> {
|
2024-07-26 15:59:17 +02:00
|
|
|
unreachable!()
|
2018-05-17 21:28:30 -04:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 19:59:37 +02:00
|
|
|
pub fn position(&self) -> Option<PhysicalPosition<i32>> {
|
2024-07-26 15:59:17 +02:00
|
|
|
unreachable!()
|
2018-06-16 10:14:12 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-06 15:27:49 +02:00
|
|
|
pub fn scale_factor(&self) -> f64 {
|
2024-07-26 15:59:17 +02:00
|
|
|
unreachable!()
|
2020-05-06 15:27:49 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-21 00:01:43 +02:00
|
|
|
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
|
2024-07-26 15:59:17 +02:00
|
|
|
unreachable!()
|
2018-06-16 10:14:12 -04:00
|
|
|
}
|
2024-07-21 00:01:43 +02:00
|
|
|
|
2024-07-26 15:59:17 +02:00
|
|
|
pub fn video_modes(&self) -> std::iter::Empty<VideoModeHandle> {
|
|
|
|
|
unreachable!()
|
2024-07-21 00:01:43 +02: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)]
|
2024-07-26 15:59:17 +02:00
|
|
|
pub struct VideoModeHandle;
|
2020-05-06 15:27:49 +02:00
|
|
|
|
2023-12-26 22:12:33 +01:00
|
|
|
impl VideoModeHandle {
|
2020-05-06 15:27:49 +02:00
|
|
|
pub fn size(&self) -> PhysicalSize<u32> {
|
2024-07-26 15:59:17 +02:00
|
|
|
unreachable!()
|
2016-10-31 17:08:55 +01:00
|
|
|
}
|
2019-09-30 17:17:01 +02:00
|
|
|
|
2024-07-23 19:59:37 +02:00
|
|
|
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
2024-07-26 15:59:17 +02:00
|
|
|
unreachable!()
|
2019-09-30 17:17:01 +02:00
|
|
|
}
|
2017-07-06 23:33:42 +02:00
|
|
|
|
2024-07-23 19:59:37 +02:00
|
|
|
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
2024-07-26 15:59:17 +02:00
|
|
|
unreachable!()
|
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 {
|
2024-07-26 15:59:17 +02:00
|
|
|
unreachable!()
|
2020-05-06 15:27:49 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-07-21 00:40:57 +02:00
|
|
|
|
|
|
|
|
fn screen_size(app: &AndroidApp) -> PhysicalSize<u32> {
|
|
|
|
|
if let Some(native_window) = app.native_window() {
|
|
|
|
|
PhysicalSize::new(native_window.width() as _, native_window.height() as _)
|
|
|
|
|
} else {
|
|
|
|
|
PhysicalSize::new(0, 0)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-26 15:59:17 +02:00
|
|
|
|
|
|
|
|
fn scale_factor(app: &AndroidApp) -> f64 {
|
|
|
|
|
app.config().density().map(|dpi| dpi as f64 / 160.0).unwrap_or(1.0)
|
|
|
|
|
}
|