winit/src/platform_impl/android/mod.rs

698 lines
25 KiB
Rust
Raw Normal View History

2015-04-24 09:51:23 +02:00
#![cfg(target_os = "android")]
use crate::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error, event,
event_loop::{self, ControlFlow},
monitor, window,
};
use ndk::{
configuration::Configuration,
2021-02-23 18:35:38 -03:00
event::{InputEvent, KeyAction, MotionAction},
looper::{ForeignLooper, Poll, ThreadLooper},
};
use ndk_glue::{Event, Rect};
use raw_window_handle::{AndroidNdkHandle, RawWindowHandle};
use std::{
collections::VecDeque,
sync::{Arc, Mutex, RwLock},
time::{Duration, Instant},
};
lazy_static! {
static ref CONFIG: RwLock<Configuration> = RwLock::new(Configuration::from_asset_manager(
&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 ref INTERNAL_EVENT: RwLock<Option<InternalEvent>> = RwLock::new(None);
}
enum InternalEvent {
RedrawRequested,
2016-10-31 17:08:55 +01:00
}
enum EventSource {
Callback,
InputQueue,
User,
Internal(InternalEvent),
}
2016-10-31 17:08:55 +01:00
fn poll(poll: Poll) -> Option<EventSource> {
match poll {
Poll::Event { ident, .. } => match ident {
ndk_glue::NDK_GLUE_LOOPER_EVENT_PIPE_IDENT => Some(EventSource::Callback),
ndk_glue::NDK_GLUE_LOOPER_INPUT_QUEUE_IDENT => Some(EventSource::InputQueue),
_ => unreachable!(),
},
Poll::Timeout => None,
Poll::Wake => Some(
INTERNAL_EVENT
.write()
.unwrap()
.take()
.map_or(EventSource::User, EventSource::Internal),
),
Poll::Callback => unreachable!(),
}
}
2016-10-31 17:08:55 +01:00
pub struct EventLoop<T: 'static> {
window_target: event_loop::EventLoopWindowTarget<T>,
user_queue: Arc<Mutex<VecDeque<T>>>,
first_event: Option<EventSource>,
start_cause: event::StartCause,
looper: ThreadLooper,
running: bool,
}
macro_rules! call_event_handler {
( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{
Add exit code to `ControlFlow::Exit` (#2100) * Add exit code to control flow and impl on linux * Fix examples to have an exit code * Fix doc examples to use an exit code * Improve documentation wording on the exit code * Add exit code example * Add exit code on windows * Change i32 as exit code to u8 This avoids nasty surprises with negative numbers on some unix-alikes due to two's complement. * Fix android usages of ControlFlow::Exit * Fix ios usages of ControlFlow::Exit * Fix web usages of ControlFlow::Exit * Add macos exit code * Add changelog note * Document exit code on display server disconnection * Revert "Change i32 as exit code to u8" This reverts commit f88fba0253b45de6a2ac0c3cbcf01f50503c9396. * Change Exit to ExitWithCode and make an Exit const * Revert "Add exit code example" This reverts commit fbd3d03de9c2d7516c7a63da489c99f498b710df. * Revert "Fix doc examples to use an exit code" This reverts commit daabcdf9ef9e16acad715c094ae442529e39fcbc. * Revert "Fix examples to have an exit code" This reverts commit 0df486896b8d106acf65ba83c45cc88d60d228e1. * Fix unix-alike to use ExitWithCode instead of Exit * Fix windows to use ExitWithCode rather than Exit * Silence warning about non-uppercase Exit const * Refactor exit code handling * Fix macos Exit usage and recover original semantic * Fix ios to use ExitWithCode instead of Exit * Update documentation to reflect ExitWithCode * Fix web to use ExitWithCode when needed, not Exit * Fix android to use ExitWithCode, not Exit * Apply documenation nits * Apply even more documentation nits * Move change in CHANGELOG.md under "Unreleased" * Try to use OS error code as exit code on wayland
2022-01-11 01:23:20 +01:00
if let ControlFlow::ExitWithCode(code) = $cf {
$event_handler($event, $window_target, &mut ControlFlow::ExitWithCode(code));
} else {
Add exit code to `ControlFlow::Exit` (#2100) * Add exit code to control flow and impl on linux * Fix examples to have an exit code * Fix doc examples to use an exit code * Improve documentation wording on the exit code * Add exit code example * Add exit code on windows * Change i32 as exit code to u8 This avoids nasty surprises with negative numbers on some unix-alikes due to two's complement. * Fix android usages of ControlFlow::Exit * Fix ios usages of ControlFlow::Exit * Fix web usages of ControlFlow::Exit * Add macos exit code * Add changelog note * Document exit code on display server disconnection * Revert "Change i32 as exit code to u8" This reverts commit f88fba0253b45de6a2ac0c3cbcf01f50503c9396. * Change Exit to ExitWithCode and make an Exit const * Revert "Add exit code example" This reverts commit fbd3d03de9c2d7516c7a63da489c99f498b710df. * Revert "Fix doc examples to use an exit code" This reverts commit daabcdf9ef9e16acad715c094ae442529e39fcbc. * Revert "Fix examples to have an exit code" This reverts commit 0df486896b8d106acf65ba83c45cc88d60d228e1. * Fix unix-alike to use ExitWithCode instead of Exit * Fix windows to use ExitWithCode rather than Exit * Silence warning about non-uppercase Exit const * Refactor exit code handling * Fix macos Exit usage and recover original semantic * Fix ios to use ExitWithCode instead of Exit * Update documentation to reflect ExitWithCode * Fix web to use ExitWithCode when needed, not Exit * Fix android to use ExitWithCode, not Exit * Apply documenation nits * Apply even more documentation nits * Move change in CHANGELOG.md under "Unreleased" * Try to use OS error code as exit code on wayland
2022-01-11 01:23:20 +01:00
$event_handler($event, $window_target, &mut $cf);
}
}};
}
2016-10-31 17:08:55 +01:00
impl<T: 'static> EventLoop<T> {
pub fn new() -> Self {
Self {
window_target: event_loop::EventLoopWindowTarget {
p: EventLoopWindowTarget {
_marker: std::marker::PhantomData,
},
_marker: std::marker::PhantomData,
},
user_queue: Default::default(),
first_event: None,
start_cause: event::StartCause::Init,
looper: ThreadLooper::for_thread().unwrap(),
running: false,
}
2016-10-31 17:08:55 +01:00
}
pub fn run<F>(mut self, event_handler: F) -> !
where
F: 'static
+ FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
{
Add exit code to `ControlFlow::Exit` (#2100) * Add exit code to control flow and impl on linux * Fix examples to have an exit code * Fix doc examples to use an exit code * Improve documentation wording on the exit code * Add exit code example * Add exit code on windows * Change i32 as exit code to u8 This avoids nasty surprises with negative numbers on some unix-alikes due to two's complement. * Fix android usages of ControlFlow::Exit * Fix ios usages of ControlFlow::Exit * Fix web usages of ControlFlow::Exit * Add macos exit code * Add changelog note * Document exit code on display server disconnection * Revert "Change i32 as exit code to u8" This reverts commit f88fba0253b45de6a2ac0c3cbcf01f50503c9396. * Change Exit to ExitWithCode and make an Exit const * Revert "Add exit code example" This reverts commit fbd3d03de9c2d7516c7a63da489c99f498b710df. * Revert "Fix doc examples to use an exit code" This reverts commit daabcdf9ef9e16acad715c094ae442529e39fcbc. * Revert "Fix examples to have an exit code" This reverts commit 0df486896b8d106acf65ba83c45cc88d60d228e1. * Fix unix-alike to use ExitWithCode instead of Exit * Fix windows to use ExitWithCode rather than Exit * Silence warning about non-uppercase Exit const * Refactor exit code handling * Fix macos Exit usage and recover original semantic * Fix ios to use ExitWithCode instead of Exit * Update documentation to reflect ExitWithCode * Fix web to use ExitWithCode when needed, not Exit * Fix android to use ExitWithCode, not Exit * Apply documenation nits * Apply even more documentation nits * Move change in CHANGELOG.md under "Unreleased" * Try to use OS error code as exit code on wayland
2022-01-11 01:23:20 +01:00
let exit_code = self.run_return(event_handler);
::std::process::exit(exit_code);
}
Add exit code to `ControlFlow::Exit` (#2100) * Add exit code to control flow and impl on linux * Fix examples to have an exit code * Fix doc examples to use an exit code * Improve documentation wording on the exit code * Add exit code example * Add exit code on windows * Change i32 as exit code to u8 This avoids nasty surprises with negative numbers on some unix-alikes due to two's complement. * Fix android usages of ControlFlow::Exit * Fix ios usages of ControlFlow::Exit * Fix web usages of ControlFlow::Exit * Add macos exit code * Add changelog note * Document exit code on display server disconnection * Revert "Change i32 as exit code to u8" This reverts commit f88fba0253b45de6a2ac0c3cbcf01f50503c9396. * Change Exit to ExitWithCode and make an Exit const * Revert "Add exit code example" This reverts commit fbd3d03de9c2d7516c7a63da489c99f498b710df. * Revert "Fix doc examples to use an exit code" This reverts commit daabcdf9ef9e16acad715c094ae442529e39fcbc. * Revert "Fix examples to have an exit code" This reverts commit 0df486896b8d106acf65ba83c45cc88d60d228e1. * Fix unix-alike to use ExitWithCode instead of Exit * Fix windows to use ExitWithCode rather than Exit * Silence warning about non-uppercase Exit const * Refactor exit code handling * Fix macos Exit usage and recover original semantic * Fix ios to use ExitWithCode instead of Exit * Update documentation to reflect ExitWithCode * Fix web to use ExitWithCode when needed, not Exit * Fix android to use ExitWithCode, not Exit * Apply documenation nits * Apply even more documentation nits * Move change in CHANGELOG.md under "Unreleased" * Try to use OS error code as exit code on wayland
2022-01-11 01:23:20 +01:00
pub fn run_return<F>(&mut self, mut event_handler: F) -> i32
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,
self.window_target(),
control_flow,
event::Event::NewEvents(self.start_cause)
);
let mut redraw = false;
let mut resized = false;
match self.first_event.take() {
Some(EventSource::Callback) => match ndk_glue::poll_events().unwrap() {
Event::WindowCreated => {
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::Resumed
);
}
Event::WindowResized => resized = true,
Event::WindowRedrawNeeded => redraw = true,
Event::WindowDestroyed => {
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::Suspended
);
}
Event::Pause => self.running = false,
Event::Resume => self.running = true,
Event::ConfigChanged => {
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,
},
};
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event
);
}
}
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),
}
);
}
_ => {}
},
Some(EventSource::InputQueue) => {
if let Some(input_queue) = ndk_glue::input_queue().as_ref() {
while let Some(event) = input_queue.get_event() {
if let Some(event) = input_queue.pre_dispatch(event) {
let mut handled = true;
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)
}
MotionAction::Move => Some(event::TouchPhase::Moved),
MotionAction::Cancel => {
Some(event::TouchPhase::Cancelled)
}
_ => {
handled = false;
None // TODO mouse events
}
};
if let Some(phase) = phase {
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
);
}
}
}
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,
};
#[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,
virtual_keycode: None,
modifiers: event::ModifiersState::default(),
},
is_synthetic: false,
},
};
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event
);
}
};
input_queue.finish_event(event, handled);
}
}
}
2019-06-24 12:14:55 -04:00
}
Some(EventSource::User) => {
let mut user_queue = self.user_queue.lock().unwrap();
while let Some(event) = user_queue.pop_front() {
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::UserEvent(event)
);
}
2019-06-24 12:14:55 -04:00
}
Some(EventSource::Internal(internal)) => match internal {
InternalEvent::RedrawRequested => redraw = true,
},
None => {}
}
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::MainEventsCleared
);
if resized && self.running {
let size = MonitorHandle.size();
let event = event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::Resized(size),
};
call_event_handler!(event_handler, self.window_target(), control_flow, event);
}
if redraw && self.running {
let event = event::Event::RedrawRequested(window::WindowId(WindowId));
call_event_handler!(event_handler, self.window_target(), control_flow, event);
}
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::RedrawEventsCleared
);
match control_flow {
Add exit code to `ControlFlow::Exit` (#2100) * Add exit code to control flow and impl on linux * Fix examples to have an exit code * Fix doc examples to use an exit code * Improve documentation wording on the exit code * Add exit code example * Add exit code on windows * Change i32 as exit code to u8 This avoids nasty surprises with negative numbers on some unix-alikes due to two's complement. * Fix android usages of ControlFlow::Exit * Fix ios usages of ControlFlow::Exit * Fix web usages of ControlFlow::Exit * Add macos exit code * Add changelog note * Document exit code on display server disconnection * Revert "Change i32 as exit code to u8" This reverts commit f88fba0253b45de6a2ac0c3cbcf01f50503c9396. * Change Exit to ExitWithCode and make an Exit const * Revert "Add exit code example" This reverts commit fbd3d03de9c2d7516c7a63da489c99f498b710df. * Revert "Fix doc examples to use an exit code" This reverts commit daabcdf9ef9e16acad715c094ae442529e39fcbc. * Revert "Fix examples to have an exit code" This reverts commit 0df486896b8d106acf65ba83c45cc88d60d228e1. * Fix unix-alike to use ExitWithCode instead of Exit * Fix windows to use ExitWithCode rather than Exit * Silence warning about non-uppercase Exit const * Refactor exit code handling * Fix macos Exit usage and recover original semantic * Fix ios to use ExitWithCode instead of Exit * Update documentation to reflect ExitWithCode * Fix web to use ExitWithCode when needed, not Exit * Fix android to use ExitWithCode, not Exit * Apply documenation nits * Apply even more documentation nits * Move change in CHANGELOG.md under "Unreleased" * Try to use OS error code as exit code on wayland
2022-01-11 01:23:20 +01:00
ControlFlow::ExitWithCode(code) => {
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,
};
Add exit code to `ControlFlow::Exit` (#2100) * Add exit code to control flow and impl on linux * Fix examples to have an exit code * Fix doc examples to use an exit code * Improve documentation wording on the exit code * Add exit code example * Add exit code on windows * Change i32 as exit code to u8 This avoids nasty surprises with negative numbers on some unix-alikes due to two's complement. * Fix android usages of ControlFlow::Exit * Fix ios usages of ControlFlow::Exit * Fix web usages of ControlFlow::Exit * Add macos exit code * Add changelog note * Document exit code on display server disconnection * Revert "Change i32 as exit code to u8" This reverts commit f88fba0253b45de6a2ac0c3cbcf01f50503c9396. * Change Exit to ExitWithCode and make an Exit const * Revert "Add exit code example" This reverts commit fbd3d03de9c2d7516c7a63da489c99f498b710df. * Revert "Fix doc examples to use an exit code" This reverts commit daabcdf9ef9e16acad715c094ae442529e39fcbc. * Revert "Fix examples to have an exit code" This reverts commit 0df486896b8d106acf65ba83c45cc88d60d228e1. * Fix unix-alike to use ExitWithCode instead of Exit * Fix windows to use ExitWithCode rather than Exit * Silence warning about non-uppercase Exit const * Refactor exit code handling * Fix macos Exit usage and recover original semantic * Fix ios to use ExitWithCode instead of Exit * Update documentation to reflect ExitWithCode * Fix web to use ExitWithCode when needed, not Exit * Fix android to use ExitWithCode, not Exit * Apply documenation nits * Apply even more documentation nits * Move change in CHANGELOG.md under "Unreleased" * Try to use OS error code as exit code on wayland
2022-01-11 01:23:20 +01:00
break 'event_loop code;
}
ControlFlow::Poll => {
self.first_event = poll(
self.looper
.poll_all_timeout(Duration::from_millis(0))
.unwrap(),
);
self.start_cause = event::StartCause::Poll;
}
ControlFlow::Wait => {
self.first_event = poll(self.looper.poll_all().unwrap());
self.start_cause = event::StartCause::WaitCancelled {
start: Instant::now(),
requested_resume: None,
}
2019-06-24 12:14:55 -04:00
}
ControlFlow::WaitUntil(instant) => {
let start = Instant::now();
let duration = if instant <= start {
Duration::default()
} else {
instant - start
};
self.first_event = poll(self.looper.poll_all_timeout(duration).unwrap());
self.start_cause = if self.first_event.is_some() {
event::StartCause::WaitCancelled {
start,
requested_resume: Some(instant),
}
} else {
event::StartCause::ResumeTimeReached {
start,
requested_resume: instant,
}
}
2019-06-24 12:14:55 -04:00
}
2016-10-31 17:08:55 +01:00
}
}
}
pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget<T> {
&self.window_target
}
pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy {
queue: self.user_queue.clone(),
looper: ForeignLooper::for_thread().expect("called from event loop thread"),
}
}
}
pub struct EventLoopProxy<T: 'static> {
queue: Arc<Mutex<VecDeque<T>>>,
looper: ForeignLooper,
}
impl<T> EventLoopProxy<T> {
pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> {
self.queue.lock().unwrap().push_back(event);
self.looper.wake();
Ok(())
}
2016-10-31 17:08:55 +01:00
}
impl<T> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self {
EventLoopProxy {
queue: self.queue.clone(),
looper: self.looper.clone(),
}
}
}
pub struct EventLoopWindowTarget<T: 'static> {
_marker: std::marker::PhantomData<T>,
}
impl<T: 'static> EventLoopWindowTarget<T> {
pub fn primary_monitor(&self) -> Option<monitor::MonitorHandle> {
Some(monitor::MonitorHandle {
inner: MonitorHandle,
})
}
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
let mut v = VecDeque::with_capacity(1);
v.push_back(MonitorHandle);
v
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct WindowId;
impl WindowId {
pub const fn dummy() -> Self {
WindowId
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct DeviceId;
impl DeviceId {
pub const fn dummy() -> Self {
DeviceId
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct PlatformSpecificWindowBuilderAttributes;
pub struct Window;
2018-06-14 19:42:18 -04:00
impl Window {
pub fn new<T: 'static>(
_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
pub fn id(&self) -> WindowId {
WindowId
2018-06-14 19:42:18 -04:00
}
2016-10-31 17:08:55 +01:00
pub fn primary_monitor(&self) -> Option<monitor::MonitorHandle> {
Some(monitor::MonitorHandle {
inner: MonitorHandle,
})
}
2016-10-31 17:08:55 +01: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
}
Move fullscreen modes to not touch physical resolutions (#270) * Fix X11 screen resolution change using XrandR The previous XF86 resolution switching was broken and everything seems to have moved on to xrandr. Use that instead while cleaning up the code a bit as well. * Use XRandR for actual multiscreen support in X11 * Use actual monitor names in X11 * Get rid of ptr::read usage in X11 * Use a bog standard Vec instead of VecDeque * Get rid of the XRandR mode switching stuff Wayland has made the decision that apps shouldn't change screen resolutions and just take the screens as they've been setup. In the modern world where GPU scaling is cheap and LCD panels are scaling anyway it makes no sense to make "physical" resolution changes when software should be taking care of it. This massively simplifies the code and makes it easier to extend to more niche setups like MST and videowalls. * Rename fullscreen options to match new semantics * Implement XRandR 1.5 support * Get rid of the FullScreen enum Moving to just having two states None and Some(MonitorId) and then being able to set full screen in the current monitor with something like: window.set_fullscreen(Some(window.current_monitor())); * Implement Window::get_current_monitor() Do it by iterating over the available monitors and finding which has the biggest overlap with the window. For this MonitorId needs a new get_position() that needs to be implemented for all platforms. * Add unimplemented get_position() to all MonitorId * Make get_current_monitor() platform specific * Add unimplemented get_current_monitor() to all * Implement proper primary monitor selection in X11 * Shut up some warnings * Remove libxxf86vm package from travis Since we're no longer using XF86 there's no need to keep the package around for CI. * Don't use new struct syntax * Fix indentation * Adjust Android/iOS fullscreen/maximized On Android and iOS we can assume single screen apps that are already fullscreen and maximized so there are a few methods that are implemented by just returning a fixed value or not doing anything. * Mark OSX/Win fullscreen/maximized unimplemented()! These would be safe as no-ops but we should make it explicit so there is more of an incentive to actually implement them.
2017-09-07 09:33:46 +01:00
pub fn current_monitor(&self) -> Option<monitor::MonitorHandle> {
Some(monitor::MonitorHandle {
inner: MonitorHandle,
})
Move fullscreen modes to not touch physical resolutions (#270) * Fix X11 screen resolution change using XrandR The previous XF86 resolution switching was broken and everything seems to have moved on to xrandr. Use that instead while cleaning up the code a bit as well. * Use XRandR for actual multiscreen support in X11 * Use actual monitor names in X11 * Get rid of ptr::read usage in X11 * Use a bog standard Vec instead of VecDeque * Get rid of the XRandR mode switching stuff Wayland has made the decision that apps shouldn't change screen resolutions and just take the screens as they've been setup. In the modern world where GPU scaling is cheap and LCD panels are scaling anyway it makes no sense to make "physical" resolution changes when software should be taking care of it. This massively simplifies the code and makes it easier to extend to more niche setups like MST and videowalls. * Rename fullscreen options to match new semantics * Implement XRandR 1.5 support * Get rid of the FullScreen enum Moving to just having two states None and Some(MonitorId) and then being able to set full screen in the current monitor with something like: window.set_fullscreen(Some(window.current_monitor())); * Implement Window::get_current_monitor() Do it by iterating over the available monitors and finding which has the biggest overlap with the window. For this MonitorId needs a new get_position() that needs to be implemented for all platforms. * Add unimplemented get_position() to all MonitorId * Make get_current_monitor() platform specific * Add unimplemented get_current_monitor() to all * Implement proper primary monitor selection in X11 * Shut up some warnings * Remove libxxf86vm package from travis Since we're no longer using XF86 there's no need to keep the package around for CI. * Don't use new struct syntax * Fix indentation * Adjust Android/iOS fullscreen/maximized On Android and iOS we can assume single screen apps that are already fullscreen and maximized so there are a few methods that are implemented by just returning a fixed value or not doing anything. * Mark OSX/Win fullscreen/maximized unimplemented()! These would be safe as no-ops but we should make it explicit so there is more of an incentive to actually implement them.
2017-09-07 09:33:46 +01:00
}
pub fn scale_factor(&self) -> f64 {
MonitorHandle.scale_factor()
}
2016-10-31 17:08:55 +01:00
pub fn request_redraw(&self) {
*INTERNAL_EVENT.write().unwrap() = Some(InternalEvent::RedrawRequested);
ForeignLooper::for_thread().unwrap().wake();
2016-10-31 17:08:55 +01:00
}
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, error::NotSupportedError> {
Err(error::NotSupportedError::new())
2016-10-31 17:08:55 +01:00
}
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, error::NotSupportedError> {
Err(error::NotSupportedError::new())
2016-10-31 17:08:55 +01:00
}
pub fn set_outer_position(&self, _position: Position) {
// no effect
2016-10-31 17:08:55 +01:00
}
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.outer_size()
2016-10-31 17:08:55 +01:00
}
pub fn set_inner_size(&self, _size: Size) {
warn!("Cannot set window size on Android");
2016-10-31 17:08:55 +01:00
}
pub fn outer_size(&self) -> PhysicalSize<u32> {
MonitorHandle.size()
}
pub fn set_min_inner_size(&self, _: Option<Size>) {}
2016-10-31 17:08:55 +01:00
pub fn set_max_inner_size(&self, _: Option<Size>) {}
pub fn set_title(&self, _title: &str) {}
pub fn set_visible(&self, _visibility: bool) {}
2018-06-14 19:42:18 -04:00
pub fn set_resizable(&self, _resizeable: bool) {}
2016-10-31 17:08:55 +01:00
pub fn set_minimized(&self, _minimized: bool) {}
2016-10-31 17:08:55 +01:00
pub fn set_maximized(&self, _maximized: bool) {}
2016-10-31 17:08:55 +01:00
pub fn is_maximized(&self) -> bool {
false
}
pub fn set_fullscreen(&self, _monitor: Option<window::Fullscreen>) {
warn!("Cannot set fullscreen on Android");
2016-10-31 17:08:55 +01:00
}
pub fn fullscreen(&self) -> Option<window::Fullscreen> {
None
2016-10-31 17:08:55 +01:00
}
pub fn set_decorations(&self, _decorations: bool) {}
pub fn set_always_on_top(&self, _always_on_top: bool) {}
2016-10-31 17:08:55 +01:00
pub fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {}
pub fn set_ime_position(&self, _position: Position) {}
2021-05-19 18:39:53 +02:00
pub fn focus_window(&self) {}
pub fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}
pub fn set_cursor_icon(&self, _: window::CursorIcon) {}
pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
Move fullscreen modes to not touch physical resolutions (#270) * Fix X11 screen resolution change using XrandR The previous XF86 resolution switching was broken and everything seems to have moved on to xrandr. Use that instead while cleaning up the code a bit as well. * Use XRandR for actual multiscreen support in X11 * Use actual monitor names in X11 * Get rid of ptr::read usage in X11 * Use a bog standard Vec instead of VecDeque * Get rid of the XRandR mode switching stuff Wayland has made the decision that apps shouldn't change screen resolutions and just take the screens as they've been setup. In the modern world where GPU scaling is cheap and LCD panels are scaling anyway it makes no sense to make "physical" resolution changes when software should be taking care of it. This massively simplifies the code and makes it easier to extend to more niche setups like MST and videowalls. * Rename fullscreen options to match new semantics * Implement XRandR 1.5 support * Get rid of the FullScreen enum Moving to just having two states None and Some(MonitorId) and then being able to set full screen in the current monitor with something like: window.set_fullscreen(Some(window.current_monitor())); * Implement Window::get_current_monitor() Do it by iterating over the available monitors and finding which has the biggest overlap with the window. For this MonitorId needs a new get_position() that needs to be implemented for all platforms. * Add unimplemented get_position() to all MonitorId * Make get_current_monitor() platform specific * Add unimplemented get_current_monitor() to all * Implement proper primary monitor selection in X11 * Shut up some warnings * Remove libxxf86vm package from travis Since we're no longer using XF86 there's no need to keep the package around for CI. * Don't use new struct syntax * Fix indentation * Adjust Android/iOS fullscreen/maximized On Android and iOS we can assume single screen apps that are already fullscreen and maximized so there are a few methods that are implemented by just returning a fixed value or not doing anything. * Mark OSX/Win fullscreen/maximized unimplemented()! These would be safe as no-ops but we should make it explicit so there is more of an incentive to actually implement them.
2017-09-07 09:33:46 +01:00
}
pub fn set_cursor_grab(&self, _: bool) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}
pub fn set_cursor_visible(&self, _: bool) {}
pub fn drag_window(&self) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}
pub fn raw_window_handle(&self) -> RawWindowHandle {
let mut handle = AndroidNdkHandle::empty();
if let Some(native_window) = ndk_glue::native_window().as_ref() {
handle.a_native_window = unsafe { native_window.ptr().as_mut() as *mut _ as *mut _ }
} else {
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.");
};
RawWindowHandle::AndroidNdk(handle)
}
pub fn config(&self) -> Configuration {
CONFIG.read().unwrap().clone()
}
pub fn content_rect(&self) -> Rect {
ndk_glue::content_rect()
}
}
#[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
}
}
2018-05-07 17:36:21 -04: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())
}
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)
}
}
2016-10-31 17:08:55 +01:00
pub fn position(&self) -> PhysicalPosition<i32> {
(0, 0).into()
}
pub fn scale_factor(&self) -> f64 {
let config = CONFIG.read().unwrap();
config
.density()
.map(|dpi| dpi as f64 / 160.0)
.unwrap_or(1.0)
}
pub fn video_modes(&self) -> impl Iterator<Item = monitor::VideoMode> {
let size = self.size().into();
let mut v = Vec::new();
// FIXME this is not the real refresh rate
// (it is guarunteed to support 32 bit color though)
v.push(monitor::VideoMode {
video_mode: VideoMode {
size,
bit_depth: 32,
refresh_rate: 60,
monitor: self.clone(),
},
});
v.into_iter()
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct VideoMode {
size: (u32, u32),
bit_depth: u16,
refresh_rate: u16,
monitor: MonitorHandle,
}
impl VideoMode {
pub fn size(&self) -> PhysicalSize<u32> {
self.size.into()
2016-10-31 17:08:55 +01:00
}
pub fn bit_depth(&self) -> u16 {
self.bit_depth
}
2017-07-06 23:33:42 +02:00
pub fn refresh_rate(&self) -> u16 {
self.refresh_rate
}
pub fn monitor(&self) -> monitor::MonitorHandle {
monitor::MonitorHandle {
inner: self.monitor.clone(),
}
}
}