chore(rustfmt): use nightly (#2325)

Stable rustfmt lacks a lot of features resulting in worse formatted
code, thus use nightly formatter.
This commit is contained in:
Kirill Chibisov 2024-04-26 19:11:44 +04:00 committed by GitHub
parent 7006c7ceca
commit 7b0c7b6cb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
154 changed files with 3439 additions and 5891 deletions

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@nightly
with: with:
components: rustfmt components: rustfmt
- name: Check Formatting - name: Check Formatting

View file

@ -35,9 +35,9 @@
//! //!
//! ### Position and Size types //! ### Position and Size types
//! //!
//! The [`PhysicalPosition`] / [`PhysicalSize`] / [`PhysicalUnit`] types correspond with the actual pixels on the //! The [`PhysicalPosition`] / [`PhysicalSize`] / [`PhysicalUnit`] types correspond with the actual
//! device, and the [`LogicalPosition`] / [`LogicalSize`] / [`LogicalUnit`] types correspond to the physical pixels //! pixels on the device, and the [`LogicalPosition`] / [`LogicalSize`] / [`LogicalUnit`] types
//! divided by the scale factor. //! correspond to the physical pixels divided by the scale factor.
//! //!
//! The position and size types are generic over their exact pixel type, `P`, to allow the //! The position and size types are generic over their exact pixel type, `P`, to allow the
//! API to have integer precision where appropriate (e.g. most window manipulation functions) and //! API to have integer precision where appropriate (e.g. most window manipulation functions) and
@ -52,19 +52,14 @@
//! //!
//! This crate provides the following Cargo features: //! This crate provides the following Cargo features:
//! //!
//! * `serde`: Enables serialization/deserialization of certain types with //! * `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde).
//! [Serde](https://crates.io/crates/serde).
//! * `mint`: Enables mint (math interoperability standard types) conversions. //! * `mint`: Enables mint (math interoperability standard types) conversions.
//! //!
//! //!
//! [points]: https://en.wikipedia.org/wiki/Point_(typography) //! [points]: https://en.wikipedia.org/wiki/Point_(typography)
//! [picas]: https://en.wikipedia.org/wiki/Pica_(typography) //! [picas]: https://en.wikipedia.org/wiki/Pica_(typography)
#![cfg_attr( #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))]
docsrs,
feature(doc_auto_cfg, doc_cfg_hide),
doc(cfg_hide(doc, docsrs))
)]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -120,9 +115,9 @@ impl Pixel for f64 {
/// Checks that the scale factor is a normal positive `f64`. /// Checks that the scale factor is a normal positive `f64`.
/// ///
/// All functions that take a scale factor assert that this will return `true`. If you're sourcing scale factors from /// All functions that take a scale factor assert that this will return `true`. If you're sourcing
/// anywhere other than winit, it's recommended to validate them using this function before passing them to winit; /// scale factors from anywhere other than winit, it's recommended to validate them using this
/// otherwise, you risk panics. /// function before passing them to winit; otherwise, you risk panics.
#[inline] #[inline]
pub fn validate_scale_factor(scale_factor: f64) -> bool { pub fn validate_scale_factor(scale_factor: f64) -> bool {
scale_factor.is_sign_positive() && scale_factor.is_normal() scale_factor.is_sign_positive() && scale_factor.is_normal()
@ -134,12 +129,12 @@ pub fn validate_scale_factor(scale_factor: f64) -> bool {
pub struct LogicalUnit<P>(pub P); pub struct LogicalUnit<P>(pub P);
impl<P> LogicalUnit<P> { impl<P> LogicalUnit<P> {
/// Represents a maximum logical unit that is equal to [`f64::MAX`].
pub const MAX: LogicalUnit<f64> = LogicalUnit::new(f64::MAX);
/// Represents a minimum logical unit of [`f64::MAX`]. /// Represents a minimum logical unit of [`f64::MAX`].
pub const MIN: LogicalUnit<f64> = LogicalUnit::new(f64::MIN); pub const MIN: LogicalUnit<f64> = LogicalUnit::new(f64::MIN);
/// Represents a logical unit of `0_f64`. /// Represents a logical unit of `0_f64`.
pub const ZERO: LogicalUnit<f64> = LogicalUnit::new(0.0); pub const ZERO: LogicalUnit<f64> = LogicalUnit::new(0.0);
/// Represents a maximum logical unit that is equal to [`f64::MAX`].
pub const MAX: LogicalUnit<f64> = LogicalUnit::new(f64::MAX);
#[inline] #[inline]
pub const fn new(v: P) -> Self { pub const fn new(v: P) -> Self {
@ -228,12 +223,12 @@ impl<P: Pixel> From<LogicalUnit<P>> for f64 {
pub struct PhysicalUnit<P>(pub P); pub struct PhysicalUnit<P>(pub P);
impl<P> PhysicalUnit<P> { impl<P> PhysicalUnit<P> {
/// Represents a maximum physical unit that is equal to [`f64::MAX`].
pub const MAX: LogicalUnit<f64> = LogicalUnit::new(f64::MAX);
/// Represents a minimum physical unit of [`f64::MAX`]. /// Represents a minimum physical unit of [`f64::MAX`].
pub const MIN: LogicalUnit<f64> = LogicalUnit::new(f64::MIN); pub const MIN: LogicalUnit<f64> = LogicalUnit::new(f64::MIN);
/// Represents a physical unit of `0_f64`. /// Represents a physical unit of `0_f64`.
pub const ZERO: LogicalUnit<f64> = LogicalUnit::new(0.0); pub const ZERO: LogicalUnit<f64> = LogicalUnit::new(0.0);
/// Represents a maximum physical unit that is equal to [`f64::MAX`].
pub const MAX: LogicalUnit<f64> = LogicalUnit::new(f64::MAX);
#[inline] #[inline]
pub const fn new(v: P) -> Self { pub const fn new(v: P) -> Self {
@ -322,12 +317,12 @@ pub enum PixelUnit {
} }
impl PixelUnit { impl PixelUnit {
/// Represents a maximum logical unit that is equal to [`f64::MAX`].
pub const MAX: PixelUnit = PixelUnit::Logical(LogicalUnit::new(f64::MAX));
/// Represents a minimum logical unit of [`f64::MAX`]. /// Represents a minimum logical unit of [`f64::MAX`].
pub const MIN: PixelUnit = PixelUnit::Logical(LogicalUnit::new(f64::MIN)); pub const MIN: PixelUnit = PixelUnit::Logical(LogicalUnit::new(f64::MIN));
/// Represents a logical unit of `0_f64`. /// Represents a logical unit of `0_f64`.
pub const ZERO: PixelUnit = PixelUnit::Logical(LogicalUnit::new(0.0)); pub const ZERO: PixelUnit = PixelUnit::Logical(LogicalUnit::new(0.0));
/// Represents a maximum logical unit that is equal to [`f64::MAX`].
pub const MAX: PixelUnit = PixelUnit::Logical(LogicalUnit::new(f64::MAX));
pub fn new<S: Into<PixelUnit>>(unit: S) -> PixelUnit { pub fn new<S: Into<PixelUnit>>(unit: S) -> PixelUnit {
unit.into() unit.into()
@ -400,10 +395,7 @@ impl<P: Pixel> LogicalPosition<P> {
#[inline] #[inline]
pub fn cast<X: Pixel>(&self) -> LogicalPosition<X> { pub fn cast<X: Pixel>(&self) -> LogicalPosition<X> {
LogicalPosition { LogicalPosition { x: self.x.cast(), y: self.y.cast() }
x: self.x.cast(),
y: self.y.cast(),
}
} }
} }
@ -479,10 +471,7 @@ impl<P: Pixel> PhysicalPosition<P> {
#[inline] #[inline]
pub fn cast<X: Pixel>(&self) -> PhysicalPosition<X> { pub fn cast<X: Pixel>(&self) -> PhysicalPosition<X> {
PhysicalPosition { PhysicalPosition { x: self.x.cast(), y: self.y.cast() }
x: self.x.cast(),
y: self.y.cast(),
}
} }
} }
@ -558,10 +547,7 @@ impl<P: Pixel> LogicalSize<P> {
#[inline] #[inline]
pub fn cast<X: Pixel>(&self) -> LogicalSize<X> { pub fn cast<X: Pixel>(&self) -> LogicalSize<X> {
LogicalSize { LogicalSize { width: self.width.cast(), height: self.height.cast() }
width: self.width.cast(),
height: self.height.cast(),
}
} }
} }
@ -599,10 +585,7 @@ impl<P: Pixel> From<mint::Vector2<P>> for LogicalSize<P> {
#[cfg(feature = "mint")] #[cfg(feature = "mint")]
impl<P: Pixel> From<LogicalSize<P>> for mint::Vector2<P> { impl<P: Pixel> From<LogicalSize<P>> for mint::Vector2<P> {
fn from(s: LogicalSize<P>) -> Self { fn from(s: LogicalSize<P>) -> Self {
mint::Vector2 { mint::Vector2 { x: s.width, y: s.height }
x: s.width,
y: s.height,
}
} }
} }
@ -637,10 +620,7 @@ impl<P: Pixel> PhysicalSize<P> {
#[inline] #[inline]
pub fn cast<X: Pixel>(&self) -> PhysicalSize<X> { pub fn cast<X: Pixel>(&self) -> PhysicalSize<X> {
PhysicalSize { PhysicalSize { width: self.width.cast(), height: self.height.cast() }
width: self.width.cast(),
height: self.height.cast(),
}
} }
} }
@ -678,10 +658,7 @@ impl<P: Pixel> From<mint::Vector2<P>> for PhysicalSize<P> {
#[cfg(feature = "mint")] #[cfg(feature = "mint")]
impl<P: Pixel> From<PhysicalSize<P>> for mint::Vector2<P> { impl<P: Pixel> From<PhysicalSize<P>> for mint::Vector2<P> {
fn from(s: PhysicalSize<P>) -> Self { fn from(s: PhysicalSize<P>) -> Self {
mint::Vector2 { mint::Vector2 { x: s.width, y: s.height }
x: s.width,
y: s.height,
}
} }
} }
@ -846,12 +823,7 @@ mod tests {
macro_rules! assert_approx_eq { macro_rules! assert_approx_eq {
($a:expr, $b:expr $(,)?) => { ($a:expr, $b:expr $(,)?) => {
assert!( assert!(($a - $b).abs() < 0.001, "{} is not approximately equal to {}", $a, $b);
($a - $b).abs() < 0.001,
"{} is not approximately equal to {}",
$a,
$b
);
}; };
} }
@ -970,14 +942,8 @@ mod tests {
assert_eq!(log_unit.to_physical::<u32>(1.0), PhysicalUnit::new(1)); assert_eq!(log_unit.to_physical::<u32>(1.0), PhysicalUnit::new(1));
assert_eq!(log_unit.to_physical::<u32>(2.0), PhysicalUnit::new(2)); assert_eq!(log_unit.to_physical::<u32>(2.0), PhysicalUnit::new(2));
assert_eq!(log_unit.cast::<u32>(), LogicalUnit::new(1)); assert_eq!(log_unit.cast::<u32>(), LogicalUnit::new(1));
assert_eq!( assert_eq!(log_unit, LogicalUnit::from_physical(PhysicalUnit::new(1.0), 1.0));
log_unit, assert_eq!(log_unit, LogicalUnit::from_physical(PhysicalUnit::new(2.0), 2.0));
LogicalUnit::from_physical(PhysicalUnit::new(1.0), 1.0)
);
assert_eq!(
log_unit,
LogicalUnit::from_physical(PhysicalUnit::new(2.0), 2.0)
);
assert_eq!(LogicalUnit::from(2.0), LogicalUnit::new(2.0)); assert_eq!(LogicalUnit::from(2.0), LogicalUnit::new(2.0));
let x: f64 = log_unit.into(); let x: f64 = log_unit.into();
@ -986,14 +952,8 @@ mod tests {
#[test] #[test]
fn test_physical_unit() { fn test_physical_unit() {
assert_eq!( assert_eq!(PhysicalUnit::from_logical(LogicalUnit::new(1.0), 1.0), PhysicalUnit::new(1));
PhysicalUnit::from_logical(LogicalUnit::new(1.0), 1.0), assert_eq!(PhysicalUnit::from_logical(LogicalUnit::new(2.0), 0.5), PhysicalUnit::new(1));
PhysicalUnit::new(1)
);
assert_eq!(
PhysicalUnit::from_logical(LogicalUnit::new(2.0), 0.5),
PhysicalUnit::new(1)
);
assert_eq!(PhysicalUnit::from(2.0), PhysicalUnit::new(2.0,)); assert_eq!(PhysicalUnit::from(2.0), PhysicalUnit::new(2.0,));
assert_eq!(PhysicalUnit::from(2.0), PhysicalUnit::new(2.0)); assert_eq!(PhysicalUnit::from(2.0), PhysicalUnit::new(2.0));
@ -1007,22 +967,10 @@ mod tests {
assert_eq!(log_pos.to_physical::<u32>(1.0), PhysicalPosition::new(1, 2)); assert_eq!(log_pos.to_physical::<u32>(1.0), PhysicalPosition::new(1, 2));
assert_eq!(log_pos.to_physical::<u32>(2.0), PhysicalPosition::new(2, 4)); assert_eq!(log_pos.to_physical::<u32>(2.0), PhysicalPosition::new(2, 4));
assert_eq!(log_pos.cast::<u32>(), LogicalPosition::new(1, 2)); assert_eq!(log_pos.cast::<u32>(), LogicalPosition::new(1, 2));
assert_eq!( assert_eq!(log_pos, LogicalPosition::from_physical(PhysicalPosition::new(1.0, 2.0), 1.0));
log_pos, assert_eq!(log_pos, LogicalPosition::from_physical(PhysicalPosition::new(2.0, 4.0), 2.0));
LogicalPosition::from_physical(PhysicalPosition::new(1.0, 2.0), 1.0) assert_eq!(LogicalPosition::from((2.0, 2.0)), LogicalPosition::new(2.0, 2.0));
); assert_eq!(LogicalPosition::from([2.0, 3.0]), LogicalPosition::new(2.0, 3.0));
assert_eq!(
log_pos,
LogicalPosition::from_physical(PhysicalPosition::new(2.0, 4.0), 2.0)
);
assert_eq!(
LogicalPosition::from((2.0, 2.0)),
LogicalPosition::new(2.0, 2.0)
);
assert_eq!(
LogicalPosition::from([2.0, 3.0]),
LogicalPosition::new(2.0, 3.0)
);
let x: (f64, f64) = log_pos.into(); let x: (f64, f64) = log_pos.into();
assert_eq!(x, (1.0, 2.0)); assert_eq!(x, (1.0, 2.0));
@ -1040,14 +988,8 @@ mod tests {
PhysicalPosition::from_logical(LogicalPosition::new(2.0, 4.0), 0.5), PhysicalPosition::from_logical(LogicalPosition::new(2.0, 4.0), 0.5),
PhysicalPosition::new(1, 2) PhysicalPosition::new(1, 2)
); );
assert_eq!( assert_eq!(PhysicalPosition::from((2.0, 2.0)), PhysicalPosition::new(2.0, 2.0));
PhysicalPosition::from((2.0, 2.0)), assert_eq!(PhysicalPosition::from([2.0, 3.0]), PhysicalPosition::new(2.0, 3.0));
PhysicalPosition::new(2.0, 2.0)
);
assert_eq!(
PhysicalPosition::from([2.0, 3.0]),
PhysicalPosition::new(2.0, 3.0)
);
let x: (f64, f64) = PhysicalPosition::new(1, 2).into(); let x: (f64, f64) = PhysicalPosition::new(1, 2).into();
assert_eq!(x, (1.0, 2.0)); assert_eq!(x, (1.0, 2.0));
@ -1061,14 +1003,8 @@ mod tests {
assert_eq!(log_size.to_physical::<u32>(1.0), PhysicalSize::new(1, 2)); assert_eq!(log_size.to_physical::<u32>(1.0), PhysicalSize::new(1, 2));
assert_eq!(log_size.to_physical::<u32>(2.0), PhysicalSize::new(2, 4)); assert_eq!(log_size.to_physical::<u32>(2.0), PhysicalSize::new(2, 4));
assert_eq!(log_size.cast::<u32>(), LogicalSize::new(1, 2)); assert_eq!(log_size.cast::<u32>(), LogicalSize::new(1, 2));
assert_eq!( assert_eq!(log_size, LogicalSize::from_physical(PhysicalSize::new(1.0, 2.0), 1.0));
log_size, assert_eq!(log_size, LogicalSize::from_physical(PhysicalSize::new(2.0, 4.0), 2.0));
LogicalSize::from_physical(PhysicalSize::new(1.0, 2.0), 1.0)
);
assert_eq!(
log_size,
LogicalSize::from_physical(PhysicalSize::new(2.0, 4.0), 2.0)
);
assert_eq!(LogicalSize::from((2.0, 2.0)), LogicalSize::new(2.0, 2.0)); assert_eq!(LogicalSize::from((2.0, 2.0)), LogicalSize::new(2.0, 2.0));
assert_eq!(LogicalSize::from([2.0, 3.0]), LogicalSize::new(2.0, 3.0)); assert_eq!(LogicalSize::from([2.0, 3.0]), LogicalSize::new(2.0, 3.0));
@ -1099,10 +1035,7 @@ mod tests {
#[test] #[test]
fn test_size() { fn test_size() {
assert_eq!( assert_eq!(Size::new(PhysicalSize::new(1, 2)), Size::Physical(PhysicalSize::new(1, 2)));
Size::new(PhysicalSize::new(1, 2)),
Size::Physical(PhysicalSize::new(1, 2))
);
assert_eq!( assert_eq!(
Size::new(LogicalSize::new(1.0, 2.0)), Size::new(LogicalSize::new(1.0, 2.0)),
Size::Logical(LogicalSize::new(1.0, 2.0)) Size::Logical(LogicalSize::new(1.0, 2.0))

View file

@ -1,7 +1,4 @@
#[cfg(all( #[cfg(all(feature = "rwh_06", any(x11_platform, macos_platform, windows_platform)))]
feature = "rwh_06",
any(x11_platform, macos_platform, windows_platform)
))]
#[allow(deprecated)] #[allow(deprecated)]
fn main() -> Result<(), impl std::error::Error> { fn main() -> Result<(), impl std::error::Error> {
use std::collections::HashMap; use std::collections::HashMap;
@ -46,25 +43,22 @@ fn main() -> Result<(), impl std::error::Error> {
println!("Parent window id: {parent_window_id:?})"); println!("Parent window id: {parent_window_id:?})");
windows.insert(window.id(), window); windows.insert(window.id(), window);
} },
Event::WindowEvent { window_id, event } => match event { Event::WindowEvent { window_id, event } => match event {
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
windows.clear(); windows.clear();
event_loop.exit(); event_loop.exit();
} },
WindowEvent::CursorEntered { device_id: _ } => { WindowEvent::CursorEntered { device_id: _ } => {
// On x11, println when the cursor entered in a window even if the child window is created // On x11, println when the cursor entered in a window even if the child window
// by some key inputs. // is created by some key inputs.
// the child windows are always placed at (0, 0) with size (200, 200) in the parent window, // the child windows are always placed at (0, 0) with size (200, 200) in the
// so we also can see this log when we move the cursor around (200, 200) in parent window. // parent window, so we also can see this log when we move
// the cursor around (200, 200) in parent window.
println!("cursor entered in the window {window_id:?}"); println!("cursor entered in the window {window_id:?}");
} },
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
event: event: KeyEvent { state: ElementState::Pressed, .. },
KeyEvent {
state: ElementState::Pressed,
..
},
.. ..
} => { } => {
let parent_window = windows.get(&parent_window_id.unwrap()).unwrap(); let parent_window = windows.get(&parent_window_id.unwrap()).unwrap();
@ -72,12 +66,12 @@ fn main() -> Result<(), impl std::error::Error> {
let child_id = child_window.id(); let child_id = child_window.id();
println!("Child window created with id: {child_id:?}"); println!("Child window created with id: {child_id:?}");
windows.insert(child_id, child_window); windows.insert(child_id, child_window);
} },
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
if let Some(window) = windows.get(&window_id) { if let Some(window) = windows.get(&window_id) {
fill::fill_window(window); fill::fill_window(window);
} }
} },
_ => (), _ => (),
}, },
_ => (), _ => (),
@ -85,10 +79,10 @@ fn main() -> Result<(), impl std::error::Error> {
}) })
} }
#[cfg(all( #[cfg(all(feature = "rwh_06", not(any(x11_platform, macos_platform, windows_platform))))]
feature = "rwh_06",
not(any(x11_platform, macos_platform, windows_platform))
))]
fn main() { fn main() {
panic!("This example is supported only on x11, macOS, and Windows, with the `rwh_06` feature enabled."); panic!(
"This example is supported only on x11, macOS, and Windows, with the `rwh_06` feature \
enabled."
);
} }

View file

@ -85,14 +85,9 @@ impl ApplicationHandler for ControlFlowDemo {
match event { match event {
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
self.close_requested = true; self.close_requested = true;
} },
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
event: event: KeyEvent { logical_key: key, state: ElementState::Pressed, .. },
KeyEvent {
logical_key: key,
state: ElementState::Pressed,
..
},
.. ..
} => match key.as_ref() { } => match key.as_ref() {
// WARNING: Consider using `key_without_modifiers()` if available on your platform. // WARNING: Consider using `key_without_modifiers()` if available on your platform.
@ -100,29 +95,29 @@ impl ApplicationHandler for ControlFlowDemo {
Key::Character("1") => { Key::Character("1") => {
self.mode = Mode::Wait; self.mode = Mode::Wait;
warn!("mode: {:?}", self.mode); warn!("mode: {:?}", self.mode);
} },
Key::Character("2") => { Key::Character("2") => {
self.mode = Mode::WaitUntil; self.mode = Mode::WaitUntil;
warn!("mode: {:?}", self.mode); warn!("mode: {:?}", self.mode);
} },
Key::Character("3") => { Key::Character("3") => {
self.mode = Mode::Poll; self.mode = Mode::Poll;
warn!("mode: {:?}", self.mode); warn!("mode: {:?}", self.mode);
} },
Key::Character("r") => { Key::Character("r") => {
self.request_redraw = !self.request_redraw; self.request_redraw = !self.request_redraw;
warn!("request_redraw: {}", self.request_redraw); warn!("request_redraw: {}", self.request_redraw);
} },
Key::Named(NamedKey::Escape) => { Key::Named(NamedKey::Escape) => {
self.close_requested = true; self.close_requested = true;
} },
_ => (), _ => (),
}, },
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
let window = self.window.as_ref().unwrap(); let window = self.window.as_ref().unwrap();
window.pre_present_notify(); window.pre_present_notify();
fill::fill_window(window); fill::fill_window(window);
} },
_ => (), _ => (),
} }
} }
@ -139,11 +134,11 @@ impl ApplicationHandler for ControlFlowDemo {
event_loop event_loop
.set_control_flow(ControlFlow::WaitUntil(time::Instant::now() + WAIT_TIME)); .set_control_flow(ControlFlow::WaitUntil(time::Instant::now() + WAIT_TIME));
} }
} },
Mode::Poll => { Mode::Poll => {
thread::sleep(POLL_SLEEP_TIME); thread::sleep(POLL_SLEEP_TIME);
event_loop.set_control_flow(ControlFlow::Poll); event_loop.set_control_flow(ControlFlow::Poll);
} },
}; };
if self.close_requested { if self.close_requested {

View file

@ -1,15 +1,11 @@
#![allow(clippy::single_match)] #![allow(clippy::single_match)]
// Limit this example to only compatible platforms. // Limit this example to only compatible platforms.
#[cfg(any( #[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform, android_platform,))]
windows_platform,
macos_platform,
x11_platform,
wayland_platform,
android_platform,
))]
fn main() -> std::process::ExitCode { fn main() -> std::process::ExitCode {
use std::{process::ExitCode, thread::sleep, time::Duration}; use std::process::ExitCode;
use std::thread::sleep;
use std::time::Duration;
use winit::application::ApplicationHandler; use winit::application::ApplicationHandler;
use winit::event::WindowEvent; use winit::event::WindowEvent;
@ -49,7 +45,7 @@ fn main() -> std::process::ExitCode {
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
fill::fill_window(window); fill::fill_window(window);
window.request_redraw(); window.request_redraw();
} },
_ => (), _ => (),
} }
} }

View file

@ -60,13 +60,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
match event { match event {
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
println!("--------------------------------------------------------- Window {} CloseRequested", self.idx); println!(
"--------------------------------------------------------- Window {} \
CloseRequested",
self.idx
);
fill::cleanup_window(window); fill::cleanup_window(window);
self.window = None; self.window = None;
} },
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
fill::fill_window(window); fill::fill_window(window);
} },
_ => (), _ => (),
} }
} }
@ -76,10 +80,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut event_loop = EventLoop::new().unwrap(); let mut event_loop = EventLoop::new().unwrap();
let mut app = App { let mut app = App { idx: 1, ..Default::default() };
idx: 1,
..Default::default()
};
event_loop.run_app_on_demand(&mut app)?; event_loop.run_app_on_demand(&mut app)?;
println!("--------------------------------------------------------- Finished first loop"); println!("--------------------------------------------------------- Finished first loop");

View file

@ -20,8 +20,7 @@ mod platform {
use std::num::NonZeroU32; use std::num::NonZeroU32;
use softbuffer::{Context, Surface}; use softbuffer::{Context, Surface};
use winit::window::Window; use winit::window::{Window, WindowId};
use winit::window::WindowId;
thread_local! { thread_local! {
// NOTE: You should never do things like that, create context and drop it before // NOTE: You should never do things like that, create context and drop it before
@ -80,24 +79,17 @@ mod platform {
// Either get the last context used or create a new one. // Either get the last context used or create a new one.
let mut gc = gc.borrow_mut(); let mut gc = gc.borrow_mut();
let surface = gc let surface =
.get_or_insert_with(|| GraphicsContext::new(window)) gc.get_or_insert_with(|| GraphicsContext::new(window)).create_surface(window);
.create_surface(window);
// Fill a buffer with a solid color. // Fill a buffer with a solid color.
const DARK_GRAY: u32 = 0xFF181818; const DARK_GRAY: u32 = 0xff181818;
surface surface.resize(width, height).expect("Failed to resize the softbuffer surface");
.resize(width, height)
.expect("Failed to resize the softbuffer surface");
let mut buffer = surface let mut buffer = surface.buffer_mut().expect("Failed to get the softbuffer buffer");
.buffer_mut()
.expect("Failed to get the softbuffer buffer");
buffer.fill(DARK_GRAY); buffer.fill(DARK_GRAY);
buffer buffer.present().expect("Failed to present the softbuffer buffer");
.present()
.expect("Failed to present the softbuffer buffer");
}) })
} }

View file

@ -4,9 +4,7 @@ pub fn init() {
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_env_filter( .with_env_filter(
EnvFilter::builder() EnvFilter::builder().with_default_directive(LevelFilter::INFO.into()).from_env_lossy(),
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
) )
.init(); .init();
} }

View file

@ -2,12 +2,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use std::mem;
#[cfg(not(any(android_platform, ios_platform)))] #[cfg(not(any(android_platform, ios_platform)))]
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::sync::Arc; use std::sync::Arc;
use std::{fmt, mem};
use ::tracing::{error, info}; use ::tracing::{error, info};
use cursor_icon::CursorIcon; use cursor_icon::CursorIcon;
@ -18,15 +17,13 @@ use softbuffer::{Context, Surface};
use winit::application::ApplicationHandler; use winit::application::ApplicationHandler;
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize}; use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
use winit::event::{DeviceEvent, DeviceId, Ime, WindowEvent}; use winit::event::{DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, WindowEvent};
use winit::event::{MouseButton, MouseScrollDelta};
use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::keyboard::{Key, ModifiersState}; use winit::keyboard::{Key, ModifiersState};
use winit::window::{ use winit::window::{
Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, Icon, ResizeDirection, Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, Icon, ResizeDirection,
Theme, Theme, Window, WindowId,
}; };
use winit::window::{Window, WindowId};
#[cfg(macos_platform)] #[cfg(macos_platform)]
use winit::platform::macos::{OptionAsAlt, WindowAttributesExtMacOS, WindowExtMacOS}; use winit::platform::macos::{OptionAsAlt, WindowAttributesExtMacOS, WindowExtMacOS};
@ -100,10 +97,11 @@ impl Application {
.unwrap(), .unwrap(),
); );
// You'll have to choose an icon size at your own discretion. On X11, the desired size varies // You'll have to choose an icon size at your own discretion. On X11, the desired size
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px, // varies by WM, and on Windows, you still have to account for screen scaling. Here
// since it seems to work well enough in most cases. Be careful about going too high, or // we use 32px, since it seems to work well enough in most cases. Be careful about
// you'll be bitten by the low-quality downscaling built into the WM. // going too high, or you'll be bitten by the low-quality downscaling built into the
// WM.
let icon = load_icon(include_bytes!("data/icon.png")); let icon = load_icon(include_bytes!("data/icon.png"));
info!("Loading cursor assets"); info!("Loading cursor assets");
@ -177,7 +175,7 @@ impl Application {
match action { match action {
Action::CloseWindow => { Action::CloseWindow => {
let _ = self.windows.remove(&window_id); let _ = self.windows.remove(&window_id);
} },
Action::CreateNewWindow => { Action::CreateNewWindow => {
#[cfg(any(x11_platform, wayland_platform))] #[cfg(any(x11_platform, wayland_platform))]
if let Err(err) = window.window.request_activation_token() { if let Err(err) = window.window.request_activation_token() {
@ -189,7 +187,7 @@ impl Application {
if let Err(err) = self.create_window(event_loop, None) { if let Err(err) = self.create_window(event_loop, None) {
error!("Error creating new window: {err}"); error!("Error creating new window: {err}");
} }
} },
Action::ToggleResizeIncrements => window.toggle_resize_increments(), Action::ToggleResizeIncrements => window.toggle_resize_increments(),
Action::ToggleCursorVisibility => window.toggle_cursor_visibility(), Action::ToggleCursorVisibility => window.toggle_cursor_visibility(),
Action::ToggleResizable => window.toggle_resizable(), Action::ToggleResizable => window.toggle_resizable(),
@ -205,7 +203,7 @@ impl Application {
#[cfg(web_platform)] #[cfg(web_platform)]
Action::AnimationCustomCursor => { Action::AnimationCustomCursor => {
window.animation_custom_cursor(event_loop, &self.custom_cursors) window.animation_custom_cursor(event_loop, &self.custom_cursors)
} },
Action::CycleCursorGrab => window.cycle_cursor_grab(), Action::CycleCursorGrab => window.cycle_cursor_grab(),
Action::DragWindow => window.drag_window(), Action::DragWindow => window.drag_window(),
Action::DragResizeWindow => window.drag_resize_window(), Action::DragResizeWindow => window.drag_resize_window(),
@ -219,7 +217,7 @@ impl Application {
if let Err(err) = self.create_window(event_loop, Some(tab_id)) { if let Err(err) = self.create_window(event_loop, Some(tab_id)) {
error!("Error creating new window: {err}"); error!("Error creating new window: {err}");
} }
} },
Action::RequestResize => window.swap_dimensions(), Action::RequestResize => window.swap_dimensions(),
} }
} }
@ -260,31 +258,23 @@ impl Application {
let PhysicalSize { width, height } = mode.size(); let PhysicalSize { width, height } = mode.size();
let bits = mode.bit_depth(); let bits = mode.bit_depth();
let m_hz = mode.refresh_rate_millihertz(); let m_hz = mode.refresh_rate_millihertz();
info!( info!(" {width}x{height}x{bits} @ {}.{} Hz", m_hz / 1000, m_hz % 1000);
" {width}x{height}x{bits} @ {}.{} Hz",
m_hz / 1000,
m_hz % 1000
);
} }
} }
} }
/// Process the key binding. /// Process the key binding.
fn process_key_binding(key: &str, mods: &ModifiersState) -> Option<Action> { fn process_key_binding(key: &str, mods: &ModifiersState) -> Option<Action> {
KEY_BINDINGS.iter().find_map(|binding| { KEY_BINDINGS
binding .iter()
.is_triggered_by(&key, mods) .find_map(|binding| binding.is_triggered_by(&key, mods).then_some(binding.action))
.then_some(binding.action)
})
} }
/// Process mouse binding. /// Process mouse binding.
fn process_mouse_binding(button: MouseButton, mods: &ModifiersState) -> Option<Action> { fn process_mouse_binding(button: MouseButton, mods: &ModifiersState) -> Option<Action> {
MOUSE_BINDINGS.iter().find_map(|binding| { MOUSE_BINDINGS
binding .iter()
.is_triggered_by(&button, mods) .find_map(|binding| binding.is_triggered_by(&button, mods).then_some(binding.action))
.then_some(binding.action)
})
} }
fn print_help(&self) { fn print_help(&self) {
@ -330,50 +320,46 @@ impl ApplicationHandler<UserEvent> for Application {
match event { match event {
WindowEvent::Resized(size) => { WindowEvent::Resized(size) => {
window.resize(size); window.resize(size);
} },
WindowEvent::Focused(focused) => { WindowEvent::Focused(focused) => {
if focused { if focused {
info!("Window={window_id:?} focused"); info!("Window={window_id:?} focused");
} else { } else {
info!("Window={window_id:?} unfocused"); info!("Window={window_id:?} unfocused");
} }
} },
WindowEvent::ScaleFactorChanged { scale_factor, .. } => { WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
info!("Window={window_id:?} changed scale to {scale_factor}"); info!("Window={window_id:?} changed scale to {scale_factor}");
} },
WindowEvent::ThemeChanged(theme) => { WindowEvent::ThemeChanged(theme) => {
info!("Theme changed to {theme:?}"); info!("Theme changed to {theme:?}");
window.set_theme(theme); window.set_theme(theme);
} },
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
if let Err(err) = window.draw() { if let Err(err) = window.draw() {
error!("Error drawing window: {err}"); error!("Error drawing window: {err}");
} }
} },
WindowEvent::Occluded(occluded) => { WindowEvent::Occluded(occluded) => {
window.set_occluded(occluded); window.set_occluded(occluded);
} },
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
info!("Closing Window={window_id:?}"); info!("Closing Window={window_id:?}");
self.windows.remove(&window_id); self.windows.remove(&window_id);
} },
WindowEvent::ModifiersChanged(modifiers) => { WindowEvent::ModifiersChanged(modifiers) => {
window.modifiers = modifiers.state(); window.modifiers = modifiers.state();
info!("Modifiers changed to {:?}", window.modifiers); info!("Modifiers changed to {:?}", window.modifiers);
} },
WindowEvent::MouseWheel { delta, .. } => match delta { WindowEvent::MouseWheel { delta, .. } => match delta {
MouseScrollDelta::LineDelta(x, y) => { MouseScrollDelta::LineDelta(x, y) => {
info!("Mouse wheel Line Delta: ({x},{y})"); info!("Mouse wheel Line Delta: ({x},{y})");
} },
MouseScrollDelta::PixelDelta(px) => { MouseScrollDelta::PixelDelta(px) => {
info!("Mouse wheel Pixel Delta: ({},{})", px.x, px.y); info!("Mouse wheel Pixel Delta: ({},{})", px.x, px.y);
} },
}, },
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput { event, is_synthetic: false, .. } => {
event,
is_synthetic: false,
..
} => {
let mods = window.modifiers; let mods = window.modifiers;
// Dispatch actions only on press. // Dispatch actions only on press.
@ -388,25 +374,23 @@ impl ApplicationHandler<UserEvent> for Application {
self.handle_action(event_loop, window_id, action); self.handle_action(event_loop, window_id, action);
} }
} }
} },
WindowEvent::MouseInput { button, state, .. } => { WindowEvent::MouseInput { button, state, .. } => {
let mods = window.modifiers; let mods = window.modifiers;
if let Some(action) = state if let Some(action) =
.is_pressed() state.is_pressed().then(|| Self::process_mouse_binding(button, &mods)).flatten()
.then(|| Self::process_mouse_binding(button, &mods))
.flatten()
{ {
self.handle_action(event_loop, window_id, action); self.handle_action(event_loop, window_id, action);
} }
} },
WindowEvent::CursorLeft { .. } => { WindowEvent::CursorLeft { .. } => {
info!("Cursor left Window={window_id:?}"); info!("Cursor left Window={window_id:?}");
window.cursor_left(); window.cursor_left();
} },
WindowEvent::CursorMoved { position, .. } => { WindowEvent::CursorMoved { position, .. } => {
info!("Moved cursor to {position:?}"); info!("Moved cursor to {position:?}");
window.cursor_moved(position); window.cursor_moved(position);
} },
WindowEvent::ActivationTokenDone { token: _token, .. } => { WindowEvent::ActivationTokenDone { token: _token, .. } => {
#[cfg(any(x11_platform, wayland_platform))] #[cfg(any(x11_platform, wayland_platform))]
{ {
@ -415,15 +399,15 @@ impl ApplicationHandler<UserEvent> for Application {
error!("Error creating new window: {err}"); error!("Error creating new window: {err}");
} }
} }
} },
WindowEvent::Ime(event) => match event { WindowEvent::Ime(event) => match event {
Ime::Enabled => info!("IME enabled for Window={window_id:?}"), Ime::Enabled => info!("IME enabled for Window={window_id:?}"),
Ime::Preedit(text, caret_pos) => { Ime::Preedit(text, caret_pos) => {
info!("Preedit: {}, with caret at {:?}", text, caret_pos); info!("Preedit: {}, with caret at {:?}", text, caret_pos);
} },
Ime::Commit(text) => { Ime::Commit(text) => {
info!("Committed: {}", text); info!("Committed: {}", text);
} },
Ime::Disabled => info!("IME disabled for Window={window_id:?}"), Ime::Disabled => info!("IME disabled for Window={window_id:?}"),
}, },
WindowEvent::PinchGesture { delta, .. } => { WindowEvent::PinchGesture { delta, .. } => {
@ -434,7 +418,7 @@ impl ApplicationHandler<UserEvent> for Application {
} else { } else {
info!("Zoomed out {delta:.5} (now: {zoom:.5})"); info!("Zoomed out {delta:.5} (now: {zoom:.5})");
} }
} },
WindowEvent::RotationGesture { delta, .. } => { WindowEvent::RotationGesture { delta, .. } => {
window.rotated += delta; window.rotated += delta;
let rotated = window.rotated; let rotated = window.rotated;
@ -443,10 +427,10 @@ impl ApplicationHandler<UserEvent> for Application {
} else { } else {
info!("Rotated clockwise {delta:.5} (now: {rotated:.5})"); info!("Rotated clockwise {delta:.5} (now: {rotated:.5})");
} }
} },
WindowEvent::DoubleTapGesture { .. } => { WindowEvent::DoubleTapGesture { .. } => {
info!("Smart zoom"); info!("Smart zoom");
} },
WindowEvent::TouchpadPressure { .. } WindowEvent::TouchpadPressure { .. }
| WindowEvent::HoveredFileCancelled | WindowEvent::HoveredFileCancelled
| WindowEvent::KeyboardInput { .. } | WindowEvent::KeyboardInput { .. }
@ -474,8 +458,7 @@ impl ApplicationHandler<UserEvent> for Application {
self.dump_monitors(event_loop); self.dump_monitors(event_loop);
// Create initial window. // Create initial window.
self.create_window(event_loop, None) self.create_window(event_loop, None).expect("failed to create initial window");
.expect("failed to create initial window");
self.print_help(); self.print_help();
} }
@ -575,8 +558,7 @@ impl WindowState {
self.ime = !self.ime; self.ime = !self.ime;
self.window.set_ime_allowed(self.ime); self.window.set_ime_allowed(self.ime);
if let Some(position) = self.ime.then_some(self.cursor_position).flatten() { if let Some(position) = self.ime.then_some(self.cursor_position).flatten() {
self.window self.window.set_ime_cursor_area(position, PhysicalSize::new(20, 20));
.set_ime_cursor_area(position, PhysicalSize::new(20, 20));
} }
} }
@ -587,8 +569,7 @@ impl WindowState {
pub fn cursor_moved(&mut self, position: PhysicalPosition<f64>) { pub fn cursor_moved(&mut self, position: PhysicalPosition<f64>) {
self.cursor_position = Some(position); self.cursor_position = Some(position);
if self.ime { if self.ime {
self.window self.window.set_ime_cursor_area(position, PhysicalSize::new(20, 20));
.set_ime_cursor_area(position, PhysicalSize::new(20, 20));
} }
} }
@ -689,8 +670,7 @@ impl WindowState {
fn next_cursor(&mut self) { fn next_cursor(&mut self) {
self.named_idx = (self.named_idx + 1) % CURSORS.len(); self.named_idx = (self.named_idx + 1) % CURSORS.len();
info!("Setting cursor to \"{:?}\"", CURSORS[self.named_idx]); info!("Setting cursor to \"{:?}\"", CURSORS[self.named_idx]);
self.window self.window.set_cursor(Cursor::Icon(CURSORS[self.named_idx]));
.set_cursor(Cursor::Icon(CURSORS[self.named_idx]));
} }
/// Pick the next custom cursor. /// Pick the next custom cursor.
@ -739,9 +719,7 @@ impl WindowState {
(Some(width), Some(height)) => (width, height), (Some(width), Some(height)) => (width, height),
_ => return, _ => return,
}; };
self.surface self.surface.resize(width, height).expect("failed to resize inner buffer");
.resize(width, height)
.expect("failed to resize inner buffer");
} }
self.window.request_redraw(); self.window.request_redraw();
} }
@ -775,7 +753,7 @@ impl WindowState {
None => { None => {
info!("Drag-resize requires cursor to be inside the window"); info!("Drag-resize requires cursor to be inside the window");
return; return;
} },
}; };
let win_size = self.window.inner_size(); let win_size = self.window.inner_size();
@ -834,8 +812,8 @@ impl WindowState {
return Ok(()); return Ok(());
} }
const WHITE: u32 = 0xFFFFFFFF; const WHITE: u32 = 0xffffffff;
const DARK_GRAY: u32 = 0xFF181818; const DARK_GRAY: u32 = 0xff181818;
let color = match self.theme { let color = match self.theme {
Theme::Light => WHITE, Theme::Light => WHITE,
@ -864,11 +842,7 @@ struct Binding<T: Eq> {
impl<T: Eq> Binding<T> { impl<T: Eq> Binding<T> {
const fn new(trigger: T, mods: ModifiersState, action: Action) -> Self { const fn new(trigger: T, mods: ModifiersState, action: Action) -> Self {
Self { Self { trigger, mods, action }
trigger,
mods,
action,
}
} }
fn is_triggered_by(&self, trigger: &T, mods: &ModifiersState) -> bool { fn is_triggered_by(&self, trigger: &T, mods: &ModifiersState) -> bool {
@ -962,10 +936,7 @@ fn url_custom_cursor() -> CustomCursorSource {
static URL_COUNTER: AtomicU64 = AtomicU64::new(0); static URL_COUNTER: AtomicU64 = AtomicU64::new(0);
CustomCursor::from_url( CustomCursor::from_url(
format!( format!("https://picsum.photos/128?random={}", URL_COUNTER.fetch_add(1, Ordering::Relaxed)),
"https://picsum.photos/128?random={}",
URL_COUNTER.fetch_add(1, Ordering::Relaxed)
),
64, 64,
64, 64,
) )
@ -1086,19 +1057,7 @@ const KEY_BINDINGS: &[Binding<&'static str>] = &[
]; ];
const MOUSE_BINDINGS: &[Binding<MouseButton>] = &[ const MOUSE_BINDINGS: &[Binding<MouseButton>] = &[
Binding::new( Binding::new(MouseButton::Left, ModifiersState::ALT, Action::DragResizeWindow),
MouseButton::Left, Binding::new(MouseButton::Left, ModifiersState::CONTROL, Action::DragWindow),
ModifiersState::ALT, Binding::new(MouseButton::Right, ModifiersState::CONTROL, Action::ShowWindowMenu),
Action::DragResizeWindow,
),
Binding::new(
MouseButton::Left,
ModifiersState::CONTROL,
Action::DragWindow,
),
Binding::new(
MouseButton::Right,
ModifiersState::CONTROL,
Action::ShowWindowMenu,
),
]; ];

View file

@ -39,7 +39,7 @@ fn main() -> Result<(), Box<dyn Error>> {
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
window.pre_present_notify(); window.pre_present_notify();
fill::fill_window(window); fill::fill_window(window);
} },
_ => (), _ => (),
} }
} }
@ -58,10 +58,7 @@ fn main() -> Result<(), Box<dyn Error>> {
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
let event_loop = EventLoop::new()?; let event_loop = EventLoop::new()?;
let mut app = XEmbedDemo { let mut app = XEmbedDemo { parent_window_id, window: None };
parent_window_id,
window: None,
};
event_loop.run_app(&mut app).map_err(Into::into) event_loop.run_app(&mut app).map_err(Into::into)
} }

View file

@ -1,3 +1,19 @@
force_explicit_abi=true format_code_in_doc_comments = true
use_field_init_shorthand=true match_block_trailing_comma = true
# merge_imports=true condense_wildcard_suffixes = true
use_field_init_shorthand = true
normalize_doc_attributes = true
overflow_delimited_expr = true
imports_granularity = "Module"
use_small_heuristics = "Max"
format_macro_matchers = true
error_on_unformatted = true
format_macro_bodies = true
hex_literal_case = "Lower"
normalize_comments = true
# Some macros break with this.
reorder_impl_items = false
newline_style = "Unix"
format_strings = true
wrap_comments = true
comment_width = 100

View file

@ -20,8 +20,8 @@ pub trait ApplicationHandler<T: 'static = ()> {
/// ///
/// For consistency, all platforms emit a `Resumed` event even if they don't themselves have a /// For consistency, all platforms emit a `Resumed` event even if they don't themselves have a
/// formal suspend/resume lifecycle. For systems without a formal suspend/resume lifecycle /// formal suspend/resume lifecycle. For systems without a formal suspend/resume lifecycle
/// the `Resumed` event is always emitted after the [`NewEvents(StartCause::Init)`][StartCause::Init] /// the `Resumed` event is always emitted after the
/// event. /// [`NewEvents(StartCause::Init)`][StartCause::Init] event.
/// ///
/// # Portability /// # Portability
/// ///
@ -33,15 +33,16 @@ pub trait ApplicationHandler<T: 'static = ()> {
/// Considering that the implementation of [`Suspended`] and `Resumed` events may be internally /// Considering that the implementation of [`Suspended`] and `Resumed` events may be internally
/// driven by multiple platform-specific events, and that there may be subtle differences across /// driven by multiple platform-specific events, and that there may be subtle differences across
/// platforms with how these internal events are delivered, it's recommended that applications /// platforms with how these internal events are delivered, it's recommended that applications
/// be able to gracefully handle redundant (i.e. back-to-back) [`Suspended`] or `Resumed` events. /// be able to gracefully handle redundant (i.e. back-to-back) [`Suspended`] or `Resumed`
/// events.
/// ///
/// Also see [`Suspended`] notes. /// Also see [`Suspended`] notes.
/// ///
/// ## Android /// ## Android
/// ///
/// On Android, the `Resumed` event is sent when a new [`SurfaceView`] has been created. This is /// On Android, the `Resumed` event is sent when a new [`SurfaceView`] has been created. This is
/// expected to closely correlate with the [`onResume`] lifecycle event but there may technically /// expected to closely correlate with the [`onResume`] lifecycle event but there may
/// be a discrepancy. /// technically be a discrepancy.
/// ///
/// [`onResume`]: https://developer.android.com/reference/android/app/Activity#onResume() /// [`onResume`]: https://developer.android.com/reference/android/app/Activity#onResume()
/// ///
@ -109,7 +110,8 @@ pub trait ApplicationHandler<T: 'static = ()> {
/// Emitted when the event loop is about to block and wait for new events. /// Emitted when the event loop is about to block and wait for new events.
/// ///
/// Most applications shouldn't need to hook into this event since there is no real relationship /// Most applications shouldn't need to hook into this event since there is no real relationship
/// between how often the event loop needs to wake up and the dispatching of any specific events. /// between how often the event loop needs to wake up and the dispatching of any specific
/// events.
/// ///
/// High frequency event sources, such as input devices could potentially lead to lots of wake /// High frequency event sources, such as input devices could potentially lead to lots of wake
/// ups and also lots of corresponding `AboutToWait` events. /// ups and also lots of corresponding `AboutToWait` events.
@ -133,7 +135,8 @@ pub trait ApplicationHandler<T: 'static = ()> {
/// Considering that the implementation of `Suspended` and [`Resumed`] events may be internally /// Considering that the implementation of `Suspended` and [`Resumed`] events may be internally
/// driven by multiple platform-specific events, and that there may be subtle differences across /// driven by multiple platform-specific events, and that there may be subtle differences across
/// platforms with how these internal events are delivered, it's recommended that applications /// platforms with how these internal events are delivered, it's recommended that applications
/// be able to gracefully handle redundant (i.e. back-to-back) `Suspended` or [`Resumed`] events. /// be able to gracefully handle redundant (i.e. back-to-back) `Suspended` or [`Resumed`]
/// events.
/// ///
/// Also see [`Resumed`] notes. /// Also see [`Resumed`] notes.
/// ///
@ -150,7 +153,8 @@ pub trait ApplicationHandler<T: 'static = ()> {
/// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]). /// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]).
/// ///
/// After being `Suspended` on Android applications must drop all render surfaces before /// After being `Suspended` on Android applications must drop all render surfaces before
/// the event callback completes, which may be re-created when the application is next [`Resumed`]. /// the event callback completes, which may be re-created when the application is next
/// [`Resumed`].
/// ///
/// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView /// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
/// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle /// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
@ -197,17 +201,17 @@ pub trait ApplicationHandler<T: 'static = ()> {
/// ///
/// ### Android /// ### Android
/// ///
/// On Android, the `MemoryWarning` event is sent when [`onLowMemory`] was called. The application /// On Android, the `MemoryWarning` event is sent when [`onLowMemory`] was called. The
/// must [release memory] or risk being killed. /// application must [release memory] or risk being killed.
/// ///
/// [`onLowMemory`]: https://developer.android.com/reference/android/app/Application.html#onLowMemory() /// [`onLowMemory`]: https://developer.android.com/reference/android/app/Application.html#onLowMemory()
/// [release memory]: https://developer.android.com/topic/performance/memory#release /// [release memory]: https://developer.android.com/topic/performance/memory#release
/// ///
/// ### iOS /// ### iOS
/// ///
/// On iOS, the `MemoryWarning` event is emitted in response to an [`applicationDidReceiveMemoryWarning`] /// On iOS, the `MemoryWarning` event is emitted in response to an
/// callback. The application must free as much memory as possible or risk being terminated, see /// [`applicationDidReceiveMemoryWarning`] callback. The application must free as much
/// [how to respond to memory warnings]. /// memory as possible or risk being terminated, see [how to respond to memory warnings].
/// ///
/// [`applicationDidReceiveMemoryWarning`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623063-applicationdidreceivememorywarni /// [`applicationDidReceiveMemoryWarning`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623063-applicationdidreceivememorywarni
/// [how to respond to memory warnings]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle/responding_to_memory_warnings /// [how to respond to memory warnings]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle/responding_to_memory_warnings

View file

@ -2,7 +2,6 @@
//! //!
//! All notable changes to this project will be documented in this module, //! All notable changes to this project will be documented in this module,
//! along with migration instructions for larger changes. //! along with migration instructions for larger changes.
//!
// Put the current entry at the top of this page, for discoverability. // Put the current entry at the top of this page, for discoverability.
// See `.cargo/config.toml` for details about `unreleased_changelogs`. // See `.cargo/config.toml` for details about `unreleased_changelogs`.
#![cfg_attr(unreleased_changelogs, doc = include_str!("unreleased.md"))] #![cfg_attr(unreleased_changelogs, doc = include_str!("unreleased.md"))]

View file

@ -1,7 +1,7 @@
use core::fmt; use core::fmt;
use std::hash::Hasher; use std::error::Error;
use std::hash::{Hash, Hasher};
use std::sync::Arc; use std::sync::Arc;
use std::{error::Error, hash::Hash};
use cursor_icon::CursorIcon; use cursor_icon::CursorIcon;
@ -88,14 +88,9 @@ impl CustomCursor {
hotspot_x: u16, hotspot_x: u16,
hotspot_y: u16, hotspot_y: u16,
) -> Result<CustomCursorSource, BadImage> { ) -> Result<CustomCursorSource, BadImage> {
let _span = tracing::debug_span!( let _span =
"winit::Cursor::from_rgba", tracing::debug_span!("winit::Cursor::from_rgba", width, height, hotspot_x, hotspot_y)
width, .entered();
height,
hotspot_x,
hotspot_y
)
.entered();
Ok(CustomCursorSource { Ok(CustomCursorSource {
inner: PlatformCustomCursorSource::from_rgba( inner: PlatformCustomCursorSource::from_rgba(
@ -129,45 +124,36 @@ pub enum BadImage {
ByteCountNotDivisibleBy4 { byte_count: usize }, ByteCountNotDivisibleBy4 { byte_count: usize },
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`. /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
/// At least one of your arguments is incorrect. /// At least one of your arguments is incorrect.
DimensionsVsPixelCount { DimensionsVsPixelCount { width: u16, height: u16, width_x_height: u64, pixel_count: u64 },
width: u16,
height: u16,
width_x_height: u64,
pixel_count: u64,
},
/// Produced when the hotspot is outside the image bounds /// Produced when the hotspot is outside the image bounds
HotspotOutOfBounds { HotspotOutOfBounds { width: u16, height: u16, hotspot_x: u16, hotspot_y: u16 },
width: u16,
height: u16,
hotspot_x: u16,
hotspot_y: u16,
},
} }
impl fmt::Display for BadImage { impl fmt::Display for BadImage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
BadImage::TooLarge { width, height } => write!(f, BadImage::TooLarge { width, height } => write!(
"The specified dimensions ({width:?}x{height:?}) are too large. The maximum is {MAX_CURSOR_SIZE:?}x{MAX_CURSOR_SIZE:?}.", f,
"The specified dimensions ({width:?}x{height:?}) are too large. The maximum is \
{MAX_CURSOR_SIZE:?}x{MAX_CURSOR_SIZE:?}.",
), ),
BadImage::ByteCountNotDivisibleBy4 { byte_count } => write!(f, BadImage::ByteCountNotDivisibleBy4 { byte_count } => write!(
"The length of the `rgba` argument ({byte_count:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.", f,
"The length of the `rgba` argument ({byte_count:?}) isn't divisible by 4, making \
it impossible to interpret as 32bpp RGBA pixels.",
), ),
BadImage::DimensionsVsPixelCount { BadImage::DimensionsVsPixelCount { width, height, width_x_height, pixel_count } => {
width, write!(
height, f,
width_x_height, "The specified dimensions ({width:?}x{height:?}) don't match the number of \
pixel_count, pixels supplied by the `rgba` argument ({pixel_count:?}). For those \
} => write!(f, dimensions, the expected pixel count is {width_x_height:?}.",
"The specified dimensions ({width:?}x{height:?}) don't match the number of pixels supplied by the `rgba` argument ({pixel_count:?}). For those dimensions, the expected pixel count is {width_x_height:?}.", )
), },
BadImage::HotspotOutOfBounds { BadImage::HotspotOutOfBounds { width, height, hotspot_x, hotspot_y } => write!(
width, f,
height, "The specified hotspot ({hotspot_x:?}, {hotspot_y:?}) is outside the image bounds \
hotspot_x, ({width:?}x{height:?}).",
hotspot_y,
} => write!(f,
"The specified hotspot ({hotspot_x:?}, {hotspot_y:?}) is outside the image bounds ({width:?}x{height:?}).",
), ),
} }
} }
@ -236,9 +222,7 @@ impl CursorImage {
} }
if rgba.len() % PIXEL_SIZE != 0 { if rgba.len() % PIXEL_SIZE != 0 {
return Err(BadImage::ByteCountNotDivisibleBy4 { return Err(BadImage::ByteCountNotDivisibleBy4 { byte_count: rgba.len() });
byte_count: rgba.len(),
});
} }
let pixel_count = (rgba.len() / PIXEL_SIZE) as u64; let pixel_count = (rgba.len() / PIXEL_SIZE) as u64;
@ -253,21 +237,10 @@ impl CursorImage {
} }
if hotspot_x >= width || hotspot_y >= height { if hotspot_x >= width || hotspot_y >= height {
return Err(BadImage::HotspotOutOfBounds { return Err(BadImage::HotspotOutOfBounds { width, height, hotspot_x, hotspot_y });
width,
height,
hotspot_x,
hotspot_y,
});
} }
Ok(CursorImage { Ok(CursorImage { rgba, width, height, hotspot_x, hotspot_y })
rgba,
width,
height,
hotspot_x,
hotspot_y,
})
} }
} }

View file

@ -71,10 +71,7 @@ macro_rules! os_error {
impl fmt::Display for OsError { impl fmt::Display for OsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.pad(&format!( f.pad(&format!("os error at {}:{}: {}", self.file, self.line, self.error))
"os error at {}:{}: {}",
self.file, self.line, self.error
))
} }
} }
@ -124,11 +121,7 @@ mod tests {
// Eat attributes for testing // Eat attributes for testing
#[test] #[test]
fn ensure_fmt_does_not_panic() { fn ensure_fmt_does_not_panic() {
let _ = format!( let _ = format!("{:?}, {}", NotSupportedError::new(), NotSupportedError::new().clone());
"{:?}, {}",
NotSupportedError::new(),
NotSupportedError::new().clone()
);
let _ = format!( let _ = format!(
"{:?}, {}", "{:?}, {}",
ExternalError::NotSupported(NotSupportedError::new()), ExternalError::NotSupported(NotSupportedError::new()),

View file

@ -1,7 +1,8 @@
//! The [`Event`] enum and assorted supporting types. //! The [`Event`] enum and assorted supporting types.
//! //!
//! These are sent to the closure given to [`EventLoop::run_app(...)`], where they get //! These are sent to the closure given to [`EventLoop::run_app(...)`], where they get
//! processed and used to modify the program state. For more details, see the root-level documentation. //! processed and used to modify the program state. For more details, see the root-level
//! documentation.
//! //!
//! Some of these events represent different "parts" of a traditional event-handling loop. You could //! Some of these events represent different "parts" of a traditional event-handling loop. You could
//! approximate the basic ordering loop of [`EventLoop::run_app(...)`] like this: //! approximate the basic ordering loop of [`EventLoop::run_app(...)`] like this:
@ -44,16 +45,14 @@ use smol_str::SmolStr;
#[cfg(web_platform)] #[cfg(web_platform)]
use web_time::Instant; use web_time::Instant;
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::error::ExternalError; use crate::error::ExternalError;
use crate::event_loop::AsyncRequestSerial;
use crate::keyboard::{self, ModifiersKeyState, ModifiersKeys, ModifiersState};
use crate::platform_impl;
#[cfg(doc)] #[cfg(doc)]
use crate::window::Window; use crate::window::Window;
use crate::{ use crate::window::{ActivationToken, Theme, WindowId};
dpi::{PhysicalPosition, PhysicalSize},
event_loop::AsyncRequestSerial,
keyboard::{self, ModifiersKeyState, ModifiersKeys, ModifiersState},
platform_impl,
window::{ActivationToken, Theme, WindowId},
};
/// Describes a generic event. /// Describes a generic event.
/// ///
@ -68,18 +67,12 @@ pub enum Event<T: 'static> {
/// See [`ApplicationHandler::window_event`] for details. /// See [`ApplicationHandler::window_event`] for details.
/// ///
/// [`ApplicationHandler::window_event`]: crate::application::ApplicationHandler::window_event /// [`ApplicationHandler::window_event`]: crate::application::ApplicationHandler::window_event
WindowEvent { WindowEvent { window_id: WindowId, event: WindowEvent },
window_id: WindowId,
event: WindowEvent,
},
/// See [`ApplicationHandler::device_event`] for details. /// See [`ApplicationHandler::device_event`] for details.
/// ///
/// [`ApplicationHandler::device_event`]: crate::application::ApplicationHandler::device_event /// [`ApplicationHandler::device_event`]: crate::application::ApplicationHandler::device_event
DeviceEvent { DeviceEvent { device_id: DeviceId, event: DeviceEvent },
device_id: DeviceId,
event: DeviceEvent,
},
/// See [`ApplicationHandler::user_event`] for details. /// See [`ApplicationHandler::user_event`] for details.
/// ///
@ -138,17 +131,11 @@ pub enum StartCause {
/// guaranteed to be equal to or after the requested resume time. /// guaranteed to be equal to or after the requested resume time.
/// ///
/// [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil /// [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
ResumeTimeReached { ResumeTimeReached { start: Instant, requested_resume: Instant },
start: Instant,
requested_resume: Instant,
},
/// Sent if the OS has new events to send to the window, after a wait was requested. Contains /// Sent if the OS has new events to send to the window, after a wait was requested. Contains
/// the moment the wait was requested and the resume time, if requested. /// the moment the wait was requested and the resume time, if requested.
WaitCancelled { WaitCancelled { start: Instant, requested_resume: Option<Instant> },
start: Instant,
requested_resume: Option<Instant>,
},
/// Sent if the event loop is being resumed after the loop's control flow was set to /// Sent if the event loop is being resumed after the loop's control flow was set to
/// [`ControlFlow::Poll`]. /// [`ControlFlow::Poll`].
@ -164,18 +151,11 @@ pub enum StartCause {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum WindowEvent { pub enum WindowEvent {
/// The activation token was delivered back and now could be used. /// The activation token was delivered back and now could be used.
/// #[cfg_attr(not(any(x11_platform, wayland_platform)), allow(rustdoc::broken_intra_doc_links))]
#[cfg_attr(
not(any(x11_platform, wayland_platform)),
allow(rustdoc::broken_intra_doc_links)
)]
/// Delivered in response to [`request_activation_token`]. /// Delivered in response to [`request_activation_token`].
/// ///
/// [`request_activation_token`]: crate::platform::startup_notify::WindowExtStartupNotify::request_activation_token /// [`request_activation_token`]: crate::platform::startup_notify::WindowExtStartupNotify::request_activation_token
ActivationTokenDone { ActivationTokenDone { serial: AsyncRequestSerial, token: ActivationToken },
serial: AsyncRequestSerial,
token: ActivationToken,
},
/// The size of the window has changed. Contains the client area's new dimensions. /// The size of the window has changed. Contains the client area's new dimensions.
Resized(PhysicalSize<u32>), Resized(PhysicalSize<u32>),
@ -229,10 +209,10 @@ pub enum WindowEvent {
/// If `true`, the event was generated synthetically by winit /// If `true`, the event was generated synthetically by winit
/// in one of the following circumstances: /// in one of the following circumstances:
/// ///
/// * Synthetic key press events are generated for all keys pressed /// * Synthetic key press events are generated for all keys pressed when a window gains
/// when a window gains focus. Likewise, synthetic key release events /// focus. Likewise, synthetic key release events are generated for all keys pressed when
/// are generated for all keys pressed when a window goes out of focus. /// a window goes out of focus. ***Currently, this is only functional on X11 and
/// ***Currently, this is only functional on X11 and Windows*** /// Windows***
/// ///
/// Otherwise, this value is always `false`. /// Otherwise, this value is always `false`.
is_synthetic: bool, is_synthetic: bool,
@ -262,9 +242,10 @@ pub enum WindowEvent {
CursorMoved { CursorMoved {
device_id: DeviceId, device_id: DeviceId,
/// (x,y) coords in pixels relative to the top-left corner of the window. Because the range of this data is /// (x,y) coords in pixels relative to the top-left corner of the window. Because the range
/// limited by the display area and it may have been transformed by the OS to implement effects such as cursor /// of this data is limited by the display area and it may have been transformed by
/// acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control. /// the OS to implement effects such as cursor acceleration, it should not be used
/// to implement non-cursor-like interactions such as 3D camera control.
position: PhysicalPosition<f64>, position: PhysicalPosition<f64>,
}, },
@ -291,18 +272,10 @@ pub enum WindowEvent {
CursorLeft { device_id: DeviceId }, CursorLeft { device_id: DeviceId },
/// A mouse wheel movement or touchpad scroll occurred. /// A mouse wheel movement or touchpad scroll occurred.
MouseWheel { MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase },
device_id: DeviceId,
delta: MouseScrollDelta,
phase: TouchPhase,
},
/// An mouse button press has been received. /// An mouse button press has been received.
MouseInput { MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton },
device_id: DeviceId,
state: ElementState,
button: MouseButton,
},
/// Two-finger pinch gesture, often used for magnification. /// Two-finger pinch gesture, often used for magnification.
/// ///
@ -349,29 +322,17 @@ pub enum WindowEvent {
/// ///
/// - Only available on **macOS** and **iOS**. /// - Only available on **macOS** and **iOS**.
/// - On iOS, not recognized by default. It must be enabled when needed. /// - On iOS, not recognized by default. It must be enabled when needed.
RotationGesture { RotationGesture { device_id: DeviceId, delta: f32, phase: TouchPhase },
device_id: DeviceId,
delta: f32,
phase: TouchPhase,
},
/// Touchpad pressure event. /// Touchpad pressure event.
/// ///
/// At the moment, only supported on Apple forcetouch-capable macbooks. /// At the moment, only supported on Apple forcetouch-capable macbooks.
/// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad /// The parameters are: pressure level (value between 0 and 1 representing how hard the
/// is being pressed) and stage (integer representing the click level). /// touchpad is being pressed) and stage (integer representing the click level).
TouchpadPressure { TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64 },
device_id: DeviceId,
pressure: f32,
stage: i64,
},
/// Motion on some analog axis. May report data redundant to other, more specific events. /// Motion on some analog axis. May report data redundant to other, more specific events.
AxisMotion { AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 },
device_id: DeviceId,
axis: AxisId,
value: f64,
},
/// Touch event has been received /// Touch event has been received
/// ///
@ -393,8 +354,8 @@ pub enum WindowEvent {
/// * Changing the display's scale factor (e.g. in Control Panel on Windows). /// * Changing the display's scale factor (e.g. in Control Panel on Windows).
/// * Moving the window to a display with a different scale factor. /// * Moving the window to a display with a different scale factor.
/// ///
/// To update the window size, use the provided [`InnerSizeWriter`] handle. By default, the window is /// To update the window size, use the provided [`InnerSizeWriter`] handle. By default, the
/// resized to the value suggested by the OS, but it can be changed to any value. /// window is resized to the value suggested by the OS, but it can be changed to any value.
/// ///
/// For more information about DPI in general, see the [`dpi`] crate. /// For more information about DPI in general, see the [`dpi`] crate.
ScaleFactorChanged { ScaleFactorChanged {
@ -424,10 +385,11 @@ pub enum WindowEvent {
/// ///
/// ### iOS /// ### iOS
/// ///
/// On iOS, the `Occluded(false)` event is emitted in response to an [`applicationWillEnterForeground`] /// On iOS, the `Occluded(false)` event is emitted in response to an
/// callback which means the application should start preparing its data. The `Occluded(true)` event is /// [`applicationWillEnterForeground`] callback which means the application should start
/// emitted in response to an [`applicationDidEnterBackground`] callback which means the application /// preparing its data. The `Occluded(true)` event is emitted in response to an
/// should free resources (according to the [iOS application lifecycle]). /// [`applicationDidEnterBackground`] callback which means the application should free
/// resources (according to the [iOS application lifecycle]).
/// ///
/// [`applicationWillEnterForeground`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623076-applicationwillenterforeground /// [`applicationWillEnterForeground`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623076-applicationwillenterforeground
/// [`applicationDidEnterBackground`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622997-applicationdidenterbackground /// [`applicationDidEnterBackground`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622997-applicationdidenterbackground
@ -457,9 +419,10 @@ pub enum WindowEvent {
/// Identifier of an input device. /// Identifier of an input device.
/// ///
/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which /// Whenever you receive an event arising from a particular input device, this event contains a
/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or /// `DeviceId` which identifies its origin. Note that devices may be virtual (representing an
/// physical. Virtual devices typically aggregate inputs from multiple physical devices. /// on-screen cursor and keyboard focus) or physical. Virtual devices typically aggregate inputs
/// from multiple physical devices.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId(pub(crate) platform_impl::DeviceId); pub struct DeviceId(pub(crate) platform_impl::DeviceId);
@ -481,10 +444,10 @@ impl DeviceId {
/// Represents raw hardware events that are not associated with any particular window. /// Represents raw hardware events that are not associated with any particular window.
/// ///
/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera or first-person /// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera
/// game controls. Many physical actions, such as mouse movement, can produce both device and window events. Because /// or first-person game controls. Many physical actions, such as mouse movement, can produce both
/// window events typically arise from virtual devices (corresponding to GUI cursors and keyboard focus) the device IDs /// device and window events. Because window events typically arise from virtual devices
/// may not match. /// (corresponding to GUI cursors and keyboard focus) the device IDs may not match.
/// ///
/// Note that these events are delivered regardless of input focus. /// Note that these events are delivered regardless of input focus.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -494,7 +457,8 @@ pub enum DeviceEvent {
/// Change in physical position of a pointing device. /// Change in physical position of a pointing device.
/// ///
/// This represents raw, unfiltered physical motion. Not to be confused with [`WindowEvent::CursorMoved`]. /// This represents raw, unfiltered physical motion. Not to be confused with
/// [`WindowEvent::CursorMoved`].
MouseMotion { MouseMotion {
/// (x, y) change in position in unspecified units. /// (x, y) change in position in unspecified units.
/// ///
@ -615,13 +579,13 @@ pub struct KeyEvent {
/// Contains the location of this key on the keyboard. /// Contains the location of this key on the keyboard.
/// ///
/// Certain keys on the keyboard may appear in more than once place. For example, the "Shift" key /// Certain keys on the keyboard may appear in more than once place. For example, the "Shift"
/// appears on the left side of the QWERTY keyboard as well as the right side. However, both keys /// key appears on the left side of the QWERTY keyboard as well as the right side. However,
/// have the same symbolic value. Another example of this phenomenon is the "1" key, which appears /// both keys have the same symbolic value. Another example of this phenomenon is the "1"
/// both above the "Q" key and as the "Keypad 1" key. /// key, which appears both above the "Q" key and as the "Keypad 1" key.
/// ///
/// This field allows the user to differentiate between keys like this that have the same symbolic /// This field allows the user to differentiate between keys like this that have the same
/// value but different locations on the keyboard. /// symbolic value but different locations on the keyboard.
/// ///
/// See the [`KeyLocation`] type for more details. /// See the [`KeyLocation`] type for more details.
/// ///
@ -636,8 +600,8 @@ pub struct KeyEvent {
/// Whether or not this key is a key repeat event. /// Whether or not this key is a key repeat event.
/// ///
/// On some systems, holding down a key for some period of time causes that key to be repeated /// On some systems, holding down a key for some period of time causes that key to be repeated
/// as though it were being pressed and released repeatedly. This field is `true` if and only if /// as though it were being pressed and released repeatedly. This field is `true` if and only
/// this event is the result of one of those repeats. /// if this event is the result of one of those repeats.
/// ///
/// # Example /// # Example
/// ///
@ -645,30 +609,31 @@ pub struct KeyEvent {
/// done by ignoring events where this property is set. /// done by ignoring events where this property is set.
/// ///
/// ``` /// ```
/// use winit::event::{WindowEvent, KeyEvent, ElementState}; /// use winit::event::{ElementState, KeyEvent, WindowEvent};
/// use winit::keyboard::{KeyCode, PhysicalKey}; /// use winit::keyboard::{KeyCode, PhysicalKey};
/// # let window_event = WindowEvent::RedrawRequested; // To make the example compile /// # let window_event = WindowEvent::RedrawRequested; // To make the example compile
/// match window_event { /// match window_event {
/// WindowEvent::KeyboardInput { /// WindowEvent::KeyboardInput {
/// event: KeyEvent { /// event:
/// physical_key: PhysicalKey::Code(KeyCode::KeyW), /// KeyEvent {
/// state: ElementState::Pressed, /// physical_key: PhysicalKey::Code(KeyCode::KeyW),
/// repeat: false, /// state: ElementState::Pressed,
/// .. /// repeat: false,
/// }, /// ..
/// },
/// .. /// ..
/// } => { /// } => {
/// // The physical key `W` was pressed, and it was not a repeat /// // The physical key `W` was pressed, and it was not a repeat
/// } /// },
/// _ => {} // Handle other events /// _ => {}, // Handle other events
/// } /// }
/// ``` /// ```
pub repeat: bool, pub repeat: bool,
/// Platform-specific key event information. /// Platform-specific key event information.
/// ///
/// On Windows, Linux and macOS, this type contains the key without modifiers and the text with all /// On Windows, Linux and macOS, this type contains the key without modifiers and the text with
/// modifiers applied. /// all modifiers applied.
/// ///
/// On Android, iOS, Redox and Web, this type is a no-op. /// On Android, iOS, Redox and Web, this type is a no-op.
pub(crate) platform_specific: platform_impl::KeyEventExtra, pub(crate) platform_specific: platform_impl::KeyEventExtra,
@ -742,10 +707,7 @@ impl Modifiers {
impl From<ModifiersState> for Modifiers { impl From<ModifiersState> for Modifiers {
fn from(value: ModifiersState) -> Self { fn from(value: ModifiersState) -> Self {
Self { Self { state: value, pressed_mods: Default::default() }
state: value,
pressed_mods: Default::default(),
}
} }
} }
@ -753,12 +715,15 @@ impl From<ModifiersState> for Modifiers {
/// ///
/// This is also called a "composition event". /// This is also called a "composition event".
/// ///
/// Most keypresses using a latin-like keyboard layout simply generate a [`WindowEvent::KeyboardInput`]. /// Most keypresses using a latin-like keyboard layout simply generate a
/// However, one couldn't possibly have a key for every single unicode character that the user might want to type /// [`WindowEvent::KeyboardInput`]. However, one couldn't possibly have a key for every single
/// - so the solution operating systems employ is to allow the user to type these using _a sequence of keypresses_ instead. /// unicode character that the user might want to type
/// - so the solution operating systems employ is to allow the user to type these using _a sequence
/// of keypresses_ instead.
/// ///
/// A prominent example of this is accents - many keyboard layouts allow you to first click the "accent key", and then /// A prominent example of this is accents - many keyboard layouts allow you to first click the
/// the character you want to apply the accent to. In this case, some platforms will generate the following event sequence: /// "accent key", and then the character you want to apply the accent to. In this case, some
/// platforms will generate the following event sequence: ```ignore
/// ```ignore /// ```ignore
/// // Press "`" key /// // Press "`" key
/// Ime::Preedit("`", Some((0, 0))) /// Ime::Preedit("`", Some((0, 0)))
@ -766,12 +731,12 @@ impl From<ModifiersState> for Modifiers {
/// Ime::Preedit("", None) // Synthetic event generated by winit to clear preedit. /// Ime::Preedit("", None) // Synthetic event generated by winit to clear preedit.
/// Ime::Commit("é") /// Ime::Commit("é")
/// ``` /// ```
/// Additionally, certain input devices are configured to display a candidate box that allow the
/// user to select the desired character interactively. (To properly position this box, you must use
/// [`Window::set_ime_cursor_area`].)
/// ///
/// Additionally, certain input devices are configured to display a candidate box that allow the user to select the /// An example of a keyboard layout which uses candidate boxes is pinyin. On a latin keyboard the
/// desired character interactively. (To properly position this box, you must use [`Window::set_ime_cursor_area`].) /// following event sequence could be obtained:
///
/// An example of a keyboard layout which uses candidate boxes is pinyin. On a latin keyboard the following event
/// sequence could be obtained:
/// ```ignore /// ```ignore
/// // Press "A" key /// // Press "A" key
/// Ime::Preedit("a", Some((1, 1))) /// Ime::Preedit("a", Some((1, 1)))
@ -813,8 +778,8 @@ pub enum Ime {
/// ///
/// After receiving this event you won't get any more [`Preedit`][Self::Preedit] or /// After receiving this event you won't get any more [`Preedit`][Self::Preedit] or
/// [`Commit`][Self::Commit] events until the next [`Enabled`][Self::Enabled] event. You should /// [`Commit`][Self::Commit] events until the next [`Enabled`][Self::Enabled] event. You should
/// also stop issuing IME related requests like [`Window::set_ime_cursor_area`] and clear pending /// also stop issuing IME related requests like [`Window::set_ime_cursor_area`] and clear
/// preedit text. /// pending preedit text.
Disabled, Disabled,
} }
@ -913,17 +878,13 @@ impl Force {
/// consistent across devices. /// consistent across devices.
pub fn normalized(&self) -> f64 { pub fn normalized(&self) -> f64 {
match self { match self {
Force::Calibrated { Force::Calibrated { force, max_possible_force, altitude_angle } => {
force,
max_possible_force,
altitude_angle,
} => {
let force = match altitude_angle { let force = match altitude_angle {
Some(altitude_angle) => force / altitude_angle.sin(), Some(altitude_angle) => force / altitude_angle.sin(),
None => *force, None => *force,
}; };
force / max_possible_force force / max_possible_force
} },
Force::Normalized(force) => *force, Force::Normalized(force) => *force,
} }
} }
@ -1040,7 +1001,9 @@ mod tests {
#[allow(deprecated)] #[allow(deprecated)]
{ {
use crate::event::{Event::*, Ime::Enabled, WindowEvent::*}; use crate::event::Event::*;
use crate::event::Ime::Enabled;
use crate::event::WindowEvent::*;
use crate::window::WindowId; use crate::window::WindowId;
// Mainline events. // Mainline events.
@ -1053,12 +1016,7 @@ mod tests {
x(Resumed); x(Resumed);
// Window events. // Window events.
let with_window_event = |wev| { let with_window_event = |wev| x(WindowEvent { window_id: wid, event: wev });
x(WindowEvent {
window_id: wid,
event: wev,
})
};
with_window_event(CloseRequested); with_window_event(CloseRequested);
with_window_event(Destroyed); with_window_event(Destroyed);
@ -1069,10 +1027,7 @@ mod tests {
with_window_event(HoveredFile("x.txt".into())); with_window_event(HoveredFile("x.txt".into()));
with_window_event(HoveredFileCancelled); with_window_event(HoveredFileCancelled);
with_window_event(Ime(Enabled)); with_window_event(Ime(Enabled));
with_window_event(CursorMoved { with_window_event(CursorMoved { device_id: did, position: (0, 0).into() });
device_id: did,
position: (0, 0).into(),
});
with_window_event(ModifiersChanged(event::Modifiers::default())); with_window_event(ModifiersChanged(event::Modifiers::default()));
with_window_event(CursorEntered { device_id: did }); with_window_event(CursorEntered { device_id: did });
with_window_event(CursorLeft { device_id: did }); with_window_event(CursorLeft { device_id: did });
@ -1097,16 +1052,8 @@ mod tests {
delta: 0.0, delta: 0.0,
phase: event::TouchPhase::Started, phase: event::TouchPhase::Started,
}); });
with_window_event(TouchpadPressure { with_window_event(TouchpadPressure { device_id: did, pressure: 0.0, stage: 0 });
device_id: did, with_window_event(AxisMotion { device_id: did, axis: 0, value: 0.0 });
pressure: 0.0,
stage: 0,
});
with_window_event(AxisMotion {
device_id: did,
axis: 0,
value: 0.0,
});
with_window_event(Touch(event::Touch { with_window_event(Touch(event::Touch {
device_id: did, device_id: did,
phase: event::TouchPhase::Started, phase: event::TouchPhase::Started,
@ -1122,29 +1069,17 @@ mod tests {
{ {
use event::DeviceEvent::*; use event::DeviceEvent::*;
let with_device_event = |dev_ev| { let with_device_event =
x(event::Event::DeviceEvent { |dev_ev| x(event::Event::DeviceEvent { device_id: did, event: dev_ev });
device_id: did,
event: dev_ev,
})
};
with_device_event(Added); with_device_event(Added);
with_device_event(Removed); with_device_event(Removed);
with_device_event(MouseMotion { with_device_event(MouseMotion { delta: (0.0, 0.0).into() });
delta: (0.0, 0.0).into(),
});
with_device_event(MouseWheel { with_device_event(MouseWheel {
delta: event::MouseScrollDelta::LineDelta(0.0, 0.0), delta: event::MouseScrollDelta::LineDelta(0.0, 0.0),
}); });
with_device_event(Motion { with_device_event(Motion { axis: 0, value: 0.0 });
axis: 0, with_device_event(Button { button: 0, state: event::ElementState::Pressed });
value: 0.0,
});
with_device_event(Button {
button: 0,
state: event::ElementState::Pressed,
});
} }
}}; }};
} }
@ -1176,11 +1111,8 @@ mod tests {
let force = event::Force::Normalized(0.0); let force = event::Force::Normalized(0.0);
assert_eq!(force.normalized(), 0.0); assert_eq!(force.normalized(), 0.0);
let force2 = event::Force::Calibrated { let force2 =
force: 5.0, event::Force::Calibrated { force: 5.0, max_possible_force: 2.5, altitude_angle: None };
max_possible_force: 2.5,
altitude_angle: None,
};
assert_eq!(force2.normalized(), 2.0); assert_eq!(force2.normalized(), 2.0);
let force3 = event::Force::Calibrated { let force3 = event::Force::Calibrated {
@ -1219,11 +1151,8 @@ mod tests {
force: Some(event::Force::Normalized(0.0)), force: Some(event::Force::Normalized(0.0)),
} }
.clone(); .clone();
let _ = event::Force::Calibrated { let _ =
force: 0.0, event::Force::Calibrated { force: 0.0, max_possible_force: 0.0, altitude_angle: None }
max_possible_force: 0.0, .clone();
altitude_angle: None,
}
.clone();
} }
} }

View file

@ -20,8 +20,10 @@ use web_time::{Duration, Instant};
use crate::application::ApplicationHandler; use crate::application::ApplicationHandler;
use crate::error::{EventLoopError, OsError}; use crate::error::{EventLoopError, OsError};
use crate::event::Event;
use crate::monitor::MonitorHandle;
use crate::platform_impl;
use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes}; use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
use crate::{event::Event, monitor::MonitorHandle, platform_impl};
/// Provides a way to retrieve events from the system and from the windows that were registered to /// Provides a way to retrieve events from the system and from the windows that were registered to
/// the events loop. /// the events loop.
@ -33,8 +35,8 @@ use crate::{event::Event, monitor::MonitorHandle, platform_impl};
/// To wake up an `EventLoop` from a another thread, see the [`EventLoopProxy`] docs. /// To wake up an `EventLoop` from a another thread, see the [`EventLoopProxy`] docs.
/// ///
/// Note that this cannot be shared across threads (due to platform-dependant logic /// Note that this cannot be shared across threads (due to platform-dependant logic
/// forbidding it), as such it is neither [`Send`] nor [`Sync`]. If you need cross-thread access, the /// forbidding it), as such it is neither [`Send`] nor [`Sync`]. If you need cross-thread access,
/// [`Window`] created from this _can_ be sent to an other thread, and the /// the [`Window`] created from this _can_ be sent to an other thread, and the
/// [`EventLoopProxy`] allows you to wake up an `EventLoop` from another thread. /// [`EventLoopProxy`] allows you to wake up an `EventLoop` from another thread.
/// ///
/// [`Window`]: crate::window::Window /// [`Window`]: crate::window::Window
@ -94,20 +96,18 @@ impl<T> EventLoopBuilder<T> {
/// ///
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **Wayland/X11:** to prevent running under `Wayland` or `X11` unset `WAYLAND_DISPLAY` /// - **Wayland/X11:** to prevent running under `Wayland` or `X11` unset `WAYLAND_DISPLAY` or
/// or `DISPLAY` respectively when building the event loop. /// `DISPLAY` respectively when building the event loop.
/// - **Android:** must be configured with an `AndroidApp` from `android_main()` by calling /// - **Android:** must be configured with an `AndroidApp` from `android_main()` by calling
/// [`.with_android_app(app)`] before calling `.build()`, otherwise it'll panic. /// [`.with_android_app(app)`] before calling `.build()`, otherwise it'll panic.
/// ///
/// [`platform`]: crate::platform /// [`platform`]: crate::platform
#[cfg_attr( #[cfg_attr(
android, android,
doc = "[`.with_android_app(app)`]: crate::platform::android::EventLoopBuilderExtAndroid::with_android_app" doc = "[`.with_android_app(app)`]: \
)] crate::platform::android::EventLoopBuilderExtAndroid::with_android_app"
#[cfg_attr(
not(android),
doc = "[`.with_android_app(app)`]: #only-available-on-android"
)] )]
#[cfg_attr(not(android), doc = "[`.with_android_app(app)`]: #only-available-on-android")]
#[inline] #[inline]
pub fn build(&mut self) -> Result<EventLoop<T>, EventLoopError> { pub fn build(&mut self) -> Result<EventLoop<T>, EventLoopError> {
let _span = tracing::debug_span!("winit::EventLoopBuilder::build").entered(); let _span = tracing::debug_span!("winit::EventLoopBuilder::build").entered();
@ -162,9 +162,9 @@ pub enum ControlFlow {
/// When the current loop iteration finishes, suspend the thread until either another event /// When the current loop iteration finishes, suspend the thread until either another event
/// arrives or the given time is reached. /// arrives or the given time is reached.
/// ///
/// Useful for implementing efficient timers. Applications which want to render at the display's /// Useful for implementing efficient timers. Applications which want to render at the
/// native refresh rate should instead use [`Poll`] and the VSync functionality of a graphics API /// display's native refresh rate should instead use [`Poll`] and the VSync functionality
/// to reduce odds of missed frames. /// of a graphics API to reduce odds of missed frames.
/// ///
/// [`Poll`]: Self::Poll /// [`Poll`]: Self::Poll
WaitUntil(Instant), WaitUntil(Instant),
@ -210,10 +210,7 @@ impl<T> EventLoop<T> {
/// Start building a new event loop, with the given type as the user event /// Start building a new event loop, with the given type as the user event
/// type. /// type.
pub fn with_user_event() -> EventLoopBuilder<T> { pub fn with_user_event() -> EventLoopBuilder<T> {
EventLoopBuilder { EventLoopBuilder { platform_specific: Default::default(), _p: PhantomData }
platform_specific: Default::default(),
_p: PhantomData,
}
} }
/// See [`run_app`]. /// See [`run_app`].
@ -239,9 +236,9 @@ impl<T> EventLoop<T> {
/// ///
/// - **iOS:** Will never return to the caller and so values not passed to this function will /// - **iOS:** Will never return to the caller and so values not passed to this function will
/// *not* be dropped before the process exits. /// *not* be dropped before the process exits.
/// - **Web:** Will _act_ as if it never returns to the caller by throwing a Javascript exception /// - **Web:** Will _act_ as if it never returns to the caller by throwing a Javascript
/// (that Rust doesn't see) that will also mean that the rest of the function is never executed /// exception (that Rust doesn't see) that will also mean that the rest of the function is
/// and any values not passed to this function will *not* be dropped. /// never executed and any values not passed to this function will *not* be dropped.
/// ///
/// Web applications are recommended to use /// Web applications are recommended to use
#[cfg_attr( #[cfg_attr(
@ -262,25 +259,20 @@ impl<T> EventLoop<T> {
#[inline] #[inline]
#[cfg(not(all(web_platform, target_feature = "exception-handling")))] #[cfg(not(all(web_platform, target_feature = "exception-handling")))]
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> { pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> {
self.event_loop self.event_loop.run(|event, event_loop| dispatch_event_for_app(app, event_loop, event))
.run(|event, event_loop| dispatch_event_for_app(app, event_loop, event))
} }
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events /// Creates an [`EventLoopProxy`] that can be used to dispatch user events
/// to the main event loop, possibly from another thread. /// to the main event loop, possibly from another thread.
pub fn create_proxy(&self) -> EventLoopProxy<T> { pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy { EventLoopProxy { event_loop_proxy: self.event_loop.create_proxy() }
event_loop_proxy: self.event_loop.create_proxy(),
}
} }
/// Gets a persistent reference to the underlying platform display. /// Gets a persistent reference to the underlying platform display.
/// ///
/// See the [`OwnedDisplayHandle`] type for more information. /// See the [`OwnedDisplayHandle`] type for more information.
pub fn owned_display_handle(&self) -> OwnedDisplayHandle { pub fn owned_display_handle(&self) -> OwnedDisplayHandle {
OwnedDisplayHandle { OwnedDisplayHandle { platform: self.event_loop.window_target().p.owned_display_handle() }
platform: self.event_loop.window_target().p.owned_display_handle(),
}
} }
/// Change if or when [`DeviceEvent`]s are captured. /// Change if or when [`DeviceEvent`]s are captured.
@ -295,18 +287,12 @@ impl<T> EventLoop<T> {
) )
.entered(); .entered();
self.event_loop self.event_loop.window_target().p.listen_device_events(allowed);
.window_target()
.p
.listen_device_events(allowed);
} }
/// Sets the [`ControlFlow`]. /// Sets the [`ControlFlow`].
pub fn set_control_flow(&self, control_flow: ControlFlow) { pub fn set_control_flow(&self, control_flow: ControlFlow) {
self.event_loop self.event_loop.window_target().p.set_control_flow(control_flow)
.window_target()
.p
.set_control_flow(control_flow)
} }
/// Create a window. /// Create a window.
@ -329,10 +315,7 @@ impl<T> EventLoop<T> {
/// Create custom cursor. /// Create custom cursor.
pub fn create_custom_cursor(&self, custom_cursor: CustomCursorSource) -> CustomCursor { pub fn create_custom_cursor(&self, custom_cursor: CustomCursorSource) -> CustomCursor {
self.event_loop self.event_loop.window_target().p.create_custom_cursor(custom_cursor)
.window_target()
.p
.create_custom_cursor(custom_cursor)
} }
} }
@ -413,10 +396,7 @@ impl ActiveEventLoop {
let _span = tracing::debug_span!("winit::ActiveEventLoop::available_monitors",).entered(); let _span = tracing::debug_span!("winit::ActiveEventLoop::available_monitors",).entered();
#[allow(clippy::useless_conversion)] // false positive on some platforms #[allow(clippy::useless_conversion)] // false positive on some platforms
self.p self.p.available_monitors().into_iter().map(|inner| MonitorHandle { inner })
.available_monitors()
.into_iter()
.map(|inner| MonitorHandle { inner })
} }
/// Returns the primary monitor of the system. /// Returns the primary monitor of the system.
@ -430,9 +410,7 @@ impl ActiveEventLoop {
pub fn primary_monitor(&self) -> Option<MonitorHandle> { pub fn primary_monitor(&self) -> Option<MonitorHandle> {
let _span = tracing::debug_span!("winit::ActiveEventLoop::primary_monitor",).entered(); let _span = tracing::debug_span!("winit::ActiveEventLoop::primary_monitor",).entered();
self.p self.p.primary_monitor().map(|inner| MonitorHandle { inner })
.primary_monitor()
.map(|inner| MonitorHandle { inner })
} }
/// Change if or when [`DeviceEvent`]s are captured. /// Change if or when [`DeviceEvent`]s are captured.
@ -486,9 +464,7 @@ impl ActiveEventLoop {
/// ///
/// See the [`OwnedDisplayHandle`] type for more information. /// See the [`OwnedDisplayHandle`] type for more information.
pub fn owned_display_handle(&self) -> OwnedDisplayHandle { pub fn owned_display_handle(&self) -> OwnedDisplayHandle {
OwnedDisplayHandle { OwnedDisplayHandle { platform: self.p.owned_display_handle() }
platform: self.p.owned_display_handle(),
}
} }
} }
@ -562,9 +538,7 @@ pub struct EventLoopProxy<T: 'static> {
impl<T: 'static> Clone for EventLoopProxy<T> { impl<T: 'static> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self { event_loop_proxy: self.event_loop_proxy.clone() }
event_loop_proxy: self.event_loop_proxy.clone(),
}
} }
} }

View file

@ -1,5 +1,6 @@
use crate::platform_impl::PlatformIcon; use crate::platform_impl::PlatformIcon;
use std::{error::Error, fmt, io, mem}; use std::error::Error;
use std::{fmt, io, mem};
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
@ -20,12 +21,7 @@ pub enum BadIcon {
ByteCountNotDivisibleBy4 { byte_count: usize }, ByteCountNotDivisibleBy4 { byte_count: usize },
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`. /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
/// At least one of your arguments is incorrect. /// At least one of your arguments is incorrect.
DimensionsVsPixelCount { DimensionsVsPixelCount { width: u32, height: u32, width_x_height: usize, pixel_count: usize },
width: u32,
height: u32,
width_x_height: usize,
pixel_count: usize,
},
/// Produced when underlying OS functionality failed to create the icon /// Produced when underlying OS functionality failed to create the icon
OsError(io::Error), OsError(io::Error),
} }
@ -33,17 +29,19 @@ pub enum BadIcon {
impl fmt::Display for BadIcon { impl fmt::Display for BadIcon {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(f, BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(
"The length of the `rgba` argument ({byte_count:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.", f,
), "The length of the `rgba` argument ({byte_count:?}) isn't divisible by 4, making \
BadIcon::DimensionsVsPixelCount { it impossible to interpret as 32bpp RGBA pixels.",
width,
height,
width_x_height,
pixel_count,
} => write!(f,
"The specified dimensions ({width:?}x{height:?}) don't match the number of pixels supplied by the `rgba` argument ({pixel_count:?}). For those dimensions, the expected pixel count is {width_x_height:?}.",
), ),
BadIcon::DimensionsVsPixelCount { width, height, width_x_height, pixel_count } => {
write!(
f,
"The specified dimensions ({width:?}x{height:?}) don't match the number of \
pixels supplied by the `rgba` argument ({pixel_count:?}). For those \
dimensions, the expected pixel count is {width_x_height:?}.",
)
},
BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {e:?}"), BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {e:?}"),
} }
} }
@ -69,9 +67,7 @@ mod constructors {
impl RgbaIcon { impl RgbaIcon {
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> { pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
if rgba.len() % PIXEL_SIZE != 0 { if rgba.len() % PIXEL_SIZE != 0 {
return Err(BadIcon::ByteCountNotDivisibleBy4 { return Err(BadIcon::ByteCountNotDivisibleBy4 { byte_count: rgba.len() });
byte_count: rgba.len(),
});
} }
let pixel_count = rgba.len() / PIXEL_SIZE; let pixel_count = rgba.len() / PIXEL_SIZE;
if pixel_count != (width * height) as usize { if pixel_count != (width * height) as usize {
@ -82,11 +78,7 @@ mod constructors {
pixel_count, pixel_count,
}) })
} else { } else {
Ok(RgbaIcon { Ok(RgbaIcon { rgba, width, height })
rgba,
width,
height,
})
} }
} }
} }
@ -120,8 +112,6 @@ impl Icon {
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> { pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
let _span = tracing::debug_span!("winit::Icon::from_rgba", width, height).entered(); let _span = tracing::debug_span!("winit::Icon::from_rgba", width, height).entered();
Ok(Icon { Ok(Icon { inner: PlatformIcon::from_rgba(rgba, width, height)? })
inner: PlatformIcon::from_rgba(rgba, width, height)?,
})
} }
} }

View file

@ -106,23 +106,23 @@ impl std::fmt::Debug for NativeKeyCode {
match self { match self {
Unidentified => { Unidentified => {
debug_tuple = f.debug_tuple("Unidentified"); debug_tuple = f.debug_tuple("Unidentified");
} },
Android(code) => { Android(code) => {
debug_tuple = f.debug_tuple("Android"); debug_tuple = f.debug_tuple("Android");
debug_tuple.field(&format_args!("0x{code:04X}")); debug_tuple.field(&format_args!("0x{code:04X}"));
} },
MacOS(code) => { MacOS(code) => {
debug_tuple = f.debug_tuple("MacOS"); debug_tuple = f.debug_tuple("MacOS");
debug_tuple.field(&format_args!("0x{code:04X}")); debug_tuple.field(&format_args!("0x{code:04X}"));
} },
Windows(code) => { Windows(code) => {
debug_tuple = f.debug_tuple("Windows"); debug_tuple = f.debug_tuple("Windows");
debug_tuple.field(&format_args!("0x{code:04X}")); debug_tuple.field(&format_args!("0x{code:04X}"));
} },
Xkb(code) => { Xkb(code) => {
debug_tuple = f.debug_tuple("Xkb"); debug_tuple = f.debug_tuple("Xkb");
debug_tuple.field(&format_args!("0x{code:04X}")); debug_tuple.field(&format_args!("0x{code:04X}"));
} },
} }
debug_tuple.finish() debug_tuple.finish()
} }
@ -162,27 +162,27 @@ impl std::fmt::Debug for NativeKey {
match self { match self {
Unidentified => { Unidentified => {
debug_tuple = f.debug_tuple("Unidentified"); debug_tuple = f.debug_tuple("Unidentified");
} },
Android(code) => { Android(code) => {
debug_tuple = f.debug_tuple("Android"); debug_tuple = f.debug_tuple("Android");
debug_tuple.field(&format_args!("0x{code:04X}")); debug_tuple.field(&format_args!("0x{code:04X}"));
} },
MacOS(code) => { MacOS(code) => {
debug_tuple = f.debug_tuple("MacOS"); debug_tuple = f.debug_tuple("MacOS");
debug_tuple.field(&format_args!("0x{code:04X}")); debug_tuple.field(&format_args!("0x{code:04X}"));
} },
Windows(code) => { Windows(code) => {
debug_tuple = f.debug_tuple("Windows"); debug_tuple = f.debug_tuple("Windows");
debug_tuple.field(&format_args!("0x{code:04X}")); debug_tuple.field(&format_args!("0x{code:04X}"));
} },
Xkb(code) => { Xkb(code) => {
debug_tuple = f.debug_tuple("Xkb"); debug_tuple = f.debug_tuple("Xkb");
debug_tuple.field(&format_args!("0x{code:04X}")); debug_tuple.field(&format_args!("0x{code:04X}"));
} },
Web(code) => { Web(code) => {
debug_tuple = f.debug_tuple("Web"); debug_tuple = f.debug_tuple("Web");
debug_tuple.field(code); debug_tuple.field(code);
} },
} }
debug_tuple.finish() debug_tuple.finish()
} }
@ -442,7 +442,8 @@ pub enum KeyCode {
Tab, Tab,
/// Japanese: <kbd>変</kbd> (henkan) /// Japanese: <kbd>変</kbd> (henkan)
Convert, Convert,
/// Japanese: <kbd>カタカナ</kbd>/<kbd>ひらがな</kbd>/<kbd>ローマ字</kbd> (katakana/hiragana/romaji) /// Japanese: <kbd>カタカナ</kbd>/<kbd>ひらがな</kbd>/<kbd>ローマ字</kbd>
/// (katakana/hiragana/romaji)
KanaMode, KanaMode,
/// Korean: HangulMode <kbd>한/영</kbd> (han/yeong) /// Korean: HangulMode <kbd>한/영</kbd> (han/yeong)
/// ///
@ -490,7 +491,8 @@ pub enum KeyCode {
NumLock, NumLock,
/// <kbd>0 Ins</kbd> on a keyboard. <kbd>0</kbd> on a phone or remote control /// <kbd>0 Ins</kbd> on a keyboard. <kbd>0</kbd> on a phone or remote control
Numpad0, Numpad0,
/// <kbd>1 End</kbd> on a keyboard. <kbd>1</kbd> or <kbd>1 QZ</kbd> on a phone or remote control /// <kbd>1 End</kbd> on a keyboard. <kbd>1</kbd> or <kbd>1 QZ</kbd> on a phone or remote
/// control
Numpad1, Numpad1,
/// <kbd>2 ↓</kbd> on a keyboard. <kbd>2 ABC</kbd> on a phone or remote control /// <kbd>2 ↓</kbd> on a keyboard. <kbd>2 ABC</kbd> on a phone or remote control
Numpad2, Numpad2,
@ -794,13 +796,14 @@ pub enum NamedKey {
// Legacy modifier key. // Legacy modifier key.
Hyper, Hyper,
/// Used to enable "super" modifier function for interpreting concurrent or subsequent keyboard /// Used to enable "super" modifier function for interpreting concurrent or subsequent keyboard
/// input. This key value is used for the "Windows Logo" key and the Apple `Command` or `⌘` key. /// input. This key value is used for the "Windows Logo" key and the Apple `Command` or `⌘`
/// key.
/// ///
/// Note: In some contexts (e.g. the Web) this is referred to as the "Meta" key. /// Note: In some contexts (e.g. the Web) this is referred to as the "Meta" key.
Super, Super,
/// The `Enter` or `↵` key. Used to activate current selection or accept current input. This key /// The `Enter` or `↵` key. Used to activate current selection or accept current input. This
/// value is also used for the `Return` (Macintosh numpad) key. This key value is also used for /// key value is also used for the `Return` (Macintosh numpad) key. This key value is also
/// the Android `KEYCODE_DPAD_CENTER`. /// used for the Android `KEYCODE_DPAD_CENTER`.
Enter, Enter,
/// The Horizontal Tabulation `Tab` key. /// The Horizontal Tabulation `Tab` key.
Tab, Tab,
@ -836,8 +839,8 @@ pub enum NamedKey {
CrSel, CrSel,
/// Cut the current selection. (`APPCOMMAND_CUT`) /// Cut the current selection. (`APPCOMMAND_CUT`)
Cut, Cut,
/// Used to delete the character to the right of the cursor. This key value is also used for the /// Used to delete the character to the right of the cursor. This key value is also used for
/// key labeled `Delete` on MacOS keyboards when `Fn` is active. /// the key labeled `Delete` on MacOS keyboards when `Fn` is active.
Delete, Delete,
/// The Erase to End of Field key. This key deletes all characters from the current cursor /// The Erase to End of Field key. This key deletes all characters from the current cursor
/// position to the end of the current field. /// position to the end of the current field.
@ -921,8 +924,8 @@ pub enum NamedKey {
/// their code points. /// their code points.
CodeInput, CodeInput,
/// The Compose key, also known as "Multi_key" on the X Window System. This key acts in a /// The Compose key, also known as "Multi_key" on the X Window System. This key acts in a
/// manner similar to a dead key, triggering a mode where subsequent key presses are combined to /// manner similar to a dead key, triggering a mode where subsequent key presses are combined
/// produce a different character. /// to produce a different character.
Compose, Compose,
/// Convert the current input method sequence. /// Convert the current input method sequence.
Convert, Convert,
@ -961,9 +964,9 @@ pub enum NamedKey {
/// The Kana Mode (Kana Lock) key. This key is used to enter hiragana mode (typically from /// The Kana Mode (Kana Lock) key. This key is used to enter hiragana mode (typically from
/// romaji mode). /// romaji mode).
KanaMode, KanaMode,
/// The Kanji (Japanese name for ideographic characters of Chinese origin) Mode key. This key is /// The Kanji (Japanese name for ideographic characters of Chinese origin) Mode key. This key
/// typically used to switch to a hiragana keyboard for the purpose of converting input into /// is typically used to switch to a hiragana keyboard for the purpose of converting input
/// kanji. (`KEYCODE_KANA`) /// into kanji. (`KEYCODE_KANA`)
KanjiMode, KanjiMode,
/// The Katakana (Japanese Kana characters) key. /// The Katakana (Japanese Kana characters) key.
Katakana, Katakana,
@ -1588,7 +1591,7 @@ impl Key {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use winit::keyboard::{NamedKey, Key}; /// use winit::keyboard::{Key, NamedKey};
/// ///
/// assert_eq!(Key::Character("a".into()).to_text(), Some("a")); /// assert_eq!(Key::Character("a".into()).to_text(), Some("a"));
/// assert_eq!(Key::Named(NamedKey::Enter).to_text(), Some("\r")); /// assert_eq!(Key::Named(NamedKey::Enter).to_text(), Some("\r"));
@ -1610,7 +1613,8 @@ impl Key {
/// keys can be above the letters or on the numpad. This enum allows the user to differentiate /// keys can be above the letters or on the numpad. This enum allows the user to differentiate
/// them. /// them.
/// ///
/// See the documentation for the [`location`] field on the [`KeyEvent`] struct for more information. /// See the documentation for the [`location`] field on the [`KeyEvent`] struct for more
/// information.
/// ///
/// [`location`]: ../event/struct.KeyEvent.html#structfield.location /// [`location`]: ../event/struct.KeyEvent.html#structfield.location
/// [`KeyEvent`]: crate::event::KeyEvent /// [`KeyEvent`]: crate::event::KeyEvent
@ -1619,8 +1623,8 @@ impl Key {
pub enum KeyLocation { pub enum KeyLocation {
/// The key is in its "normal" location on the keyboard. /// The key is in its "normal" location on the keyboard.
/// ///
/// For instance, the "1" key above the "Q" key on a QWERTY keyboard will use this location. This /// For instance, the "1" key above the "Q" key on a QWERTY keyboard will use this location.
/// invariant is also returned when the location of the key cannot be identified. /// This invariant is also returned when the location of the key cannot be identified.
/// ///
/// ![Standard 1 key](https://raw.githubusercontent.com/rust-windowing/winit/master/docs/res/keyboard_standard_1_key.svg) /// ![Standard 1 key](https://raw.githubusercontent.com/rust-windowing/winit/master/docs/res/keyboard_standard_1_key.svg)
/// ///
@ -1703,14 +1707,17 @@ impl ModifiersState {
pub fn shift_key(&self) -> bool { pub fn shift_key(&self) -> bool {
self.intersects(Self::SHIFT) self.intersects(Self::SHIFT)
} }
/// Returns `true` if the control key is pressed. /// Returns `true` if the control key is pressed.
pub fn control_key(&self) -> bool { pub fn control_key(&self) -> bool {
self.intersects(Self::CONTROL) self.intersects(Self::CONTROL)
} }
/// Returns `true` if the alt key is pressed. /// Returns `true` if the alt key is pressed.
pub fn alt_key(&self) -> bool { pub fn alt_key(&self) -> bool {
self.intersects(Self::ALT) self.intersects(Self::ALT)
} }
/// Returns `true` if the super key is pressed. /// Returns `true` if the super key is pressed.
pub fn super_key(&self) -> bool { pub fn super_key(&self) -> bool {
self.intersects(Self::SUPER) self.intersects(Self::SUPER)
@ -1784,12 +1791,8 @@ mod modifiers_serde {
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let ModifiersStateSerialize { let ModifiersStateSerialize { shift_key, control_key, alt_key, super_key } =
shift_key, ModifiersStateSerialize::deserialize(deserializer)?;
control_key,
alt_key,
super_key,
} = ModifiersStateSerialize::deserialize(deserializer)?;
let mut m = ModifiersState::empty(); let mut m = ModifiersState::empty();
m.set(ModifiersState::SHIFT, shift_key); m.set(ModifiersState::SHIFT, shift_key);
m.set(ModifiersState::CONTROL, control_key); m.set(ModifiersState::CONTROL, control_key);

View file

@ -19,33 +19,22 @@
//! window or a key getting pressed while the window is focused. Devices can generate //! window or a key getting pressed while the window is focused. Devices can generate
//! [`DeviceEvent`]s, which contain unfiltered event data that isn't specific to a certain window. //! [`DeviceEvent`]s, which contain unfiltered event data that isn't specific to a certain window.
//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a //! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
//! [`DeviceEvent`]. You can also create and handle your own custom [`Event::UserEvent`]s, if desired. //! [`DeviceEvent`]. You can also create and handle your own custom [`Event::UserEvent`]s, if
//! desired.
//! //!
//! You can retrieve events by calling [`EventLoop::run_app()`]. This function will //! You can retrieve events by calling [`EventLoop::run_app()`]. This function will
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and //! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
//! will run until [`exit()`] is used, at which point [`Event::LoopExiting`]. //! will run until [`exit()`] is used, at which point [`Event::LoopExiting`].
//! //!
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop //! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
//! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works poorly on //! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works
//! most other platforms. However, this model can be re-implemented to an extent with //! poorly on most other platforms. However, this model can be re-implemented to an extent with
#![cfg_attr( #![cfg_attr(
any( any(windows_platform, macos_platform, android_platform, x11_platform, wayland_platform),
windows_platform,
macos_platform,
android_platform,
x11_platform,
wayland_platform
),
doc = "[`EventLoopExtPumpEvents::pump_app_events()`][platform::pump_events::EventLoopExtPumpEvents::pump_app_events()]" doc = "[`EventLoopExtPumpEvents::pump_app_events()`][platform::pump_events::EventLoopExtPumpEvents::pump_app_events()]"
)] )]
#![cfg_attr( #![cfg_attr(
not(any( not(any(windows_platform, macos_platform, android_platform, x11_platform, wayland_platform)),
windows_platform,
macos_platform,
android_platform,
x11_platform,
wayland_platform
)),
doc = "`EventLoopExtPumpEvents::pump_app_events()`" doc = "`EventLoopExtPumpEvents::pump_app_events()`"
)] )]
//! [^1]. See that method's documentation for more reasons about why //! [^1]. See that method's documentation for more reasons about why
@ -116,16 +105,16 @@
//! //!
//! # Drawing on the window //! # Drawing on the window
//! //!
//! Winit doesn't directly provide any methods for drawing on a [`Window`]. However, it allows you to //! Winit doesn't directly provide any methods for drawing on a [`Window`]. However, it allows you
//! retrieve the raw handle of the window and display (see the [`platform`] module and/or the //! to retrieve the raw handle of the window and display (see the [`platform`] module and/or the
//! [`raw_window_handle`] and [`raw_display_handle`] methods), which in turn allows //! [`raw_window_handle`] and [`raw_display_handle`] methods), which in turn allows
//! you to create an OpenGL/Vulkan/DirectX/Metal/etc. context that can be used to render graphics. //! you to create an OpenGL/Vulkan/DirectX/Metal/etc. context that can be used to render graphics.
//! //!
//! Note that many platforms will display garbage data in the window's client area if the //! Note that many platforms will display garbage data in the window's client area if the
//! application doesn't render anything to the window by the time the desktop compositor is ready to //! application doesn't render anything to the window by the time the desktop compositor is ready to
//! display the window to the user. If you notice this happening, you should create the window with //! display the window to the user. If you notice this happening, you should create the window with
//! [`visible` set to `false`][crate::window::WindowAttributes::with_visible] and explicitly make the //! [`visible` set to `false`][crate::window::WindowAttributes::with_visible] and explicitly make
//! window visible only once you're ready to render into it. //! the window visible only once you're ready to render into it.
//! //!
//! # UI scaling //! # UI scaling
//! //!
@ -151,13 +140,11 @@
//! Winit provides the following Cargo features: //! Winit provides the following Cargo features:
//! //!
//! * `x11` (enabled by default): On Unix platforms, enables the X11 backend. //! * `x11` (enabled by default): On Unix platforms, enables the X11 backend.
//! * `wayland` (enabled by default): On Unix platforms, enables the Wayland //! * `wayland` (enabled by default): On Unix platforms, enables the Wayland backend.
//! backend.
//! * `rwh_04`: Implement `raw-window-handle v0.4` traits. //! * `rwh_04`: Implement `raw-window-handle v0.4` traits.
//! * `rwh_05`: Implement `raw-window-handle v0.5` traits. //! * `rwh_05`: Implement `raw-window-handle v0.5` traits.
//! * `rwh_06`: Implement `raw-window-handle v0.6` traits. //! * `rwh_06`: Implement `raw-window-handle v0.6` traits.
//! * `serde`: Enables serialization/deserialization of certain types with //! * `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde).
//! [Serde](https://crates.io/crates/serde).
//! * `mint`: Enables mint (math interoperability standard types) conversions. //! * `mint`: Enables mint (math interoperability standard types) conversions.
//! //!
//! See the [`platform`] module for documentation on platform-specific cargo //! See the [`platform`] module for documentation on platform-specific cargo
@ -186,12 +173,9 @@
#![deny(clippy::all)] #![deny(clippy::all)]
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(clippy, deny(warnings))] #![cfg_attr(clippy, deny(warnings))]
// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc // Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly
#![cfg_attr( // doc
docsrs, #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))]
feature(doc_auto_cfg, doc_cfg_hide),
doc(cfg_hide(doc, docsrs))
)]
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
#[cfg(feature = "rwh_06")] #[cfg(feature = "rwh_06")]

View file

@ -5,10 +5,8 @@
//! methods, which return an iterator of [`MonitorHandle`]: //! methods, which return an iterator of [`MonitorHandle`]:
//! - [`ActiveEventLoop::available_monitors`][crate::event_loop::ActiveEventLoop::available_monitors]. //! - [`ActiveEventLoop::available_monitors`][crate::event_loop::ActiveEventLoop::available_monitors].
//! - [`Window::available_monitors`][crate::window::Window::available_monitors]. //! - [`Window::available_monitors`][crate::window::Window::available_monitors].
use crate::{ use crate::dpi::{PhysicalPosition, PhysicalSize};
dpi::{PhysicalPosition, PhysicalSize}, use crate::platform_impl;
platform_impl,
};
/// Deprecated! Use `VideoModeHandle` instead. /// Deprecated! Use `VideoModeHandle` instead.
#[deprecated = "Renamed to `VideoModeHandle`"] #[deprecated = "Renamed to `VideoModeHandle`"]
@ -79,9 +77,7 @@ impl VideoModeHandle {
/// a separate set of valid video modes. /// a separate set of valid video modes.
#[inline] #[inline]
pub fn monitor(&self) -> MonitorHandle { pub fn monitor(&self) -> MonitorHandle {
MonitorHandle { MonitorHandle { inner: self.video_mode.monitor() }
inner: self.video_mode.monitor(),
}
} }
} }
@ -166,8 +162,6 @@ impl MonitorHandle {
/// - **Web:** Always returns an empty iterator /// - **Web:** Always returns an empty iterator
#[inline] #[inline]
pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> { pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> {
self.inner self.inner.video_modes().map(|video_mode| VideoModeHandle { video_mode })
.video_modes()
.map(|video_mode| VideoModeHandle { video_mode })
} }
} }

View file

@ -58,16 +58,19 @@
//! //!
//! ## Converting from `ndk-glue` to `android-activity` //! ## Converting from `ndk-glue` to `android-activity`
//! //!
//! If your application is currently based on `NativeActivity` via the `ndk-glue` crate and building with `cargo apk`, then the minimal changes would be: //! If your application is currently based on `NativeActivity` via the `ndk-glue` crate and building
//! with `cargo apk`, then the minimal changes would be:
//! 1. Remove `ndk-glue` from your `Cargo.toml` //! 1. Remove `ndk-glue` from your `Cargo.toml`
//! 2. Enable the `"android-native-activity"` feature for Winit: `winit = { version = "0.29.15", features = [ "android-native-activity" ] }` //! 2. Enable the `"android-native-activity"` feature for Winit: `winit = { version = "0.29.15",
//! 3. Add an `android_main` entrypoint (as above), instead of using the '`[ndk_glue::main]` proc macro from `ndk-macros` (optionally add a dependency on `android_logger` and initialize logging as above). //! features = [ "android-native-activity" ] }`
//! 4. Pass a clone of the `AndroidApp` that your application receives to Winit when building your event loop (as shown above). //! 3. Add an `android_main` entrypoint (as above), instead of using the '`[ndk_glue::main]` proc
//! macro from `ndk-macros` (optionally add a dependency on `android_logger` and initialize
//! logging as above).
//! 4. Pass a clone of the `AndroidApp` that your application receives to Winit when building your
//! event loop (as shown above).
use crate::{ use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder};
event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}, use crate::window::{Window, WindowAttributes};
window::{Window, WindowAttributes},
};
use self::activity::{AndroidApp, ConfigurationRef, Rect}; use self::activity::{AndroidApp, ConfigurationRef, Rect};
@ -146,7 +149,7 @@ impl<T> EventLoopBuilderExtAndroid for EventLoopBuilder<T> {
/// For compatibility applications should then import the `AndroidApp` type for /// For compatibility applications should then import the `AndroidApp` type for
/// their `android_main(app: AndroidApp)` function like: /// their `android_main(app: AndroidApp)` function like:
/// ```rust /// ```rust
/// #[cfg(target_os="android")] /// #[cfg(target_os = "android")]
/// use winit::platform::android::activity::AndroidApp; /// use winit::platform::android::activity::AndroidApp;
/// ``` /// ```
pub mod activity { pub mod activity {

View file

@ -66,11 +66,9 @@
use std::os::raw::c_void; use std::os::raw::c_void;
use crate::{ use crate::event_loop::EventLoop;
event_loop::EventLoop, use crate::monitor::{MonitorHandle, VideoModeHandle};
monitor::{MonitorHandle, VideoModeHandle}, use crate::window::{Window, WindowAttributes};
window::{Window, WindowAttributes},
};
/// Additional methods on [`EventLoop`] that are specific to iOS. /// Additional methods on [`EventLoop`] that are specific to iOS.
pub trait EventLoopExtIOS { pub trait EventLoopExtIOS {
@ -171,20 +169,17 @@ pub trait WindowExtIOS {
impl WindowExtIOS for Window { impl WindowExtIOS for Window {
#[inline] #[inline]
fn set_scale_factor(&self, scale_factor: f64) { fn set_scale_factor(&self, scale_factor: f64) {
self.window self.window.maybe_queue_on_main(move |w| w.set_scale_factor(scale_factor))
.maybe_queue_on_main(move |w| w.set_scale_factor(scale_factor))
} }
#[inline] #[inline]
fn set_valid_orientations(&self, valid_orientations: ValidOrientations) { fn set_valid_orientations(&self, valid_orientations: ValidOrientations) {
self.window self.window.maybe_queue_on_main(move |w| w.set_valid_orientations(valid_orientations))
.maybe_queue_on_main(move |w| w.set_valid_orientations(valid_orientations))
} }
#[inline] #[inline]
fn set_prefers_home_indicator_hidden(&self, hidden: bool) { fn set_prefers_home_indicator_hidden(&self, hidden: bool) {
self.window self.window.maybe_queue_on_main(move |w| w.set_prefers_home_indicator_hidden(hidden))
.maybe_queue_on_main(move |w| w.set_prefers_home_indicator_hidden(hidden))
} }
#[inline] #[inline]
@ -196,32 +191,27 @@ impl WindowExtIOS for Window {
#[inline] #[inline]
fn set_prefers_status_bar_hidden(&self, hidden: bool) { fn set_prefers_status_bar_hidden(&self, hidden: bool) {
self.window self.window.maybe_queue_on_main(move |w| w.set_prefers_status_bar_hidden(hidden))
.maybe_queue_on_main(move |w| w.set_prefers_status_bar_hidden(hidden))
} }
#[inline] #[inline]
fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) { fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) {
self.window self.window.maybe_queue_on_main(move |w| w.set_preferred_status_bar_style(status_bar_style))
.maybe_queue_on_main(move |w| w.set_preferred_status_bar_style(status_bar_style))
} }
#[inline] #[inline]
fn recognize_pinch_gesture(&self, should_recognize: bool) { fn recognize_pinch_gesture(&self, should_recognize: bool) {
self.window self.window.maybe_queue_on_main(move |w| w.recognize_pinch_gesture(should_recognize));
.maybe_queue_on_main(move |w| w.recognize_pinch_gesture(should_recognize));
} }
#[inline] #[inline]
fn recognize_doubletap_gesture(&self, should_recognize: bool) { fn recognize_doubletap_gesture(&self, should_recognize: bool) {
self.window self.window.maybe_queue_on_main(move |w| w.recognize_doubletap_gesture(should_recognize));
.maybe_queue_on_main(move |w| w.recognize_doubletap_gesture(should_recognize));
} }
#[inline] #[inline]
fn recognize_rotation_gesture(&self, should_recognize: bool) { fn recognize_rotation_gesture(&self, should_recognize: bool) {
self.window self.window.maybe_queue_on_main(move |w| w.recognize_rotation_gesture(should_recognize));
.maybe_queue_on_main(move |w| w.recognize_rotation_gesture(should_recognize));
} }
} }
@ -301,8 +291,7 @@ impl WindowAttributesExtIOS for WindowAttributes {
#[inline] #[inline]
fn with_preferred_screen_edges_deferring_system_gestures(mut self, edges: ScreenEdge) -> Self { fn with_preferred_screen_edges_deferring_system_gestures(mut self, edges: ScreenEdge) -> Self {
self.platform_specific self.platform_specific.preferred_screen_edges_deferring_system_gestures = edges;
.preferred_screen_edges_deferring_system_gestures = edges;
self self
} }
@ -342,9 +331,7 @@ impl MonitorHandleExtIOS for MonitorHandle {
#[inline] #[inline]
fn preferred_video_mode(&self) -> VideoModeHandle { fn preferred_video_mode(&self) -> VideoModeHandle {
VideoModeHandle { VideoModeHandle { video_mode: self.inner.preferred_video_mode() }
video_mode: self.inner.preferred_video_mode(),
}
} }
} }

View file

@ -19,11 +19,9 @@ use std::os::raw::c_void;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::event_loop::{ActiveEventLoop, EventLoopBuilder};
event_loop::{ActiveEventLoop, EventLoopBuilder}, use crate::monitor::MonitorHandle;
monitor::MonitorHandle, use crate::window::{Window, WindowAttributes};
window::{Window, WindowAttributes},
};
/// Additional methods on [`Window`] that are specific to MacOS. /// Additional methods on [`Window`] that are specific to MacOS.
pub trait WindowExtMacOS { pub trait WindowExtMacOS {
@ -106,8 +104,7 @@ impl WindowExtMacOS for Window {
#[inline] #[inline]
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool { fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
self.window self.window.maybe_wait_on_main(move |w| w.set_simple_fullscreen(fullscreen))
.maybe_wait_on_main(move |w| w.set_simple_fullscreen(fullscreen))
} }
#[inline] #[inline]
@ -117,14 +114,12 @@ impl WindowExtMacOS for Window {
#[inline] #[inline]
fn set_has_shadow(&self, has_shadow: bool) { fn set_has_shadow(&self, has_shadow: bool) {
self.window self.window.maybe_queue_on_main(move |w| w.set_has_shadow(has_shadow))
.maybe_queue_on_main(move |w| w.set_has_shadow(has_shadow))
} }
#[inline] #[inline]
fn set_tabbing_identifier(&self, identifier: &str) { fn set_tabbing_identifier(&self, identifier: &str) {
self.window self.window.maybe_wait_on_main(|w| w.set_tabbing_identifier(identifier))
.maybe_wait_on_main(|w| w.set_tabbing_identifier(identifier))
} }
#[inline] #[inline]
@ -144,8 +139,7 @@ impl WindowExtMacOS for Window {
#[inline] #[inline]
fn select_tab_at_index(&self, index: usize) { fn select_tab_at_index(&self, index: usize) {
self.window self.window.maybe_queue_on_main(move |w| w.select_tab_at_index(index))
.maybe_queue_on_main(move |w| w.select_tab_at_index(index))
} }
#[inline] #[inline]
@ -160,14 +154,12 @@ impl WindowExtMacOS for Window {
#[inline] #[inline]
fn set_document_edited(&self, edited: bool) { fn set_document_edited(&self, edited: bool) {
self.window self.window.maybe_queue_on_main(move |w| w.set_document_edited(edited))
.maybe_queue_on_main(move |w| w.set_document_edited(edited))
} }
#[inline] #[inline]
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) { fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) {
self.window self.window.maybe_queue_on_main(move |w| w.set_option_as_alt(option_as_alt))
.maybe_queue_on_main(move |w| w.set_option_as_alt(option_as_alt))
} }
#[inline] #[inline]
@ -192,7 +184,8 @@ pub enum ActivationPolicy {
/// Additional methods on [`WindowAttributes`] that are specific to MacOS. /// Additional methods on [`WindowAttributes`] that are specific to MacOS.
/// ///
/// **Note:** Properties dealing with the titlebar will be overwritten by the [`WindowAttributes::with_decorations`] method: /// **Note:** Properties dealing with the titlebar will be overwritten by the
/// [`WindowAttributes::with_decorations`] method:
/// - `with_titlebar_transparent` /// - `with_titlebar_transparent`
/// - `with_title_hidden` /// - `with_title_hidden`
/// - `with_titlebar_hidden` /// - `with_titlebar_hidden`
@ -282,9 +275,7 @@ impl WindowAttributesExtMacOS for WindowAttributes {
#[inline] #[inline]
fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> Self { fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> Self {
self.platform_specific self.platform_specific.tabbing_identifier.replace(tabbing_identifier.to_string());
.tabbing_identifier
.replace(tabbing_identifier.to_string());
self self
} }
@ -307,7 +298,7 @@ pub trait EventLoopBuilderExtMacOS {
/// ``` /// ```
/// use winit::event_loop::EventLoopBuilder; /// use winit::event_loop::EventLoopBuilder;
/// #[cfg(target_os = "macos")] /// #[cfg(target_os = "macos")]
/// use winit::platform::macos::{EventLoopBuilderExtMacOS, ActivationPolicy}; /// use winit::platform::macos::{ActivationPolicy, EventLoopBuilderExtMacOS};
/// ///
/// let mut builder = EventLoopBuilder::new(); /// let mut builder = EventLoopBuilder::new();
/// #[cfg(target_os = "macos")] /// #[cfg(target_os = "macos")]
@ -384,17 +375,17 @@ impl MonitorHandleExtMacOS for MonitorHandle {
fn ns_screen(&self) -> Option<*mut c_void> { fn ns_screen(&self) -> Option<*mut c_void> {
// SAFETY: We only use the marker to get a pointer // SAFETY: We only use the marker to get a pointer
let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() }; let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
self.inner self.inner.ns_screen(mtm).map(|s| objc2::rc::Id::as_ptr(&s) as _)
.ns_screen(mtm)
.map(|s| objc2::rc::Id::as_ptr(&s) as _)
} }
} }
/// Additional methods on [`ActiveEventLoop`] that are specific to macOS. /// Additional methods on [`ActiveEventLoop`] that are specific to macOS.
pub trait ActiveEventLoopExtMacOS { pub trait ActiveEventLoopExtMacOS {
/// Hide the entire application. In most applications this is typically triggered with Command-H. /// Hide the entire application. In most applications this is typically triggered with
/// Command-H.
fn hide_application(&self); fn hide_application(&self);
/// Hide the other applications. In most applications this is typically triggered with Command+Option-H. /// Hide the other applications. In most applications this is typically triggered with
/// Command+Option-H.
fn hide_other_applications(&self); fn hide_other_applications(&self);
/// Set whether the system can automatically organize windows into tabs. /// Set whether the system can automatically organize windows into tabs.
/// ///

View file

@ -51,11 +51,5 @@ pub mod pump_events;
))] ))]
pub mod modifier_supplement; pub mod modifier_supplement;
#[cfg(any( #[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform, docsrs))]
windows_platform,
macos_platform,
x11_platform,
wayland_platform,
docsrs
))]
pub mod scancode; pub mod scancode;

View file

@ -25,10 +25,7 @@ pub trait KeyEventExtModifierSupplement {
impl KeyEventExtModifierSupplement for KeyEvent { impl KeyEventExtModifierSupplement for KeyEvent {
#[inline] #[inline]
fn text_with_all_modifiers(&self) -> Option<&str> { fn text_with_all_modifiers(&self) -> Option<&str> {
self.platform_specific self.platform_specific.text_with_all_modifiers.as_ref().map(|s| s.as_str())
.text_with_all_modifiers
.as_ref()
.map(|s| s.as_str())
} }
#[inline] #[inline]

View file

@ -84,12 +84,11 @@ pub trait EventLoopExtPumpEvents {
/// ///
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **Windows**: The implementation will use `PeekMessage` when checking for /// - **Windows**: The implementation will use `PeekMessage` when checking for window messages
/// window messages to avoid blocking your external event loop. /// to avoid blocking your external event loop.
/// ///
/// - **MacOS**: The implementation works in terms of stopping the global application /// - **MacOS**: The implementation works in terms of stopping the global application whenever
/// whenever the application `RunLoop` indicates that it is preparing to block /// the application `RunLoop` indicates that it is preparing to block and wait for new events.
/// and wait for new events.
/// ///
/// This is very different to the polling APIs that are available on other /// This is very different to the polling APIs that are available on other
/// platforms (the lower level polling primitives on MacOS are private /// platforms (the lower level polling primitives on MacOS are private

View file

@ -21,8 +21,8 @@ pub trait EventLoopExtRunOnDemand {
/// Run the application with the event loop on the calling thread. /// Run the application with the event loop on the calling thread.
/// ///
/// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`) closures /// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`)
/// and it is possible to return control back to the caller without /// closures and it is possible to return control back to the caller without
/// consuming the `EventLoop` (by using [`exit()`]) and /// consuming the `EventLoop` (by using [`exit()`]) and
/// so the event loop can be re-run after it has exit. /// so the event loop can be re-run after it has exit.
/// ///
@ -55,17 +55,13 @@ pub trait EventLoopExtRunOnDemand {
/// - Android /// - Android
/// ///
/// # Unsupported Platforms /// # Unsupported Platforms
/// - **Web:** This API is fundamentally incompatible with the event-based way in which /// - **Web:** This API is fundamentally incompatible with the event-based way in which Web
/// Web browsers work because it's not possible to have a long-running external /// browsers work because it's not possible to have a long-running external loop that would
/// loop that would block the browser and there is nothing that can be /// block the browser and there is nothing that can be polled to ask for new events. Events
/// polled to ask for new events. Events are delivered via callbacks based /// are delivered via callbacks based on an event loop that is internal to the browser itself.
/// on an event loop that is internal to the browser itself.
/// - **iOS:** It's not possible to stop and start an `UIApplication` repeatedly on iOS. /// - **iOS:** It's not possible to stop and start an `UIApplication` repeatedly on iOS.
/// #[cfg_attr(not(web_platform), doc = "[^1]: `spawn()` is only available on `wasm` platforms.")]
#[cfg_attr( #[rustfmt::skip]
not(web_platform),
doc = "[^1]: `spawn()` is only available on `wasm` platforms."
)]
/// ///
/// [`exit()`]: ActiveEventLoop::exit() /// [`exit()`]: ActiveEventLoop::exit()
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow() /// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()

View file

@ -2,8 +2,8 @@ use crate::keyboard::{KeyCode, PhysicalKey};
// TODO: Describe what this value contains for each platform // TODO: Describe what this value contains for each platform
/// Additional methods for the [`PhysicalKey`] type that allow the user to access the platform-specific /// Additional methods for the [`PhysicalKey`] type that allow the user to access the
/// scancode. /// platform-specific scancode.
/// ///
/// [`PhysicalKey`]: crate::keyboard::PhysicalKey /// [`PhysicalKey`]: crate::keyboard::PhysicalKey
pub trait PhysicalKeyExtScancode { pub trait PhysicalKeyExtScancode {
@ -23,7 +23,7 @@ pub trait PhysicalKeyExtScancode {
/// ///
/// ## Platform-specific /// ## Platform-specific
/// - **Wayland/X11**: A 32-bit linux scancode. When building from X11/Wayland keycode subtract /// - **Wayland/X11**: A 32-bit linux scancode. When building from X11/Wayland keycode subtract
/// `8` to get the value you wanted. /// `8` to get the value you wanted.
fn from_scancode(scancode: u32) -> PhysicalKey; fn from_scancode(scancode: u32) -> PhysicalKey;
} }

View file

@ -13,11 +13,9 @@
//! * `wayland-csd-adwaita` (default). //! * `wayland-csd-adwaita` (default).
//! * `wayland-csd-adwaita-crossfont`. //! * `wayland-csd-adwaita-crossfont`.
//! * `wayland-csd-adwaita-notitle`. //! * `wayland-csd-adwaita-notitle`.
use crate::{ use crate::event_loop::{ActiveEventLoop, EventLoopBuilder};
event_loop::{ActiveEventLoop, EventLoopBuilder}, use crate::monitor::MonitorHandle;
monitor::MonitorHandle, use crate::window::{Window, WindowAttributes};
window::{Window, WindowAttributes},
};
pub use crate::window::Theme; pub use crate::window::Theme;
@ -80,10 +78,8 @@ pub trait WindowAttributesExtWayland {
impl WindowAttributesExtWayland for WindowAttributes { impl WindowAttributesExtWayland for WindowAttributes {
#[inline] #[inline]
fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self { fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
self.platform_specific.name = Some(crate::platform_impl::ApplicationName::new( self.platform_specific.name =
general.into(), Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into()));
instance.into(),
));
self self
} }
} }

View file

@ -30,8 +30,8 @@
//! The following APIs can't take them into account and will therefore provide inaccurate results: //! The following APIs can't take them into account and will therefore provide inaccurate results:
//! - [`WindowEvent::Resized`] and [`Window::(set_)inner_size()`] //! - [`WindowEvent::Resized`] and [`Window::(set_)inner_size()`]
//! - [`WindowEvent::Occluded`] //! - [`WindowEvent::Occluded`]
//! - [`WindowEvent::CursorMoved`], [`WindowEvent::CursorEntered`], [`WindowEvent::CursorLeft`], //! - [`WindowEvent::CursorMoved`], [`WindowEvent::CursorEntered`], [`WindowEvent::CursorLeft`], and
//! and [`WindowEvent::Touch`]. //! [`WindowEvent::Touch`].
//! - [`Window::set_outer_position()`] //! - [`Window::set_outer_position()`]
//! //!
//! [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized //! [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized
@ -109,11 +109,7 @@ pub trait WindowAttributesExtWebSys {
/// In any case, the canvas won't be automatically inserted into the web page. /// In any case, the canvas won't be automatically inserted into the web page.
/// ///
/// [`None`] by default. /// [`None`] by default.
#[cfg_attr( #[cfg_attr(not(web_platform), doc = "", doc = "[`HtmlCanvasElement`]: #only-available-on-wasm")]
not(web_platform),
doc = "",
doc = "[`HtmlCanvasElement`]: #only-available-on-wasm"
)]
fn with_canvas(self, canvas: Option<HtmlCanvasElement>) -> Self; fn with_canvas(self, canvas: Option<HtmlCanvasElement>) -> Self;
/// Sets whether `event.preventDefault()` should be called on events on the /// Sets whether `event.preventDefault()` should be called on events on the
@ -166,10 +162,7 @@ pub trait EventLoopExtWebSys {
/// Initializes the winit event loop. /// Initializes the winit event loop.
/// ///
/// Unlike /// Unlike
#[cfg_attr( #[cfg_attr(all(web_platform, target_feature = "exception-handling"), doc = "`run_app()`")]
all(web_platform, target_feature = "exception-handling"),
doc = "`run_app()`"
)]
#[cfg_attr( #[cfg_attr(
not(all(web_platform, target_feature = "exception-handling")), not(all(web_platform, target_feature = "exception-handling")),
doc = "[`run_app()`]" doc = "[`run_app()`]"
@ -181,6 +174,7 @@ pub trait EventLoopExtWebSys {
/// by calling this function again. This can be useful if you want to recreate the event loop /// by calling this function again. This can be useful if you want to recreate the event loop
/// while the WebAssembly module is still loaded. For example, this can be used to recreate the /// while the WebAssembly module is still loaded. For example, this can be used to recreate the
/// event loop when switching between tabs on a single page application. /// event loop when switching between tabs on a single page application.
#[rustfmt::skip]
/// ///
#[cfg_attr( #[cfg_attr(
not(all(web_platform, target_feature = "exception-handling")), not(all(web_platform, target_feature = "exception-handling")),
@ -303,13 +297,7 @@ impl CustomCursorExtWebSys for CustomCursor {
} }
fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> CustomCursorSource { fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> CustomCursorSource {
CustomCursorSource { CustomCursorSource { inner: PlatformCustomCursorSource::Url { url, hotspot_x, hotspot_y } }
inner: PlatformCustomCursorSource::Url {
url,
hotspot_x,
hotspot_y,
},
}
} }
fn from_animation( fn from_animation(
@ -360,9 +348,7 @@ impl Future for CustomCursorFuture {
type Output = Result<CustomCursor, CustomCursorError>; type Output = Result<CustomCursor, CustomCursorError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.0) Pin::new(&mut self.0).poll(cx).map_ok(|cursor| CustomCursor { inner: cursor })
.poll(cx)
.map_ok(|cursor| CustomCursor { inner: cursor })
} }
} }
@ -378,10 +364,9 @@ impl Display for CustomCursorError {
match self { match self {
Self::Blob => write!(f, "failed to create `Blob`"), Self::Blob => write!(f, "failed to create `Blob`"),
Self::Decode(error) => write!(f, "failed to decode image: {error}"), Self::Decode(error) => write!(f, "failed to decode image: {error}"),
Self::Animation => write!( Self::Animation => {
f, write!(f, "found `CustomCursor` that is an animation when building an animation")
"found `CustomCursor` that is an animation when building an animation" },
),
} }
} }
} }

View file

@ -2,15 +2,14 @@
//! //!
//! The supported OS version is Windows 7 or higher, though Windows 10 is //! The supported OS version is Windows 7 or higher, though Windows 10 is
//! tested regularly. //! tested regularly.
use std::{ffi::c_void, path::Path}; use std::ffi::c_void;
use std::path::Path;
use crate::{ use crate::dpi::PhysicalSize;
dpi::PhysicalSize, use crate::event::DeviceId;
event::DeviceId, use crate::event_loop::EventLoopBuilder;
event_loop::EventLoopBuilder, use crate::monitor::MonitorHandle;
monitor::MonitorHandle, use crate::window::{BadIcon, Icon, Window, WindowAttributes};
window::{BadIcon, Icon, Window, WindowAttributes},
};
/// Window Handle type used by Win32 API /// Window Handle type used by Win32 API
pub type HWND = isize; pub type HWND = isize;
@ -57,11 +56,11 @@ pub enum BackdropType {
pub struct Color(u32); pub struct Color(u32);
impl Color { impl Color {
// Special constant only valid for the window border and therefore modeled using Option<Color>
// for user facing code
const NONE: Color = Color(0xfffffffe);
/// Use the system's default color /// Use the system's default color
pub const SYSTEM_DEFAULT: Color = Color(0xFFFFFFFF); pub const SYSTEM_DEFAULT: Color = Color(0xffffffff);
//Special constant only valid for the window border and therefore modeled using Option<Color> for user facing code
const NONE: Color = Color(0xFFFFFFFE);
/// Create a new color from the given RGB values /// Create a new color from the given RGB values
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self { pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
@ -202,8 +201,8 @@ pub trait WindowExtWindows {
/// ///
/// A window must be enabled before it can be activated. /// A window must be enabled before it can be activated.
/// If an application has create a modal dialog box by disabling its owner window /// If an application has create a modal dialog box by disabling its owner window
/// (as described in [`WindowAttributesExtWindows::with_owner_window`]), the application must enable /// (as described in [`WindowAttributesExtWindows::with_owner_window`]), the application must
/// the owner window before destroying the dialog box. /// enable the owner window before destroying the dialog box.
/// Otherwise, another window will receive the keyboard focus and be activated. /// Otherwise, another window will receive the keyboard focus and be activated.
/// ///
/// If a child window is disabled, it is ignored when the system tries to determine which /// If a child window is disabled, it is ignored when the system tries to determine which
@ -283,10 +282,10 @@ impl WindowExtWindows for Window {
#[inline] #[inline]
fn set_title_background_color(&self, color: Option<Color>) { fn set_title_background_color(&self, color: Option<Color>) {
// The windows docs don't mention NONE as a valid options but it works in practice and is useful // The windows docs don't mention NONE as a valid options but it works in practice and is
// to circumvent the Windows option "Show accent color on title bars and window borders" // useful to circumvent the Windows option "Show accent color on title bars and
self.window // window borders"
.set_title_background_color(color.unwrap_or(Color::NONE)) self.window.set_title_background_color(color.unwrap_or(Color::NONE))
} }
#[inline] #[inline]
@ -305,8 +304,9 @@ impl WindowExtWindows for Window {
pub trait WindowAttributesExtWindows { pub trait WindowAttributesExtWindows {
/// Set an owner to the window to be created. Can be used to create a dialog box, for example. /// Set an owner to the window to be created. Can be used to create a dialog box, for example.
/// This only works when [`WindowAttributes::with_parent_window`] isn't called or set to `None`. /// This only works when [`WindowAttributes::with_parent_window`] isn't called or set to `None`.
/// Can be used in combination with [`WindowExtWindows::set_enable(false)`][WindowExtWindows::set_enable] /// Can be used in combination with
/// on the owner window to create a modal dialog box. /// [`WindowExtWindows::set_enable(false)`][WindowExtWindows::set_enable] on the owner
/// window to create a modal dialog box.
/// ///
/// From MSDN: /// From MSDN:
/// - An owned window is always above its owner in the z-order. /// - An owned window is always above its owner in the z-order.
@ -322,17 +322,14 @@ pub trait WindowAttributesExtWindows {
/// ///
/// The menu must have been manually created beforehand with [`CreateMenu`] or similar. /// The menu must have been manually created beforehand with [`CreateMenu`] or similar.
/// ///
/// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look. /// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how
/// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect. /// the menus look. If you use this, it is recommended that you combine it with
/// /// `with_theme(Some(Theme::Light))` to avoid a jarring effect.
#[cfg_attr( #[cfg_attr(
platform_windows, platform_windows,
doc = "[`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu" doc = "[`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu"
)] )]
#[cfg_attr( #[cfg_attr(not(platform_windows), doc = "[`CreateMenu`]: #only-available-on-windows")]
not(platform_windows),
doc = "[`CreateMenu`]: #only-available-on-windows"
)]
fn with_menu(self, menu: HMENU) -> Self; fn with_menu(self, menu: HMENU) -> Self;
/// This sets `ICON_BIG`. A good ceiling here is 256x256. /// This sets `ICON_BIG`. A good ceiling here is 256x256.
@ -341,12 +338,12 @@ pub trait WindowAttributesExtWindows {
/// This sets `WS_EX_NOREDIRECTIONBITMAP`. /// This sets `WS_EX_NOREDIRECTIONBITMAP`.
fn with_no_redirection_bitmap(self, flag: bool) -> Self; fn with_no_redirection_bitmap(self, flag: bool) -> Self;
/// Enables or disables drag and drop support (enabled by default). Will interfere with other crates /// Enables or disables drag and drop support (enabled by default). Will interfere with other
/// that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED` instead of /// crates that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED`
/// `COINIT_APARTMENTTHREADED`) on the same thread. Note that winit may still attempt to initialize /// instead of `COINIT_APARTMENTTHREADED`) on the same thread. Note that winit may still
/// COM API regardless of this option. Currently only fullscreen mode does that, but there may be more in the future. /// attempt to initialize COM API regardless of this option. Currently only fullscreen mode
/// If you need COM API with `COINIT_MULTITHREADED` you must initialize it before calling any winit functions. /// does that, but there may be more in the future. If you need COM API with
/// See <https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize#remarks> for more information. /// `COINIT_MULTITHREADED` you must initialize it before calling any winit functions. See <https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize#remarks> for more information.
fn with_drag_and_drop(self, flag: bool) -> Self; fn with_drag_and_drop(self, flag: bool) -> Self;
/// Whether show or hide the window icon in the taskbar. /// Whether show or hide the window icon in the taskbar.

View file

@ -2,11 +2,9 @@
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::event_loop::{ActiveEventLoop, EventLoopBuilder};
event_loop::{ActiveEventLoop, EventLoopBuilder}, use crate::monitor::MonitorHandle;
monitor::MonitorHandle, use crate::window::{Window, WindowAttributes};
window::{Window, WindowAttributes},
};
use crate::dpi::Size; use crate::dpi::Size;
@ -15,11 +13,12 @@ use crate::dpi::Size;
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum WindowType { pub enum WindowType {
/// A desktop feature. This can include a single window containing desktop icons with the same dimensions as the /// A desktop feature. This can include a single window containing desktop icons with the same
/// screen, allowing the desktop environment to have full control of the desktop, without the need for proxying /// dimensions as the screen, allowing the desktop environment to have full control of the
/// root window clicks. /// desktop, without the need for proxying root window clicks.
Desktop, Desktop,
/// A dock or panel feature. Typically a Window Manager would keep such windows on top of all other windows. /// A dock or panel feature. Typically a Window Manager would keep such windows on top of all
/// other windows.
Dock, Dock,
/// Toolbar windows. "Torn off" from the main application. /// Toolbar windows. "Torn off" from the main application.
Toolbar, Toolbar,
@ -37,8 +36,8 @@ pub enum WindowType {
/// A popup menu that usually appears when the user right clicks on an object. /// A popup menu that usually appears when the user right clicks on an object.
/// This property is typically used on override-redirect windows. /// This property is typically used on override-redirect windows.
PopupMenu, PopupMenu,
/// A tooltip window. Usually used to show additional information when hovering over an object with the cursor. /// A tooltip window. Usually used to show additional information when hovering over an object
/// This property is typically used on override-redirect windows. /// with the cursor. This property is typically used on override-redirect windows.
Tooltip, Tooltip,
/// The window is a notification. /// The window is a notification.
/// This property is typically used on override-redirect windows. /// This property is typically used on override-redirect windows.
@ -83,10 +82,7 @@ pub type XWindow = u32;
pub fn register_xlib_error_hook(hook: XlibErrorHook) { pub fn register_xlib_error_hook(hook: XlibErrorHook) {
// Append new hook. // Append new hook.
unsafe { unsafe {
crate::platform_impl::XLIB_ERROR_HOOKS crate::platform_impl::XLIB_ERROR_HOOKS.lock().unwrap().push(hook);
.lock()
.unwrap()
.push(hook);
} }
} }
@ -144,7 +140,8 @@ pub trait WindowAttributesExtX11 {
/// Build window with the given `general` and `instance` names. /// Build window with the given `general` and `instance` names.
/// ///
/// The `general` sets general class of `WM_CLASS(STRING)`, while `instance` set the /// The `general` sets general class of `WM_CLASS(STRING)`, while `instance` set the
/// instance part of it. The resulted property looks like `WM_CLASS(STRING) = "instance", "general"`. /// instance part of it. The resulted property looks like `WM_CLASS(STRING) = "instance",
/// "general"`.
/// ///
/// For details about application ID conventions, see the /// For details about application ID conventions, see the
/// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
@ -202,10 +199,8 @@ impl WindowAttributesExtX11 for WindowAttributes {
#[inline] #[inline]
fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self { fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
self.platform_specific.name = Some(crate::platform_impl::ApplicationName::new( self.platform_specific.name =
general.into(), Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into()));
instance.into(),
));
self self
} }

View file

@ -1,7 +1,5 @@
use android_activity::{ use android_activity::input::{KeyAction, KeyEvent, KeyMapChar, Keycode};
input::{KeyAction, KeyEvent, KeyMapChar, Keycode}, use android_activity::AndroidApp;
AndroidApp,
};
use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey}; use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey};
@ -105,7 +103,7 @@ pub fn to_physical_key(keycode: Keycode) -> PhysicalKey {
Keycode::VolumeUp => KeyCode::AudioVolumeUp, Keycode::VolumeUp => KeyCode::AudioVolumeUp,
Keycode::VolumeDown => KeyCode::AudioVolumeDown, Keycode::VolumeDown => KeyCode::AudioVolumeDown,
Keycode::VolumeMute => KeyCode::AudioVolumeMute, Keycode::VolumeMute => KeyCode::AudioVolumeMute,
//Keycode::Mute => None, // Microphone mute // Keycode::Mute => None, // Microphone mute
Keycode::MediaPlayPause => KeyCode::MediaPlayPause, Keycode::MediaPlayPause => KeyCode::MediaPlayPause,
Keycode::MediaStop => KeyCode::MediaStop, Keycode::MediaStop => KeyCode::MediaStop,
Keycode::MediaNext => KeyCode::MediaTrackNext, Keycode::MediaNext => KeyCode::MediaTrackNext,
@ -176,7 +174,7 @@ pub fn character_map_and_combine_key(
Err(err) => { Err(err) => {
tracing::warn!("Failed to look up `KeyCharacterMap` for device {device_id}: {err:?}"); tracing::warn!("Failed to look up `KeyCharacterMap` for device {device_id}: {err:?}");
return None; return None;
} },
}; };
match key_map.get(key_event.key_code(), key_event.meta_state()) { match key_map.get(key_event.key_code(), key_event.meta_state()) {
@ -188,9 +186,12 @@ pub fn character_map_and_combine_key(
Ok(Some(key)) => Some(key), Ok(Some(key)) => Some(key),
Ok(None) => None, Ok(None) => None,
Err(err) => { Err(err) => {
tracing::warn!("KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}"); tracing::warn!(
"KeyEvent: Failed to combine 'dead key' accent '{accent}' with \
'{unicode}': {err:?}"
);
None None
} },
} }
} else { } else {
Some(unicode) Some(unicode)
@ -200,23 +201,23 @@ pub fn character_map_and_combine_key(
} else { } else {
Some(KeyMapChar::Unicode(unicode)) Some(KeyMapChar::Unicode(unicode))
} }
} },
Ok(KeyMapChar::CombiningAccent(accent)) => { Ok(KeyMapChar::CombiningAccent(accent)) => {
if key_event.action() == KeyAction::Down { if key_event.action() == KeyAction::Down {
*combining_accent = Some(accent); *combining_accent = Some(accent);
} }
Some(KeyMapChar::CombiningAccent(accent)) Some(KeyMapChar::CombiningAccent(accent))
} },
Ok(KeyMapChar::None) => { Ok(KeyMapChar::None) => {
// Leave any combining_accent state in tact (seems to match how other // Leave any combining_accent state in tact (seems to match how other
// Android apps work) // Android apps work)
None None
} },
Err(err) => { Err(err) => {
tracing::warn!("KeyEvent: Failed to get key map character: {err:?}"); tracing::warn!("KeyEvent: Failed to get key map character: {err:?}");
*combining_accent = None; *combining_accent = None;
None None
} },
} }
} }

View file

@ -1,16 +1,12 @@
#![cfg(android_platform)] #![cfg(android_platform)]
use std::{ use std::cell::Cell;
cell::Cell, use std::collections::VecDeque;
collections::VecDeque, use std::hash::Hash;
hash::Hash, use std::marker::PhantomData;
marker::PhantomData, use std::sync::atomic::{AtomicBool, Ordering};
sync::{ use std::sync::{mpsc, Arc, Mutex};
atomic::{AtomicBool, Ordering}, use std::time::{Duration, Instant};
mpsc, Arc, Mutex,
},
time::{Duration, Instant},
};
use android_activity::input::{InputEvent, KeyAction, Keycode, MotionAction}; use android_activity::input::{InputEvent, KeyAction, Keycode, MotionAction};
use android_activity::{ use android_activity::{
@ -18,24 +14,24 @@ use android_activity::{
}; };
use tracing::{debug, trace, warn}; use tracing::{debug, trace, warn};
use crate::{ use crate::cursor::Cursor;
cursor::Cursor, use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
dpi::{PhysicalPosition, PhysicalSize, Position, Size}, use crate::error;
error, use crate::error::EventLoopError;
event::{self, Force, InnerSizeWriter, StartCause}, use crate::event::{self, Force, InnerSizeWriter, StartCause};
event_loop::{self, ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents}, use crate::event_loop::{self, ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents};
platform::pump_events::PumpStatus, use crate::platform::pump_events::PumpStatus;
window::{ use crate::platform_impl::Fullscreen;
self, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose, ResizeDirection, Theme, use crate::window::{
WindowButtons, WindowLevel, self, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose, ResizeDirection, Theme,
}, WindowButtons, WindowLevel,
}; };
use crate::{error::EventLoopError, platform_impl::Fullscreen};
mod keycodes; mod keycodes;
pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursor; pub(crate) use crate::cursor::{
pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorSource; NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource,
};
pub(crate) use crate::icon::NoIcon as PlatformIcon; pub(crate) use crate::icon::NoIcon as PlatformIcon;
static HAS_FOCUS: AtomicBool = AtomicBool::new(true); static HAS_FOCUS: AtomicBool = AtomicBool::new(true);
@ -44,9 +40,7 @@ static HAS_FOCUS: AtomicBool = AtomicBool::new(true);
/// equates to an infinite timeout, not a zero timeout (so can't just use /// equates to an infinite timeout, not a zero timeout (so can't just use
/// `Option::min`) /// `Option::min`)
fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> { fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
a.map_or(b, |a_timeout| { a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))
})
} }
struct PeekableReceiver<T> { struct PeekableReceiver<T> {
@ -58,6 +52,7 @@ impl<T> PeekableReceiver<T> {
pub fn from_recv(recv: mpsc::Receiver<T>) -> Self { pub fn from_recv(recv: mpsc::Receiver<T>) -> Self {
Self { recv, first: None } Self { recv, first: None }
} }
pub fn has_incoming(&mut self) -> bool { pub fn has_incoming(&mut self) -> bool {
if self.first.is_some() { if self.first.is_some() {
return true; return true;
@ -66,14 +61,15 @@ impl<T> PeekableReceiver<T> {
Ok(v) => { Ok(v) => {
self.first = Some(v); self.first = Some(v);
true true
} },
Err(mpsc::TryRecvError::Empty) => false, Err(mpsc::TryRecvError::Empty) => false,
Err(mpsc::TryRecvError::Disconnected) => { Err(mpsc::TryRecvError::Disconnected) => {
warn!("Channel was disconnected when checking incoming"); warn!("Channel was disconnected when checking incoming");
false false
} },
} }
} }
pub fn try_recv(&mut self) -> Result<T, mpsc::TryRecvError> { pub fn try_recv(&mut self) -> Result<T, mpsc::TryRecvError> {
if let Some(first) = self.first.take() { if let Some(first) = self.first.take() {
return Ok(first); return Ok(first);
@ -88,9 +84,7 @@ struct SharedFlagSetter {
} }
impl SharedFlagSetter { impl SharedFlagSetter {
pub fn set(&self) -> bool { pub fn set(&self) -> bool {
self.flag self.flag.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed).is_ok()
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
.is_ok()
} }
} }
@ -104,15 +98,13 @@ struct SharedFlag {
// was queued and be able to read and clear the state atomically) // was queued and be able to read and clear the state atomically)
impl SharedFlag { impl SharedFlag {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self { flag: Arc::new(AtomicBool::new(false)) }
flag: Arc::new(AtomicBool::new(false)),
}
} }
pub fn setter(&self) -> SharedFlagSetter { pub fn setter(&self) -> SharedFlagSetter {
SharedFlagSetter { SharedFlagSetter { flag: self.flag.clone() }
flag: self.flag.clone(),
}
} }
pub fn get_and_reset(&self) -> bool { pub fn get_and_reset(&self) -> bool {
self.flag.swap(false, std::sync::atomic::Ordering::AcqRel) self.flag.swap(false, std::sync::atomic::Ordering::AcqRel)
} }
@ -126,11 +118,9 @@ pub struct RedrawRequester {
impl RedrawRequester { impl RedrawRequester {
fn new(flag: &SharedFlag, waker: AndroidAppWaker) -> Self { fn new(flag: &SharedFlag, waker: AndroidAppWaker) -> Self {
RedrawRequester { RedrawRequester { flag: flag.setter(), waker }
flag: flag.setter(),
waker,
}
} }
pub fn request_redraw(&self) { pub fn request_redraw(&self) {
if self.flag.set() { if self.flag.set() {
// Only explicitly try to wake up the main loop when the flag // Only explicitly try to wake up the main loop when the flag
@ -148,7 +138,7 @@ pub struct EventLoop<T: 'static> {
window_target: event_loop::ActiveEventLoop, window_target: event_loop::ActiveEventLoop,
redraw_flag: SharedFlag, redraw_flag: SharedFlag,
user_events_sender: mpsc::Sender<T>, user_events_sender: mpsc::Sender<T>,
user_events_receiver: PeekableReceiver<T>, //must wake looper whenever something gets sent user_events_receiver: PeekableReceiver<T>, // must wake looper whenever something gets sent
loop_running: bool, // Dispatched `NewEvents<Init>` loop_running: bool, // Dispatched `NewEvents<Init>`
running: bool, running: bool,
pending_redraw: bool, pending_redraw: bool,
@ -165,10 +155,7 @@ pub(crate) struct PlatformSpecificEventLoopAttributes {
impl Default for PlatformSpecificEventLoopAttributes { impl Default for PlatformSpecificEventLoopAttributes {
fn default() -> Self { fn default() -> Self {
Self { Self { android_app: Default::default(), ignore_volume_keys: true }
android_app: Default::default(),
ignore_volume_keys: true,
}
} }
} }
@ -178,7 +165,10 @@ impl<T: 'static> EventLoop<T> {
) -> Result<Self, EventLoopError> { ) -> Result<Self, EventLoopError> {
let (user_events_sender, user_events_receiver) = mpsc::channel(); let (user_events_sender, user_events_receiver) = mpsc::channel();
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 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(); let redraw_flag = SharedFlag::new();
Ok(Self { Ok(Self {
@ -225,15 +215,15 @@ impl<T: 'static> EventLoop<T> {
match event { match event {
MainEvent::InitWindow { .. } => { MainEvent::InitWindow { .. } => {
callback(event::Event::Resumed, self.window_target()); callback(event::Event::Resumed, self.window_target());
} },
MainEvent::TerminateWindow { .. } => { MainEvent::TerminateWindow { .. } => {
callback(event::Event::Suspended, self.window_target()); callback(event::Event::Suspended, self.window_target());
} },
MainEvent::WindowResized { .. } => resized = true, MainEvent::WindowResized { .. } => resized = true,
MainEvent::RedrawNeeded { .. } => pending_redraw = true, MainEvent::RedrawNeeded { .. } => pending_redraw = true,
MainEvent::ContentRectChanged { .. } => { MainEvent::ContentRectChanged { .. } => {
warn!("TODO: find a way to notify application of content rect change"); warn!("TODO: find a way to notify application of content rect change");
} },
MainEvent::GainedFocus => { MainEvent::GainedFocus => {
HAS_FOCUS.store(true, Ordering::Relaxed); HAS_FOCUS.store(true, Ordering::Relaxed);
callback( callback(
@ -243,7 +233,7 @@ impl<T: 'static> EventLoop<T> {
}, },
self.window_target(), self.window_target(),
); );
} },
MainEvent::LostFocus => { MainEvent::LostFocus => {
HAS_FOCUS.store(false, Ordering::Relaxed); HAS_FOCUS.store(false, Ordering::Relaxed);
callback( callback(
@ -253,7 +243,7 @@ impl<T: 'static> EventLoop<T> {
}, },
self.window_target(), self.window_target(),
); );
} },
MainEvent::ConfigChanged { .. } => { MainEvent::ConfigChanged { .. } => {
let monitor = MonitorHandle::new(self.android_app.clone()); let monitor = MonitorHandle::new(self.android_app.clone());
let old_scale_factor = monitor.scale_factor(); let old_scale_factor = monitor.scale_factor();
@ -273,43 +263,43 @@ impl<T: 'static> EventLoop<T> {
}; };
callback(event, self.window_target()); callback(event, self.window_target());
} }
} },
MainEvent::LowMemory => { MainEvent::LowMemory => {
callback(event::Event::MemoryWarning, self.window_target()); callback(event::Event::MemoryWarning, self.window_target());
} },
MainEvent::Start => { MainEvent::Start => {
// XXX: how to forward this state to applications? // XXX: how to forward this state to applications?
warn!("TODO: forward onStart notification to application"); warn!("TODO: forward onStart notification to application");
} },
MainEvent::Resume { .. } => { MainEvent::Resume { .. } => {
debug!("App Resumed - is running"); debug!("App Resumed - is running");
self.running = true; self.running = true;
} },
MainEvent::SaveState { .. } => { MainEvent::SaveState { .. } => {
// XXX: how to forward this state to applications? // XXX: how to forward this state to applications?
// XXX: also how do we expose state restoration to apps? // XXX: also how do we expose state restoration to apps?
warn!("TODO: forward saveState notification to application"); warn!("TODO: forward saveState notification to application");
} },
MainEvent::Pause => { MainEvent::Pause => {
debug!("App Paused - stopped running"); debug!("App Paused - stopped running");
self.running = false; self.running = false;
} },
MainEvent::Stop => { MainEvent::Stop => {
// XXX: how to forward this state to applications? // XXX: how to forward this state to applications?
warn!("TODO: forward onStop notification to application"); warn!("TODO: forward onStop notification to application");
} },
MainEvent::Destroy => { MainEvent::Destroy => {
// XXX: maybe exit mainloop to drop things before being // XXX: maybe exit mainloop to drop things before being
// killed by the OS? // killed by the OS?
warn!("TODO: forward onDestroy notification to application"); warn!("TODO: forward onDestroy notification to application");
} },
MainEvent::InsetsChanged { .. } => { MainEvent::InsetsChanged { .. } => {
// XXX: how to forward this state to applications? // XXX: how to forward this state to applications?
warn!("TODO: handle Android InsetsChanged notification"); warn!("TODO: handle Android InsetsChanged notification");
} },
unknown => { unknown => {
trace!("Unknown MainEvent {unknown:?} (ignored)"); trace!("Unknown MainEvent {unknown:?} (ignored)");
} },
} }
} else { } else {
trace!("No main event to handle"); trace!("No main event to handle");
@ -331,7 +321,7 @@ impl<T: 'static> EventLoop<T> {
}, },
Err(err) => { Err(err) => {
tracing::warn!("Failed to get input events iterator: {err:?}"); tracing::warn!("Failed to get input events iterator: {err:?}");
} },
} }
// Empty the user event buffer // Empty the user event buffer
@ -392,13 +382,13 @@ impl<T: 'static> EventLoop<T> {
let phase = match motion_event.action() { let phase = match motion_event.action() {
MotionAction::Down | MotionAction::PointerDown => { MotionAction::Down | MotionAction::PointerDown => {
Some(event::TouchPhase::Started) Some(event::TouchPhase::Started)
} },
MotionAction::Up | MotionAction::PointerUp => Some(event::TouchPhase::Ended), MotionAction::Up | MotionAction::PointerUp => Some(event::TouchPhase::Ended),
MotionAction::Move => Some(event::TouchPhase::Moved), MotionAction::Move => Some(event::TouchPhase::Moved),
MotionAction::Cancel => Some(event::TouchPhase::Cancelled), MotionAction::Cancel => Some(event::TouchPhase::Cancelled),
_ => { _ => {
None // TODO mouse events None // TODO mouse events
} },
}; };
if let Some(phase) = phase { if let Some(phase) = phase {
let pointers: Box<dyn Iterator<Item = android_activity::input::Pointer<'_>>> = let pointers: Box<dyn Iterator<Item = android_activity::input::Pointer<'_>>> =
@ -407,18 +397,19 @@ impl<T: 'static> EventLoop<T> {
Box::new(std::iter::once( Box::new(std::iter::once(
motion_event.pointer_at_index(motion_event.pointer_index()), motion_event.pointer_at_index(motion_event.pointer_index()),
)) ))
} },
event::TouchPhase::Moved | event::TouchPhase::Cancelled => { event::TouchPhase::Moved | event::TouchPhase::Cancelled => {
Box::new(motion_event.pointers()) Box::new(motion_event.pointers())
} },
}; };
for pointer in pointers { for pointer in pointers {
let location = PhysicalPosition { let location =
x: pointer.x() as _, PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ };
y: pointer.y() as _, trace!(
}; "Input event {device_id:?}, {phase:?}, loc={location:?}, \
trace!("Input event {device_id:?}, {phase:?}, loc={location:?}, pointer={pointer:?}"); pointer={pointer:?}"
);
let event = event::Event::WindowEvent { let event = event::Event::WindowEvent {
window_id, window_id,
event: event::WindowEvent::Touch(event::Touch { event: event::WindowEvent::Touch(event::Touch {
@ -432,17 +423,18 @@ impl<T: 'static> EventLoop<T> {
callback(event, self.window_target()); callback(event, self.window_target());
} }
} }
} },
InputEvent::KeyEvent(key) => { InputEvent::KeyEvent(key) => {
match key.key_code() { match key.key_code() {
// Flag keys related to volume as unhandled. While winit does not have a way for applications // Flag keys related to volume as unhandled. While winit does not have a way for
// to configure what keys to flag as handled, this appears to be a good default until winit // applications to configure what keys to flag as handled,
// this appears to be a good default until winit
// can be configured. // can be configured.
Keycode::VolumeUp | Keycode::VolumeDown | Keycode::VolumeMute Keycode::VolumeUp | Keycode::VolumeDown | Keycode::VolumeMute
if self.ignore_volume_keys => if self.ignore_volume_keys =>
{ {
input_status = InputStatus::Unhandled input_status = InputStatus::Unhandled
} },
keycode => { keycode => {
let state = match key.action() { let state = match key.action() {
KeyAction::Down => event::ElementState::Pressed, KeyAction::Down => event::ElementState::Pressed,
@ -473,12 +465,12 @@ impl<T: 'static> EventLoop<T> {
}, },
}; };
callback(event, self.window_target()); callback(event, self.window_target());
} },
} }
} },
_ => { _ => {
warn!("Unknown android_activity input event {event:?}") warn!("Unknown android_activity input event {event:?}")
} },
} }
input_status input_status
@ -499,13 +491,13 @@ impl<T: 'static> EventLoop<T> {
match self.pump_events(None, &mut event_handler) { match self.pump_events(None, &mut event_handler) {
PumpStatus::Exit(0) => { PumpStatus::Exit(0) => {
break Ok(()); break Ok(());
} },
PumpStatus::Exit(code) => { PumpStatus::Exit(code) => {
break Err(EventLoopError::ExitFailure(code)); break Err(EventLoopError::ExitFailure(code));
} },
_ => { _ => {
continue; continue;
} },
} }
} }
} }
@ -561,7 +553,7 @@ impl<T: 'static> EventLoop<T> {
ControlFlow::Poll => Some(Duration::ZERO), ControlFlow::Poll => Some(Duration::ZERO),
ControlFlow::WaitUntil(wait_deadline) => { ControlFlow::WaitUntil(wait_deadline) => {
Some(wait_deadline.saturating_duration_since(start)) Some(wait_deadline.saturating_duration_since(start))
} },
}; };
min_timeout(control_flow_timeout, timeout) min_timeout(control_flow_timeout, timeout)
@ -574,8 +566,9 @@ impl<T: 'static> EventLoop<T> {
match poll_event { match poll_event {
android_activity::PollEvent::Wake => { android_activity::PollEvent::Wake => {
// In the X11 backend it's noted that too many false-positive wake ups // 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 // would cause the event loop to run continuously. They handle this by
// for pending events (assuming they cover all valid reasons for a wake up). // 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 // 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. // a wake up here so we can ignore the wake up if there are no events/requests.
@ -586,35 +579,26 @@ impl<T: 'static> EventLoop<T> {
{ {
return; return;
} }
} },
android_activity::PollEvent::Timeout => {} android_activity::PollEvent::Timeout => {},
android_activity::PollEvent::Main(event) => { android_activity::PollEvent::Main(event) => {
main_event = Some(event); main_event = Some(event);
} },
unknown_event => { unknown_event => {
warn!("Unknown poll event {unknown_event:?} (ignored)"); warn!("Unknown poll event {unknown_event:?} (ignored)");
} },
} }
self.cause = match self.control_flow() { self.cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll, ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled { ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
start,
requested_resume: None,
},
ControlFlow::WaitUntil(deadline) => { ControlFlow::WaitUntil(deadline) => {
if Instant::now() < deadline { if Instant::now() < deadline {
StartCause::WaitCancelled { StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
start,
requested_resume: Some(deadline),
}
} else { } else {
StartCause::ResumeTimeReached { StartCause::ResumeTimeReached { start, requested_resume: deadline }
start,
requested_resume: deadline,
}
} }
} },
}; };
self.single_iteration(main_event, &mut callback); self.single_iteration(main_event, &mut callback);
@ -657,9 +641,7 @@ impl<T: 'static> Clone for EventLoopProxy<T> {
impl<T> EventLoopProxy<T> { impl<T> EventLoopProxy<T> {
pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> { pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> {
self.user_events_sender self.user_events_sender.send(event).map_err(|err| event_loop::EventLoopClosed(err.0))?;
.send(event)
.map_err(|err| event_loop::EventLoopClosed(err.0))?;
self.waker.wake(); self.waker.wake();
Ok(()) Ok(())
} }
@ -679,9 +661,7 @@ impl ActiveEventLoop {
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor { pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor {
let _ = source.inner; let _ = source.inner;
CustomCursor { CustomCursor { inner: PlatformCustomCursor }
inner: PlatformCustomCursor,
}
} }
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> { pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
@ -704,9 +684,7 @@ impl ActiveEventLoop {
pub fn raw_display_handle_rwh_06( pub fn raw_display_handle_rwh_06(
&self, &self,
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> { ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
Ok(rwh_06::RawDisplayHandle::Android( Ok(rwh_06::RawDisplayHandle::Android(rwh_06::AndroidDisplayHandle::new()))
rwh_06::AndroidDisplayHandle::new(),
))
} }
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) { pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
@ -798,10 +776,7 @@ impl Window {
) -> Result<Self, error::OsError> { ) -> Result<Self, error::OsError> {
// FIXME this ignores requested window attributes // FIXME this ignores requested window attributes
Ok(Self { Ok(Self { app: el.app.clone(), redraw_requester: el.redraw_requester.clone() })
app: el.app.clone(),
redraw_requester: el.redraw_requester.clone(),
})
} }
pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) { pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) {
@ -941,41 +916,31 @@ impl Window {
pub fn set_cursor(&self, _: Cursor) {} pub fn set_cursor(&self, _: Cursor) {}
pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> { pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported( Err(error::ExternalError::NotSupported(error::NotSupportedError::new()))
error::NotSupportedError::new(),
))
} }
pub fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), error::ExternalError> { pub fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported( Err(error::ExternalError::NotSupported(error::NotSupportedError::new()))
error::NotSupportedError::new(),
))
} }
pub fn set_cursor_visible(&self, _: bool) {} pub fn set_cursor_visible(&self, _: bool) {}
pub fn drag_window(&self) -> Result<(), error::ExternalError> { pub fn drag_window(&self) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported( Err(error::ExternalError::NotSupported(error::NotSupportedError::new()))
error::NotSupportedError::new(),
))
} }
pub fn drag_resize_window( pub fn drag_resize_window(
&self, &self,
_direction: ResizeDirection, _direction: ResizeDirection,
) -> Result<(), error::ExternalError> { ) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported( Err(error::ExternalError::NotSupported(error::NotSupportedError::new()))
error::NotSupportedError::new(),
))
} }
#[inline] #[inline]
pub fn show_window_menu(&self, _position: Position) {} pub fn show_window_menu(&self, _position: Position) {}
pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> { pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported( Err(error::ExternalError::NotSupported(error::NotSupportedError::new()))
error::NotSupportedError::new(),
))
} }
#[cfg(feature = "rwh_04")] #[cfg(feature = "rwh_04")]
@ -985,7 +950,11 @@ impl Window {
if let Some(native_window) = self.app.native_window().as_ref() { if let Some(native_window) = self.app.native_window().as_ref() {
native_window.raw_window_handle() native_window.raw_window_handle()
} else { } 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."); 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."
);
} }
} }
@ -996,7 +965,11 @@ impl Window {
if let Some(native_window) = self.app.native_window().as_ref() { if let Some(native_window) = self.app.native_window().as_ref() {
native_window.raw_window_handle() native_window.raw_window_handle()
} else { } 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."); 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."
);
} }
} }
@ -1014,7 +987,11 @@ impl Window {
if let Some(native_window) = self.app.native_window().as_ref() { if let Some(native_window) = self.app.native_window().as_ref() {
native_window.raw_window_handle() native_window.raw_window_handle()
} else { } 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."); 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) Err(rwh_06::HandleError::Unavailable)
} }
} }
@ -1023,9 +1000,7 @@ impl Window {
pub fn raw_display_handle_rwh_06( pub fn raw_display_handle_rwh_06(
&self, &self,
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> { ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
Ok(rwh_06::RawDisplayHandle::Android( Ok(rwh_06::RawDisplayHandle::Android(rwh_06::AndroidDisplayHandle::new()))
rwh_06::AndroidDisplayHandle::new(),
))
} }
pub fn config(&self) -> ConfigurationRef { pub fn config(&self) -> ConfigurationRef {
@ -1102,11 +1077,7 @@ impl MonitorHandle {
} }
pub fn scale_factor(&self) -> f64 { pub fn scale_factor(&self) -> f64 {
self.app self.app.config().density().map(|dpi| dpi as f64 / 160.0).unwrap_or(1.0)
.config()
.density()
.map(|dpi| dpi as f64 / 160.0)
.unwrap_or(1.0)
} }
pub fn refresh_rate_millihertz(&self) -> Option<u32> { pub fn refresh_rate_millihertz(&self) -> Option<u32> {

View file

@ -4,10 +4,8 @@ use objc2_foundation::{MainThreadMarker, NSObject, NSObjectProtocol};
use super::app_state::{self, EventWrapper}; use super::app_state::{self, EventWrapper};
use super::uikit::{UIApplication, UIWindow}; use super::uikit::{UIApplication, UIWindow};
use super::window::WinitUIWindow; use super::window::WinitUIWindow;
use crate::{ use crate::event::{Event, WindowEvent};
event::{Event, WindowEvent}, use crate::window::WindowId as RootWindowId;
window::WindowId as RootWindowId,
};
declare_class!( declare_class!(
pub struct AppDelegate; pub struct AppDelegate;

View file

@ -1,14 +1,11 @@
#![deny(unused_results)] #![deny(unused_results)]
use std::{ use std::cell::{RefCell, RefMut};
cell::{RefCell, RefMut}, use std::collections::HashSet;
collections::HashSet, use std::os::raw::c_void;
fmt, mem, use std::sync::{Arc, Mutex, OnceLock};
os::raw::c_void, use std::time::Instant;
ptr, use std::{fmt, mem, ptr};
sync::{Arc, Mutex, OnceLock},
time::Instant,
};
use core_foundation::base::CFRelease; use core_foundation::base::CFRelease;
use core_foundation::date::CFAbsoluteTimeGetCurrent; use core_foundation::date::CFAbsoluteTimeGetCurrent;
@ -25,12 +22,10 @@ use objc2_foundation::{
use super::uikit::UIView; use super::uikit::UIView;
use super::window::WinitUIWindow; use super::window::WinitUIWindow;
use crate::{ use crate::dpi::PhysicalSize;
dpi::PhysicalSize, use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
event::{Event, InnerSizeWriter, StartCause, WindowEvent}, use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow};
event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow}, use crate::window::WindowId as RootWindowId;
window::WindowId as RootWindowId,
};
macro_rules! bug { macro_rules! bug {
($($msg:tt)*) => { ($($msg:tt)*) => {
@ -94,13 +89,7 @@ enum UserCallbackTransitionResult<'a> {
impl Event<HandlePendingUserEvents> { impl Event<HandlePendingUserEvents> {
fn is_redraw(&self) -> bool { fn is_redraw(&self) -> bool {
matches!( matches!(self, Event::WindowEvent { event: WindowEvent::RedrawRequested, .. })
self,
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
}
)
} }
} }
@ -216,10 +205,7 @@ impl AppState {
} }
fn has_launched(&self) -> bool { fn has_launched(&self) -> bool {
!matches!( !matches!(self.state(), AppStateImpl::NotLaunched { .. } | AppStateImpl::Launching { .. })
self.state(),
AppStateImpl::NotLaunched { .. } | AppStateImpl::Launching { .. }
)
} }
fn has_terminated(&self) -> bool { fn has_terminated(&self) -> bool {
@ -228,11 +214,9 @@ impl AppState {
fn will_launch_transition(&mut self, queued_handler: EventLoopHandler) { fn will_launch_transition(&mut self, queued_handler: EventLoopHandler) {
let (queued_windows, queued_events, queued_gpu_redraws) = match self.take_state() { let (queued_windows, queued_events, queued_gpu_redraws) = match self.take_state() {
AppStateImpl::NotLaunched { AppStateImpl::NotLaunched { queued_windows, queued_events, queued_gpu_redraws } => {
queued_windows, (queued_windows, queued_events, queued_gpu_redraws)
queued_events, },
queued_gpu_redraws,
} => (queued_windows, queued_events, queued_gpu_redraws),
s => bug!("unexpected state {:?}", s), s => bug!("unexpected state {:?}", s),
}; };
self.set_state(AppStateImpl::Launching { self.set_state(AppStateImpl::Launching {
@ -250,12 +234,7 @@ impl AppState {
queued_events, queued_events,
queued_handler, queued_handler,
queued_gpu_redraws, queued_gpu_redraws,
} => ( } => (queued_windows, queued_events, queued_handler, queued_gpu_redraws),
queued_windows,
queued_events,
queued_handler,
queued_gpu_redraws,
),
s => bug!("unexpected state {:?}", s), s => bug!("unexpected state {:?}", s),
}; };
self.set_state(AppStateImpl::ProcessingEvents { self.set_state(AppStateImpl::ProcessingEvents {
@ -274,17 +253,10 @@ impl AppState {
} }
let (handler, event) = match (self.control_flow, self.take_state()) { let (handler, event) = match (self.control_flow, self.take_state()) {
(ControlFlow::Poll, AppStateImpl::PollFinished { waiting_handler }) => ( (ControlFlow::Poll, AppStateImpl::PollFinished { waiting_handler }) => {
waiting_handler, (waiting_handler, EventWrapper::StaticEvent(Event::NewEvents(StartCause::Poll)))
EventWrapper::StaticEvent(Event::NewEvents(StartCause::Poll)), },
), (ControlFlow::Wait, AppStateImpl::Waiting { waiting_handler, start }) => (
(
ControlFlow::Wait,
AppStateImpl::Waiting {
waiting_handler,
start,
},
) => (
waiting_handler, waiting_handler,
EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled { EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled {
start, start,
@ -293,10 +265,7 @@ impl AppState {
), ),
( (
ControlFlow::WaitUntil(requested_resume), ControlFlow::WaitUntil(requested_resume),
AppStateImpl::Waiting { AppStateImpl::Waiting { waiting_handler, start },
waiting_handler,
start,
},
) => { ) => {
let event = if Instant::now() >= requested_resume { let event = if Instant::now() >= requested_resume {
EventWrapper::StaticEvent(Event::NewEvents(StartCause::ResumeTimeReached { EventWrapper::StaticEvent(Event::NewEvents(StartCause::ResumeTimeReached {
@ -310,7 +279,7 @@ impl AppState {
})) }))
}; };
(waiting_handler, event) (waiting_handler, event)
} },
s => bug!("`EventHandler` unexpectedly woke up {:?}", s), s => bug!("`EventHandler` unexpectedly woke up {:?}", s),
}; };
@ -326,18 +295,9 @@ impl AppState {
// If we're not able to process an event due to recursion or `Init` not having been sent out // If we're not able to process an event due to recursion or `Init` not having been sent out
// yet, then queue the events up. // yet, then queue the events up.
match self.state_mut() { match self.state_mut() {
&mut AppStateImpl::Launching { &mut AppStateImpl::Launching { ref mut queued_events, .. }
ref mut queued_events, | &mut AppStateImpl::NotLaunched { ref mut queued_events, .. }
.. | &mut AppStateImpl::InUserCallback { ref mut queued_events, .. } => {
}
| &mut AppStateImpl::NotLaunched {
ref mut queued_events,
..
}
| &mut AppStateImpl::InUserCallback {
ref mut queued_events,
..
} => {
// A lifetime cast: early returns are not currently handled well with NLL, but // A lifetime cast: early returns are not currently handled well with NLL, but
// polonius handles them well. This transmute is a safe workaround. // polonius handles them well. This transmute is a safe workaround.
return unsafe { return unsafe {
@ -348,60 +308,49 @@ impl AppState {
queued_events, queued_events,
}) })
}; };
} },
&mut AppStateImpl::ProcessingEvents { .. } &mut AppStateImpl::ProcessingEvents { .. }
| &mut AppStateImpl::ProcessingRedraws { .. } => {} | &mut AppStateImpl::ProcessingRedraws { .. } => {},
s @ &mut AppStateImpl::PollFinished { .. } s @ &mut AppStateImpl::PollFinished { .. }
| s @ &mut AppStateImpl::Waiting { .. } | s @ &mut AppStateImpl::Waiting { .. }
| s @ &mut AppStateImpl::Terminated => { | s @ &mut AppStateImpl::Terminated => {
bug!("unexpected attempted to process an event {:?}", s) bug!("unexpected attempted to process an event {:?}", s)
} },
} }
let (handler, queued_gpu_redraws, active_control_flow, processing_redraws) = let (handler, queued_gpu_redraws, active_control_flow, processing_redraws) = match self
match self.take_state() { .take_state()
AppStateImpl::Launching { .. } {
| AppStateImpl::NotLaunched { .. } AppStateImpl::Launching { .. }
| AppStateImpl::InUserCallback { .. } => unreachable!(), | AppStateImpl::NotLaunched { .. }
AppStateImpl::ProcessingEvents { | AppStateImpl::InUserCallback { .. } => unreachable!(),
handler, AppStateImpl::ProcessingEvents { handler, queued_gpu_redraws, active_control_flow } => {
queued_gpu_redraws, (handler, queued_gpu_redraws, active_control_flow, false)
active_control_flow, },
} => (handler, queued_gpu_redraws, active_control_flow, false), AppStateImpl::ProcessingRedraws { handler, active_control_flow } => {
AppStateImpl::ProcessingRedraws { (handler, Default::default(), active_control_flow, true)
handler, },
active_control_flow, AppStateImpl::PollFinished { .. }
} => (handler, Default::default(), active_control_flow, true), | AppStateImpl::Waiting { .. }
AppStateImpl::PollFinished { .. } | AppStateImpl::Terminated => unreachable!(),
| AppStateImpl::Waiting { .. } };
| AppStateImpl::Terminated => unreachable!(),
};
self.set_state(AppStateImpl::InUserCallback { self.set_state(AppStateImpl::InUserCallback {
queued_events: Vec::new(), queued_events: Vec::new(),
queued_gpu_redraws, queued_gpu_redraws,
}); });
UserCallbackTransitionResult::Success { UserCallbackTransitionResult::Success { handler, active_control_flow, processing_redraws }
handler,
active_control_flow,
processing_redraws,
}
} }
fn main_events_cleared_transition(&mut self) -> HashSet<Id<WinitUIWindow>> { fn main_events_cleared_transition(&mut self) -> HashSet<Id<WinitUIWindow>> {
let (handler, queued_gpu_redraws, active_control_flow) = match self.take_state() { let (handler, queued_gpu_redraws, active_control_flow) = match self.take_state() {
AppStateImpl::ProcessingEvents { AppStateImpl::ProcessingEvents { handler, queued_gpu_redraws, active_control_flow } => {
handler, (handler, queued_gpu_redraws, active_control_flow)
queued_gpu_redraws, },
active_control_flow,
} => (handler, queued_gpu_redraws, active_control_flow),
s => bug!("unexpected state {:?}", s), s => bug!("unexpected state {:?}", s),
}; };
self.set_state(AppStateImpl::ProcessingRedraws { self.set_state(AppStateImpl::ProcessingRedraws { handler, active_control_flow });
handler,
active_control_flow,
});
queued_gpu_redraws queued_gpu_redraws
} }
@ -410,10 +359,9 @@ impl AppState {
return; return;
} }
let (waiting_handler, old) = match self.take_state() { let (waiting_handler, old) = match self.take_state() {
AppStateImpl::ProcessingRedraws { AppStateImpl::ProcessingRedraws { handler, active_control_flow } => {
handler, (handler, active_control_flow)
active_control_flow, },
} => (handler, active_control_flow),
s => bug!("unexpected state {:?}", s), s => bug!("unexpected state {:?}", s),
}; };
@ -421,41 +369,29 @@ impl AppState {
match (old, new) { match (old, new) {
(ControlFlow::Wait, ControlFlow::Wait) => { (ControlFlow::Wait, ControlFlow::Wait) => {
let start = Instant::now(); let start = Instant::now();
self.set_state(AppStateImpl::Waiting { self.set_state(AppStateImpl::Waiting { waiting_handler, start });
waiting_handler, },
start,
});
}
(ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant)) (ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant))
if old_instant == new_instant => if old_instant == new_instant =>
{ {
let start = Instant::now(); let start = Instant::now();
self.set_state(AppStateImpl::Waiting { self.set_state(AppStateImpl::Waiting { waiting_handler, start });
waiting_handler, },
start,
});
}
(_, ControlFlow::Wait) => { (_, ControlFlow::Wait) => {
let start = Instant::now(); let start = Instant::now();
self.set_state(AppStateImpl::Waiting { self.set_state(AppStateImpl::Waiting { waiting_handler, start });
waiting_handler,
start,
});
self.waker.stop() self.waker.stop()
} },
(_, ControlFlow::WaitUntil(new_instant)) => { (_, ControlFlow::WaitUntil(new_instant)) => {
let start = Instant::now(); let start = Instant::now();
self.set_state(AppStateImpl::Waiting { self.set_state(AppStateImpl::Waiting { waiting_handler, start });
waiting_handler,
start,
});
self.waker.start_at(new_instant) self.waker.start_at(new_instant)
} },
// Unlike on macOS, handle Poll to Poll transition here to call the waker // Unlike on macOS, handle Poll to Poll transition here to call the waker
(_, ControlFlow::Poll) => { (_, ControlFlow::Poll) => {
self.set_state(AppStateImpl::PollFinished { waiting_handler }); self.set_state(AppStateImpl::PollFinished { waiting_handler });
self.waker.start() self.waker.start()
} },
} }
} }
@ -478,19 +414,18 @@ impl AppState {
pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Id<WinitUIWindow>) { pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Id<WinitUIWindow>) {
let mut this = AppState::get_mut(mtm); let mut this = AppState::get_mut(mtm);
match this.state_mut() { match this.state_mut() {
&mut AppStateImpl::NotLaunched { &mut AppStateImpl::NotLaunched { ref mut queued_windows, .. } => {
ref mut queued_windows, return queued_windows.push(window.clone())
.. },
} => return queued_windows.push(window.clone()),
&mut AppStateImpl::ProcessingEvents { .. } &mut AppStateImpl::ProcessingEvents { .. }
| &mut AppStateImpl::InUserCallback { .. } | &mut AppStateImpl::InUserCallback { .. }
| &mut AppStateImpl::ProcessingRedraws { .. } => {} | &mut AppStateImpl::ProcessingRedraws { .. } => {},
s @ &mut AppStateImpl::Launching { .. } s @ &mut AppStateImpl::Launching { .. }
| s @ &mut AppStateImpl::Waiting { .. } | s @ &mut AppStateImpl::Waiting { .. }
| s @ &mut AppStateImpl::PollFinished { .. } => bug!("unexpected state {:?}", s), | s @ &mut AppStateImpl::PollFinished { .. } => bug!("unexpected state {:?}", s),
&mut AppStateImpl::Terminated => { &mut AppStateImpl::Terminated => {
panic!("Attempt to create a `Window` after the app has terminated") panic!("Attempt to create a `Window` after the app has terminated")
} },
} }
drop(this); drop(this);
window.makeKeyAndVisible(); window.makeKeyAndVisible();
@ -499,30 +434,18 @@ pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Id<WinitUIWindow>)
pub(crate) fn queue_gl_or_metal_redraw(mtm: MainThreadMarker, window: Id<WinitUIWindow>) { pub(crate) fn queue_gl_or_metal_redraw(mtm: MainThreadMarker, window: Id<WinitUIWindow>) {
let mut this = AppState::get_mut(mtm); let mut this = AppState::get_mut(mtm);
match this.state_mut() { match this.state_mut() {
&mut AppStateImpl::NotLaunched { &mut AppStateImpl::NotLaunched { ref mut queued_gpu_redraws, .. }
ref mut queued_gpu_redraws, | &mut AppStateImpl::Launching { ref mut queued_gpu_redraws, .. }
.. | &mut AppStateImpl::ProcessingEvents { ref mut queued_gpu_redraws, .. }
} | &mut AppStateImpl::InUserCallback { ref mut queued_gpu_redraws, .. } => {
| &mut AppStateImpl::Launching {
ref mut queued_gpu_redraws,
..
}
| &mut AppStateImpl::ProcessingEvents {
ref mut queued_gpu_redraws,
..
}
| &mut AppStateImpl::InUserCallback {
ref mut queued_gpu_redraws,
..
} => {
let _ = queued_gpu_redraws.insert(window); let _ = queued_gpu_redraws.insert(window);
} },
s @ &mut AppStateImpl::ProcessingRedraws { .. } s @ &mut AppStateImpl::ProcessingRedraws { .. }
| s @ &mut AppStateImpl::Waiting { .. } | s @ &mut AppStateImpl::Waiting { .. }
| s @ &mut AppStateImpl::PollFinished { .. } => bug!("unexpected state {:?}", s), | s @ &mut AppStateImpl::PollFinished { .. } => bug!("unexpected state {:?}", s),
&mut AppStateImpl::Terminated => { &mut AppStateImpl::Terminated => {
panic!("Attempt to create a `Window` after the app has terminated") panic!("Attempt to create a `Window` after the app has terminated")
} },
} }
} }
@ -566,10 +489,8 @@ pub fn did_finish_launching(mtm: MainThreadMarker) {
let (windows, events) = AppState::get_mut(mtm).did_finish_launching_transition(); let (windows, events) = AppState::get_mut(mtm).did_finish_launching_transition();
let events = std::iter::once(EventWrapper::StaticEvent(Event::NewEvents( let events = std::iter::once(EventWrapper::StaticEvent(Event::NewEvents(StartCause::Init)))
StartCause::Init, .chain(events);
)))
.chain(events);
handle_nonuser_events(mtm, events); handle_nonuser_events(mtm, events);
// the above window dance hack, could possibly trigger new windows to be created. // the above window dance hack, could possibly trigger new windows to be created.
@ -609,7 +530,7 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
UserCallbackTransitionResult::ReentrancyPrevented { queued_events } => { UserCallbackTransitionResult::ReentrancyPrevented { queued_events } => {
queued_events.extend(events); queued_events.extend(events);
return; return;
} },
UserCallbackTransitionResult::Success { UserCallbackTransitionResult::Success {
handler, handler,
active_control_flow, active_control_flow,
@ -630,7 +551,7 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
); );
} }
handler.handle_event(event) handler.handle_event(event)
} },
EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event), EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event),
} }
} }
@ -638,18 +559,16 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
loop { loop {
let mut this = AppState::get_mut(mtm); let mut this = AppState::get_mut(mtm);
let queued_events = match this.state_mut() { let queued_events = match this.state_mut() {
&mut AppStateImpl::InUserCallback { &mut AppStateImpl::InUserCallback { ref mut queued_events, queued_gpu_redraws: _ } => {
ref mut queued_events, mem::take(queued_events)
queued_gpu_redraws: _, },
} => mem::take(queued_events),
s => bug!("unexpected state {:?}", s), s => bug!("unexpected state {:?}", s),
}; };
if queued_events.is_empty() { if queued_events.is_empty() {
let queued_gpu_redraws = match this.take_state() { let queued_gpu_redraws = match this.take_state() {
AppStateImpl::InUserCallback { AppStateImpl::InUserCallback { queued_events: _, queued_gpu_redraws } => {
queued_events: _, queued_gpu_redraws
queued_gpu_redraws, },
} => queued_gpu_redraws,
_ => unreachable!(), _ => unreachable!(),
}; };
this.app_state = Some(if processing_redraws { this.app_state = Some(if processing_redraws {
@ -657,16 +576,9 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
queued_gpu_redraws.is_empty(), queued_gpu_redraws.is_empty(),
"redraw queued while processing redraws" "redraw queued while processing redraws"
); );
AppStateImpl::ProcessingRedraws { AppStateImpl::ProcessingRedraws { handler, active_control_flow }
handler,
active_control_flow,
}
} else { } else {
AppStateImpl::ProcessingEvents { AppStateImpl::ProcessingEvents { handler, queued_gpu_redraws, active_control_flow }
handler,
queued_gpu_redraws,
active_control_flow,
}
}); });
break; break;
} }
@ -679,12 +591,13 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
tracing::info!("processing `RedrawRequested` during the main event loop"); tracing::info!("processing `RedrawRequested` during the main event loop");
} else if processing_redraws && !event.is_redraw() { } else if processing_redraws && !event.is_redraw() {
tracing::warn!( tracing::warn!(
"processing non-`RedrawRequested` event after the main event loop: {:#?}", "processing non-`RedrawRequested` event after the main event loop: \
{:#?}",
event event
); );
} }
handler.handle_event(event) handler.handle_event(event)
} },
EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event), EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event),
} }
} }
@ -697,7 +610,7 @@ fn handle_user_events(mtm: MainThreadMarker) {
match this.try_user_callback_transition() { match this.try_user_callback_transition() {
UserCallbackTransitionResult::ReentrancyPrevented { .. } => { UserCallbackTransitionResult::ReentrancyPrevented { .. } => {
bug!("unexpected attempted to process an event") bug!("unexpected attempted to process an event")
} },
UserCallbackTransitionResult::Success { UserCallbackTransitionResult::Success {
handler, handler,
active_control_flow, active_control_flow,
@ -714,18 +627,16 @@ fn handle_user_events(mtm: MainThreadMarker) {
loop { loop {
let mut this = AppState::get_mut(mtm); let mut this = AppState::get_mut(mtm);
let queued_events = match this.state_mut() { let queued_events = match this.state_mut() {
&mut AppStateImpl::InUserCallback { &mut AppStateImpl::InUserCallback { ref mut queued_events, queued_gpu_redraws: _ } => {
ref mut queued_events, mem::take(queued_events)
queued_gpu_redraws: _, },
} => mem::take(queued_events),
s => bug!("unexpected state {:?}", s), s => bug!("unexpected state {:?}", s),
}; };
if queued_events.is_empty() { if queued_events.is_empty() {
let queued_gpu_redraws = match this.take_state() { let queued_gpu_redraws = match this.take_state() {
AppStateImpl::InUserCallback { AppStateImpl::InUserCallback { queued_events: _, queued_gpu_redraws } => {
queued_events: _, queued_gpu_redraws
queued_gpu_redraws, },
} => queued_gpu_redraws,
_ => unreachable!(), _ => unreachable!(),
}; };
this.app_state = Some(AppStateImpl::ProcessingEvents { this.app_state = Some(AppStateImpl::ProcessingEvents {
@ -754,7 +665,7 @@ pub fn handle_main_events_cleared(mtm: MainThreadMarker) {
return; return;
} }
match this.state_mut() { match this.state_mut() {
AppStateImpl::ProcessingEvents { .. } => {} AppStateImpl::ProcessingEvents { .. } => {},
_ => bug!("`ProcessingRedraws` happened unexpectedly"), _ => bug!("`ProcessingRedraws` happened unexpectedly"),
}; };
drop(this); drop(this);
@ -791,11 +702,7 @@ pub fn terminated(mtm: MainThreadMarker) {
} }
fn handle_hidpi_proxy(handler: &mut EventLoopHandler, event: ScaleFactorChanged) { fn handle_hidpi_proxy(handler: &mut EventLoopHandler, event: ScaleFactorChanged) {
let ScaleFactorChanged { let ScaleFactorChanged { suggested_size, scale_factor, window } = event;
suggested_size,
scale_factor,
window,
} = event;
let new_inner_size = Arc::new(Mutex::new(suggested_size)); let new_inner_size = Arc::new(Mutex::new(suggested_size));
let event = Event::WindowEvent { let event = Event::WindowEvent {
window_id: RootWindowId(window.id()), window_id: RootWindowId(window.id()),
@ -956,11 +863,12 @@ fn get_version() -> NSOperatingSystemVersion {
&process_info, &process_info,
respondsToSelector: sel!(operatingSystemVersion) respondsToSelector: sel!(operatingSystemVersion)
]; ];
// winit requires atleast iOS 8 because no one has put the time into supporting earlier os versions. // winit requires atleast iOS 8 because no one has put the time into supporting earlier os
// Older iOS versions are increasingly difficult to test. For example, Xcode 11 does not support // versions. Older iOS versions are increasingly difficult to test. For example,
// debugging on devices with an iOS version of less than 8. Another example, in order to use an iOS // Xcode 11 does not support debugging on devices with an iOS version of less than
// simulator older than iOS 8, you must download an older version of Xcode (<9), and at least Xcode 7 // 8. Another example, in order to use an iOS simulator older than iOS 8, you must
// has been tested to not even run on macOS 10.15 - Xcode 8 might? // download an older version of Xcode (<9), and at least Xcode 7 has been tested to
// not even run on macOS 10.15 - Xcode 8 might?
// //
// The minimum required iOS version is likely to grow in the future. // The minimum required iOS version is likely to grow in the future.
assert!(atleast_ios_8, "`winit` requires iOS version 8 or greater"); assert!(atleast_ios_8, "`winit` requires iOS version 8 or greater");
@ -971,7 +879,5 @@ fn get_version() -> NSOperatingSystemVersion {
pub fn os_capabilities() -> OSCapabilities { pub fn os_capabilities() -> OSCapabilities {
// Cache the version lookup for efficiency // Cache the version lookup for efficiency
static OS_CAPABILITIES: OnceLock<OSCapabilities> = OnceLock::new(); static OS_CAPABILITIES: OnceLock<OSCapabilities> = OnceLock::new();
OS_CAPABILITIES OS_CAPABILITIES.get_or_init(|| OSCapabilities::from_os_version(get_version())).clone()
.get_or_init(|| OSCapabilities::from_os_version(get_version()))
.clone()
} }

View file

@ -1,10 +1,8 @@
use std::{ use std::collections::VecDeque;
collections::VecDeque, use std::ffi::c_void;
ffi::c_void, use std::marker::PhantomData;
marker::PhantomData, use std::ptr;
ptr, use std::sync::mpsc::{self, Receiver, Sender};
sync::mpsc::{self, Receiver, Sender},
};
use core_foundation::base::{CFIndex, CFRelease}; use core_foundation::base::{CFIndex, CFRelease};
use core_foundation::runloop::{ use core_foundation::runloop::{
@ -16,23 +14,19 @@ use core_foundation::runloop::{
use objc2::ClassType; use objc2::ClassType;
use objc2_foundation::{MainThreadMarker, NSString}; use objc2_foundation::{MainThreadMarker, NSString};
use crate::{ use crate::error::EventLoopError;
error::EventLoopError, use crate::event::Event;
event::Event, use crate::event_loop::{
event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, EventLoopClosed,
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, EventLoopClosed,
},
platform::ios::Idiom,
platform_impl::platform::app_state::{EventLoopHandler, HandlePendingUserEvents},
window::{CustomCursor, CustomCursorSource},
}; };
use crate::platform::ios::Idiom;
use crate::platform_impl::platform::app_state::{EventLoopHandler, HandlePendingUserEvents};
use crate::window::{CustomCursor, CustomCursorSource};
use super::{app_delegate::AppDelegate, uikit::UIUserInterfaceIdiom}; use super::app_delegate::AppDelegate;
use super::app_state::AppState;
use super::uikit::{UIApplication, UIApplicationMain, UIDevice, UIScreen, UIUserInterfaceIdiom};
use super::{app_state, monitor, MonitorHandle}; use super::{app_state, monitor, MonitorHandle};
use super::{
app_state::AppState,
uikit::{UIApplication, UIApplicationMain, UIDevice, UIScreen},
};
#[derive(Debug)] #[derive(Debug)]
pub struct ActiveEventLoop { pub struct ActiveEventLoop {
@ -42,9 +36,7 @@ pub struct ActiveEventLoop {
impl ActiveEventLoop { impl ActiveEventLoop {
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor { pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor {
let _ = source.inner; let _ = source.inner;
CustomCursor { CustomCursor { inner: super::PlatformCustomCursor }
inner: super::PlatformCustomCursor,
}
} }
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> { pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
@ -69,9 +61,7 @@ impl ActiveEventLoop {
pub fn raw_display_handle_rwh_06( pub fn raw_display_handle_rwh_06(
&self, &self,
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> { ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
Ok(rwh_06::RawDisplayHandle::UiKit( Ok(rwh_06::RawDisplayHandle::UiKit(rwh_06::UiKitDisplayHandle::new()))
rwh_06::UiKitDisplayHandle::new(),
))
} }
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) { pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
@ -126,7 +116,7 @@ fn map_user_event<T: 'static>(
for event in receiver.try_iter() { for event in receiver.try_iter() {
(handler)(Event::UserEvent(event), window_target); (handler)(Event::UserEvent(event), window_target);
} }
} },
} }
} }
@ -151,8 +141,7 @@ impl<T: 'static> EventLoop<T> {
unsafe { unsafe {
assert!( assert!(
!SINGLETON_INIT, !SINGLETON_INIT,
"Only one `EventLoop` is supported on iOS. \ "Only one `EventLoop` is supported on iOS. `EventLoopProxy` might be helpful"
`EventLoopProxy` might be helpful"
); );
SINGLETON_INIT = true; SINGLETON_INIT = true;
} }
@ -166,10 +155,7 @@ impl<T: 'static> EventLoop<T> {
mtm, mtm,
sender, sender,
receiver, receiver,
window_target: RootActiveEventLoop { window_target: RootActiveEventLoop { p: ActiveEventLoop { mtm }, _marker: PhantomData },
p: ActiveEventLoop { mtm },
_marker: PhantomData,
},
}) })
} }
@ -181,8 +167,8 @@ impl<T: 'static> EventLoop<T> {
assert!( assert!(
application.is_none(), application.is_none(),
"\ "\
`EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\n\ `EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\nNote: \
Note: `EventLoop::run_app` calls `UIApplicationMain` on iOS", `EventLoop::run_app` calls `UIApplicationMain` on iOS",
); );
let handler = map_user_event(handler, self.receiver); let handler = map_user_event(handler, self.receiver);
@ -194,10 +180,7 @@ impl<T: 'static> EventLoop<T> {
>(Box::new(handler)) >(Box::new(handler))
}; };
let handler = EventLoopHandler { let handler = EventLoopHandler { handler, event_loop: self.window_target };
handler,
event_loop: self.window_target,
};
app_state::will_launch(self.mtm, handler); app_state::will_launch(self.mtm, handler);
@ -205,12 +188,7 @@ impl<T: 'static> EventLoop<T> {
let _ = AppDelegate::class(); let _ = AppDelegate::class();
unsafe { unsafe {
UIApplicationMain( UIApplicationMain(0, ptr::null(), None, Some(&NSString::from_str(AppDelegate::NAME)))
0,
ptr::null(),
None,
Some(&NSString::from_str(AppDelegate::NAME)),
)
}; };
unreachable!() unreachable!()
} }
@ -292,9 +270,7 @@ impl<T> EventLoopProxy<T> {
} }
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
self.sender self.sender.send(event).map_err(|::std::sync::mpsc::SendError(x)| EventLoopClosed(x))?;
.send(event)
.map_err(|::std::sync::mpsc::SendError(x)| EventLoopClosed(x))?;
unsafe { unsafe {
// let the main thread know there's a new event // let the main thread know there's a new event
CFRunLoopSourceSignal(self.source); CFRunLoopSourceSignal(self.source);
@ -307,7 +283,8 @@ impl<T> EventLoopProxy<T> {
fn setup_control_flow_observers() { fn setup_control_flow_observers() {
unsafe { unsafe {
// begin is queued with the highest priority to ensure it is processed before other observers // begin is queued with the highest priority to ensure it is processed before other
// observers
extern "C" fn control_flow_begin_handler( extern "C" fn control_flow_begin_handler(
_: CFRunLoopObserverRef, _: CFRunLoopObserverRef,
activity: CFRunLoopActivity, activity: CFRunLoopActivity,
@ -341,7 +318,7 @@ fn setup_control_flow_observers() {
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
match activity { match activity {
kCFRunLoopBeforeWaiting => app_state::handle_main_events_cleared(mtm), kCFRunLoopBeforeWaiting => app_state::handle_main_events_cleared(mtm),
kCFRunLoopExit => {} // may happen when running on macOS kCFRunLoopExit => {}, // may happen when running on macOS
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -356,7 +333,7 @@ fn setup_control_flow_observers() {
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
match activity { match activity {
kCFRunLoopBeforeWaiting => app_state::handle_events_cleared(mtm), kCFRunLoopBeforeWaiting => app_state::handle_events_cleared(mtm),
kCFRunLoopExit => {} // may happen when running on macOS kCFRunLoopExit => {}, // may happen when running on macOS
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -14,16 +14,15 @@ use std::fmt;
use crate::event::DeviceId as RootDeviceId; use crate::event::DeviceId as RootDeviceId;
pub(crate) use self::{ pub(crate) use self::event_loop::{
event_loop::{ ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes,
PlatformSpecificEventLoopAttributes, };
}, pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
monitor::{MonitorHandle, VideoModeHandle}, pub(crate) use self::window::{PlatformSpecificWindowAttributes, Window, WindowId};
window::{PlatformSpecificWindowAttributes, Window, WindowId}, pub(crate) use crate::cursor::{
NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource,
}; };
pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursor;
pub(crate) use crate::cursor::NoCustomCursor as PlatformCustomCursorSource;
pub(crate) use crate::icon::NoIcon as PlatformIcon; pub(crate) use crate::icon::NoIcon as PlatformIcon;
pub(crate) use crate::platform_impl::Fullscreen; pub(crate) use crate::platform_impl::Fullscreen;

View file

@ -1,9 +1,7 @@
#![allow(clippy::unnecessary_cast)] #![allow(clippy::unnecessary_cast)]
use std::{ use std::collections::{BTreeSet, VecDeque};
collections::{BTreeSet, VecDeque}, use std::{fmt, hash, ptr};
fmt, hash, ptr,
};
use objc2::mutability::IsRetainable; use objc2::mutability::IsRetainable;
use objc2::rc::Id; use objc2::rc::Id;
@ -11,11 +9,9 @@ use objc2::Message;
use objc2_foundation::{run_on_main, MainThreadBound, MainThreadMarker, NSInteger}; use objc2_foundation::{run_on_main, MainThreadBound, MainThreadMarker, NSInteger};
use super::uikit::{UIScreen, UIScreenMode}; use super::uikit::{UIScreen, UIScreenMode};
use crate::{ use crate::dpi::{PhysicalPosition, PhysicalSize};
dpi::{PhysicalPosition, PhysicalSize}, use crate::monitor::VideoModeHandle as RootVideoModeHandle;
monitor::VideoModeHandle as RootVideoModeHandle, use crate::platform_impl::platform::app_state;
platform_impl::platform::app_state,
};
// Workaround for `MainThreadBound` implementing almost no traits // Workaround for `MainThreadBound` implementing almost no traits
#[derive(Debug)] #[derive(Debug)]
@ -23,9 +19,7 @@ struct MainThreadBoundDelegateImpls<T>(MainThreadBound<Id<T>>);
impl<T: IsRetainable + Message> Clone for MainThreadBoundDelegateImpls<T> { impl<T: IsRetainable + Message> Clone for MainThreadBoundDelegateImpls<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self(run_on_main(|mtm| { Self(run_on_main(|mtm| MainThreadBound::new(Id::clone(self.0.get(mtm)), mtm)))
MainThreadBound::new(Id::clone(self.0.get(mtm)), mtm)
}))
} }
} }
@ -149,9 +143,7 @@ impl MonitorHandle {
pub(crate) fn new(ui_screen: Id<UIScreen>) -> Self { pub(crate) fn new(ui_screen: Id<UIScreen>) -> Self {
// Holding `Id<UIScreen>` implies we're on the main thread. // Holding `Id<UIScreen>` implies we're on the main thread.
let mtm = MainThreadMarker::new().unwrap(); let mtm = MainThreadMarker::new().unwrap();
Self { Self { ui_screen: MainThreadBound::new(ui_screen, mtm) }
ui_screen: MainThreadBound::new(ui_screen, mtm),
}
} }
pub fn name(&self) -> Option<String> { pub fn name(&self) -> Option<String> {
@ -171,29 +163,21 @@ impl MonitorHandle {
} }
pub fn size(&self) -> PhysicalSize<u32> { pub fn size(&self) -> PhysicalSize<u32> {
let bounds = self let bounds = self.ui_screen.get_on_main(|ui_screen| ui_screen.nativeBounds());
.ui_screen
.get_on_main(|ui_screen| ui_screen.nativeBounds());
PhysicalSize::new(bounds.size.width as u32, bounds.size.height as u32) PhysicalSize::new(bounds.size.width as u32, bounds.size.height as u32)
} }
pub fn position(&self) -> PhysicalPosition<i32> { pub fn position(&self) -> PhysicalPosition<i32> {
let bounds = self let bounds = self.ui_screen.get_on_main(|ui_screen| ui_screen.nativeBounds());
.ui_screen
.get_on_main(|ui_screen| ui_screen.nativeBounds());
(bounds.origin.x as f64, bounds.origin.y as f64).into() (bounds.origin.x as f64, bounds.origin.y as f64).into()
} }
pub fn scale_factor(&self) -> f64 { pub fn scale_factor(&self) -> f64 {
self.ui_screen self.ui_screen.get_on_main(|ui_screen| ui_screen.nativeScale()) as f64
.get_on_main(|ui_screen| ui_screen.nativeScale()) as f64
} }
pub fn refresh_rate_millihertz(&self) -> Option<u32> { pub fn refresh_rate_millihertz(&self) -> Option<u32> {
Some( Some(self.ui_screen.get_on_main(|ui_screen| refresh_rate_millihertz(ui_screen)))
self.ui_screen
.get_on_main(|ui_screen| refresh_rate_millihertz(ui_screen)),
)
} }
pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> { pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> {
@ -253,8 +237,5 @@ fn refresh_rate_millihertz(uiscreen: &UIScreen) -> u32 {
} }
pub fn uiscreens(mtm: MainThreadMarker) -> VecDeque<MonitorHandle> { pub fn uiscreens(mtm: MainThreadMarker) -> VecDeque<MonitorHandle> {
UIScreen::screens(mtm) UIScreen::screens(mtm).into_iter().map(MonitorHandle::new).collect()
.into_iter()
.map(MonitorHandle::new)
.collect()
} }

View file

@ -1,7 +1,5 @@
use objc2::{ use objc2::encode::{Encode, Encoding};
encode::{Encode, Encoding}, use objc2::{extern_class, extern_methods, mutability, ClassType};
extern_class, extern_methods, mutability, ClassType,
};
use objc2_foundation::{CGFloat, NSInteger, NSObject, NSUInteger}; use objc2_foundation::{CGFloat, NSInteger, NSObject, NSUInteger};
// https://developer.apple.com/documentation/uikit/uigesturerecognizer // https://developer.apple.com/documentation/uikit/uigesturerecognizer

View file

@ -84,13 +84,10 @@ pub struct UIEdgeInsets {
} }
unsafe impl Encode for UIEdgeInsets { unsafe impl Encode for UIEdgeInsets {
const ENCODING: Encoding = Encoding::Struct( const ENCODING: Encoding = Encoding::Struct("UIEdgeInsets", &[
"UIEdgeInsets", CGFloat::ENCODING,
&[ CGFloat::ENCODING,
CGFloat::ENCODING, CGFloat::ENCODING,
CGFloat::ENCODING, CGFloat::ENCODING,
CGFloat::ENCODING, ]);
CGFloat::ENCODING,
],
);
} }

View file

@ -15,12 +15,10 @@ use super::uikit::{
UITouchType, UITraitCollection, UIView, UITouchType, UITraitCollection, UIView,
}; };
use super::window::WinitUIWindow; use super::window::WinitUIWindow;
use crate::{ use crate::dpi::PhysicalPosition;
dpi::PhysicalPosition, use crate::event::{Event, Force, Touch, TouchPhase, WindowEvent};
event::{Event, Force, Touch, TouchPhase, WindowEvent}, use crate::platform_impl::platform::DEVICE_ID;
platform_impl::platform::DEVICE_ID, use crate::window::{WindowAttributes, WindowId as RootWindowId};
window::{WindowAttributes, WindowId as RootWindowId},
};
pub struct WinitViewState { pub struct WinitViewState {
pinch_gesture_recognizer: RefCell<Option<Id<UIPinchGestureRecognizer>>>, pinch_gesture_recognizer: RefCell<Option<Id<UIPinchGestureRecognizer>>>,
@ -314,9 +312,7 @@ impl WinitView {
msg_send_id![UIRotationGestureRecognizer::alloc(), initWithTarget: self, action: sel!(rotationGesture:)] msg_send_id![UIRotationGestureRecognizer::alloc(), initWithTarget: self, action: sel!(rotationGesture:)]
}; };
self.addGestureRecognizer(&rotation); self.addGestureRecognizer(&rotation);
self.ivars() self.ivars().rotation_gesture_recognizer.replace(Some(rotation));
.rotation_gesture_recognizer
.replace(Some(rotation));
} }
} else if let Some(recognizer) = self.ivars().rotation_gesture_recognizer.take() { } else if let Some(recognizer) = self.ivars().rotation_gesture_recognizer.take() {
self.removeGestureRecognizer(&recognizer); self.removeGestureRecognizer(&recognizer);

View file

@ -9,8 +9,8 @@ use super::uikit::{
UIDevice, UIInterfaceOrientationMask, UIRectEdge, UIResponder, UIStatusBarStyle, UIDevice, UIInterfaceOrientationMask, UIRectEdge, UIResponder, UIStatusBarStyle,
UIUserInterfaceIdiom, UIView, UIViewController, UIUserInterfaceIdiom, UIView, UIViewController,
}; };
use crate::platform::ios::{ScreenEdge, StatusBarStyle}; use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations};
use crate::{platform::ios::ValidOrientations, window::WindowAttributes}; use crate::window::WindowAttributes;
pub struct ViewControllerState { pub struct ViewControllerState {
prefers_status_bar_hidden: Cell<bool>, prefers_status_bar_hidden: Cell<bool>,
@ -97,16 +97,10 @@ impl WinitViewController {
pub(crate) fn set_preferred_screen_edges_deferring_system_gestures(&self, val: ScreenEdge) { pub(crate) fn set_preferred_screen_edges_deferring_system_gestures(&self, val: ScreenEdge) {
let val = { let val = {
assert_eq!( assert_eq!(val.bits() & !ScreenEdge::ALL.bits(), 0, "invalid `ScreenEdge`");
val.bits() & !ScreenEdge::ALL.bits(),
0,
"invalid `ScreenEdge`"
);
UIRectEdge(val.bits().into()) UIRectEdge(val.bits().into())
}; };
self.ivars() self.ivars().preferred_screen_edges_deferring_system_gestures.set(val);
.preferred_screen_edges_deferring_system_gestures
.set(val);
let os_capabilities = app_state::os_capabilities(); let os_capabilities = app_state::os_capabilities();
if os_capabilities.defer_system_gestures { if os_capabilities.defer_system_gestures {
self.setNeedsUpdateOfScreenEdgesDeferringSystemGestures(); self.setNeedsUpdateOfScreenEdgesDeferringSystemGestures();
@ -120,22 +114,19 @@ impl WinitViewController {
mtm: MainThreadMarker, mtm: MainThreadMarker,
valid_orientations: ValidOrientations, valid_orientations: ValidOrientations,
) { ) {
let mask = match ( let mask = match (valid_orientations, UIDevice::current(mtm).userInterfaceIdiom()) {
valid_orientations,
UIDevice::current(mtm).userInterfaceIdiom(),
) {
(ValidOrientations::LandscapeAndPortrait, UIUserInterfaceIdiom::Phone) => { (ValidOrientations::LandscapeAndPortrait, UIUserInterfaceIdiom::Phone) => {
UIInterfaceOrientationMask::AllButUpsideDown UIInterfaceOrientationMask::AllButUpsideDown
} },
(ValidOrientations::LandscapeAndPortrait, _) => UIInterfaceOrientationMask::All, (ValidOrientations::LandscapeAndPortrait, _) => UIInterfaceOrientationMask::All,
(ValidOrientations::Landscape, _) => UIInterfaceOrientationMask::Landscape, (ValidOrientations::Landscape, _) => UIInterfaceOrientationMask::Landscape,
(ValidOrientations::Portrait, UIUserInterfaceIdiom::Phone) => { (ValidOrientations::Portrait, UIUserInterfaceIdiom::Phone) => {
UIInterfaceOrientationMask::Portrait UIInterfaceOrientationMask::Portrait
} },
(ValidOrientations::Portrait, _) => { (ValidOrientations::Portrait, _) => {
UIInterfaceOrientationMask::Portrait UIInterfaceOrientationMask::Portrait
| UIInterfaceOrientationMask::PortraitUpsideDown | UIInterfaceOrientationMask::PortraitUpsideDown
} },
}; };
self.ivars().supported_orientations.set(mask); self.ivars().supported_orientations.set(mask);
UIViewController::attemptRotationToDeviceOrientation(); UIViewController::attemptRotationToDeviceOrientation();
@ -157,15 +148,11 @@ impl WinitViewController {
let this: Id<Self> = unsafe { msg_send_id![super(this), init] }; let this: Id<Self> = unsafe { msg_send_id![super(this), init] };
this.set_prefers_status_bar_hidden( this.set_prefers_status_bar_hidden(
window_attributes window_attributes.platform_specific.prefers_status_bar_hidden,
.platform_specific
.prefers_status_bar_hidden,
); );
this.set_preferred_status_bar_style( this.set_preferred_status_bar_style(
window_attributes window_attributes.platform_specific.preferred_status_bar_style,
.platform_specific
.preferred_status_bar_style,
); );
this.set_supported_interface_orientations( this.set_supported_interface_orientations(
@ -174,15 +161,11 @@ impl WinitViewController {
); );
this.set_prefers_home_indicator_auto_hidden( this.set_prefers_home_indicator_auto_hidden(
window_attributes window_attributes.platform_specific.prefers_home_indicator_hidden,
.platform_specific
.prefers_home_indicator_hidden,
); );
this.set_preferred_screen_edges_deferring_system_gestures( this.set_preferred_screen_edges_deferring_system_gestures(
window_attributes window_attributes.platform_specific.preferred_screen_edges_deferring_system_gestures,
.platform_specific
.preferred_screen_edges_deferring_system_gestures,
); );
this.setView(Some(view)); this.setView(Some(view));

View file

@ -14,18 +14,18 @@ use super::uikit::{
}; };
use super::view::WinitView; use super::view::WinitView;
use super::view_controller::WinitViewController; use super::view_controller::WinitViewController;
use crate::{ use crate::cursor::Cursor;
cursor::Cursor, use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}, use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
error::{ExternalError, NotSupportedError, OsError as RootOsError}, use crate::event::{Event, WindowEvent};
event::{Event, WindowEvent}, use crate::icon::Icon;
icon::Icon, use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations};
platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations}, use crate::platform_impl::platform::{
platform_impl::platform::{app_state, monitor, ActiveEventLoop, Fullscreen, MonitorHandle}, app_state, monitor, ActiveEventLoop, Fullscreen, MonitorHandle,
window::{ };
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes, use crate::window::{
WindowButtons, WindowId as RootWindowId, WindowLevel, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
}, WindowButtons, WindowId as RootWindowId, WindowLevel,
}; };
declare_class!( declare_class!(
@ -87,11 +87,11 @@ impl WinitUIWindow {
let screen = monitor.ui_screen(mtm); let screen = monitor.ui_screen(mtm);
screen.setCurrentMode(Some(video_mode.screen_mode(mtm))); screen.setCurrentMode(Some(video_mode.screen_mode(mtm)));
this.setScreen(screen); this.setScreen(screen);
} },
Some(Fullscreen::Borderless(Some(ref monitor))) => { Some(Fullscreen::Borderless(Some(ref monitor))) => {
let screen = monitor.ui_screen(mtm); let screen = monitor.ui_screen(mtm);
this.setScreen(screen); this.setScreen(screen);
} },
_ => (), _ => (),
} }
@ -135,12 +135,13 @@ impl Inner {
pub fn request_redraw(&self) { pub fn request_redraw(&self) {
if self.gl_or_metal_backed { if self.gl_or_metal_backed {
let mtm = MainThreadMarker::new().unwrap(); let mtm = MainThreadMarker::new().unwrap();
// `setNeedsDisplay` does nothing on UIViews which are directly backed by CAEAGLLayer or CAMetalLayer. // `setNeedsDisplay` does nothing on UIViews which are directly backed by CAEAGLLayer or
// Ordinarily the OS sets up a bunch of UIKit state before calling drawRect: on a UIView, but when using // CAMetalLayer. Ordinarily the OS sets up a bunch of UIKit state before
// raw or gl/metal for drawing this work is completely avoided. // calling drawRect: on a UIView, but when using raw or gl/metal for drawing
// this work is completely avoided.
// //
// The docs for `setNeedsDisplay` don't mention `CAMetalLayer`; however, this has been confirmed via // The docs for `setNeedsDisplay` don't mention `CAMetalLayer`; however, this has been
// testing. // confirmed via testing.
// //
// https://developer.apple.com/documentation/uikit/uiview/1622437-setneedsdisplay?language=objc // https://developer.apple.com/documentation/uikit/uiview/1622437-setneedsdisplay?language=objc
app_state::queue_gl_or_metal_redraw(mtm, self.window.clone()); app_state::queue_gl_or_metal_redraw(mtm, self.window.clone());
@ -153,20 +154,16 @@ impl Inner {
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> { pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let safe_area = self.safe_area_screen_space(); let safe_area = self.safe_area_screen_space();
let position = LogicalPosition { let position =
x: safe_area.origin.x as f64, LogicalPosition { x: safe_area.origin.x as f64, y: safe_area.origin.y as f64 };
y: safe_area.origin.y as f64,
};
let scale_factor = self.scale_factor(); let scale_factor = self.scale_factor();
Ok(position.to_physical(scale_factor)) Ok(position.to_physical(scale_factor))
} }
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> { pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let screen_frame = self.screen_frame(); let screen_frame = self.screen_frame();
let position = LogicalPosition { let position =
x: screen_frame.origin.x as f64, LogicalPosition { x: screen_frame.origin.x as f64, y: screen_frame.origin.y as f64 };
y: screen_frame.origin.y as f64,
};
let scale_factor = self.scale_factor(); let scale_factor = self.scale_factor();
Ok(position.to_physical(scale_factor)) Ok(position.to_physical(scale_factor))
} }
@ -176,10 +173,7 @@ impl Inner {
let position = physical_position.to_logical::<f64>(scale_factor); let position = physical_position.to_logical::<f64>(scale_factor);
let screen_frame = self.screen_frame(); let screen_frame = self.screen_frame();
let new_screen_frame = CGRect { let new_screen_frame = CGRect {
origin: CGPoint { origin: CGPoint { x: position.x as _, y: position.y as _ },
x: position.x as _,
y: position.y as _,
},
size: screen_frame.size, size: screen_frame.size,
}; };
let bounds = self.rect_from_screen_space(new_screen_frame); let bounds = self.rect_from_screen_space(new_screen_frame);
@ -307,15 +301,15 @@ impl Inner {
let uiscreen = video_mode.monitor.ui_screen(mtm); let uiscreen = video_mode.monitor.ui_screen(mtm);
uiscreen.setCurrentMode(Some(video_mode.screen_mode(mtm))); uiscreen.setCurrentMode(Some(video_mode.screen_mode(mtm)));
uiscreen.clone() uiscreen.clone()
} },
Some(Fullscreen::Borderless(Some(monitor))) => monitor.ui_screen(mtm).clone(), Some(Fullscreen::Borderless(Some(monitor))) => monitor.ui_screen(mtm).clone(),
Some(Fullscreen::Borderless(None)) => { Some(Fullscreen::Borderless(None)) => {
self.current_monitor_inner().ui_screen(mtm).clone() self.current_monitor_inner().ui_screen(mtm).clone()
} },
None => { None => {
warn!("`Window::set_fullscreen(None)` ignored on iOS"); warn!("`Window::set_fullscreen(None)` ignored on iOS");
return; return;
} },
}; };
// this is pretty slow on iOS, so avoid doing it if we can // this is pretty slow on iOS, so avoid doing it if we can
@ -400,9 +394,7 @@ impl Inner {
} }
pub fn primary_monitor(&self) -> Option<MonitorHandle> { pub fn primary_monitor(&self) -> Option<MonitorHandle> {
Some(MonitorHandle::new(UIScreen::main( Some(MonitorHandle::new(UIScreen::main(MainThreadMarker::new().unwrap())))
MainThreadMarker::new().unwrap(),
)))
} }
pub fn id(&self) -> WindowId { pub fn id(&self) -> WindowId {
@ -505,12 +497,9 @@ impl Window {
let size = dim.to_logical::<f64>(scale_factor as f64); let size = dim.to_logical::<f64>(scale_factor as f64);
CGRect { CGRect {
origin: screen_bounds.origin, origin: screen_bounds.origin,
size: CGSize { size: CGSize { width: size.width as _, height: size.height as _ },
width: size.width as _,
height: size.height as _,
},
} }
} },
None => screen_bounds, None => screen_bounds,
}; };
@ -544,13 +533,11 @@ impl Window {
let window_id = RootWindowId(window.id()); let window_id = RootWindowId(window.id());
app_state::handle_nonuser_events( app_state::handle_nonuser_events(
mtm, mtm,
std::iter::once(EventWrapper::ScaleFactorChanged( std::iter::once(EventWrapper::ScaleFactorChanged(app_state::ScaleFactorChanged {
app_state::ScaleFactorChanged { window: window.clone(),
window: window.clone(), scale_factor,
scale_factor, suggested_size: size.to_physical(scale_factor),
suggested_size: size.to_physical(scale_factor), }))
},
))
.chain(std::iter::once(EventWrapper::StaticEvent( .chain(std::iter::once(EventWrapper::StaticEvent(
Event::WindowEvent { Event::WindowEvent {
window_id, window_id,
@ -560,15 +547,8 @@ impl Window {
); );
} }
let inner = Inner { let inner = Inner { window, view_controller, view, gl_or_metal_backed };
window, Ok(Window { inner: MainThreadBound::new(inner, mtm) })
view_controller,
view,
gl_or_metal_backed,
};
Ok(Window {
inner: MainThreadBound::new(inner, mtm),
})
} }
pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Inner) + Send + 'static) { pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Inner) + Send + 'static) {
@ -597,9 +577,7 @@ impl Window {
pub(crate) fn raw_display_handle_rwh_06( pub(crate) fn raw_display_handle_rwh_06(
&self, &self,
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> { ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
Ok(rwh_06::RawDisplayHandle::UiKit( Ok(rwh_06::RawDisplayHandle::UiKit(rwh_06::UiKitDisplayHandle::new()))
rwh_06::UiKitDisplayHandle::new(),
))
} }
} }
@ -622,13 +600,11 @@ impl Inner {
} }
pub fn set_prefers_home_indicator_hidden(&self, hidden: bool) { pub fn set_prefers_home_indicator_hidden(&self, hidden: bool) {
self.view_controller self.view_controller.set_prefers_home_indicator_auto_hidden(hidden);
.set_prefers_home_indicator_auto_hidden(hidden);
} }
pub fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) { pub fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) {
self.view_controller self.view_controller.set_preferred_screen_edges_deferring_system_gestures(edges);
.set_preferred_screen_edges_deferring_system_gestures(edges);
} }
pub fn set_prefers_status_bar_hidden(&self, hidden: bool) { pub fn set_prefers_status_bar_hidden(&self, hidden: bool) {
@ -636,8 +612,7 @@ impl Inner {
} }
pub fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) { pub fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) {
self.view_controller self.view_controller.set_preferred_status_bar_style(status_bar_style);
.set_preferred_status_bar_style(status_bar_style);
} }
pub fn recognize_pinch_gesture(&self, should_recognize: bool) { pub fn recognize_pinch_gesture(&self, should_recognize: bool) {
@ -660,14 +635,12 @@ impl Inner {
fn rect_to_screen_space(&self, rect: CGRect) -> CGRect { fn rect_to_screen_space(&self, rect: CGRect) -> CGRect {
let screen_space = self.window.screen().coordinateSpace(); let screen_space = self.window.screen().coordinateSpace();
self.window self.window.convertRect_toCoordinateSpace(rect, &screen_space)
.convertRect_toCoordinateSpace(rect, &screen_space)
} }
fn rect_from_screen_space(&self, rect: CGRect) -> CGRect { fn rect_from_screen_space(&self, rect: CGRect) -> CGRect {
let screen_space = self.window.screen().coordinateSpace(); let screen_space = self.window.screen().coordinateSpace();
self.window self.window.convertRect_fromCoordinateSpace(rect, &screen_space)
.convertRect_fromCoordinateSpace(rect, &screen_space)
} }
fn safe_area_screen_space(&self) -> CGRect { fn safe_area_screen_space(&self) -> CGRect {
@ -689,7 +662,8 @@ impl Inner {
let screen_frame = self.rect_to_screen_space(bounds); let screen_frame = self.rect_to_screen_space(bounds);
let status_bar_frame = { let status_bar_frame = {
let app = UIApplication::shared(MainThreadMarker::new().unwrap()).expect( let app = UIApplication::shared(MainThreadMarker::new().unwrap()).expect(
"`Window::get_inner_position` cannot be called before `EventLoop::run_app` on iOS", "`Window::get_inner_position` cannot be called before `EventLoop::run_app` on \
iOS",
); );
app.statusBarFrame() app.statusBarFrame()
}; };
@ -702,14 +676,8 @@ impl Inner {
(y, height) (y, height)
}; };
CGRect { CGRect {
origin: CGPoint { origin: CGPoint { x: screen_frame.origin.x, y },
x: screen_frame.origin.x, size: CGSize { width: screen_frame.size.width, height },
y,
},
size: CGSize {
width: screen_frame.size.width,
height,
},
} }
} }
} }
@ -722,9 +690,7 @@ pub struct WindowId {
impl WindowId { impl WindowId {
pub const unsafe fn dummy() -> Self { pub const unsafe fn dummy() -> Self {
WindowId { WindowId { window: std::ptr::null_mut() }
window: std::ptr::null_mut(),
}
} }
} }
@ -736,9 +702,7 @@ impl From<WindowId> for u64 {
impl From<u64> for WindowId { impl From<u64> for WindowId {
fn from(raw_id: u64) -> Self { fn from(raw_id: u64) -> Self {
Self { Self { window: raw_id as _ }
window: raw_id as _,
}
} }
} }
@ -747,9 +711,7 @@ unsafe impl Sync for WindowId {}
impl From<&AnyObject> for WindowId { impl From<&AnyObject> for WindowId {
fn from(window: &AnyObject) -> WindowId { fn from(window: &AnyObject) -> WindowId {
WindowId { WindowId { window: window as *const _ as _ }
window: window as *const _ as _,
}
} }
} }

View file

@ -6,8 +6,7 @@ use std::ops::Deref;
use std::os::unix::ffi::OsStringExt; use std::os::unix::ffi::OsStringExt;
use std::ptr::NonNull; use std::ptr::NonNull;
use super::XkbContext; use super::{XkbContext, XKBCH};
use super::XKBCH;
use smol_str::SmolStr; use smol_str::SmolStr;
use xkbcommon_dl::{ use xkbcommon_dl::{
xkb_compose_compile_flags, xkb_compose_feed_result, xkb_compose_state, xkb_compose_state_flags, xkb_compose_compile_flags, xkb_compose_feed_result, xkb_compose_state, xkb_compose_state_flags,
@ -91,7 +90,7 @@ impl XkbComposeState {
xkb_compose_feed_result::XKB_COMPOSE_FEED_IGNORED => ComposeStatus::Ignored, xkb_compose_feed_result::XKB_COMPOSE_FEED_IGNORED => ComposeStatus::Ignored,
xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED => { xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED => {
ComposeStatus::Accepted(self.status()) ComposeStatus::Accepted(self.status())
} },
} }
} }

View file

@ -296,7 +296,7 @@ pub fn physicalkey_to_scancode(key: PhysicalKey) -> Option<u32> {
NativeKeyCode::Xkb(raw) => Some(raw), NativeKeyCode::Xkb(raw) => Some(raw),
_ => None, _ => None,
}; };
} },
}; };
match code { match code {
@ -627,7 +627,6 @@ pub fn keysym_to_key(keysym: u32) -> Key {
// keysyms::ISO_First_Group_Lock => NamedKey::GroupFirstLock, // keysyms::ISO_First_Group_Lock => NamedKey::GroupFirstLock,
keysyms::ISO_Last_Group => NamedKey::GroupLast, keysyms::ISO_Last_Group => NamedKey::GroupLast,
// keysyms::ISO_Last_Group_Lock => NamedKey::GroupLastLock, // keysyms::ISO_Last_Group_Lock => NamedKey::GroupLastLock,
//
keysyms::ISO_Left_Tab => NamedKey::Tab, keysyms::ISO_Left_Tab => NamedKey::Tab,
// keysyms::ISO_Move_Line_Up => NamedKey::IsoMoveLineUp, // keysyms::ISO_Move_Line_Up => NamedKey::IsoMoveLineUp,
// keysyms::ISO_Move_Line_Down => NamedKey::IsoMoveLineDown, // keysyms::ISO_Move_Line_Down => NamedKey::IsoMoveLineDown,
@ -809,18 +808,15 @@ pub fn keysym_to_key(keysym: u32) -> Key {
keysyms::XF86_Music => NamedKey::LaunchMusicPlayer, keysyms::XF86_Music => NamedKey::LaunchMusicPlayer,
// XF86_Battery..XF86_UWB // XF86_Battery..XF86_UWB
//
keysyms::XF86_AudioForward => NamedKey::MediaFastForward, keysyms::XF86_AudioForward => NamedKey::MediaFastForward,
// XF86_AudioRepeat // XF86_AudioRepeat
keysyms::XF86_AudioRandomPlay => NamedKey::RandomToggle, keysyms::XF86_AudioRandomPlay => NamedKey::RandomToggle,
keysyms::XF86_Subtitle => NamedKey::Subtitle, keysyms::XF86_Subtitle => NamedKey::Subtitle,
keysyms::XF86_AudioCycleTrack => NamedKey::MediaAudioTrack, keysyms::XF86_AudioCycleTrack => NamedKey::MediaAudioTrack,
// XF86_CycleAngle..XF86_Blue // XF86_CycleAngle..XF86_Blue
//
keysyms::XF86_Suspend => NamedKey::Standby, keysyms::XF86_Suspend => NamedKey::Standby,
keysyms::XF86_Hibernate => NamedKey::Hibernate, keysyms::XF86_Hibernate => NamedKey::Hibernate,
// XF86_TouchpadToggle..XF86_TouchpadOff // XF86_TouchpadToggle..XF86_TouchpadOff
//
keysyms::XF86_AudioMute => NamedKey::AudioVolumeMute, keysyms::XF86_AudioMute => NamedKey::AudioVolumeMute,
// XF86_Switch_VT_1..XF86_Switch_VT_12 // XF86_Switch_VT_1..XF86_Switch_VT_12
@ -853,7 +849,6 @@ pub fn keysym_to_key(keysym: u32) -> Key {
keysyms::SUN_VideoLowerBrightness => NamedKey::BrightnessDown, keysyms::SUN_VideoLowerBrightness => NamedKey::BrightnessDown,
keysyms::SUN_VideoRaiseBrightness => NamedKey::BrightnessUp, keysyms::SUN_VideoRaiseBrightness => NamedKey::BrightnessUp,
// SunPowerSwitchShift // SunPowerSwitchShift
//
0 => return Key::Unidentified(NativeKey::Unidentified), 0 => return Key::Unidentified(NativeKey::Unidentified),
_ => return Key::Unidentified(NativeKey::Xkb(keysym)), _ => return Key::Unidentified(NativeKey::Xkb(keysym)),
}) })
@ -968,11 +963,7 @@ impl XkbKeymap {
mod5: mod_index_for_name(keymap, b"Mod5\0"), mod5: mod_index_for_name(keymap, b"Mod5\0"),
}; };
Self { Self { keymap, _mods_indices: mods_indices, _core_keyboard_id }
keymap,
_mods_indices: mods_indices,
_core_keyboard_id,
}
} }
#[cfg(x11_platform)] #[cfg(x11_platform)]
@ -1020,6 +1011,7 @@ impl Drop for XkbKeymap {
impl Deref for XkbKeymap { impl Deref for XkbKeymap {
type Target = NonNull<xkb_keymap>; type Target = NonNull<xkb_keymap>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.keymap &self.keymap
} }

View file

@ -15,8 +15,7 @@ use xkbcommon_dl::{
#[cfg(x11_platform)] #[cfg(x11_platform)]
use {x11_dl::xlib_xcb::xcb_connection_t, xkbcommon_dl::x11::xkbcommon_x11_handle}; use {x11_dl::xlib_xcb::xcb_connection_t, xkbcommon_dl::x11::xkbcommon_x11_handle};
use crate::event::ElementState; use crate::event::{ElementState, KeyEvent};
use crate::event::KeyEvent;
use crate::keyboard::{Key, KeyLocation}; use crate::keyboard::{Key, KeyLocation};
use crate::platform_impl::KeyEventExtra; use crate::platform_impl::KeyEventExtra;
@ -143,9 +142,7 @@ impl Context {
#[cfg(x11_platform)] #[cfg(x11_platform)]
pub fn set_keymap_from_x11(&mut self, xcb: *mut xcb_connection_t) { pub fn set_keymap_from_x11(&mut self, xcb: *mut xcb_connection_t) {
let keymap = XkbKeymap::from_x11_keymap(&self.context, xcb, self.core_keyboard_id); let keymap = XkbKeymap::from_x11_keymap(&self.context, xcb, self.core_keyboard_id);
let state = keymap let state = keymap.as_ref().and_then(|keymap| XkbState::new_x11(xcb, keymap));
.as_ref()
.and_then(|keymap| XkbState::new_x11(xcb, keymap));
if keymap.is_none() || state.is_none() { if keymap.is_none() || state.is_none() {
warn!("failed to update xkb keymap"); warn!("failed to update xkb keymap");
} }
@ -160,13 +157,7 @@ impl Context {
let compose_state1 = self.compose_state1.as_mut(); let compose_state1 = self.compose_state1.as_mut();
let compose_state2 = self.compose_state2.as_mut(); let compose_state2 = self.compose_state2.as_mut();
let scratch_buffer = &mut self.scratch_buffer; let scratch_buffer = &mut self.scratch_buffer;
Some(KeyContext { Some(KeyContext { state, keymap, compose_state1, compose_state2, scratch_buffer })
state,
keymap,
compose_state1,
compose_state2,
scratch_buffer,
})
} }
/// Key builder context with the user provided xkb state. /// Key builder context with the user provided xkb state.
@ -181,13 +172,7 @@ impl Context {
let compose_state1 = self.compose_state1.as_mut(); let compose_state1 = self.compose_state1.as_mut();
let compose_state2 = self.compose_state2.as_mut(); let compose_state2 = self.compose_state2.as_mut();
let scratch_buffer = &mut self.scratch_buffer; let scratch_buffer = &mut self.scratch_buffer;
Some(KeyContext { Some(KeyContext { state, keymap, compose_state1, compose_state2, scratch_buffer })
state,
keymap,
compose_state1,
compose_state2,
scratch_buffer,
})
} }
} }
@ -214,20 +199,9 @@ impl<'a> KeyContext<'a> {
let (key_without_modifiers, _) = event.key_without_modifiers(); let (key_without_modifiers, _) = event.key_without_modifiers();
let text_with_all_modifiers = event.text_with_all_modifiers(); let text_with_all_modifiers = event.text_with_all_modifiers();
let platform_specific = KeyEventExtra { let platform_specific = KeyEventExtra { text_with_all_modifiers, key_without_modifiers };
text_with_all_modifiers,
key_without_modifiers,
};
KeyEvent { KeyEvent { physical_key, logical_key, text, location, state, repeat, platform_specific }
physical_key,
logical_key,
text,
location,
state,
repeat,
platform_specific,
}
} }
fn keysym_to_utf8_raw(&mut self, keysym: u32) -> Option<SmolStr> { fn keysym_to_utf8_raw(&mut self, keysym: u32) -> Option<SmolStr> {
@ -246,10 +220,7 @@ impl<'a> KeyContext<'a> {
} else if bytes_written == -1 { } else if bytes_written == -1 {
self.scratch_buffer.reserve(8); self.scratch_buffer.reserve(8);
} else { } else {
unsafe { unsafe { self.scratch_buffer.set_len(bytes_written.try_into().unwrap()) };
self.scratch_buffer
.set_len(bytes_written.try_into().unwrap())
};
break; break;
} }
} }
@ -281,12 +252,7 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
ComposeStatus::None ComposeStatus::None
}; };
KeyEventResults { KeyEventResults { context, keycode, keysym, compose }
context,
keycode,
keysym,
compose,
}
} }
pub fn key(&mut self) -> (Key, KeyLocation) { pub fn key(&mut self) -> (Key, KeyLocation) {
@ -323,23 +289,18 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
} }
pub fn key_without_modifiers(&mut self) -> (Key, KeyLocation) { pub fn key_without_modifiers(&mut self) -> (Key, KeyLocation) {
// This will become a pointer to an array which libxkbcommon owns, so we don't need to deallocate it. // This will become a pointer to an array which libxkbcommon owns, so we don't need to
// deallocate it.
let layout = self.context.state.layout(self.keycode); let layout = self.context.state.layout(self.keycode);
let keysym = self let keysym = self.context.keymap.first_keysym_by_level(layout, self.keycode);
.context
.keymap
.first_keysym_by_level(layout, self.keycode);
match self.keysym_to_key(keysym) { match self.keysym_to_key(keysym) {
Ok((key, location)) => (key, location), Ok((key, location)) => (key, location),
Err((key, location)) => { Err((key, location)) => {
let key = self let key =
.context self.context.keysym_to_utf8_raw(keysym).map(Key::Character).unwrap_or(key);
.keysym_to_utf8_raw(keysym)
.map(Key::Character)
.unwrap_or(key);
(key, location) (key, location)
} },
} }
} }
@ -354,8 +315,7 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
} }
pub fn text(&mut self) -> Option<SmolStr> { pub fn text(&mut self) -> Option<SmolStr> {
self.composed_text() self.composed_text().unwrap_or_else(|_| self.context.keysym_to_utf8_raw(self.keysym))
.unwrap_or_else(|_| self.context.keysym_to_utf8_raw(self.keysym))
} }
// The current behaviour makes it so composing a character overrides attempts to input a // The current behaviour makes it so composing a character overrides attempts to input a
@ -364,10 +324,7 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
pub fn text_with_all_modifiers(&mut self) -> Option<SmolStr> { pub fn text_with_all_modifiers(&mut self) -> Option<SmolStr> {
match self.composed_text() { match self.composed_text() {
Ok(text) => text, Ok(text) => text,
Err(_) => self Err(_) => self.context.state.get_utf8_raw(self.keycode, self.context.scratch_buffer),
.context
.state
.get_utf8_raw(self.keycode, self.context.scratch_buffer),
} }
} }
@ -377,7 +334,7 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
xkb_compose_status::XKB_COMPOSE_COMPOSED => { xkb_compose_status::XKB_COMPOSE_COMPOSED => {
let state = self.context.compose_state1.as_mut().unwrap(); let state = self.context.compose_state1.as_mut().unwrap();
Ok(state.get_string(self.context.scratch_buffer)) Ok(state.get_string(self.context.scratch_buffer))
} },
xkb_compose_status::XKB_COMPOSE_COMPOSING xkb_compose_status::XKB_COMPOSE_COMPOSING
| xkb_compose_status::XKB_COMPOSE_CANCELLED => Ok(None), | xkb_compose_status::XKB_COMPOSE_CANCELLED => Ok(None),
xkb_compose_status::XKB_COMPOSE_NOTHING => Err(()), xkb_compose_status::XKB_COMPOSE_NOTHING => Err(()),
@ -436,10 +393,7 @@ where
// The allocated buffer must include space for the null-terminator. // The allocated buffer must include space for the null-terminator.
scratch_buffer.reserve(size + 1); scratch_buffer.reserve(size + 1);
unsafe { unsafe {
let written = f( let written = f(scratch_buffer.as_mut_ptr().cast(), scratch_buffer.capacity());
scratch_buffer.as_mut_ptr().cast(),
scratch_buffer.capacity(),
);
if usize::try_from(written).unwrap() != size { if usize::try_from(written).unwrap() != size {
// This will likely never happen. // This will likely never happen.
return None; return None;
@ -456,10 +410,7 @@ fn byte_slice_to_smol_str(bytes: &[u8]) -> Option<SmolStr> {
std::str::from_utf8(bytes) std::str::from_utf8(bytes)
.map(SmolStr::new) .map(SmolStr::new)
.map_err(|e| { .map_err(|e| {
tracing::warn!( tracing::warn!("UTF-8 received from libxkbcommon ({:?}) was invalid: {e}", bytes)
"UTF-8 received from libxkbcommon ({:?}) was invalid: {e}",
bytes
)
}) })
.ok() .ok()
} }

View file

@ -3,10 +3,11 @@
#[cfg(all(not(x11_platform), not(wayland_platform)))] #[cfg(all(not(x11_platform), not(wayland_platform)))]
compile_error!("Please select a feature to build for unix: `x11`, `wayland`"); compile_error!("Please select a feature to build for unix: `x11`, `wayland`");
use std::collections::VecDeque;
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::{collections::VecDeque, env, fmt}; use std::{env, fmt};
#[cfg(x11_platform)] #[cfg(x11_platform)]
use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex}; use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex};
@ -16,22 +17,19 @@ use smol_str::SmolStr;
#[cfg(x11_platform)] #[cfg(x11_platform)]
use self::x11::{X11Error, XConnection, XError, XNotSupported}; use self::x11::{X11Error, XConnection, XError, XNotSupported};
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError};
use crate::event_loop::{
ActiveEventLoop as RootELW, AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
};
use crate::icon::Icon;
use crate::keyboard::Key;
use crate::platform::pump_events::PumpStatus;
#[cfg(x11_platform)] #[cfg(x11_platform)]
use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook}; use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook};
use crate::window::{CustomCursor, CustomCursorSource}; use crate::window::{
use crate::{ ActivationToken, Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose,
dpi::{PhysicalPosition, PhysicalSize, Position, Size}, ResizeDirection, Theme, UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError},
event_loop::{
ActiveEventLoop as RootELW, AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
},
icon::Icon,
keyboard::Key,
platform::pump_events::PumpStatus,
window::{
ActivationToken, Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme,
UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
},
}; };
pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey}; pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
@ -294,11 +292,11 @@ impl Window {
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
ActiveEventLoop::Wayland(ref window_target) => { ActiveEventLoop::Wayland(ref window_target) => {
wayland::Window::new(window_target, attribs).map(Window::Wayland) wayland::Window::new(window_target, attribs).map(Window::Wayland)
} },
#[cfg(x11_platform)] #[cfg(x11_platform)]
ActiveEventLoop::X(ref window_target) => { ActiveEventLoop::X(ref window_target) => {
x11::Window::new(window_target, attribs).map(Window::X) x11::Window::new(window_target, attribs).map(Window::X)
} },
} }
} }
@ -534,6 +532,7 @@ impl Window {
pub fn focus_window(&self) { pub fn focus_window(&self) {
x11_or_wayland!(match self; Window(w) => w.focus_window()) x11_or_wayland!(match self; Window(w) => w.focus_window())
} }
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) { pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
x11_or_wayland!(match self; Window(w) => w.request_user_attention(request_type)) x11_or_wayland!(match self; Window(w) => w.request_user_attention(request_type))
} }
@ -557,17 +556,13 @@ impl Window {
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> { pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
match self { match self {
#[cfg(x11_platform)] #[cfg(x11_platform)]
Window::X(ref window) => window Window::X(ref window) => {
.available_monitors() window.available_monitors().into_iter().map(MonitorHandle::X).collect()
.into_iter() },
.map(MonitorHandle::X)
.collect(),
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
Window::Wayland(ref window) => window Window::Wayland(ref window) => {
.available_monitors() window.available_monitors().into_iter().map(MonitorHandle::Wayland).collect()
.into_iter() },
.map(MonitorHandle::Wayland)
.collect(),
} }
} }
@ -741,12 +736,10 @@ impl<T: 'static> EventLoop<T> {
.or_else(|| env::var("WAYLAND_SOCKET").ok()) .or_else(|| env::var("WAYLAND_SOCKET").ok())
.filter(|var| !var.is_empty()) .filter(|var| !var.is_empty())
.is_some(), .is_some(),
env::var("DISPLAY") env::var("DISPLAY").map(|var| !var.is_empty()).unwrap_or(false),
.map(|var| !var.is_empty())
.unwrap_or(false),
) { ) {
// User is forcing a backend. // User is forcing a backend.
(Some(backend), _, _) => backend, (Some(backend), ..) => backend,
// Wayland is present. // Wayland is present.
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
(None, true, _) => Backend::Wayland, (None, true, _) => Backend::Wayland,
@ -756,14 +749,16 @@ impl<T: 'static> EventLoop<T> {
// No backend is present. // No backend is present.
(_, wayland_display, x11_display) => { (_, wayland_display, x11_display) => {
let msg = if wayland_display && !cfg!(wayland_platform) { let msg = if wayland_display && !cfg!(wayland_platform) {
"DISPLAY is not set; note: enable the `winit/wayland` feature to support Wayland" "DISPLAY is not set; note: enable the `winit/wayland` feature to support \
Wayland"
} else if x11_display && !cfg!(x11_platform) { } else if x11_display && !cfg!(x11_platform) {
"neither WAYLAND_DISPLAY nor WAYLAND_SOCKET is set; note: enable the `winit/x11` feature to support X11" "neither WAYLAND_DISPLAY nor WAYLAND_SOCKET is set; note: enable the \
`winit/x11` feature to support X11"
} else { } else {
"neither WAYLAND_DISPLAY nor WAYLAND_SOCKET nor DISPLAY is set." "neither WAYLAND_DISPLAY nor WAYLAND_SOCKET nor DISPLAY is set."
}; };
return Err(EventLoopError::Os(os_error!(OsError::Misc(msg)))); return Err(EventLoopError::Os(os_error!(OsError::Misc(msg))));
} },
}; };
// Create the display based on the backend. // Create the display based on the backend.
@ -864,14 +859,13 @@ impl ActiveEventLoop {
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> { pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
match *self { match *self {
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
ActiveEventLoop::Wayland(ref evlp) => evlp ActiveEventLoop::Wayland(ref evlp) => {
.available_monitors() evlp.available_monitors().map(MonitorHandle::Wayland).collect()
.map(MonitorHandle::Wayland) },
.collect(),
#[cfg(x11_platform)] #[cfg(x11_platform)]
ActiveEventLoop::X(ref evlp) => { ActiveEventLoop::X(ref evlp) => {
evlp.available_monitors().map(MonitorHandle::X).collect() evlp.available_monitors().map(MonitorHandle::X).collect()
} },
} }
} }
@ -961,7 +955,7 @@ impl OwnedDisplayHandle {
xlib_handle.display = xconn.display.cast(); xlib_handle.display = xconn.display.cast();
xlib_handle.screen = xconn.default_screen_index() as _; xlib_handle.screen = xconn.default_screen_index() as _;
xlib_handle.into() xlib_handle.into()
} },
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
Self::Wayland(conn) => { Self::Wayland(conn) => {
@ -970,7 +964,7 @@ impl OwnedDisplayHandle {
let mut wayland_handle = rwh_05::WaylandDisplayHandle::empty(); let mut wayland_handle = rwh_05::WaylandDisplayHandle::empty();
wayland_handle.display = conn.display().id().as_ptr() as *mut _; wayland_handle.display = conn.display().id().as_ptr() as *mut _;
wayland_handle.into() wayland_handle.into()
} },
} }
} }
@ -997,7 +991,7 @@ impl OwnedDisplayHandle {
NonNull::new(conn.display().id().as_ptr().cast()).unwrap(), NonNull::new(conn.display().id().as_ptr().cast()).unwrap(),
) )
.into()) .into())
} },
} }
} }
} }
@ -1006,9 +1000,7 @@ impl OwnedDisplayHandle {
/// equates to an infinite timeout, not a zero timeout (so can't just use /// equates to an infinite timeout, not a zero timeout (so can't just use
/// `Option::min`) /// `Option::min`)
fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> { fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
a.map_or(b, |a_timeout| { a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))
})
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]

View file

@ -12,8 +12,7 @@ use std::time::{Duration, Instant};
use sctk::reexports::calloop::Error as CalloopError; use sctk::reexports::calloop::Error as CalloopError;
use sctk::reexports::calloop_wayland_source::WaylandSource; use sctk::reexports::calloop_wayland_source::WaylandSource;
use sctk::reexports::client::globals; use sctk::reexports::client::{globals, Connection, QueueHandle};
use sctk::reexports::client::{Connection, QueueHandle};
use crate::cursor::OnlyCursorImage; use crate::cursor::OnlyCursorImage;
use crate::dpi::LogicalSize; use crate::dpi::LogicalSize;
@ -81,26 +80,19 @@ impl<T: 'static> EventLoop<T> {
let connection = map_err!(Connection::connect_to_env(), WaylandError::Connection)?; let connection = map_err!(Connection::connect_to_env(), WaylandError::Connection)?;
let (globals, mut event_queue) = map_err!( let (globals, mut event_queue) =
globals::registry_queue_init(&connection), map_err!(globals::registry_queue_init(&connection), WaylandError::Global)?;
WaylandError::Global
)?;
let queue_handle = event_queue.handle(); let queue_handle = event_queue.handle();
let event_loop = map_err!( let event_loop =
calloop::EventLoop::<WinitState>::try_new(), map_err!(calloop::EventLoop::<WinitState>::try_new(), WaylandError::Calloop)?;
WaylandError::Calloop
)?;
let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle()) let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle())
.map_err(|error| os_error!(error))?; .map_err(|error| os_error!(error))?;
// NOTE: do a roundtrip after binding the globals to prevent potential // NOTE: do a roundtrip after binding the globals to prevent potential
// races with the server. // races with the server.
map_err!( map_err!(event_queue.roundtrip(&mut winit_state), WaylandError::Dispatch)?;
event_queue.roundtrip(&mut winit_state),
WaylandError::Dispatch
)?;
// Register Wayland source. // Register Wayland source.
let wayland_source = WaylandSource::new(connection.clone(), event_queue); let wayland_source = WaylandSource::new(connection.clone(), event_queue);
@ -117,9 +109,7 @@ impl<T: 'static> EventLoop<T> {
}); });
map_err!( map_err!(
event_loop event_loop.handle().register_dispatcher(wayland_dispatcher.clone()),
.handle()
.register_dispatcher(wayland_dispatcher.clone()),
WaylandError::Calloop WaylandError::Calloop
)?; )?;
@ -129,15 +119,12 @@ impl<T: 'static> EventLoop<T> {
let (user_events_sender, user_events_channel) = calloop::channel::channel(); let (user_events_sender, user_events_channel) = calloop::channel::channel();
let result = event_loop let result = event_loop
.handle() .handle()
.insert_source( .insert_source(user_events_channel, move |event, _, winit_state: &mut WinitState| {
user_events_channel, if let calloop::channel::Event::Msg(msg) = event {
move |event, _, winit_state: &mut WinitState| { winit_state.dispatched_events = true;
if let calloop::channel::Event::Msg(msg) = event { pending_user_events_clone.borrow_mut().push(msg);
winit_state.dispatched_events = true; }
pending_user_events_clone.borrow_mut().push(msg); })
}
},
)
.map_err(|error| error.error); .map_err(|error| error.error);
map_err!(result, WaylandError::Calloop)?; map_err!(result, WaylandError::Calloop)?;
@ -150,13 +137,10 @@ impl<T: 'static> EventLoop<T> {
let result = event_loop let result = event_loop
.handle() .handle()
.insert_source( .insert_source(event_loop_awakener_source, move |_, _, winit_state: &mut WinitState| {
event_loop_awakener_source, // Mark that we have something to dispatch.
move |_, _, winit_state: &mut WinitState| { winit_state.dispatched_events = true;
// Mark that we have something to dispatch. })
winit_state.dispatched_events = true;
},
)
.map_err(|error| error.error); .map_err(|error| error.error);
map_err!(result, WaylandError::Calloop)?; map_err!(result, WaylandError::Calloop)?;
@ -197,13 +181,13 @@ impl<T: 'static> EventLoop<T> {
match self.pump_events(None, &mut event_handler) { match self.pump_events(None, &mut event_handler) {
PumpStatus::Exit(0) => { PumpStatus::Exit(0) => {
break Ok(()); break Ok(());
} },
PumpStatus::Exit(code) => { PumpStatus::Exit(code) => {
break Err(EventLoopError::ExitFailure(code)); break Err(EventLoopError::ExitFailure(code));
} },
_ => { _ => {
continue; continue;
} },
} }
}; };
@ -256,7 +240,7 @@ impl<T: 'static> EventLoop<T> {
ControlFlow::Poll => Some(Duration::ZERO), ControlFlow::Poll => Some(Duration::ZERO),
ControlFlow::WaitUntil(wait_deadline) => { ControlFlow::WaitUntil(wait_deadline) => {
Some(wait_deadline.saturating_duration_since(start)) Some(wait_deadline.saturating_duration_since(start))
} },
}; };
min_timeout(control_flow_timeout, timeout) min_timeout(control_flow_timeout, timeout)
}; };
@ -274,11 +258,12 @@ impl<T: 'static> EventLoop<T> {
if let Err(error) = self.loop_dispatch(timeout) { if let Err(error) = self.loop_dispatch(timeout) {
// NOTE We exit on errors from dispatches, since if we've got protocol error // NOTE We exit on errors from dispatches, since if we've got protocol error
// libwayland-client/wayland-rs will inform us anyway, but crashing downstream is not // libwayland-client/wayland-rs will inform us anyway, but crashing downstream is
// really an option. Instead we inform that the event loop got destroyed. We may // not really an option. Instead we inform that the event loop got
// communicate an error that something was terminated, but winit doesn't provide us // destroyed. We may communicate an error that something was
// with an API to do that via some event. // terminated, but winit doesn't provide us with an API to do that
// Still, we set the exit code to the error's OS error code, or to 1 if not possible. // via some event. Still, we set the exit code to the error's OS
// error code, or to 1 if not possible.
let exit_code = error.raw_os_error().unwrap_or(1); let exit_code = error.raw_os_error().unwrap_or(1);
self.set_exit_code(exit_code); self.set_exit_code(exit_code);
return; return;
@ -288,23 +273,14 @@ impl<T: 'static> EventLoop<T> {
// to be considered here // to be considered here
let cause = match self.control_flow() { let cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll, ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled { ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
start,
requested_resume: None,
},
ControlFlow::WaitUntil(deadline) => { ControlFlow::WaitUntil(deadline) => {
if Instant::now() < deadline { if Instant::now() < deadline {
StartCause::WaitCancelled { StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
start,
requested_resume: Some(deadline),
}
} else { } else {
StartCause::ResumeTimeReached { StartCause::ResumeTimeReached { start, requested_resume: deadline }
start,
requested_resume: deadline,
}
} }
} },
}; };
// Reduce spurious wake-ups. // Reduce spurious wake-ups.
@ -471,13 +447,8 @@ impl<T: 'static> EventLoop<T> {
return Some(WindowEvent::Destroyed); return Some(WindowEvent::Destroyed);
} }
let mut window = state let mut window =
.windows state.windows.get_mut().get_mut(window_id).unwrap().lock().unwrap();
.get_mut()
.get_mut(window_id)
.unwrap()
.lock()
.unwrap();
if window.frame_callback_state() == FrameCallbackState::Requested { if window.frame_callback_state() == FrameCallbackState::Requested {
return None; return None;
@ -485,10 +456,8 @@ impl<T: 'static> EventLoop<T> {
// Reset the frame callbacks state. // Reset the frame callbacks state.
window.frame_callback_reset(); window.frame_callback_reset();
let mut redraw_requested = window_requests let mut redraw_requested =
.get(window_id) window_requests.get(window_id).unwrap().take_redraw_requested();
.unwrap()
.take_redraw_requested();
// Redraw the frame while at it. // Redraw the frame while at it.
redraw_requested |= window.refresh_frame(); redraw_requested |= window.refresh_frame();
@ -498,10 +467,7 @@ impl<T: 'static> EventLoop<T> {
if let Some(event) = event { if let Some(event) = event {
callback( callback(
Event::WindowEvent { Event::WindowEvent { window_id: crate::window::WindowId(*window_id), event },
window_id: crate::window::WindowId(*window_id),
event,
},
&self.window_target, &self.window_target,
); );
} }
@ -532,7 +498,7 @@ impl<T: 'static> EventLoop<T> {
} }
refresh refresh
} },
None => false, None => false,
}); });
} }
@ -545,7 +511,7 @@ impl<T: 'static> EventLoop<T> {
match &self.window_target.p { match &self.window_target.p {
PlatformActiveEventLoop::Wayland(window_target) => { PlatformActiveEventLoop::Wayland(window_target) => {
window_target.event_loop_awakener.ping(); window_target.event_loop_awakener.ping();
} },
#[cfg(x11_platform)] #[cfg(x11_platform)]
PlatformActiveEventLoop::X(_) => unreachable!(), PlatformActiveEventLoop::X(_) => unreachable!(),
} }
@ -599,9 +565,7 @@ impl<T: 'static> EventLoop<T> {
let mut wayland_source = self.wayland_dispatcher.as_source_mut(); let mut wayland_source = self.wayland_dispatcher.as_source_mut();
let event_queue = wayland_source.queue(); let event_queue = wayland_source.queue();
event_queue.roundtrip(state).map_err(|error| { event_queue.roundtrip(state).map_err(|error| {
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch( os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
error
))))
}) })
} }

View file

@ -13,9 +13,7 @@ pub struct EventLoopProxy<T: 'static> {
impl<T: 'static> Clone for EventLoopProxy<T> { impl<T: 'static> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
EventLoopProxy { EventLoopProxy { user_events_sender: self.user_events_sender.clone() }
user_events_sender: self.user_events_sender.clone(),
}
} }
} }
@ -25,8 +23,6 @@ impl<T: 'static> EventLoopProxy<T> {
} }
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
self.user_events_sender self.user_events_sender.send(event).map_err(|SendError(error)| EventLoopClosed(error))
.send(event)
.map_err(|SendError(error)| EventLoopClosed(error))
} }
} }

View file

@ -38,10 +38,7 @@ impl EventSink {
/// Add new window event to a queue. /// Add new window event to a queue.
#[inline] #[inline]
pub fn push_window_event(&mut self, event: WindowEvent, window_id: WindowId) { pub fn push_window_event(&mut self, event: WindowEvent, window_id: WindowId) {
self.window_events.push(Event::WindowEvent { self.window_events.push(Event::WindowEvent { event, window_id: RootWindowId(window_id) });
event,
window_id: RootWindowId(window_id),
});
} }
#[inline] #[inline]

View file

@ -11,11 +11,7 @@ use super::event_loop::ActiveEventLoop;
impl ActiveEventLoop { impl ActiveEventLoop {
#[inline] #[inline]
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> { pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
self.state self.state.borrow().output_state.outputs().map(MonitorHandle::new)
.borrow()
.output_state
.outputs()
.map(MonitorHandle::new)
} }
#[inline] #[inline]
@ -52,9 +48,7 @@ impl MonitorHandle {
pub fn size(&self) -> PhysicalSize<u32> { pub fn size(&self) -> PhysicalSize<u32> {
let output_data = self.proxy.data::<OutputData>().unwrap(); let output_data = self.proxy.data::<OutputData>().unwrap();
let dimensions = output_data.with_output_info(|info| { let dimensions = output_data.with_output_info(|info| {
info.modes info.modes.iter().find_map(|mode| mode.current.then_some(mode.dimensions))
.iter()
.find_map(|mode| mode.current.then_some(mode.dimensions))
}); });
match dimensions { match dimensions {
@ -85,9 +79,7 @@ impl MonitorHandle {
pub fn refresh_rate_millihertz(&self) -> Option<u32> { pub fn refresh_rate_millihertz(&self) -> Option<u32> {
let output_data = self.proxy.data::<OutputData>().unwrap(); let output_data = self.proxy.data::<OutputData>().unwrap();
output_data.with_output_info(|info| { output_data.with_output_info(|info| {
info.modes info.modes.iter().find_map(|mode| mode.current.then_some(mode.refresh_rate as u32))
.iter()
.find_map(|mode| mode.current.then_some(mode.refresh_rate as u32))
}) })
} }

View file

@ -7,9 +7,8 @@ use calloop::timer::{TimeoutAction, Timer};
use calloop::{LoopHandle, RegistrationToken}; use calloop::{LoopHandle, RegistrationToken};
use tracing::warn; use tracing::warn;
use sctk::reexports::client::protocol::wl_keyboard::WlKeyboard;
use sctk::reexports::client::protocol::wl_keyboard::{ use sctk::reexports::client::protocol::wl_keyboard::{
Event as WlKeyboardEvent, KeyState as WlKeyState, KeymapFormat as WlKeymapFormat, Event as WlKeyboardEvent, KeyState as WlKeyState, KeymapFormat as WlKeymapFormat, WlKeyboard,
}; };
use sctk::reexports::client::protocol::wl_seat::WlSeat; use sctk::reexports::client::protocol::wl_seat::WlSeat;
use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, WEnum}; use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, WEnum};
@ -42,16 +41,16 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
WEnum::Value(format) => match format { WEnum::Value(format) => match format {
WlKeymapFormat::NoKeymap => { WlKeymapFormat::NoKeymap => {
warn!("non-xkb compatible keymap") warn!("non-xkb compatible keymap")
} },
WlKeymapFormat::XkbV1 => { WlKeymapFormat::XkbV1 => {
let context = &mut seat_state.keyboard_state.as_mut().unwrap().xkb_context; let context = &mut seat_state.keyboard_state.as_mut().unwrap().xkb_context;
context.set_keymap_from_fd(fd, size as usize); context.set_keymap_from_fd(fd, size as usize);
} },
_ => unreachable!(), _ => unreachable!(),
}, },
WEnum::Unknown(value) => { WEnum::Unknown(value) => {
warn!("unknown keymap format 0x{:x}", value) warn!("unknown keymap format 0x{:x}", value)
} },
}, },
WlKeyboardEvent::Enter { surface, .. } => { WlKeyboardEvent::Enter { surface, .. } => {
let window_id = wayland::make_wid(&surface); let window_id = wayland::make_wid(&surface);
@ -63,7 +62,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
let was_unfocused = !window.has_focus(); let was_unfocused = !window.has_focus();
window.add_seat_focus(data.seat.id()); window.add_seat_focus(data.seat.id());
was_unfocused was_unfocused
} },
None => return, None => return,
}; };
@ -78,9 +77,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
// The keyboard focus is considered as general focus. // The keyboard focus is considered as general focus.
if was_unfocused { if was_unfocused {
state state.events_sink.push_window_event(WindowEvent::Focused(true), window_id);
.events_sink
.push_window_event(WindowEvent::Focused(true), window_id);
} }
// HACK: this is just for GNOME not fixing their ordering issue of modifiers. // HACK: this is just for GNOME not fixing their ordering issue of modifiers.
@ -90,7 +87,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
window_id, window_id,
); );
} }
} },
WlKeyboardEvent::Leave { surface, .. } => { WlKeyboardEvent::Leave { surface, .. } => {
let window_id = wayland::make_wid(&surface); let window_id = wayland::make_wid(&surface);
@ -109,7 +106,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
let mut window = window.lock().unwrap(); let mut window = window.lock().unwrap();
window.remove_seat_focus(&data.seat.id()); window.remove_seat_focus(&data.seat.id());
window.has_focus() window.has_focus()
} },
None => return, None => return,
}; };
@ -124,16 +121,10 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
window_id, window_id,
); );
state state.events_sink.push_window_event(WindowEvent::Focused(false), window_id);
.events_sink
.push_window_event(WindowEvent::Focused(false), window_id);
} }
} },
WlKeyboardEvent::Key { WlKeyboardEvent::Key { key, state: WEnum::Value(WlKeyState::Pressed), .. } => {
key,
state: WEnum::Value(WlKeyState::Pressed),
..
} => {
let key = key + 8; let key = key + 8;
key_input( key_input(
@ -151,12 +142,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
RepeatInfo::Disable => return, RepeatInfo::Disable => return,
}; };
if !keyboard_state if !keyboard_state.xkb_context.keymap_mut().unwrap().key_repeats(key) {
.xkb_context
.keymap_mut()
.unwrap()
.key_repeats(key)
{
return; return;
} }
@ -203,12 +189,8 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
} }
}) })
.ok(); .ok();
} },
WlKeyboardEvent::Key { WlKeyboardEvent::Key { key, state: WEnum::Value(WlKeyState::Released), .. } => {
key,
state: WEnum::Value(WlKeyState::Released),
..
} => {
let key = key + 8; let key = key + 8;
key_input( key_input(
@ -222,11 +204,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
let keyboard_state = seat_state.keyboard_state.as_mut().unwrap(); let keyboard_state = seat_state.keyboard_state.as_mut().unwrap();
if keyboard_state.repeat_info != RepeatInfo::Disable if keyboard_state.repeat_info != RepeatInfo::Disable
&& keyboard_state && keyboard_state.xkb_context.keymap_mut().unwrap().key_repeats(key)
.xkb_context
.keymap_mut()
.unwrap()
.key_repeats(key)
&& Some(key) == keyboard_state.current_repeat && Some(key) == keyboard_state.current_repeat
{ {
keyboard_state.current_repeat = None; keyboard_state.current_repeat = None;
@ -234,13 +212,9 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
keyboard_state.loop_handle.remove(token); keyboard_state.loop_handle.remove(token);
} }
} }
} },
WlKeyboardEvent::Modifiers { WlKeyboardEvent::Modifiers {
mods_depressed, mods_depressed, mods_latched, mods_locked, group, ..
mods_latched,
mods_locked,
group,
..
} => { } => {
let xkb_context = &mut seat_state.keyboard_state.as_mut().unwrap().xkb_context; let xkb_context = &mut seat_state.keyboard_state.as_mut().unwrap().xkb_context;
let xkb_state = match xkb_context.state_mut() { let xkb_state = match xkb_context.state_mut() {
@ -257,14 +231,14 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
None => { None => {
seat_state.modifiers_pending = true; seat_state.modifiers_pending = true;
return; return;
} },
}; };
state.events_sink.push_window_event( state.events_sink.push_window_event(
WindowEvent::ModifiersChanged(seat_state.modifiers.into()), WindowEvent::ModifiersChanged(seat_state.modifiers.into()),
window_id, window_id,
); );
} },
WlKeyboardEvent::RepeatInfo { rate, delay } => { WlKeyboardEvent::RepeatInfo { rate, delay } => {
let keyboard_state = seat_state.keyboard_state.as_mut().unwrap(); let keyboard_state = seat_state.keyboard_state.as_mut().unwrap();
keyboard_state.repeat_info = if rate == 0 { keyboard_state.repeat_info = if rate == 0 {
@ -279,7 +253,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
let delay = Duration::from_millis(delay as u64); let delay = Duration::from_millis(delay as u64);
RepeatInfo::Repeat { gap, delay } RepeatInfo::Repeat { gap, delay }
}; };
} },
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -353,10 +327,7 @@ impl Default for RepeatInfo {
/// ///
/// The values are picked based on the default in various compositors and Xorg. /// The values are picked based on the default in various compositors and Xorg.
fn default() -> Self { fn default() -> Self {
Self::Repeat { Self::Repeat { gap: Duration::from_millis(40), delay: Duration::from_millis(200) }
gap: Duration::from_millis(40),
delay: Duration::from_millis(200),
}
} }
} }
@ -372,10 +343,7 @@ pub struct KeyboardData {
impl KeyboardData { impl KeyboardData {
pub fn new(seat: WlSeat) -> Self { pub fn new(seat: WlSeat) -> Self {
Self { Self { window_id: Default::default(), seat }
window_id: Default::default(),
seat,
}
} }
} }
@ -397,11 +365,7 @@ fn key_input(
let device_id = crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)); let device_id = crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId));
if let Some(mut key_context) = keyboard_state.xkb_context.key_context() { if let Some(mut key_context) = keyboard_state.xkb_context.key_context() {
let event = key_context.process_key_event(keycode, state, repeat); let event = key_context.process_key_event(keycode, state, repeat);
let event = WindowEvent::KeyboardInput { let event = WindowEvent::KeyboardInput { device_id, event, is_synthetic: false };
device_id,
event,
is_synthetic: false,
};
event_sink.push_window_event(event, window_id); event_sink.push_window_event(event, window_id);
} }
} }

View file

@ -81,12 +81,12 @@ impl SeatHandler for WinitState {
match capability { match capability {
SeatCapability::Touch if seat_state.touch.is_none() => { SeatCapability::Touch if seat_state.touch.is_none() => {
seat_state.touch = self.seat_state.get_touch(queue_handle, &seat).ok(); seat_state.touch = self.seat_state.get_touch(queue_handle, &seat).ok();
} },
SeatCapability::Keyboard if seat_state.keyboard_state.is_none() => { SeatCapability::Keyboard if seat_state.keyboard_state.is_none() => {
let keyboard = seat.get_keyboard(queue_handle, KeyboardData::new(seat.clone())); let keyboard = seat.get_keyboard(queue_handle, KeyboardData::new(seat.clone()));
seat_state.keyboard_state = seat_state.keyboard_state =
Some(KeyboardState::new(keyboard, self.loop_handle.clone())); Some(KeyboardState::new(keyboard, self.loop_handle.clone()));
} },
SeatCapability::Pointer if seat_state.pointer.is_none() => { SeatCapability::Pointer if seat_state.pointer.is_none() => {
let surface = self.compositor_state.create_surface(queue_handle); let surface = self.compositor_state.create_surface(queue_handle);
let surface_id = surface.id(); let surface_id = surface.id();
@ -114,19 +114,15 @@ impl SeatHandler for WinitState {
let themed_pointer = Arc::new(themed_pointer); let themed_pointer = Arc::new(themed_pointer);
// Register cursor surface. // Register cursor surface.
self.pointer_surfaces self.pointer_surfaces.insert(surface_id, themed_pointer.clone());
.insert(surface_id, themed_pointer.clone());
seat_state.pointer = Some(themed_pointer); seat_state.pointer = Some(themed_pointer);
} },
_ => (), _ => (),
} }
if let Some(text_input_state) = seat_state if let Some(text_input_state) =
.text_input seat_state.text_input.is_none().then_some(self.text_input_state.as_ref()).flatten()
.is_none()
.then_some(self.text_input_state.as_ref())
.flatten()
{ {
seat_state.text_input = Some(Arc::new(text_input_state.get_text_input( seat_state.text_input = Some(Arc::new(text_input_state.get_text_input(
&seat, &seat,
@ -156,7 +152,7 @@ impl SeatHandler for WinitState {
touch.release(); touch.release();
} }
} }
} },
SeatCapability::Pointer => { SeatCapability::Pointer => {
if let Some(relative_pointer) = seat_state.relative_pointer.take() { if let Some(relative_pointer) = seat_state.relative_pointer.take() {
relative_pointer.destroy(); relative_pointer.destroy();
@ -177,11 +173,11 @@ impl SeatHandler for WinitState {
pointer.pointer().release(); pointer.pointer().release();
} }
} }
} },
SeatCapability::Keyboard => { SeatCapability::Keyboard => {
seat_state.keyboard_state = None; seat_state.keyboard_state = None;
self.on_keyboard_destroy(&seat.id()); self.on_keyboard_destroy(&seat.id());
} },
_ => (), _ => (),
} }
} }
@ -213,8 +209,7 @@ impl WinitState {
let had_focus = window.has_focus(); let had_focus = window.has_focus();
window.remove_seat_focus(seat); window.remove_seat_focus(seat);
if had_focus != window.has_focus() { if had_focus != window.has_focus() {
self.events_sink self.events_sink.push_window_event(WindowEvent::Focused(false), *window_id);
.push_window_event(WindowEvent::Focused(false), *window_id);
} }
} }
} }

View file

@ -19,8 +19,9 @@ use sctk::reexports::csd_frame::FrameClick;
use sctk::compositor::SurfaceData; use sctk::compositor::SurfaceData;
use sctk::globals::GlobalData; use sctk::globals::GlobalData;
use sctk::seat::pointer::{PointerData, PointerDataExt}; use sctk::seat::pointer::{
use sctk::seat::pointer::{PointerEvent, PointerEventKind, PointerHandler}; PointerData, PointerDataExt, PointerEvent, PointerEventKind, PointerHandler,
};
use sctk::seat::SeatState; use sctk::seat::SeatState;
use crate::dpi::{LogicalPosition, PhysicalPosition}; use crate::dpi::{LogicalPosition, PhysicalPosition};
@ -81,20 +82,14 @@ impl PointerHandler for WinitState {
let _ = pointer.set_cursor(connection, icon); let _ = pointer.set_cursor(connection, icon);
} }
} }
} },
PointerEventKind::Leave { .. } if parent_surface != surface => { PointerEventKind::Leave { .. } if parent_surface != surface => {
window.frame_point_left(); window.frame_point_left();
} },
ref kind @ PointerEventKind::Press { ref kind @ PointerEventKind::Press { button, serial, time }
button, | ref kind @ PointerEventKind::Release { button, serial, time }
serial, if parent_surface != surface =>
time, {
}
| ref kind @ PointerEventKind::Release {
button,
serial,
time,
} if parent_surface != surface => {
let click = match wayland_button_to_winit(button) { let click = match wayland_button_to_winit(button) {
MouseButton::Left => FrameClick::Normal, MouseButton::Left => FrameClick::Normal,
MouseButton::Right => FrameClick::Alternate, MouseButton::Right => FrameClick::Alternate,
@ -112,7 +107,7 @@ impl PointerHandler for WinitState {
window_id, window_id,
&mut self.window_compositor_updates, &mut self.window_compositor_updates,
); );
} },
// Regular events on the main surface. // Regular events on the main surface.
PointerEventKind::Enter { .. } => { PointerEventKind::Enter { .. } => {
self.events_sink self.events_sink
@ -126,13 +121,10 @@ impl PointerHandler for WinitState {
pointer.winit_data().inner.lock().unwrap().surface = Some(window_id); pointer.winit_data().inner.lock().unwrap().surface = Some(window_id);
self.events_sink.push_window_event( self.events_sink.push_window_event(
WindowEvent::CursorMoved { WindowEvent::CursorMoved { device_id, position },
device_id,
position,
},
window_id, window_id,
); );
} },
PointerEventKind::Leave { .. } => { PointerEventKind::Leave { .. } => {
if let Some(pointer) = seat_state.pointer.as_ref().map(Arc::downgrade) { if let Some(pointer) = seat_state.pointer.as_ref().map(Arc::downgrade) {
window.pointer_left(pointer); window.pointer_left(pointer);
@ -143,25 +135,17 @@ impl PointerHandler for WinitState {
self.events_sink self.events_sink
.push_window_event(WindowEvent::CursorLeft { device_id }, window_id); .push_window_event(WindowEvent::CursorLeft { device_id }, window_id);
} },
PointerEventKind::Motion { .. } => { PointerEventKind::Motion { .. } => {
self.events_sink.push_window_event( self.events_sink.push_window_event(
WindowEvent::CursorMoved { WindowEvent::CursorMoved { device_id, position },
device_id,
position,
},
window_id, window_id,
); );
} },
ref kind @ PointerEventKind::Press { button, serial, .. } ref kind @ PointerEventKind::Press { button, serial, .. }
| ref kind @ PointerEventKind::Release { button, serial, .. } => { | ref kind @ PointerEventKind::Release { button, serial, .. } => {
// Update the last button serial. // Update the last button serial.
pointer pointer.winit_data().inner.lock().unwrap().latest_button_serial = serial;
.winit_data()
.inner
.lock()
.unwrap()
.latest_button_serial = serial;
let button = wayland_button_to_winit(button); let button = wayland_button_to_winit(button);
let state = if matches!(kind, PointerEventKind::Press { .. }) { let state = if matches!(kind, PointerEventKind::Press { .. }) {
@ -170,19 +154,11 @@ impl PointerHandler for WinitState {
ElementState::Released ElementState::Released
}; };
self.events_sink.push_window_event( self.events_sink.push_window_event(
WindowEvent::MouseInput { WindowEvent::MouseInput { device_id, state, button },
device_id,
state,
button,
},
window_id, window_id,
); );
} },
PointerEventKind::Axis { PointerEventKind::Axis { horizontal, vertical, .. } => {
horizontal,
vertical,
..
} => {
// Get the current phase. // Get the current phase.
let mut pointer_data = pointer.winit_data().inner.lock().unwrap(); let mut pointer_data = pointer.winit_data().inner.lock().unwrap();
@ -223,14 +199,10 @@ impl PointerHandler for WinitState {
}; };
self.events_sink.push_window_event( self.events_sink.push_window_event(
WindowEvent::MouseWheel { WindowEvent::MouseWheel { device_id, delta, phase },
device_id,
delta,
phase,
},
window_id, window_id,
) )
} },
} }
} }
} }
@ -407,8 +379,7 @@ pub trait WinitPointerDataExt {
impl WinitPointerDataExt for WlPointer { impl WinitPointerDataExt for WlPointer {
fn winit_data(&self) -> &WinitPointerData { fn winit_data(&self) -> &WinitPointerData {
self.data::<WinitPointerData>() self.data::<WinitPointerData>().expect("failed to get pointer data.")
.expect("failed to get pointer data.")
} }
} }
@ -422,14 +393,13 @@ impl PointerConstraintsState {
queue_handle: &QueueHandle<WinitState>, queue_handle: &QueueHandle<WinitState>,
) -> Result<Self, BindError> { ) -> Result<Self, BindError> {
let pointer_constraints = globals.bind(queue_handle, 1..=1, GlobalData)?; let pointer_constraints = globals.bind(queue_handle, 1..=1, GlobalData)?;
Ok(Self { Ok(Self { pointer_constraints })
pointer_constraints,
})
} }
} }
impl Deref for PointerConstraintsState { impl Deref for PointerConstraintsState {
type Target = ZwpPointerConstraintsV1; type Target = ZwpPointerConstraintsV1;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.pointer_constraints &self.pointer_constraints
} }

View file

@ -61,31 +61,19 @@ impl Dispatch<ZwpRelativePointerV1, GlobalData, WinitState> for RelativePointerS
_qhandle: &QueueHandle<WinitState>, _qhandle: &QueueHandle<WinitState>,
) { ) {
let (dx_unaccel, dy_unaccel) = match event { let (dx_unaccel, dy_unaccel) = match event {
zwp_relative_pointer_v1::Event::RelativeMotion { zwp_relative_pointer_v1::Event::RelativeMotion { dx_unaccel, dy_unaccel, .. } => {
dx_unaccel, (dx_unaccel, dy_unaccel)
dy_unaccel, },
..
} => (dx_unaccel, dy_unaccel),
_ => return, _ => return,
}; };
state
.events_sink
.push_device_event(DeviceEvent::Motion { axis: 0, value: dx_unaccel }, super::DeviceId);
state
.events_sink
.push_device_event(DeviceEvent::Motion { axis: 1, value: dy_unaccel }, super::DeviceId);
state.events_sink.push_device_event( state.events_sink.push_device_event(
DeviceEvent::Motion { DeviceEvent::MouseMotion { delta: (dx_unaccel, dy_unaccel) },
axis: 0,
value: dx_unaccel,
},
super::DeviceId,
);
state.events_sink.push_device_event(
DeviceEvent::Motion {
axis: 1,
value: dy_unaccel,
},
super::DeviceId,
);
state.events_sink.push_device_event(
DeviceEvent::MouseMotion {
delta: (dx_unaccel, dy_unaccel),
},
super::DeviceId, super::DeviceId,
); );
} }

View file

@ -3,14 +3,12 @@ use std::ops::Deref;
use sctk::globals::GlobalData; use sctk::globals::GlobalData;
use sctk::reexports::client::{Connection, Proxy, QueueHandle}; use sctk::reexports::client::{Connection, Proxy, QueueHandle};
use sctk::reexports::client::delegate_dispatch;
use sctk::reexports::client::globals::{BindError, GlobalList}; use sctk::reexports::client::globals::{BindError, GlobalList};
use sctk::reexports::client::protocol::wl_surface::WlSurface; use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::Dispatch; use sctk::reexports::client::{delegate_dispatch, Dispatch};
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_manager_v3::ZwpTextInputManagerV3; use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_manager_v3::ZwpTextInputManagerV3;
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::Event as TextInputEvent;
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::{ use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::{
ContentHint, ContentPurpose, ZwpTextInputV3, ContentHint, ContentPurpose, Event as TextInputEvent, ZwpTextInputV3,
}; };
use crate::event::{Ime, WindowEvent}; use crate::event::{Ime, WindowEvent};
@ -77,13 +75,11 @@ impl Dispatch<ZwpTextInputV3, TextInputData, WinitState> for TextInputState {
text_input.enable(); text_input.enable();
text_input.set_content_type_by_purpose(window.ime_purpose()); text_input.set_content_type_by_purpose(window.ime_purpose());
text_input.commit(); text_input.commit();
state state.events_sink.push_window_event(WindowEvent::Ime(Ime::Enabled), window_id);
.events_sink
.push_window_event(WindowEvent::Ime(Ime::Enabled), window_id);
} }
window.text_input_entered(text_input); window.text_input_entered(text_input);
} },
TextInputEvent::Leave { surface } => { TextInputEvent::Leave { surface } => {
text_input_data.surface = None; text_input_data.surface = None;
@ -102,15 +98,9 @@ impl Dispatch<ZwpTextInputV3, TextInputData, WinitState> for TextInputState {
window.text_input_left(text_input); window.text_input_left(text_input);
state state.events_sink.push_window_event(WindowEvent::Ime(Ime::Disabled), window_id);
.events_sink },
.push_window_event(WindowEvent::Ime(Ime::Disabled), window_id); TextInputEvent::PreeditString { text, cursor_begin, cursor_end } => {
}
TextInputEvent::PreeditString {
text,
cursor_begin,
cursor_end,
} => {
let text = text.unwrap_or_default(); let text = text.unwrap_or_default();
let cursor_begin = usize::try_from(cursor_begin) let cursor_begin = usize::try_from(cursor_begin)
.ok() .ok()
@ -119,16 +109,12 @@ impl Dispatch<ZwpTextInputV3, TextInputData, WinitState> for TextInputState {
.ok() .ok()
.and_then(|idx| text.is_char_boundary(idx).then_some(idx)); .and_then(|idx| text.is_char_boundary(idx).then_some(idx));
text_input_data.pending_preedit = Some(Preedit { text_input_data.pending_preedit = Some(Preedit { text, cursor_begin, cursor_end })
text, },
cursor_begin,
cursor_end,
})
}
TextInputEvent::CommitString { text } => { TextInputEvent::CommitString { text } => {
text_input_data.pending_preedit = None; text_input_data.pending_preedit = None;
text_input_data.pending_commit = text; text_input_data.pending_commit = text;
} },
TextInputEvent::Done { .. } => { TextInputEvent::Done { .. } => {
let window_id = match text_input_data.surface.as_ref() { let window_id = match text_input_data.surface.as_ref() {
Some(surface) => wayland::make_wid(surface), Some(surface) => wayland::make_wid(surface),
@ -150,20 +136,19 @@ impl Dispatch<ZwpTextInputV3, TextInputData, WinitState> for TextInputState {
// Send preedit. // Send preedit.
if let Some(preedit) = text_input_data.pending_preedit.take() { if let Some(preedit) = text_input_data.pending_preedit.take() {
let cursor_range = preedit let cursor_range =
.cursor_begin preedit.cursor_begin.map(|b| (b, preedit.cursor_end.unwrap_or(b)));
.map(|b| (b, preedit.cursor_end.unwrap_or(b)));
state.events_sink.push_window_event( state.events_sink.push_window_event(
WindowEvent::Ime(Ime::Preedit(preedit.text, cursor_range)), WindowEvent::Ime(Ime::Preedit(preedit.text, cursor_range)),
window_id, window_id,
); );
} }
} },
TextInputEvent::DeleteSurroundingText { .. } => { TextInputEvent::DeleteSurroundingText { .. } => {
// Not handled. // Not handled.
} },
_ => {} _ => {},
} }
} }
} }

View file

@ -36,9 +36,7 @@ impl TouchHandler for WinitState {
let seat_state = self.seats.get_mut(&touch.seat().id()).unwrap(); let seat_state = self.seats.get_mut(&touch.seat().id()).unwrap();
// Update the state of the point. // Update the state of the point.
seat_state seat_state.touch_map.insert(id, TouchPoint { surface, location });
.touch_map
.insert(id, TouchPoint { surface, location });
self.events_sink.push_window_event( self.events_sink.push_window_event(
WindowEvent::Touch(Touch { WindowEvent::Touch(Touch {
@ -190,9 +188,7 @@ pub trait TouchDataExt {
impl TouchDataExt for WlTouch { impl TouchDataExt for WlTouch {
fn seat(&self) -> &WlSeat { fn seat(&self) -> &WlSeat {
self.data::<TouchData>() self.data::<TouchData>().expect("failed to get touch data.").seat()
.expect("failed to get touch data.")
.seat()
} }
} }

View file

@ -135,7 +135,7 @@ impl WinitState {
Err(e) => { Err(e) => {
tracing::warn!("Subcompositor protocol not available, ignoring CSD: {e:?}"); tracing::warn!("Subcompositor protocol not available, ignoring CSD: {e:?}");
None None
} },
}; };
let output_state = OutputState::new(globals, queue_handle); let output_state = OutputState::new(globals, queue_handle);
@ -218,8 +218,7 @@ impl WinitState {
{ {
pos pos
} else { } else {
self.window_compositor_updates self.window_compositor_updates.push(WindowCompositorUpdate::new(window_id));
.push(WindowCompositorUpdate::new(window_id));
self.window_compositor_updates.len() - 1 self.window_compositor_updates.len() - 1
}; };
@ -240,9 +239,7 @@ impl WinitState {
} }
pub fn queue_close(updates: &mut Vec<WindowCompositorUpdate>, window_id: WindowId) { pub fn queue_close(updates: &mut Vec<WindowCompositorUpdate>, window_id: WindowId) {
let pos = if let Some(pos) = updates let pos = if let Some(pos) = updates.iter().position(|update| update.window_id == window_id)
.iter()
.position(|update| update.window_id == window_id)
{ {
pos pos
} else { } else {
@ -276,15 +273,12 @@ impl WindowHandler for WinitState {
) { ) {
let window_id = super::make_wid(window.wl_surface()); let window_id = super::make_wid(window.wl_surface());
let pos = if let Some(pos) = self let pos = if let Some(pos) =
.window_compositor_updates self.window_compositor_updates.iter().position(|update| update.window_id == window_id)
.iter()
.position(|update| update.window_id == window_id)
{ {
pos pos
} else { } else {
self.window_compositor_updates self.window_compositor_updates.push(WindowCompositorUpdate::new(window_id));
.push(WindowCompositorUpdate::new(window_id));
self.window_compositor_updates.len() - 1 self.window_compositor_updates.len() - 1
}; };
@ -318,10 +312,7 @@ impl OutputHandler for WinitState {
} }
fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, output: WlOutput) { fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, output: WlOutput) {
self.monitors self.monitors.lock().unwrap().push(MonitorHandle::new(output));
.lock()
.unwrap()
.push(MonitorHandle::new(output));
} }
fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, updated: WlOutput) { fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, updated: WlOutput) {
@ -388,11 +379,11 @@ impl CompositorHandler for WinitState {
} }
impl ProvidesRegistryState for WinitState { impl ProvidesRegistryState for WinitState {
sctk::registry_handlers![OutputState, SeatState];
fn registry(&mut self) -> &mut RegistryState { fn registry(&mut self) -> &mut RegistryState {
&mut self.registry_state &mut self.registry_state
} }
sctk::registry_handlers![OutputState, SeatState];
} }
// The window update coming from the compositor. // The window update coming from the compositor.
@ -413,12 +404,7 @@ pub struct WindowCompositorUpdate {
impl WindowCompositorUpdate { impl WindowCompositorUpdate {
fn new(window_id: WindowId) -> Self { fn new(window_id: WindowId) -> Self {
Self { Self { window_id, resized: false, scale_changed: false, close_window: false }
window_id,
resized: false,
scale_changed: false,
close_window: false,
}
} }
} }

View file

@ -2,11 +2,9 @@
use sctk::reexports::client::globals::{BindError, GlobalList}; use sctk::reexports::client::globals::{BindError, GlobalList};
use sctk::reexports::client::protocol::wl_surface::WlSurface; use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::Dispatch; use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
use sctk::reexports::client::{delegate_dispatch, Connection, Proxy, QueueHandle}; use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
use wayland_protocols_plasma::blur::client::{ use wayland_protocols_plasma::blur::client::org_kde_kwin_blur_manager::OrgKdeKwinBlurManager;
org_kde_kwin_blur::OrgKdeKwinBlur, org_kde_kwin_blur_manager::OrgKdeKwinBlurManager,
};
use sctk::globals::GlobalData; use sctk::globals::GlobalData;

View file

@ -2,11 +2,11 @@
use sctk::reexports::client::globals::{BindError, GlobalList}; use sctk::reexports::client::globals::{BindError, GlobalList};
use sctk::reexports::client::protocol::wl_surface::WlSurface; use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::Dispatch; use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
use sctk::reexports::client::{delegate_dispatch, Connection, Proxy, QueueHandle};
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1; use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1;
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::Event as FractionalScalingEvent; use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::{
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1; Event as FractionalScalingEvent, WpFractionalScaleV1,
};
use sctk::globals::GlobalData; use sctk::globals::GlobalData;
@ -41,11 +41,8 @@ impl FractionalScalingManager {
surface: &WlSurface, surface: &WlSurface,
queue_handle: &QueueHandle<WinitState>, queue_handle: &QueueHandle<WinitState>,
) -> WpFractionalScaleV1 { ) -> WpFractionalScaleV1 {
let data = FractionalScaling { let data = FractionalScaling { surface: surface.clone() };
surface: surface.clone(), self.manager.get_fractional_scale(surface, queue_handle, data)
};
self.manager
.get_fractional_scale(surface, queue_handle, data)
} }
} }

View file

@ -2,8 +2,7 @@
use sctk::reexports::client::globals::{BindError, GlobalList}; use sctk::reexports::client::globals::{BindError, GlobalList};
use sctk::reexports::client::protocol::wl_surface::WlSurface; use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::Dispatch; use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
use sctk::reexports::client::{delegate_dispatch, Connection, Proxy, QueueHandle};
use sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport; use sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport;
use sctk::reexports::protocols::wp::viewporter::client::wp_viewporter::WpViewporter; use sctk::reexports::protocols::wp::viewporter::client::wp_viewporter::WpViewporter;
@ -33,8 +32,7 @@ impl ViewporterState {
surface: &WlSurface, surface: &WlSurface,
queue_handle: &QueueHandle<WinitState>, queue_handle: &QueueHandle<WinitState>,
) -> WpViewport { ) -> WpViewport {
self.viewporter self.viewporter.get_viewport(surface, queue_handle, GlobalData)
.get_viewport(surface, queue_handle, GlobalData)
} }
} }

View file

@ -3,12 +3,9 @@
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::Weak; use std::sync::Weak;
use sctk::reexports::client::delegate_dispatch; use sctk::reexports::client::globals::{BindError, GlobalList};
use sctk::reexports::client::globals::BindError;
use sctk::reexports::client::globals::GlobalList;
use sctk::reexports::client::protocol::wl_surface::WlSurface; use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::Dispatch; use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
use sctk::reexports::client::{Connection, Proxy, QueueHandle};
use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_token_v1::{ use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_token_v1::{
Event as ActivationTokenEvent, XdgActivationTokenV1, Event as ActivationTokenEvent, XdgActivationTokenV1,
}; };
@ -78,7 +75,7 @@ impl Dispatch<XdgActivationTokenV1, XdgActivationTokenData, WinitState> for XdgA
if let Some(attention_requested) = fence.upgrade() { if let Some(attention_requested) = fence.upgrade() {
attention_requested.store(false, std::sync::atomic::Ordering::Relaxed); attention_requested.store(false, std::sync::atomic::Ordering::Relaxed);
} }
} },
XdgActivationTokenData::Obtain((window_id, serial)) => { XdgActivationTokenData::Obtain((window_id, serial)) => {
state.events_sink.push_window_event( state.events_sink.push_window_event(
crate::event::WindowEvent::ActivationTokenDone { crate::event::WindowEvent::ActivationTokenDone {
@ -87,7 +84,7 @@ impl Dispatch<XdgActivationTokenV1, XdgActivationTokenData, WinitState> for XdgA
}, },
*window_id, *window_id,
); );
} },
} }
proxy.destroy(); proxy.destroy();

View file

@ -5,13 +5,11 @@ use std::sync::{Arc, Mutex};
use sctk::reexports::client::protocol::wl_display::WlDisplay; use sctk::reexports::client::protocol::wl_display::WlDisplay;
use sctk::reexports::client::protocol::wl_surface::WlSurface; use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::Proxy; use sctk::reexports::client::{Proxy, QueueHandle};
use sctk::reexports::client::QueueHandle;
use sctk::compositor::{CompositorState, Region, SurfaceData}; use sctk::compositor::{CompositorState, Region, SurfaceData};
use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_v1::XdgActivationV1; use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_v1::XdgActivationV1;
use sctk::shell::xdg::window::Window as SctkWindow; use sctk::shell::xdg::window::{Window as SctkWindow, WindowDecorations};
use sctk::shell::xdg::window::WindowDecorations;
use sctk::shell::WaylandSurface; use sctk::shell::WaylandSurface;
use tracing::warn; use tracing::warn;
@ -90,15 +88,11 @@ impl Window {
let surface = state.compositor_state.create_surface(&queue_handle); let surface = state.compositor_state.create_surface(&queue_handle);
let compositor = state.compositor_state.clone(); let compositor = state.compositor_state.clone();
let xdg_activation = state let xdg_activation =
.xdg_activation state.xdg_activation.as_ref().map(|activation_state| activation_state.global().clone());
.as_ref()
.map(|activation_state| activation_state.global().clone());
let display = event_loop_window_target.connection.display(); let display = event_loop_window_target.connection.display();
let size: Size = attributes let size: Size = attributes.inner_size.unwrap_or(LogicalSize::new(800., 600.).into());
.inner_size
.unwrap_or(LogicalSize::new(800., 600.).into());
// We prefer server side decorations, however to not have decorations we ask for client // We prefer server side decorations, however to not have decorations we ask for client
// side decorations instead. // side decorations instead.
@ -109,9 +103,7 @@ impl Window {
}; };
let window = let window =
state state.xdg_shell.create_window(surface.clone(), default_decorations, &queue_handle);
.xdg_shell
.create_window(surface.clone(), default_decorations, &queue_handle);
let mut window_state = WindowState::new( let mut window_state = WindowState::new(
event_loop_window_target.connection.clone(), event_loop_window_target.connection.clone(),
@ -152,7 +144,7 @@ impl Window {
match attributes.fullscreen.map(Into::into) { match attributes.fullscreen.map(Into::into) {
Some(Fullscreen::Exclusive(_)) => { Some(Fullscreen::Exclusive(_)) => {
warn!("`Fullscreen::Exclusive` is ignored on Wayland"); warn!("`Fullscreen::Exclusive` is ignored on Wayland");
} },
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))] #[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
Some(Fullscreen::Borderless(monitor)) => { Some(Fullscreen::Borderless(monitor)) => {
let output = monitor.and_then(|monitor| match monitor { let output = monitor.and_then(|monitor| match monitor {
@ -162,7 +154,7 @@ impl Window {
}); });
window.set_fullscreen(output.as_ref()) window.set_fullscreen(output.as_ref())
} },
_ if attributes.maximized => window.set_maximized(), _ if attributes.maximized => window.set_maximized(),
_ => (), _ => (),
}; };
@ -173,10 +165,9 @@ impl Window {
} }
// Activate the window when the token is passed. // Activate the window when the token is passed.
if let (Some(xdg_activation), Some(token)) = ( if let (Some(xdg_activation), Some(token)) =
xdg_activation.as_ref(), (xdg_activation.as_ref(), attributes.platform_specific.activation_token)
attributes.platform_specific.activation_token, {
) {
xdg_activation.activate(token._token, &surface); xdg_activation.activate(token._token, &surface);
} }
@ -186,20 +177,14 @@ impl Window {
// Add the window and window requests into the state. // Add the window and window requests into the state.
let window_state = Arc::new(Mutex::new(window_state)); let window_state = Arc::new(Mutex::new(window_state));
let window_id = super::make_wid(&surface); let window_id = super::make_wid(&surface);
state state.windows.get_mut().insert(window_id, window_state.clone());
.windows
.get_mut()
.insert(window_id, window_state.clone());
let window_requests = WindowRequests { let window_requests = WindowRequests {
redraw_requested: AtomicBool::new(true), redraw_requested: AtomicBool::new(true),
closed: AtomicBool::new(false), closed: AtomicBool::new(false),
}; };
let window_requests = Arc::new(window_requests); let window_requests = Arc::new(window_requests);
state state.window_requests.get_mut().insert(window_id, window_requests.clone());
.window_requests
.get_mut()
.insert(window_id, window_requests.clone());
// Setup the event sync to insert `WindowEvents` right from the window. // Setup the event sync to insert `WindowEvents` right from the window.
let window_events_sink = state.window_events_sink.clone(); let window_events_sink = state.window_events_sink.clone();
@ -209,17 +194,13 @@ impl Window {
// Do a roundtrip. // Do a roundtrip.
event_queue.roundtrip(&mut state).map_err(|error| { event_queue.roundtrip(&mut state).map_err(|error| {
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch( os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
error
))))
})?; })?;
// XXX Wait for the initial configure to arrive. // XXX Wait for the initial configure to arrive.
while !window_state.lock().unwrap().is_configured() { while !window_state.lock().unwrap().is_configured() {
event_queue.blocking_dispatch(&mut state).map_err(|error| { event_queue.blocking_dispatch(&mut state).map_err(|error| {
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch( os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
error
))))
})?; })?;
} }
@ -329,10 +310,7 @@ impl Window {
pub fn set_min_inner_size(&self, min_size: Option<Size>) { pub fn set_min_inner_size(&self, min_size: Option<Size>) {
let scale_factor = self.scale_factor(); let scale_factor = self.scale_factor();
let min_size = min_size.map(|size| size.to_logical(scale_factor)); let min_size = min_size.map(|size| size.to_logical(scale_factor));
self.window_state self.window_state.lock().unwrap().set_min_inner_size(min_size);
.lock()
.unwrap()
.set_min_inner_size(min_size);
// NOTE: Requires commit to be applied. // NOTE: Requires commit to be applied.
self.request_redraw(); self.request_redraw();
} }
@ -342,10 +320,7 @@ impl Window {
pub fn set_max_inner_size(&self, max_size: Option<Size>) { pub fn set_max_inner_size(&self, max_size: Option<Size>) {
let scale_factor = self.scale_factor(); let scale_factor = self.scale_factor();
let max_size = max_size.map(|size| size.to_logical(scale_factor)); let max_size = max_size.map(|size| size.to_logical(scale_factor));
self.window_state self.window_state.lock().unwrap().set_max_inner_size(max_size);
.lock()
.unwrap()
.set_max_inner_size(max_size);
// NOTE: Requires commit to be applied. // NOTE: Requires commit to be applied.
self.request_redraw(); self.request_redraw();
} }
@ -362,10 +337,7 @@ impl Window {
#[inline] #[inline]
pub fn set_transparent(&self, transparent: bool) { pub fn set_transparent(&self, transparent: bool) {
self.window_state self.window_state.lock().unwrap().set_transparent(transparent);
.lock()
.unwrap()
.set_transparent(transparent);
} }
#[inline] #[inline]
@ -388,10 +360,7 @@ impl Window {
#[inline] #[inline]
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
self.window_state self.window_state.lock().unwrap().drag_resize_window(direction)
.lock()
.unwrap()
.drag_resize_window(direction)
} }
#[inline] #[inline]
@ -499,7 +468,7 @@ impl Window {
match fullscreen { match fullscreen {
Some(Fullscreen::Exclusive(_)) => { Some(Fullscreen::Exclusive(_)) => {
warn!("`Fullscreen::Exclusive` is ignored on Wayland"); warn!("`Fullscreen::Exclusive` is ignored on Wayland");
} },
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))] #[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
Some(Fullscreen::Borderless(monitor)) => { Some(Fullscreen::Borderless(monitor)) => {
let output = monitor.and_then(|monitor| match monitor { let output = monitor.and_then(|monitor| match monitor {
@ -509,7 +478,7 @@ impl Window {
}); });
self.window.set_fullscreen(output.as_ref()) self.window.set_fullscreen(output.as_ref())
} },
None => self.window.unset_fullscreen(), None => self.window.unset_fullscreen(),
} }
} }
@ -526,10 +495,7 @@ impl Window {
#[inline] #[inline]
pub fn set_cursor_visible(&self, visible: bool) { pub fn set_cursor_visible(&self, visible: bool) {
self.window_state self.window_state.lock().unwrap().set_cursor_visible(visible);
.lock()
.unwrap()
.set_cursor_visible(visible);
} }
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) { pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
@ -538,7 +504,7 @@ impl Window {
None => { None => {
warn!("`request_user_attention` isn't supported"); warn!("`request_user_attention` isn't supported");
return; return;
} },
}; };
// Urgency is only removed by the compositor and there's no need to raise urgency when it // Urgency is only removed by the compositor and there's no need to raise urgency when it
@ -630,10 +596,7 @@ impl Window {
if window_state.ime_allowed() != allowed && window_state.set_ime_allowed(allowed) { if window_state.ime_allowed() != allowed && window_state.set_ime_allowed(allowed) {
let event = WindowEvent::Ime(if allowed { Ime::Enabled } else { Ime::Disabled }); let event = WindowEvent::Ime(if allowed { Ime::Enabled } else { Ime::Disabled });
self.window_events_sink self.window_events_sink.lock().unwrap().push_window_event(event, self.window_id);
.lock()
.unwrap()
.push_window_event(event, self.window_id);
self.event_loop_awakener.ping(); self.event_loop_awakener.ping();
} }
} }

View file

@ -226,13 +226,10 @@ impl WindowState {
&self, &self,
callback: F, callback: F,
) { ) {
self.pointers self.pointers.iter().filter_map(Weak::upgrade).for_each(|pointer| {
.iter() let data = pointer.pointer().winit_data();
.filter_map(Weak::upgrade) callback(pointer.as_ref(), data);
.for_each(|pointer| { })
let data = pointer.pointer().winit_data();
callback(pointer.as_ref(), data);
})
} }
/// Get the current state of the frame callback. /// Get the current state of the frame callback.
@ -257,7 +254,7 @@ impl WindowState {
FrameCallbackState::None | FrameCallbackState::Received => { FrameCallbackState::None | FrameCallbackState::Received => {
self.frame_callback_state = FrameCallbackState::Requested; self.frame_callback_state = FrameCallbackState::Requested;
surface.frame(&self.queue_handle, surface.clone()); surface.frame(&self.queue_handle, surface.clone());
} },
FrameCallbackState::Requested => (), FrameCallbackState::Requested => (),
} }
} }
@ -297,11 +294,11 @@ impl WindowState {
// Hide the frame if we were asked to not decorate. // Hide the frame if we were asked to not decorate.
frame.set_hidden(!self.decorate); frame.set_hidden(!self.decorate);
self.frame = Some(frame); self.frame = Some(frame);
} },
Err(err) => { Err(err) => {
warn!("Failed to create client side decorations frame: {err}"); warn!("Failed to create client side decorations frame: {err}");
self.csd_fails = true; self.csd_fails = true;
} },
} }
} else if configure.decoration_mode == DecorationMode::Server { } else if configure.decoration_mode == DecorationMode::Server {
// Drop the frame for server side decorations to save resources. // Drop the frame for server side decorations to save resources.
@ -320,8 +317,8 @@ impl WindowState {
let width = width.map(|w| w.get()).unwrap_or(1); let width = width.map(|w| w.get()).unwrap_or(1);
let height = height.map(|h| h.get()).unwrap_or(1); let height = height.map(|h| h.get()).unwrap_or(1);
((width, height).into(), false) ((width, height).into(), false)
} },
(_, _) if stateless => (self.stateless_size, true), (..) if stateless => (self.stateless_size, true),
_ => (self.size, true), _ => (self.size, true),
} }
} else { } else {
@ -335,10 +332,8 @@ impl WindowState {
// Apply configure bounds only when compositor let the user decide what size to pick. // Apply configure bounds only when compositor let the user decide what size to pick.
if constrain { if constrain {
let bounds = self.inner_size_bounds(&configure); let bounds = self.inner_size_bounds(&configure);
new_size.width = bounds new_size.width =
.0 bounds.0.map(|bound_w| new_size.width.min(bound_w.get())).unwrap_or(new_size.width);
.map(|bound_w| new_size.width.min(bound_w.get()))
.unwrap_or(new_size.width);
new_size.height = bounds new_size.height = bounds
.1 .1
.map(|bound_h| new_size.height.min(bound_h.get())) .map(|bound_h| new_size.height.min(bound_h.get()))
@ -346,10 +341,7 @@ impl WindowState {
} }
let new_state = configure.state; let new_state = configure.state;
let old_state = self let old_state = self.last_configure.as_ref().map(|configure| configure.state);
.last_configure
.as_ref()
.map(|configure| configure.state);
let state_change_requires_resize = old_state let state_change_requires_resize = old_state
.map(|old_state| { .map(|old_state| {
@ -387,10 +379,7 @@ impl WindowState {
configure_bounds.0.unwrap_or(NonZeroU32::new(1).unwrap()), configure_bounds.0.unwrap_or(NonZeroU32::new(1).unwrap()),
configure_bounds.1.unwrap_or(NonZeroU32::new(1).unwrap()), configure_bounds.1.unwrap_or(NonZeroU32::new(1).unwrap()),
); );
( (configure_bounds.0.and(width), configure_bounds.1.and(height))
configure_bounds.0.and(width),
configure_bounds.1.and(height),
)
} else { } else {
configure_bounds configure_bounds
} }
@ -460,7 +449,7 @@ impl WindowState {
_ => return None, _ => return None,
}; };
self.window.resize(seat, serial, edge); self.window.resize(seat, serial, edge);
} },
FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)), FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)),
_ => (), _ => (),
}; };
@ -643,12 +632,7 @@ impl WindowState {
/// Try to resize the window when the user can do so. /// Try to resize the window when the user can do so.
pub fn request_inner_size(&mut self, inner_size: Size) -> PhysicalSize<u32> { pub fn request_inner_size(&mut self, inner_size: Size) -> PhysicalSize<u32> {
if self if self.last_configure.as_ref().map(Self::is_stateless).unwrap_or(true) {
.last_configure
.as_ref()
.map(Self::is_stateless)
.unwrap_or(true)
{
self.resize(inner_size.to_logical(self.scale_factor())) self.resize(inner_size.to_logical(self.scale_factor()))
} }
@ -674,10 +658,7 @@ impl WindowState {
); );
} }
( (frame.location(), frame.add_borders(self.size.width, self.size.height).into())
frame.location(),
frame.add_borders(self.size.width, self.size.height).into(),
)
} else { } else {
((0, 0), self.size) ((0, 0), self.size)
}; };
@ -724,16 +705,12 @@ impl WindowState {
/// Set the custom cursor icon. /// Set the custom cursor icon.
pub(crate) fn set_custom_cursor(&mut self, cursor: RootCustomCursor) { pub(crate) fn set_custom_cursor(&mut self, cursor: RootCustomCursor) {
let cursor = match cursor { let cursor = match cursor {
RootCustomCursor { RootCustomCursor { inner: PlatformCustomCursor::Wayland(cursor) } => cursor.0,
inner: PlatformCustomCursor::Wayland(cursor),
} => cursor.0,
#[cfg(x11_platform)] #[cfg(x11_platform)]
RootCustomCursor { RootCustomCursor { inner: PlatformCustomCursor::X(_) } => {
inner: PlatformCustomCursor::X(_),
} => {
tracing::error!("passed a X11 cursor to Wayland backend"); tracing::error!("passed a X11 cursor to Wayland backend");
return; return;
} },
}; };
let cursor = { let cursor = {
@ -752,11 +729,7 @@ impl WindowState {
self.apply_on_pointer(|pointer, _| { self.apply_on_pointer(|pointer, _| {
let surface = pointer.surface(); let surface = pointer.surface();
let scale = surface let scale = surface.data::<SurfaceData>().unwrap().surface_data().scale_factor();
.data::<SurfaceData>()
.unwrap()
.surface_data()
.scale_factor();
surface.set_buffer_scale(scale); surface.set_buffer_scale(scale);
surface.attach(Some(cursor.buffer.wl_buffer()), 0, 0); surface.attach(Some(cursor.buffer.wl_buffer()), 0, 0);
@ -864,7 +837,7 @@ impl WindowState {
}), }),
CursorGrabMode::Locked => { CursorGrabMode::Locked => {
self.apply_on_pointer(|_, data| data.unlock_pointer()); self.apply_on_pointer(|_, data| data.unlock_pointer());
} },
} }
let surface = self.window.wl_surface(); let surface = self.window.wl_surface();
@ -879,7 +852,7 @@ impl WindowState {
}), }),
CursorGrabMode::None => { CursorGrabMode::None => {
// Current lock/confine was already removed. // Current lock/confine was already removed.
} },
} }
Ok(()) Ok(())
@ -902,11 +875,9 @@ impl WindowState {
// Position can be set only for locked cursor. // Position can be set only for locked cursor.
if self.cursor_grab_mode.current_grab_mode != CursorGrabMode::Locked { if self.cursor_grab_mode.current_grab_mode != CursorGrabMode::Locked {
return Err(ExternalError::Os(os_error!( return Err(ExternalError::Os(os_error!(crate::platform_impl::OsError::Misc(
crate::platform_impl::OsError::Misc( "cursor position can be set only for locked cursor."
"cursor position can be set only for locked cursor." ))));
)
)));
} }
self.apply_on_pointer(|_, data| { self.apply_on_pointer(|_, data| {
@ -929,9 +900,7 @@ impl WindowState {
for pointer in self.pointers.iter().filter_map(|pointer| pointer.upgrade()) { for pointer in self.pointers.iter().filter_map(|pointer| pointer.upgrade()) {
let latest_enter_serial = pointer.pointer().winit_data().latest_enter_serial(); let latest_enter_serial = pointer.pointer().winit_data().latest_enter_serial();
pointer pointer.pointer().set_cursor(latest_enter_serial, None, 0, 0);
.pointer()
.set_cursor(latest_enter_serial, None, 0, 0);
} }
} }
} }
@ -945,19 +914,12 @@ impl WindowState {
self.decorate = decorate; self.decorate = decorate;
match self match self.last_configure.as_ref().map(|configure| configure.decoration_mode) {
.last_configure
.as_ref()
.map(|configure| configure.decoration_mode)
{
Some(DecorationMode::Server) if !self.decorate => { Some(DecorationMode::Server) if !self.decorate => {
// To disable decorations we should request client and hide the frame. // To disable decorations we should request client and hide the frame.
self.window self.window.request_decoration_mode(Some(DecorationMode::Client))
.request_decoration_mode(Some(DecorationMode::Client)) },
} _ if self.decorate => self.window.request_decoration_mode(Some(DecorationMode::Server)),
_ if self.decorate => self
.window
.request_decoration_mode(Some(DecorationMode::Server)),
_ => (), _ => (),
} }
@ -1054,10 +1016,7 @@ impl WindowState {
info!("Blur manager unavailable, unable to change blur") info!("Blur manager unavailable, unable to change blur")
} }
} else if !blurred && self.blur.is_some() { } else if !blurred && self.blur.is_some() {
self.blur_manager self.blur_manager.as_ref().unwrap().unset(self.window.wl_surface());
.as_ref()
.unwrap()
.unset(self.window.wl_surface());
self.blur.take().unwrap().release(); self.blur.take().unwrap().release();
} }
} }
@ -1146,10 +1105,7 @@ struct GrabState {
impl GrabState { impl GrabState {
fn new() -> Self { fn new() -> Self {
Self { Self { user_grab_mode: CursorGrabMode::None, current_grab_mode: CursorGrabMode::None }
user_grab_mode: CursorGrabMode::None,
current_grab_mode: CursorGrabMode::None,
}
} }
} }

View file

@ -5,7 +5,8 @@
//! X11 has a "startup notification" specification similar to Wayland's, see this URL: //! X11 has a "startup notification" specification similar to Wayland's, see this URL:
//! <https://specifications.freedesktop.org/startup-notification-spec/startup-notification-latest.txt> //! <https://specifications.freedesktop.org/startup-notification-spec/startup-notification-latest.txt>
use super::{atoms::*, VoidCookie, X11Error, XConnection}; use super::atoms::*;
use super::{VoidCookie, X11Error, XConnection};
use std::ffi::CString; use std::ffi::CString;
use std::fmt::Write; use std::fmt::Write;
@ -105,11 +106,9 @@ impl XConnection {
0, 0,
xproto::WindowClass::INPUT_OUTPUT, xproto::WindowClass::INPUT_OUTPUT,
screen.root_visual, screen.root_visual,
&xproto::CreateWindowAux::new() &xproto::CreateWindowAux::new().override_redirect(1).event_mask(
.override_redirect(1) xproto::EventMask::STRUCTURE_NOTIFY | xproto::EventMask::PROPERTY_CHANGE,
.event_mask( ),
xproto::EventMask::STRUCTURE_NOTIFY | xproto::EventMask::PROPERTY_CHANGE,
),
)?; )?;
// Serialize the messages in 20-byte chunks. // Serialize the messages in 20-byte chunks.
@ -130,12 +129,7 @@ impl XConnection {
.try_for_each(|event| { .try_for_each(|event| {
// Send each event in order. // Send each event in order.
self.xcb_connection() self.xcb_connection()
.send_event( .send_event(false, screen.root, xproto::EventMask::PROPERTY_CHANGE, event)
false,
screen.root,
xproto::EventMask::PROPERTY_CHANGE,
event,
)
.map(VoidCookie::ignore_error) .map(VoidCookie::ignore_error)
})?; })?;

View file

@ -1,18 +1,15 @@
use std::{ use std::io;
io, use std::os::raw::*;
os::raw::*, use std::path::{Path, PathBuf};
path::{Path, PathBuf}, use std::str::Utf8Error;
str::Utf8Error, use std::sync::Arc;
sync::Arc,
};
use percent_encoding::percent_decode; use percent_encoding::percent_decode;
use x11rb::protocol::xproto::{self, ConnectionExt}; use x11rb::protocol::xproto::{self, ConnectionExt};
use super::{ use super::atoms::AtomName::None as DndNone;
atoms::{AtomName::None as DndNone, *}, use super::atoms::*;
util, CookieResultExt, X11Error, XConnection, use super::{util, CookieResultExt, X11Error, XConnection};
};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum DndState { pub enum DndState {
@ -54,13 +51,7 @@ pub struct Dnd {
impl Dnd { impl Dnd {
pub fn new(xconn: Arc<XConnection>) -> Result<Self, X11Error> { pub fn new(xconn: Arc<XConnection>) -> Result<Self, X11Error> {
Ok(Dnd { Ok(Dnd { xconn, version: None, type_list: None, source_window: None, result: None })
xconn,
version: None,
type_list: None,
source_window: None,
result: None,
})
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
@ -82,13 +73,13 @@ impl Dnd {
DndState::Rejected => (0, atoms[DndNone]), DndState::Rejected => (0, atoms[DndNone]),
}; };
self.xconn self.xconn
.send_client_msg( .send_client_msg(target_window, target_window, atoms[XdndStatus] as _, None, [
target_window, this_window,
target_window, accepted,
atoms[XdndStatus] as _, 0,
None, 0,
[this_window, accepted, 0, 0, action as _], action as _,
)? ])?
.ignore_error(); .ignore_error();
Ok(()) Ok(())
@ -106,13 +97,13 @@ impl Dnd {
DndState::Rejected => (0, atoms[DndNone]), DndState::Rejected => (0, atoms[DndNone]),
}; };
self.xconn self.xconn
.send_client_msg( .send_client_msg(target_window, target_window, atoms[XdndFinished] as _, None, [
target_window, this_window,
target_window, accepted,
atoms[XdndFinished] as _, action as _,
None, 0,
[this_window, accepted, action as _, 0, 0], 0,
)? ])?
.ignore_error(); .ignore_error();
Ok(()) Ok(())
@ -149,8 +140,7 @@ impl Dnd {
window: xproto::Window, window: xproto::Window,
) -> Result<Vec<c_uchar>, util::GetPropertyError> { ) -> Result<Vec<c_uchar>, util::GetPropertyError> {
let atoms = self.xconn.atoms(); let atoms = self.xconn.atoms();
self.xconn self.xconn.get_property(window, atoms[XdndSelection], atoms[TextUriList])
.get_property(window, atoms[XdndSelection], atoms[TextUriList])
} }
pub fn parse_data(&self, data: &mut [c_uchar]) -> Result<Vec<PathBuf>, DndDataParseError> { pub fn parse_data(&self, data: &mut [c_uchar]) -> Result<Vec<PathBuf>, DndDataParseError> {

View file

@ -16,16 +16,14 @@ use x11_dl::xlib::{
use x11rb::protocol::xinput; use x11rb::protocol::xinput;
use x11rb::protocol::xkb::ID as XkbId; use x11rb::protocol::xkb::ID as XkbId;
use x11rb::protocol::xproto::{self, ConnectionExt as _, ModMask}; use x11rb::protocol::xproto::{self, ConnectionExt as _, ModMask};
use x11rb::x11_utils::ExtensionInformation; use x11rb::x11_utils::{ExtensionInformation, Serialize};
use x11rb::x11_utils::Serialize;
use xkbcommon_dl::xkb_mod_mask_t; use xkbcommon_dl::xkb_mod_mask_t;
use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::event::{ use crate::event::{
DeviceEvent, ElementState, Event, Ime, MouseScrollDelta, RawKeyEvent, Touch, TouchPhase, DeviceEvent, ElementState, Event, Ime, InnerSizeWriter, MouseButton, MouseScrollDelta,
WindowEvent, RawKeyEvent, Touch, TouchPhase, WindowEvent,
}; };
use crate::event::{InnerSizeWriter, MouseButton};
use crate::event_loop::ActiveEventLoop as RootAEL; use crate::event_loop::ActiveEventLoop as RootAEL;
use crate::keyboard::ModifiersState; use crate::keyboard::ModifiersState;
use crate::platform_impl::common::xkb::{self, XkbState}; use crate::platform_impl::common::xkb::{self, XkbState};
@ -33,10 +31,11 @@ use crate::platform_impl::platform::common::xkb::Context;
use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver, ImeRequest}; use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver, ImeRequest};
use crate::platform_impl::platform::x11::ActiveEventLoop; use crate::platform_impl::platform::x11::ActiveEventLoop;
use crate::platform_impl::platform::ActiveEventLoop as PlatformActiveEventLoop; use crate::platform_impl::platform::ActiveEventLoop as PlatformActiveEventLoop;
use crate::platform_impl::x11::atoms::*;
use crate::platform_impl::x11::util::cookie::GenericEventCookie; use crate::platform_impl::x11::util::cookie::GenericEventCookie;
use crate::platform_impl::x11::{ use crate::platform_impl::x11::{
atoms::*, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState, ImeReceiver,
ImeReceiver, ScrollOrientation, UnownedWindow, WindowId, ScrollOrientation, UnownedWindow, WindowId,
}; };
/// The maximum amount of X modifiers to replay. /// The maximum amount of X modifiers to replay.
@ -91,10 +90,10 @@ impl EventProcessor {
match request { match request {
ImeRequest::Position(window_id, x, y) => { ImeRequest::Position(window_id, x, y) => {
ime.send_xim_spot(window_id, x, y); ime.send_xim_spot(window_id, x, y);
} },
ImeRequest::Allow(window_id, allowed) => { ImeRequest::Allow(window_id, allowed) => {
ime.set_ime_allowed(window_id, allowed); ime.set_ime_allowed(window_id, allowed);
} },
} }
} }
@ -106,19 +105,19 @@ impl EventProcessor {
ImeEvent::Start => { ImeEvent::Start => {
self.is_composing = true; self.is_composing = true;
WindowEvent::Ime(Ime::Preedit("".to_owned(), None)) WindowEvent::Ime(Ime::Preedit("".to_owned(), None))
} },
ImeEvent::Update(text, position) if self.is_composing => { ImeEvent::Update(text, position) if self.is_composing => {
WindowEvent::Ime(Ime::Preedit(text, Some((position, position)))) WindowEvent::Ime(Ime::Preedit(text, Some((position, position))))
} },
ImeEvent::End => { ImeEvent::End => {
self.is_composing = false; self.is_composing = false;
// Issue empty preedit on `Done`. // Issue empty preedit on `Done`.
WindowEvent::Ime(Ime::Preedit(String::new(), None)) WindowEvent::Ime(Ime::Preedit(String::new(), None))
} },
ImeEvent::Disabled => { ImeEvent::Disabled => {
self.is_composing = false; self.is_composing = false;
WindowEvent::Ime(Ime::Disabled) WindowEvent::Ime(Ime::Disabled)
} },
_ => continue, _ => continue,
}; };
@ -182,7 +181,7 @@ impl EventProcessor {
}; };
self.xinput_key_input(xev.as_mut(), state, &mut callback); self.xinput_key_input(xev.as_mut(), state, &mut callback);
} },
xlib::GenericEvent => { xlib::GenericEvent => {
let wt = Self::window_target(&self.target); let wt = Self::window_target(&self.target);
let xev: GenericEventCookie = let xev: GenericEventCookie =
@ -209,7 +208,7 @@ impl EventProcessor {
&mut callback, &mut callback,
); );
self.xinput2_button_input(xev, state, &mut callback); self.xinput2_button_input(xev, state, &mut callback);
} },
xinput2::XI_Motion => { xinput2::XI_Motion => {
let xev: &XIDeviceEvent = unsafe { xev.as_event() }; let xev: &XIDeviceEvent = unsafe { xev.as_event() };
self.update_mods_from_xinput2_event( self.update_mods_from_xinput2_event(
@ -219,11 +218,11 @@ impl EventProcessor {
&mut callback, &mut callback,
); );
self.xinput2_mouse_motion(xev, &mut callback); self.xinput2_mouse_motion(xev, &mut callback);
} },
xinput2::XI_Enter => { xinput2::XI_Enter => {
let xev: &XIEnterEvent = unsafe { xev.as_event() }; let xev: &XIEnterEvent = unsafe { xev.as_event() };
self.xinput2_mouse_enter(xev, &mut callback); self.xinput2_mouse_enter(xev, &mut callback);
} },
xinput2::XI_Leave => { xinput2::XI_Leave => {
let xev: &XILeaveEvent = unsafe { xev.as_event() }; let xev: &XILeaveEvent = unsafe { xev.as_event() };
self.update_mods_from_xinput2_event( self.update_mods_from_xinput2_event(
@ -233,15 +232,15 @@ impl EventProcessor {
&mut callback, &mut callback,
); );
self.xinput2_mouse_left(xev, &mut callback); self.xinput2_mouse_left(xev, &mut callback);
} },
xinput2::XI_FocusIn => { xinput2::XI_FocusIn => {
let xev: &XIFocusInEvent = unsafe { xev.as_event() }; let xev: &XIFocusInEvent = unsafe { xev.as_event() };
self.xinput2_focused(xev, &mut callback); self.xinput2_focused(xev, &mut callback);
} },
xinput2::XI_FocusOut => { xinput2::XI_FocusOut => {
let xev: &XIFocusOutEvent = unsafe { xev.as_event() }; let xev: &XIFocusOutEvent = unsafe { xev.as_event() };
self.xinput2_unfocused(xev, &mut callback); self.xinput2_unfocused(xev, &mut callback);
} },
xinput2::XI_TouchBegin | xinput2::XI_TouchUpdate | xinput2::XI_TouchEnd => { xinput2::XI_TouchBegin | xinput2::XI_TouchUpdate | xinput2::XI_TouchEnd => {
let phase = match evtype { let phase = match evtype {
xinput2::XI_TouchBegin => TouchPhase::Started, xinput2::XI_TouchBegin => TouchPhase::Started,
@ -252,7 +251,7 @@ impl EventProcessor {
let xev: &XIDeviceEvent = unsafe { xev.as_event() }; let xev: &XIDeviceEvent = unsafe { xev.as_event() };
self.xinput2_touch(xev, phase, &mut callback); self.xinput2_touch(xev, phase, &mut callback);
} },
xinput2::XI_RawButtonPress | xinput2::XI_RawButtonRelease => { xinput2::XI_RawButtonPress | xinput2::XI_RawButtonRelease => {
let state = match evtype { let state = match evtype {
xinput2::XI_RawButtonPress => ElementState::Pressed, xinput2::XI_RawButtonPress => ElementState::Pressed,
@ -262,11 +261,11 @@ impl EventProcessor {
let xev: &XIRawEvent = unsafe { xev.as_event() }; let xev: &XIRawEvent = unsafe { xev.as_event() };
self.xinput2_raw_button_input(xev, state, &mut callback); self.xinput2_raw_button_input(xev, state, &mut callback);
} },
xinput2::XI_RawMotion => { xinput2::XI_RawMotion => {
let xev: &XIRawEvent = unsafe { xev.as_event() }; let xev: &XIRawEvent = unsafe { xev.as_event() };
self.xinput2_raw_mouse_motion(xev, &mut callback); self.xinput2_raw_mouse_motion(xev, &mut callback);
} },
xinput2::XI_RawKeyPress | xinput2::XI_RawKeyRelease => { xinput2::XI_RawKeyPress | xinput2::XI_RawKeyRelease => {
let state = match evtype { let state = match evtype {
xinput2::XI_RawKeyPress => ElementState::Pressed, xinput2::XI_RawKeyPress => ElementState::Pressed,
@ -276,15 +275,15 @@ impl EventProcessor {
let xev: &xinput2::XIRawEvent = unsafe { xev.as_event() }; let xev: &xinput2::XIRawEvent = unsafe { xev.as_event() };
self.xinput2_raw_key_input(xev, state, &mut callback); self.xinput2_raw_key_input(xev, state, &mut callback);
} },
xinput2::XI_HierarchyChanged => { xinput2::XI_HierarchyChanged => {
let xev: &XIHierarchyEvent = unsafe { xev.as_event() }; let xev: &XIHierarchyEvent = unsafe { xev.as_event() };
self.xinput2_hierarchy_changed(xev, &mut callback); self.xinput2_hierarchy_changed(xev, &mut callback);
} },
_ => {} _ => {},
} }
} },
_ => { _ => {
if event_type == self.xkbext.first_event as _ { if event_type == self.xkbext.first_event as _ {
let xev: &XkbAnyEvent = unsafe { &*(xev as *const _ as *const XkbAnyEvent) }; let xev: &XkbAnyEvent = unsafe { &*(xev as *const _ as *const XkbAnyEvent) };
@ -293,7 +292,7 @@ impl EventProcessor {
if event_type == self.randr_event_offset as c_int { if event_type == self.randr_event_offset as c_int {
self.process_dpi_change(&mut callback); self.process_dpi_change(&mut callback);
} }
} },
} }
} }
@ -399,10 +398,7 @@ impl EventProcessor {
let window_id = mkwid(window); let window_id = mkwid(window);
if xev.data.get_long(0) as xproto::Atom == wt.wm_delete_window { if xev.data.get_long(0) as xproto::Atom == wt.wm_delete_window {
let event = Event::WindowEvent { let event = Event::WindowEvent { window_id, event: WindowEvent::CloseRequested };
window_id,
event: WindowEvent::CloseRequested,
};
callback(&self.target, event); callback(&self.target, event);
return; return;
} }
@ -467,16 +463,16 @@ impl EventProcessor {
// where `shift = mem::size_of::<c_short>() * 8` // where `shift = mem::size_of::<c_short>() * 8`
// Note that coordinates are in "desktop space", not "window space" // Note that coordinates are in "desktop space", not "window space"
// (in X11 parlance, they're root window coordinates) // (in X11 parlance, they're root window coordinates)
//let packed_coordinates = xev.data.get_long(2); // let packed_coordinates = xev.data.get_long(2);
//let shift = mem::size_of::<libc::c_short>() * 8; // let shift = mem::size_of::<libc::c_short>() * 8;
//let x = packed_coordinates >> shift; // let x = packed_coordinates >> shift;
//let y = packed_coordinates & !(x << shift); // let y = packed_coordinates & !(x << shift);
// By our own state flow, `version` should never be `None` at this point. // By our own state flow, `version` should never be `None` at this point.
let version = self.dnd.version.unwrap_or(5); let version = self.dnd.version.unwrap_or(5);
// Action is specified in versions 2 and up, though we don't need it anyway. // Action is specified in versions 2 and up, though we don't need it anyway.
//let action = xev.data.get_long(4); // let action = xev.data.get_long(4);
let accepted = if let Some(ref type_list) = self.dnd.type_list { let accepted = if let Some(ref type_list) = self.dnd.type_list {
type_list.contains(&atoms[TextUriList]) type_list.contains(&atoms[TextUriList])
@ -533,8 +529,8 @@ impl EventProcessor {
} }
(source_window, DndState::Accepted) (source_window, DndState::Accepted)
} else { } else {
// `source_window` won't be part of our DND state if we already rejected the drop in our // `source_window` won't be part of our DND state if we already rejected the drop in
// `XdndPosition` handler. // our `XdndPosition` handler.
let source_window = xev.data.get_long(0) as xproto::Window; let source_window = xev.data.get_long(0) as xproto::Window;
(source_window, DndState::Rejected) (source_window, DndState::Rejected)
}; };
@ -551,10 +547,7 @@ impl EventProcessor {
if xev.message_type == atoms[XdndLeave] as c_ulong { if xev.message_type == atoms[XdndLeave] as c_ulong {
self.dnd.reset(); self.dnd.reset();
let event = Event::WindowEvent { let event = Event::WindowEvent { window_id, event: WindowEvent::HoveredFileCancelled };
window_id,
event: WindowEvent::HoveredFileCancelled,
};
callback(&self.target, event); callback(&self.target, event);
} }
} }
@ -628,8 +621,8 @@ impl EventProcessor {
util::maybe_change(&mut shared_state_lock.inner_position, new_inner_position) util::maybe_change(&mut shared_state_lock.inner_position, new_inner_position)
} else { } else {
// Detect when frame extents change. // Detect when frame extents change.
// Since this isn't synthetic, as per the notes above, this position is relative to the // Since this isn't synthetic, as per the notes above, this position is relative to
// parent window. // the parent window.
let rel_parent = new_inner_position; let rel_parent = new_inner_position;
if util::maybe_change(&mut shared_state_lock.inner_position_rel_parent, rel_parent) if util::maybe_change(&mut shared_state_lock.inner_position_rel_parent, rel_parent)
{ {
@ -651,11 +644,8 @@ impl EventProcessor {
let mut shared_state_lock = window.shared_state_lock(); let mut shared_state_lock = window.shared_state_lock();
// We need to convert client area position to window position. // We need to convert client area position to window position.
let frame_extents = shared_state_lock let frame_extents =
.frame_extents shared_state_lock.frame_extents.as_ref().cloned().unwrap_or_else(|| {
.as_ref()
.cloned()
.unwrap_or_else(|| {
let frame_extents = wt.xconn.get_frame_extents_heuristic(xwindow, wt.root); let frame_extents = wt.xconn.get_frame_extents_heuristic(xwindow, wt.root);
shared_state_lock.frame_extents = Some(frame_extents.clone()); shared_state_lock.frame_extents = Some(frame_extents.clone());
frame_extents frame_extents
@ -668,24 +658,21 @@ impl EventProcessor {
drop(shared_state_lock); drop(shared_state_lock);
if moved { if moved {
callback( callback(&self.target, Event::WindowEvent {
&self.target, window_id,
Event::WindowEvent { event: WindowEvent::Moved(outer.into()),
window_id, });
event: WindowEvent::Moved(outer.into()),
},
);
} }
outer outer
}; };
if is_synthetic { if is_synthetic {
let mut shared_state_lock = window.shared_state_lock(); let mut shared_state_lock = window.shared_state_lock();
// If we don't use the existing adjusted value when available, then the user can screw up the // If we don't use the existing adjusted value when available, then the user can screw
// resizing by dragging across monitors *without* dropping the window. // up the resizing by dragging across monitors *without* dropping the
let (width, height) = shared_state_lock // window.
.dpi_adjusted let (width, height) =
.unwrap_or((xev.width as u32, xev.height as u32)); shared_state_lock.dpi_adjusted.unwrap_or((xev.width as u32, xev.height as u32));
let last_scale_factor = shared_state_lock.last_monitor.scale_factor; let last_scale_factor = shared_state_lock.last_monitor.scale_factor;
let new_scale_factor = { let new_scale_factor = {
@ -719,16 +706,13 @@ impl EventProcessor {
drop(shared_state_lock); drop(shared_state_lock);
let inner_size = Arc::new(Mutex::new(new_inner_size)); let inner_size = Arc::new(Mutex::new(new_inner_size));
callback( callback(&self.target, Event::WindowEvent {
&self.target, window_id,
Event::WindowEvent { event: WindowEvent::ScaleFactorChanged {
window_id, scale_factor: new_scale_factor,
event: WindowEvent::ScaleFactorChanged { inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&inner_size)),
scale_factor: new_scale_factor,
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&inner_size)),
},
}, },
); });
let new_inner_size = *inner_size.lock().unwrap(); let new_inner_size = *inner_size.lock().unwrap();
drop(inner_size); drop(inner_size);
@ -775,13 +759,10 @@ impl EventProcessor {
} }
if resized { if resized {
callback( callback(&self.target, Event::WindowEvent {
&self.target, window_id,
Event::WindowEvent { event: WindowEvent::Resized(new_inner_size.into()),
window_id, });
event: WindowEvent::Resized(new_inner_size.into()),
},
);
} }
} }
@ -812,13 +793,8 @@ impl EventProcessor {
// The purpose of it is to deliver initial focused state of the newly created // The purpose of it is to deliver initial focused state of the newly created
// window, given that we can't rely on `CreateNotify`, due to it being not // window, given that we can't rely on `CreateNotify`, due to it being not
// sent. // sent.
let focus = self let focus = self.with_window(window, |window| window.has_focus()).unwrap_or_default();
.with_window(window, |window| window.has_focus()) let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(focus) };
.unwrap_or_default();
let event = Event::WindowEvent {
window_id,
event: WindowEvent::Focused(focus),
};
callback(&self.target, event); callback(&self.target, event);
} }
@ -844,13 +820,7 @@ impl EventProcessor {
.expect("Failed to destroy input context"); .expect("Failed to destroy input context");
} }
callback( callback(&self.target, Event::WindowEvent { window_id, event: WindowEvent::Destroyed });
&self.target,
Event::WindowEvent {
window_id,
event: WindowEvent::Destroyed,
},
);
} }
fn property_notify<T: 'static, F>(&mut self, xev: &XPropertyEvent, mut callback: F) fn property_notify<T: 'static, F>(&mut self, xev: &XPropertyEvent, mut callback: F)
@ -895,10 +865,7 @@ impl EventProcessor {
let window = xev.window as xproto::Window; let window = xev.window as xproto::Window;
let window_id = mkwid(window); let window_id = mkwid(window);
let event = Event::WindowEvent { let event = Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested };
window_id,
event: WindowEvent::RedrawRequested,
};
callback(&self.target, event); callback(&self.target, event);
} }
@ -937,11 +904,8 @@ impl EventProcessor {
// Only keys that can repeat should change the held_key_press state since a // Only keys that can repeat should change the held_key_press state since a
// continuously held repeatable key may continue repeating after the press of a // continuously held repeatable key may continue repeating after the press of a
// non-repeatable key. // non-repeatable key.
let key_repeats = self let key_repeats =
.xkb_context self.xkb_context.keymap_mut().map(|k| k.key_repeats(keycode)).unwrap_or(false);
.keymap_mut()
.map(|k| k.key_repeats(keycode))
.unwrap_or(false);
let repeat = if key_repeats { let repeat = if key_repeats {
let is_latest_held = self.held_key_press == Some(keycode); let is_latest_held = self.held_key_press == Some(keycode);
@ -964,16 +928,12 @@ impl EventProcessor {
// NOTE: When the modifier was captured by the XFilterEvents the modifiers for the modifier // NOTE: When the modifier was captured by the XFilterEvents the modifiers for the modifier
// itself are out of sync due to XkbState being delivered before XKeyEvent, since it's // itself are out of sync due to XkbState being delivered before XKeyEvent, since it's
// being replayed by the XIM, thus we should replay ourselves. // being replayed by the XIM, thus we should replay ourselves.
let replay = if let Some(position) = self let replay = if let Some(position) =
.xfiltered_modifiers self.xfiltered_modifiers.iter().rev().position(|&s| s == xev.serial)
.iter()
.rev()
.position(|&s| s == xev.serial)
{ {
// We don't have to replay modifiers pressed before the current event if some events // We don't have to replay modifiers pressed before the current event if some events
// were not forwarded to us, since their state is irrelevant. // were not forwarded to us, since their state is irrelevant.
self.xfiltered_modifiers self.xfiltered_modifiers.resize(self.xfiltered_modifiers.len() - 1 - position, 0);
.resize(self.xfiltered_modifiers.len() - 1 - position, 0);
true true
} else { } else {
false false
@ -994,11 +954,7 @@ impl EventProcessor {
let event = key_processor.process_key_event(keycode, state, repeat); let event = key_processor.process_key_event(keycode, state, repeat);
let event = Event::WindowEvent { let event = Event::WindowEvent {
window_id, window_id,
event: WindowEvent::KeyboardInput { event: WindowEvent::KeyboardInput { device_id, event, is_synthetic: false },
device_id,
event,
is_synthetic: false,
},
}; };
callback(&self.target, event); callback(&self.target, event);
} }
@ -1013,10 +969,8 @@ impl EventProcessor {
let wt = Self::window_target(&self.target); let wt = Self::window_target(&self.target);
if let Some(ic) = wt if let Some(ic) =
.ime wt.ime.as_ref().and_then(|ime| ime.borrow().get_context(window as XWindow))
.as_ref()
.and_then(|ime| ime.borrow().get_context(window as XWindow))
{ {
let written = wt.xconn.lookup_utf8(ic, xev); let written = wt.xconn.lookup_utf8(ic, xev);
if !written.is_empty() { if !written.is_empty() {
@ -1026,10 +980,8 @@ impl EventProcessor {
}; };
callback(&self.target, event); callback(&self.target, event);
let event = Event::WindowEvent { let event =
window_id, Event::WindowEvent { window_id, event: WindowEvent::Ime(Ime::Commit(written)) };
event: WindowEvent::Ime(Ime::Commit(written)),
};
self.is_composing = false; self.is_composing = false;
callback(&self.target, event); callback(&self.target, event);
@ -1064,10 +1016,8 @@ impl EventProcessor {
xkb_state.update_modifiers(mask, 0, 0, 0, 0, Self::core_keyboard_group(state)); xkb_state.update_modifiers(mask, 0, 0, 0, 0, Self::core_keyboard_group(state));
let mods: ModifiersState = xkb_state.modifiers().into(); let mods: ModifiersState = xkb_state.modifiers().into();
let event = Event::WindowEvent { let event =
window_id, Event::WindowEvent { window_id, event: WindowEvent::ModifiersChanged(mods.into()) };
event: WindowEvent::ModifiersChanged(mods.into()),
};
callback(&self.target, event); callback(&self.target, event);
} }
@ -1093,26 +1043,21 @@ impl EventProcessor {
} }
let event = match event.detail as u32 { let event = match event.detail as u32 {
xlib::Button1 => WindowEvent::MouseInput { xlib::Button1 => {
device_id, WindowEvent::MouseInput { device_id, state, button: MouseButton::Left }
state,
button: MouseButton::Left,
}, },
xlib::Button2 => WindowEvent::MouseInput { xlib::Button2 => {
device_id, WindowEvent::MouseInput { device_id, state, button: MouseButton::Middle }
state,
button: MouseButton::Middle,
}, },
xlib::Button3 => WindowEvent::MouseInput { xlib::Button3 => {
device_id, WindowEvent::MouseInput { device_id, state, button: MouseButton::Right }
state,
button: MouseButton::Right,
}, },
// Suppress emulated scroll wheel clicks, since we handle the real motion events for those. // Suppress emulated scroll wheel clicks, since we handle the real motion events for
// In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in // those. In practice, even clicky scroll wheels appear to be reported by
// turn) as axis motion, so we don't otherwise special-case these button presses. // evdev (and XInput2 in turn) as axis motion, so we don't otherwise
// special-case these button presses.
4..=7 => WindowEvent::MouseWheel { 4..=7 => WindowEvent::MouseWheel {
device_id, device_id,
delta: match event.detail { delta: match event.detail {
@ -1124,22 +1069,10 @@ impl EventProcessor {
}, },
phase: TouchPhase::Moved, phase: TouchPhase::Moved,
}, },
8 => WindowEvent::MouseInput { 8 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Back },
device_id,
state,
button: MouseButton::Back,
},
9 => WindowEvent::MouseInput { 9 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Forward },
device_id, x => WindowEvent::MouseInput { device_id, state, button: MouseButton::Other(x as u16) },
state,
button: MouseButton::Forward,
},
x => WindowEvent::MouseInput {
device_id,
state,
button: MouseButton::Other(x as u16),
},
}; };
let event = Event::WindowEvent { window_id, event }; let event = Event::WindowEvent { window_id, event };
@ -1170,10 +1103,7 @@ impl EventProcessor {
let event = Event::WindowEvent { let event = Event::WindowEvent {
window_id, window_id,
event: WindowEvent::CursorMoved { event: WindowEvent::CursorMoved { device_id, position },
device_id,
position,
},
}; };
callback(&self.target, event); callback(&self.target, event);
} else if cursor_moved.is_none() { } else if cursor_moved.is_none() {
@ -1199,10 +1129,8 @@ impl EventProcessor {
let x = unsafe { *value }; let x = unsafe { *value };
let event = if let Some(&mut (_, ref mut info)) = physical_device let event = if let Some(&mut (_, ref mut info)) =
.scroll_axes physical_device.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == i as _)
.iter_mut()
.find(|&&mut (axis, _)| axis == i as _)
{ {
let delta = (x - info.position) / info.increment; let delta = (x - info.position) / info.increment;
info.position = x; info.position = x;
@ -1210,21 +1138,13 @@ impl EventProcessor {
let delta = match info.orientation { let delta = match info.orientation {
ScrollOrientation::Horizontal => { ScrollOrientation::Horizontal => {
MouseScrollDelta::LineDelta(-delta as f32, 0.0) MouseScrollDelta::LineDelta(-delta as f32, 0.0)
} },
ScrollOrientation::Vertical => MouseScrollDelta::LineDelta(0.0, -delta as f32), ScrollOrientation::Vertical => MouseScrollDelta::LineDelta(0.0, -delta as f32),
}; };
WindowEvent::MouseWheel { WindowEvent::MouseWheel { device_id, delta, phase: TouchPhase::Moved }
device_id,
delta,
phase: TouchPhase::Moved,
}
} else { } else {
WindowEvent::AxisMotion { WindowEvent::AxisMotion { device_id, axis: i as u32, value: unsafe { *value } }
device_id,
axis: i as u32,
value: unsafe { *value },
}
}; };
events.push(Event::WindowEvent { window_id, event }); events.push(Event::WindowEvent { window_id, event });
@ -1253,12 +1173,11 @@ impl EventProcessor {
if let Some(all_info) = DeviceInfo::get(&wt.xconn, super::ALL_DEVICES.into()) { if let Some(all_info) = DeviceInfo::get(&wt.xconn, super::ALL_DEVICES.into()) {
let mut devices = self.devices.borrow_mut(); let mut devices = self.devices.borrow_mut();
for device_info in all_info.iter() { for device_info in all_info.iter() {
// The second expression is need for resetting to work correctly on i3, and
// presumably some other WMs. On those, `XI_Enter` doesn't include the physical
// device ID, so both `sourceid` and `deviceid` are the virtual device.
if device_info.deviceid == event.sourceid if device_info.deviceid == event.sourceid
// This is needed for resetting to work correctly on i3, and || device_info.attachment == event.sourceid
// presumably some other WMs. On those, `XI_Enter` doesn't include
// the physical device ID, so both `sourceid` and `deviceid` are
// the virtual device.
|| device_info.attachment == event.sourceid
{ {
let device_id = DeviceId(device_info.deviceid as _); let device_id = DeviceId(device_info.deviceid as _);
if let Some(device) = devices.get_mut(&device_id) { if let Some(device) = devices.get_mut(&device_id) {
@ -1271,18 +1190,13 @@ impl EventProcessor {
if self.window_exists(window) { if self.window_exists(window) {
let position = PhysicalPosition::new(event.event_x, event.event_y); let position = PhysicalPosition::new(event.event_x, event.event_y);
let event = Event::WindowEvent { let event =
window_id, Event::WindowEvent { window_id, event: WindowEvent::CursorEntered { device_id } };
event: WindowEvent::CursorEntered { device_id },
};
callback(&self.target, event); callback(&self.target, event);
let event = Event::WindowEvent { let event = Event::WindowEvent {
window_id, window_id,
event: WindowEvent::CursorMoved { event: WindowEvent::CursorMoved { device_id, position },
device_id,
position,
},
}; };
callback(&self.target, event); callback(&self.target, event);
} }
@ -1322,9 +1236,7 @@ impl EventProcessor {
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
if let Some(ime) = wt.ime.as_ref() { if let Some(ime) = wt.ime.as_ref() {
ime.borrow_mut() ime.borrow_mut().focus(xev.event).expect("Failed to focus input context");
.focus(xev.event)
.expect("Failed to focus input context");
} }
if self.active_window == Some(window) { if self.active_window == Some(window) {
@ -1342,10 +1254,7 @@ impl EventProcessor {
window.shared_state_lock().has_focus = true; window.shared_state_lock().has_focus = true;
} }
let event = Event::WindowEvent { let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(true) };
window_id,
event: WindowEvent::Focused(true),
};
callback(&self.target, event); callback(&self.target, event);
// Issue key press events for all pressed keys // Issue key press events for all pressed keys
@ -1370,10 +1279,7 @@ impl EventProcessor {
let event = Event::WindowEvent { let event = Event::WindowEvent {
window_id, window_id,
event: WindowEvent::CursorMoved { event: WindowEvent::CursorMoved { device_id: mkdid(pointer_id as _), position },
device_id: mkdid(pointer_id as _),
position,
},
}; };
callback(&self.target, event); callback(&self.target, event);
} }
@ -1393,9 +1299,7 @@ impl EventProcessor {
} }
if let Some(ime) = wt.ime.as_ref() { if let Some(ime) = wt.ime.as_ref() {
ime.borrow_mut() ime.borrow_mut().unfocus(xev.event).expect("Failed to unfocus input context");
.unfocus(xev.event)
.expect("Failed to unfocus input context");
} }
if self.active_window.take() == Some(window) { if self.active_window.take() == Some(window) {
@ -1427,10 +1331,7 @@ impl EventProcessor {
window.shared_state_lock().has_focus = false; window.shared_state_lock().has_focus = false;
} }
let event = Event::WindowEvent { let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(false) };
window_id,
event: WindowEvent::Focused(false),
};
callback(&self.target, event) callback(&self.target, event)
} }
} }
@ -1497,10 +1398,7 @@ impl EventProcessor {
if xev.flags & xinput2::XIPointerEmulated == 0 { if xev.flags & xinput2::XIPointerEmulated == 0 {
let event = Event::DeviceEvent { let event = Event::DeviceEvent {
device_id: mkdid(xev.deviceid as xinput::DeviceId), device_id: mkdid(xev.deviceid as xinput::DeviceId),
event: DeviceEvent::Button { event: DeviceEvent::Button { state, button: xev.detail as u32 },
state,
button: xev.detail as u32,
},
}; };
callback(&self.target, event); callback(&self.target, event);
} }
@ -1535,15 +1433,12 @@ impl EventProcessor {
1 => mouse_delta.set_y(x), 1 => mouse_delta.set_y(x),
2 => scroll_delta.set_x(x as f32), 2 => scroll_delta.set_x(x as f32),
3 => scroll_delta.set_y(x as f32), 3 => scroll_delta.set_y(x as f32),
_ => {} _ => {},
} }
let event = Event::DeviceEvent { let event = Event::DeviceEvent {
device_id: did, device_id: did,
event: DeviceEvent::Motion { event: DeviceEvent::Motion { axis: i as u32, value: x },
axis: i as u32,
value: x,
},
}; };
callback(&self.target, event); callback(&self.target, event);
@ -1589,16 +1484,10 @@ impl EventProcessor {
} }
let physical_key = xkb::raw_keycode_to_physicalkey(keycode); let physical_key = xkb::raw_keycode_to_physicalkey(keycode);
callback( callback(&self.target, Event::DeviceEvent {
&self.target, device_id,
Event::DeviceEvent { event: DeviceEvent::Key(RawKeyEvent { physical_key, state }),
device_id, });
event: DeviceEvent::Key(RawKeyEvent {
physical_key,
state,
}),
},
);
} }
fn xinput2_hierarchy_changed<T: 'static, F>(&mut self, xev: &XIHierarchyEvent, mut callback: F) fn xinput2_hierarchy_changed<T: 'static, F>(&mut self, xev: &XIHierarchyEvent, mut callback: F)
@ -1613,21 +1502,15 @@ impl EventProcessor {
for info in infos { for info in infos {
if 0 != info.flags & (xinput2::XISlaveAdded | xinput2::XIMasterAdded) { if 0 != info.flags & (xinput2::XISlaveAdded | xinput2::XIMasterAdded) {
self.init_device(info.deviceid as xinput::DeviceId); self.init_device(info.deviceid as xinput::DeviceId);
callback( callback(&self.target, Event::DeviceEvent {
&self.target, device_id: mkdid(info.deviceid as xinput::DeviceId),
Event::DeviceEvent { event: DeviceEvent::Added,
device_id: mkdid(info.deviceid as xinput::DeviceId), });
event: DeviceEvent::Added,
},
);
} else if 0 != info.flags & (xinput2::XISlaveRemoved | xinput2::XIMasterRemoved) { } else if 0 != info.flags & (xinput2::XISlaveRemoved | xinput2::XIMasterRemoved) {
callback( callback(&self.target, Event::DeviceEvent {
&self.target, device_id: mkdid(info.deviceid as xinput::DeviceId),
Event::DeviceEvent { event: DeviceEvent::Removed,
device_id: mkdid(info.deviceid as xinput::DeviceId), });
event: DeviceEvent::Removed,
},
);
let mut devices = self.devices.borrow_mut(); let mut devices = self.devices.borrow_mut();
devices.remove(&DeviceId(info.deviceid as xinput::DeviceId)); devices.remove(&DeviceId(info.deviceid as xinput::DeviceId));
} }
@ -1669,7 +1552,7 @@ impl EventProcessor {
self.send_modifiers(window_id, mods, true, &mut callback); self.send_modifiers(window_id, mods, true, &mut callback);
} }
} }
} },
xlib::XkbMapNotify => { xlib::XkbMapNotify => {
let xcb = wt.xconn.xcb_connection().get_raw_xcb_connection(); let xcb = wt.xconn.xcb_connection().get_raw_xcb_connection();
self.xkb_context.set_keymap_from_x11(xcb); self.xkb_context.set_keymap_from_x11(xcb);
@ -1683,7 +1566,7 @@ impl EventProcessor {
let mods = state.modifiers().into(); let mods = state.modifiers().into();
self.send_modifiers(window_id, mods, true, &mut callback); self.send_modifiers(window_id, mods, true, &mut callback);
} }
} },
xlib::XkbStateNotify => { xlib::XkbStateNotify => {
let xev = unsafe { &*(xev as *const _ as *const xlib::XkbStateNotifyEvent) }; let xev = unsafe { &*(xev as *const _ as *const xlib::XkbStateNotifyEvent) };
@ -1708,8 +1591,8 @@ impl EventProcessor {
let mods = state.modifiers().into(); let mods = state.modifiers().into();
self.send_modifiers(window_id, mods, true, &mut callback); self.send_modifiers(window_id, mods, true, &mut callback);
} }
} },
_ => {} _ => {},
} }
} }
@ -1825,22 +1708,13 @@ impl EventProcessor {
// Build the XKB modifiers from the regular state. // Build the XKB modifiers from the regular state.
let mut depressed = 0u32; let mut depressed = 0u32;
if let Some(shift) = mods_indices if let Some(shift) = mods_indices.shift.filter(|_| ModMask::SHIFT.intersects(state)) {
.shift
.filter(|_| ModMask::SHIFT.intersects(state))
{
depressed |= 1 << shift; depressed |= 1 << shift;
} }
if let Some(caps) = mods_indices if let Some(caps) = mods_indices.caps.filter(|_| ModMask::LOCK.intersects(state)) {
.caps
.filter(|_| ModMask::LOCK.intersects(state))
{
depressed |= 1 << caps; depressed |= 1 << caps;
} }
if let Some(ctrl) = mods_indices if let Some(ctrl) = mods_indices.ctrl.filter(|_| ModMask::CONTROL.intersects(state)) {
.ctrl
.filter(|_| ModMask::CONTROL.intersects(state))
{
depressed |= 1 << ctrl; depressed |= 1 << ctrl;
} }
if let Some(alt) = mods_indices.alt.filter(|_| ModMask::M1.intersects(state)) { if let Some(alt) = mods_indices.alt.filter(|_| ModMask::M1.intersects(state)) {
@ -1897,10 +1771,7 @@ impl EventProcessor {
// Update modifiers state and emit key events based on which keys are currently pressed. // Update modifiers state and emit key events based on which keys are currently pressed.
let window_target = Self::window_target(target); let window_target = Self::window_target(target);
let xcb = window_target let xcb = window_target.xconn.xcb_connection().get_raw_xcb_connection();
.xconn
.xcb_connection()
.get_raw_xcb_connection();
let keymap = match xkb_context.keymap_mut() { let keymap = match xkb_context.keymap_mut() {
Some(keymap) => keymap, Some(keymap) => keymap,
@ -1917,20 +1788,13 @@ impl EventProcessor {
None => return, None => return,
}; };
for keycode in window_target for keycode in
.xconn window_target.xconn.query_keymap().into_iter().filter(|k| *k >= KEYCODE_OFFSET)
.query_keymap()
.into_iter()
.filter(|k| *k >= KEYCODE_OFFSET)
{ {
let event = key_processor.process_key_event(keycode as u32, state, false); let event = key_processor.process_key_event(keycode as u32, state, false);
let event = Event::WindowEvent { let event = Event::WindowEvent {
window_id, window_id,
event: WindowEvent::KeyboardInput { event: WindowEvent::KeyboardInput { device_id, event, is_synthetic: true },
device_id,
event,
is_synthetic: true,
},
}; };
callback(target, event); callback(target, event);
} }
@ -1941,9 +1805,7 @@ impl EventProcessor {
F: FnMut(&RootAEL, Event<T>), F: FnMut(&RootAEL, Event<T>),
{ {
let wt = Self::window_target(&self.target); let wt = Self::window_target(&self.target);
wt.xconn wt.xconn.reload_database().expect("failed to reload Xft database");
.reload_database()
.expect("failed to reload Xft database");
// In the future, it would be quite easy to emit monitor hotplug events. // In the future, it would be quite easy to emit monitor hotplug events.
let prev_list = { let prev_list = {
@ -1954,10 +1816,7 @@ impl EventProcessor {
} }
}; };
let new_list = wt let new_list = wt.xconn.available_monitors().expect("Failed to get monitor list");
.xconn
.available_monitors()
.expect("Failed to get monitor list");
for new_monitor in new_list { for new_monitor in new_list {
// Previous list may be empty, in case of disconnecting and // Previous list may be empty, in case of disconnecting and
// reconnecting the only one monitor. We still need to emit events in // reconnecting the only one monitor. We still need to emit events in
@ -1988,13 +1847,13 @@ fn is_first_touch(first: &mut Option<u64>, num: &mut u32, id: u64, phase: TouchP
*first = Some(id); *first = Some(id);
} }
*num += 1; *num += 1;
} },
TouchPhase::Cancelled | TouchPhase::Ended => { TouchPhase::Cancelled | TouchPhase::Ended => {
if *first == Some(id) { if *first == Some(id) {
*first = None; *first = None;
} }
*num = num.saturating_sub(1); *num = num.saturating_sub(1);
} },
_ => (), _ => (),
} }

View file

@ -1 +1,5 @@
pub use x11_dl::{error::OpenError, xcursor::*, xinput2::*, xlib::*, xlib_xcb::*}; pub use x11_dl::error::OpenError;
pub use x11_dl::xcursor::*;
pub use x11_dl::xinput2::*;
pub use x11_dl::xlib::*;
pub use x11_dl::xlib_xcb::*;

View file

@ -1,12 +1,13 @@
use std::{collections::HashMap, os::raw::c_char, ptr, sync::Arc}; use std::collections::HashMap;
use std::os::raw::c_char;
use std::ptr;
use std::sync::Arc;
use super::{ffi, XConnection, XError}; use super::{ffi, XConnection, XError};
use super::{ use super::context::{ImeContext, ImeContextCreationError};
context::{ImeContext, ImeContextCreationError}, use super::inner::{close_im, ImeInner};
inner::{close_im, ImeInner}, use super::input_method::PotentialInputMethods;
input_method::PotentialInputMethods,
};
pub(crate) unsafe fn xim_set_callback( pub(crate) unsafe fn xim_set_callback(
xconn: &Arc<XConnection>, xconn: &Arc<XConnection>,
@ -24,8 +25,8 @@ pub(crate) unsafe fn xim_set_callback(
// available. Note that this has nothing to do with what input methods are open or able to be // available. Note that this has nothing to do with what input methods are open or able to be
// opened, and simply uses the modifiers that are set when the callback is set. // opened, and simply uses the modifiers that are set when the callback is set.
// * This is called per locale modifier, not per input method opened with that locale modifier. // * This is called per locale modifier, not per input method opened with that locale modifier.
// * Trying to set this for multiple locale modifiers causes problems, i.e. one of the rebuilt // * Trying to set this for multiple locale modifiers causes problems, i.e. one of the rebuilt input
// input contexts would always silently fail to use the input method. // contexts would always silently fail to use the input method.
pub(crate) unsafe fn set_instantiate_callback( pub(crate) unsafe fn set_instantiate_callback(
xconn: &Arc<XConnection>, xconn: &Arc<XConnection>,
client_data: ffi::XPointer, client_data: ffi::XPointer,
@ -119,18 +120,12 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> {
let spot = old_context.as_ref().map(|old_context| old_context.ic_spot); let spot = old_context.as_ref().map(|old_context| old_context.ic_spot);
// Check if the IME was allowed on that context. // Check if the IME was allowed on that context.
let is_allowed = old_context let is_allowed =
.as_ref() old_context.as_ref().map(|old_context| old_context.is_allowed()).unwrap_or_default();
.map(|old_context| old_context.is_allowed())
.unwrap_or_default();
// We can't use the style from the old context here, since it may change on reload, so // We can't use the style from the old context here, since it may change on reload, so
// pick style from the new XIM based on the old state. // pick style from the new XIM based on the old state.
let style = if is_allowed { let style = if is_allowed { new_im.preedit_style } else { new_im.none_style };
new_im.preedit_style
} else {
new_im.none_style
};
let new_context = { let new_context = {
let result = unsafe { let result = unsafe {
@ -208,7 +203,7 @@ pub unsafe extern "C" fn xim_destroy_callback(
Err(err) => { Err(err) => {
// We have no usable input methods! // We have no usable input methods!
panic!("Failed to open fallback input method: {err:?}"); panic!("Failed to open fallback input method: {err:?}");
} },
} }
} }
} }

View file

@ -26,10 +26,7 @@ type XIMProcNonnull = unsafe extern "C" fn(ffi::XIM, ffi::XPointer, ffi::XPointe
/// Wrapper for creating XIM callbacks. /// Wrapper for creating XIM callbacks.
#[inline] #[inline]
fn create_xim_callback(client_data: ffi::XPointer, callback: XIMProcNonnull) -> ffi::XIMCallback { fn create_xim_callback(client_data: ffi::XPointer, callback: XIMProcNonnull) -> ffi::XIMCallback {
XIMCallback { XIMCallback { client_data, callback: Some(callback) }
client_data,
callback: Some(callback),
}
} }
/// The server started preedit. /// The server started preedit.
@ -68,9 +65,7 @@ extern "C" fn preedit_done_callback(
} }
fn calc_byte_position(text: &[char], pos: usize) -> usize { fn calc_byte_position(text: &[char], pos: usize) -> usize {
text.iter() text.iter().take(pos).fold(0, |byte_pos, text| byte_pos + text.len_utf8())
.take(pos)
.fold(0, |byte_pos, text| byte_pos + text.len_utf8())
} }
/// Preedit text information to be drawn inline by the client. /// Preedit text information to be drawn inline by the client.
@ -112,9 +107,7 @@ extern "C" fn preedit_draw_callback(
let new_text = unsafe { CStr::from_ptr(new_text) }; let new_text = unsafe { CStr::from_ptr(new_text) };
String::from(new_text.to_str().expect("Invalid UTF-8 String from IME")) String::from(new_text.to_str().expect("Invalid UTF-8 String from IME")).chars().collect()
.chars()
.collect()
}; };
let mut old_text_tail = client_data.text.split_off(chg_range.end); let mut old_text_tail = client_data.text.split_off(chg_range.end);
client_data.text.truncate(chg_range.start); client_data.text.truncate(chg_range.start);
@ -171,12 +164,7 @@ impl PreeditCallbacks {
let caret_callback = create_xim_callback(client_data, preedit_caret_callback); let caret_callback = create_xim_callback(client_data, preedit_caret_callback);
let draw_callback = create_xim_callback(client_data, preedit_draw_callback); let draw_callback = create_xim_callback(client_data, preedit_draw_callback);
PreeditCallbacks { PreeditCallbacks { start_callback, done_callback, caret_callback, draw_callback }
start_callback,
done_callback,
caret_callback,
draw_callback,
}
} }
} }
@ -195,8 +183,8 @@ pub struct ImeContext {
pub(crate) ic: ffi::XIC, pub(crate) ic: ffi::XIC,
pub(crate) ic_spot: ffi::XPoint, pub(crate) ic_spot: ffi::XPoint,
pub(crate) style: Style, pub(crate) style: Style,
// Since the data is passed shared between X11 XIM callbacks, but couldn't be directly free from // Since the data is passed shared between X11 XIM callbacks, but couldn't be directly free
// there we keep the pointer to automatically deallocate it. // from there we keep the pointer to automatically deallocate it.
_client_data: Box<ImeContextClientData>, _client_data: Box<ImeContextClientData>,
} }
@ -233,9 +221,7 @@ impl ImeContext {
} }
.ok_or(ImeContextCreationError::Null)?; .ok_or(ImeContextCreationError::Null)?;
xconn xconn.check_errors().map_err(ImeContextCreationError::XError)?;
.check_errors()
.map_err(ImeContextCreationError::XError)?;
let mut context = ImeContext { let mut context = ImeContext {
ic, ic,

View file

@ -1,11 +1,11 @@
use std::{collections::HashMap, mem, sync::Arc}; use std::collections::HashMap;
use std::mem;
use std::sync::Arc;
use super::{ffi, XConnection, XError}; use super::{ffi, XConnection, XError};
use super::{ use super::context::ImeContext;
context::ImeContext, use super::input_method::{InputMethod, PotentialInputMethods};
input_method::{InputMethod, PotentialInputMethods},
};
use crate::platform_impl::platform::x11::ime::ImeEventSender; use crate::platform_impl::platform::x11::ime::ImeEventSender;
pub(crate) unsafe fn close_im(xconn: &Arc<XConnection>, im: ffi::XIM) -> Result<(), XError> { pub(crate) unsafe fn close_im(xconn: &Arc<XConnection>, im: ffi::XIM) -> Result<(), XError> {

View file

@ -1,13 +1,10 @@
use std::{ use std::ffi::{CStr, CString, IntoStringError};
env, use std::os::raw::{c_char, c_ulong, c_ushort};
ffi::{CStr, CString, IntoStringError}, use std::sync::{Arc, Mutex};
fmt, use std::{env, fmt, ptr};
os::raw::{c_char, c_ulong, c_ushort},
ptr,
sync::{Arc, Mutex},
};
use super::{super::atoms::*, ffi, util, XConnection, XError}; use super::super::atoms::*;
use super::{ffi, util, XConnection, XError};
use x11rb::protocol::xproto; use x11rb::protocol::xproto;
static GLOBAL_LOCK: Mutex<()> = Mutex::new(()); static GLOBAL_LOCK: Mutex<()> = Mutex::new(());
@ -18,17 +15,12 @@ unsafe fn open_im(xconn: &Arc<XConnection>, locale_modifiers: &CStr) -> Option<f
// XSetLocaleModifiers returns... // XSetLocaleModifiers returns...
// * The current locale modifiers if it's given a NULL pointer. // * The current locale modifiers if it's given a NULL pointer.
// * The new locale modifiers if we succeeded in setting them. // * The new locale modifiers if we succeeded in setting them.
// * NULL if the locale modifiers string is malformed or if the // * NULL if the locale modifiers string is malformed or if the current locale is not supported
// current locale is not supported by Xlib. // by Xlib.
unsafe { (xconn.xlib.XSetLocaleModifiers)(locale_modifiers.as_ptr()) }; unsafe { (xconn.xlib.XSetLocaleModifiers)(locale_modifiers.as_ptr()) };
let im = unsafe { let im = unsafe {
(xconn.xlib.XOpenIM)( (xconn.xlib.XOpenIM)(xconn.display, ptr::null_mut(), ptr::null_mut(), ptr::null_mut())
xconn.display,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
)
}; };
if im.is_null() { if im.is_null() {
@ -73,10 +65,10 @@ impl InputMethod {
.for_each(|style| match *style { .for_each(|style| match *style {
XIM_PREEDIT_STYLE => { XIM_PREEDIT_STYLE => {
preedit_style = Some(Style::Preedit(*style)); preedit_style = Some(Style::Preedit(*style));
} },
XIM_NOTHING_STYLE if preedit_style.is_none() => { XIM_NOTHING_STYLE if preedit_style.is_none() => {
preedit_style = Some(Style::Nothing(*style)) preedit_style = Some(Style::Nothing(*style))
} },
XIM_NONE_STYLE => none_style = Some(Style::None(*style)), XIM_NONE_STYLE => none_style = Some(Style::None(*style)),
_ => (), _ => (),
}); });
@ -91,12 +83,7 @@ impl InputMethod {
let preedit_style = preedit_style.unwrap_or_else(|| none_style.unwrap()); let preedit_style = preedit_style.unwrap_or_else(|| none_style.unwrap());
let none_style = none_style.unwrap_or(preedit_style); let none_style = none_style.unwrap_or(preedit_style);
Some(InputMethod { Some(InputMethod { im, _name: name, preedit_style, none_style })
im,
_name: name,
preedit_style,
none_style,
})
} }
} }
@ -232,10 +219,7 @@ impl InputMethodName {
pub fn from_str(string: &str) -> Self { pub fn from_str(string: &str) -> Self {
let c_string = let c_string =
CString::new(string).expect("String used to construct CString contained null byte"); CString::new(string).expect("String used to construct CString contained null byte");
InputMethodName { InputMethodName { c_string, string: string.to_owned() }
c_string,
string: string.to_owned(),
}
} }
} }
@ -253,17 +237,11 @@ struct PotentialInputMethod {
impl PotentialInputMethod { impl PotentialInputMethod {
pub fn from_string(string: String) -> Self { pub fn from_string(string: String) -> Self {
PotentialInputMethod { PotentialInputMethod { name: InputMethodName::from_string(string), successful: None }
name: InputMethodName::from_string(string),
successful: None,
}
} }
pub fn from_str(string: &str) -> Self { pub fn from_str(string: &str) -> Self {
PotentialInputMethod { PotentialInputMethod { name: InputMethodName::from_str(string), successful: None }
name: InputMethodName::from_str(string),
successful: None,
}
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
@ -297,9 +275,7 @@ pub(crate) struct PotentialInputMethods {
impl PotentialInputMethods { impl PotentialInputMethods {
pub fn new(xconn: &Arc<XConnection>) -> Self { pub fn new(xconn: &Arc<XConnection>) -> Self {
let xmodifiers = env::var("XMODIFIERS") let xmodifiers = env::var("XMODIFIERS").ok().map(PotentialInputMethod::from_string);
.ok()
.map(PotentialInputMethod::from_string);
PotentialInputMethods { PotentialInputMethods {
// Since passing "" to XSetLocaleModifiers results in it defaulting to the value of // Since passing "" to XSetLocaleModifiers results in it defaulting to the value of
// XMODIFIERS, it's worth noting what happens if XMODIFIERS is also "". If simply // XMODIFIERS, it's worth noting what happens if XMODIFIERS is also "". If simply

View file

@ -5,10 +5,8 @@ mod context;
mod inner; mod inner;
mod input_method; mod input_method;
use std::sync::{ use std::sync::mpsc::{Receiver, Sender};
mpsc::{Receiver, Sender}, use std::sync::Arc;
Arc,
};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -16,13 +14,11 @@ use tracing::debug;
use super::{ffi, util, XConnection, XError}; use super::{ffi, util, XConnection, XError};
use self::callbacks::*;
use self::context::ImeContext;
pub use self::context::ImeContextCreationError; pub use self::context::ImeContextCreationError;
use self::{ use self::inner::{close_im, ImeInner};
callbacks::*, use self::input_method::{PotentialInputMethods, Style};
context::ImeContext,
inner::{close_im, ImeInner},
input_method::{PotentialInputMethods, Style},
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -73,10 +69,8 @@ impl Ime {
let mut inner = Box::new(ImeInner::new(xconn, potential_input_methods, event_sender)); let mut inner = Box::new(ImeInner::new(xconn, potential_input_methods, event_sender));
let inner_ptr = Box::into_raw(inner); let inner_ptr = Box::into_raw(inner);
let client_data = inner_ptr as _; let client_data = inner_ptr as _;
let destroy_callback = ffi::XIMCallback { let destroy_callback =
client_data, ffi::XIMCallback { client_data, callback: Some(xim_destroy_callback) };
callback: Some(xim_destroy_callback),
};
inner = unsafe { Box::from_raw(inner_ptr) }; inner = unsafe { Box::from_raw(inner_ptr) };
inner.destroy_callback = destroy_callback; inner.destroy_callback = destroy_callback;
(inner, client_data) (inner, client_data)
@ -105,9 +99,7 @@ impl Ime {
inner.im = Some(input_method); inner.im = Some(input_method);
Ok(Ime { xconn, inner }) Ok(Ime { xconn, inner })
} else { } else {
Err(ImeCreationError::OpenFailure(Box::new( Err(ImeCreationError::OpenFailure(Box::new(inner.potential_input_methods)))
inner.potential_input_methods,
)))
} }
} }
@ -129,11 +121,7 @@ impl Ime {
None None
} else { } else {
let im = self.inner.im.as_ref().unwrap(); let im = self.inner.im.as_ref().unwrap();
let style = if with_preedit { let style = if with_preedit { im.preedit_style } else { im.none_style };
im.preedit_style
} else {
im.none_style
};
let context = unsafe { let context = unsafe {
ImeContext::new( ImeContext::new(
@ -159,10 +147,7 @@ impl Ime {
ImeEvent::Enabled ImeEvent::Enabled
}; };
self.inner self.inner.event_sender.send((window, event)).expect("Failed to send enabled event");
.event_sender
.send((window, event))
.expect("Failed to send enabled event");
Some(context) Some(context)
}; };

View file

@ -3,7 +3,6 @@
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::{HashMap, HashSet, VecDeque}; use std::collections::{HashMap, HashSet, VecDeque};
use std::ffi::CStr; use std::ffi::CStr;
use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::ops::Deref; use std::ops::Deref;
@ -12,11 +11,11 @@ use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError}; use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::{ptr, slice, str}; use std::{fmt, ptr, slice, str};
use calloop::generic::Generic; use calloop::generic::Generic;
use calloop::EventLoop as Loop; use calloop::ping::Ping;
use calloop::{ping::Ping, Readiness}; use calloop::{EventLoop as Loop, Readiness};
use libc::{setlocale, LC_CTYPE}; use libc::{setlocale, LC_CTYPE};
use tracing::warn; use tracing::warn;
@ -78,10 +77,7 @@ struct WakeSender<T> {
impl<T> Clone for WakeSender<T> { impl<T> Clone for WakeSender<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self { sender: self.sender.clone(), waker: self.waker.clone() }
sender: self.sender.clone(),
waker: self.waker.clone(),
}
} }
} }
@ -104,6 +100,7 @@ impl<T> PeekableReceiver<T> {
pub fn from_recv(recv: Receiver<T>) -> Self { pub fn from_recv(recv: Receiver<T>) -> Self {
Self { recv, first: None } Self { recv, first: None }
} }
pub fn has_incoming(&mut self) -> bool { pub fn has_incoming(&mut self) -> bool {
if self.first.is_some() { if self.first.is_some() {
return true; return true;
@ -113,14 +110,15 @@ impl<T> PeekableReceiver<T> {
Ok(v) => { Ok(v) => {
self.first = Some(v); self.first = Some(v);
true true
} },
Err(TryRecvError::Empty) => false, Err(TryRecvError::Empty) => false,
Err(TryRecvError::Disconnected) => { Err(TryRecvError::Disconnected) => {
warn!("Channel was disconnected when checking incoming"); warn!("Channel was disconnected when checking incoming");
false false
} },
} }
} }
pub fn try_recv(&mut self) -> Result<T, TryRecvError> { pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
if let Some(first) = self.first.take() { if let Some(first) = self.first.take() {
return Ok(first); return Ok(first);
@ -171,9 +169,7 @@ pub struct EventLoopProxy<T: 'static> {
impl<T: 'static> Clone for EventLoopProxy<T> { impl<T: 'static> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
EventLoopProxy { EventLoopProxy { user_sender: self.user_sender.clone() }
user_sender: self.user_sender.clone(),
}
} }
} }
@ -223,9 +219,8 @@ impl<T: 'static> EventLoop<T> {
let ime = ime.ok().map(RefCell::new); let ime = ime.ok().map(RefCell::new);
let randr_event_offset = xconn let randr_event_offset =
.select_xrandr_input(root) xconn.select_xrandr_input(root).expect("Failed to query XRandR extension");
.expect("Failed to query XRandR extension");
let xi2ext = xconn let xi2ext = xconn
.xcb_connection() .xcb_connection()
@ -315,10 +310,8 @@ impl<T: 'static> EventLoop<T> {
// Set initial device event filter. // Set initial device event filter.
window_target.update_listen_device_events(true); window_target.update_listen_device_events(true);
let root_window_target = RootAEL { let root_window_target =
p: PlatformActiveEventLoop::X(window_target), RootAEL { p: PlatformActiveEventLoop::X(window_target), _marker: PhantomData };
_marker: PhantomData,
};
let event_processor = EventProcessor { let event_processor = EventProcessor {
target: root_window_target, target: root_window_target,
@ -372,18 +365,13 @@ impl<T: 'static> EventLoop<T> {
activation_receiver: PeekableReceiver::from_recv(activation_token_channel), activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
user_receiver: PeekableReceiver::from_recv(user_channel), user_receiver: PeekableReceiver::from_recv(user_channel),
user_sender, user_sender,
state: EventLoopState { state: EventLoopState { x11_readiness: Readiness::EMPTY },
x11_readiness: Readiness::EMPTY,
},
} }
} }
pub fn create_proxy(&self) -> EventLoopProxy<T> { pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy { EventLoopProxy {
user_sender: WakeSender { user_sender: WakeSender { sender: self.user_sender.clone(), waker: self.waker.clone() },
sender: self.user_sender.clone(),
waker: self.waker.clone(),
},
} }
} }
@ -399,13 +387,13 @@ impl<T: 'static> EventLoop<T> {
match self.pump_events(None, &mut event_handler) { match self.pump_events(None, &mut event_handler) {
PumpStatus::Exit(0) => { PumpStatus::Exit(0) => {
break Ok(()); break Ok(());
} },
PumpStatus::Exit(code) => { PumpStatus::Exit(code) => {
break Err(EventLoopError::ExitFailure(code)); break Err(EventLoopError::ExitFailure(code));
} },
_ => { _ => {
continue; continue;
} },
} }
}; };
@ -471,17 +459,15 @@ impl<T: 'static> EventLoop<T> {
ControlFlow::Poll => Some(Duration::ZERO), ControlFlow::Poll => Some(Duration::ZERO),
ControlFlow::WaitUntil(wait_deadline) => { ControlFlow::WaitUntil(wait_deadline) => {
Some(wait_deadline.saturating_duration_since(start)) Some(wait_deadline.saturating_duration_since(start))
} },
}; };
min_timeout(control_flow_timeout, timeout) min_timeout(control_flow_timeout, timeout)
}; };
self.state.x11_readiness = Readiness::EMPTY; self.state.x11_readiness = Readiness::EMPTY;
if let Err(error) = self if let Err(error) =
.event_loop self.event_loop.dispatch(timeout, &mut self.state).map_err(std::io::Error::from)
.dispatch(timeout, &mut self.state)
.map_err(std::io::Error::from)
{ {
tracing::error!("Failed to poll for events: {error:?}"); tracing::error!("Failed to poll for events: {error:?}");
let exit_code = error.raw_os_error().unwrap_or(1); let exit_code = error.raw_os_error().unwrap_or(1);
@ -493,23 +479,14 @@ impl<T: 'static> EventLoop<T> {
// to be considered here // to be considered here
let cause = match self.control_flow() { let cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll, ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled { ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
start,
requested_resume: None,
},
ControlFlow::WaitUntil(deadline) => { ControlFlow::WaitUntil(deadline) => {
if Instant::now() < deadline { if Instant::now() < deadline {
StartCause::WaitCancelled { StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
start,
requested_resume: Some(deadline),
}
} else { } else {
StartCause::ResumeTimeReached { StartCause::ResumeTimeReached { start, requested_resume: deadline }
start,
requested_resume: deadline,
}
} }
} },
}; };
// False positive / spurious wake ups could lead to us spamming // False positive / spurious wake ups could lead to us spamming
@ -521,10 +498,7 @@ impl<T: 'static> EventLoop<T> {
// running a loop iteration. // running a loop iteration.
// If we don't have any pending `_receiver` // If we don't have any pending `_receiver`
if !self.has_pending() if !self.has_pending()
&& !matches!( && !matches!(&cause, StartCause::ResumeTimeReached { .. } | StartCause::Poll)
&cause,
StartCause::ResumeTimeReached { .. } | StartCause::Poll
)
{ {
return; return;
} }
@ -549,11 +523,9 @@ impl<T: 'static> EventLoop<T> {
// Empty activation tokens. // Empty activation tokens.
while let Ok((window_id, serial)) = self.activation_receiver.try_recv() { while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
let token = self let token = self.event_processor.with_window(window_id.0 as xproto::Window, |window| {
.event_processor window.generate_activation_token()
.with_window(window_id.0 as xproto::Window, |window| { });
window.generate_activation_token()
});
match token { match token {
Some(Ok(token)) => { Some(Ok(token)) => {
@ -565,11 +537,11 @@ impl<T: 'static> EventLoop<T> {
}, },
}; };
callback(event, &self.event_processor.target) callback(event, &self.event_processor.target)
} },
Some(Err(e)) => { Some(Err(e)) => {
tracing::error!("Failed to get activation token: {}", e); tracing::error!("Failed to get activation token: {}", e);
} },
None => {} None => {},
} }
} }
@ -591,10 +563,7 @@ impl<T: 'static> EventLoop<T> {
for window_id in windows { for window_id in windows {
let window_id = crate::window::WindowId(window_id); let window_id = crate::window::WindowId(window_id);
callback( callback(
Event::WindowEvent { Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested },
window_id,
event: WindowEvent::RedrawRequested,
},
&self.event_processor.target, &self.event_processor.target,
); );
} }
@ -614,19 +583,18 @@ impl<T: 'static> EventLoop<T> {
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } { while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
let mut xev = unsafe { xev.assume_init() }; let mut xev = unsafe { xev.assume_init() };
self.event_processor self.event_processor.process_event(&mut xev, |window_target, event| {
.process_event(&mut xev, |window_target, event| { if let Event::WindowEvent {
if let Event::WindowEvent { window_id: crate::window::WindowId(wid),
window_id: crate::window::WindowId(wid), event: WindowEvent::RedrawRequested,
event: WindowEvent::RedrawRequested, } = event
} = event {
{ let window_target = EventProcessor::window_target(window_target);
let window_target = EventProcessor::window_target(window_target); window_target.redraw_sender.send(wid).unwrap();
window_target.redraw_sender.send(wid).unwrap(); } else {
} else { callback(event, window_target);
callback(event, window_target); }
} });
});
} }
} }
@ -679,9 +647,7 @@ impl ActiveEventLoop {
} }
pub(crate) fn create_custom_cursor(&self, cursor: CustomCursorSource) -> RootCustomCursor { pub(crate) fn create_custom_cursor(&self, cursor: CustomCursorSource) -> RootCustomCursor {
RootCustomCursor { RootCustomCursor { inner: PlatformCustomCursor::X(CustomCursor::new(self, cursor.inner)) }
inner: PlatformCustomCursor::X(CustomCursor::new(self, cursor.inner)),
}
} }
pub fn listen_device_events(&self, allowed: DeviceEvents) { pub fn listen_device_events(&self, allowed: DeviceEvents) {
@ -761,9 +727,7 @@ impl ActiveEventLoop {
impl<T: 'static> EventLoopProxy<T> { impl<T: 'static> EventLoopProxy<T> {
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
self.user_sender self.user_sender.send(event).map_err(|e| EventLoopClosed(e.0))
.send(event)
.map_err(|e| EventLoopClosed(e.0))
} }
} }
@ -783,11 +747,7 @@ impl<'a> DeviceInfo<'a> {
if info.is_null() || count == 0 { if info.is_null() || count == 0 {
None None
} else { } else {
Some(DeviceInfo { Some(DeviceInfo { xconn, info, count: count as usize })
xconn,
info,
count: count as usize,
})
} }
} }
} }
@ -802,6 +762,7 @@ impl<'a> Drop for DeviceInfo<'a> {
impl<'a> Deref for DeviceInfo<'a> { impl<'a> Deref for DeviceInfo<'a> {
type Target = [ffi::XIDeviceInfo]; type Target = [ffi::XIDeviceInfo];
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { slice::from_raw_parts(self.info, self.count) } unsafe { slice::from_raw_parts(self.info, self.count) }
} }
@ -821,6 +782,7 @@ pub(crate) struct Window(Arc<UnownedWindow>);
impl Deref for Window { impl Deref for Window {
type Target = UnownedWindow; type Target = UnownedWindow;
#[inline] #[inline]
fn deref(&self) -> &UnownedWindow { fn deref(&self) -> &UnownedWindow {
&self.0 &self.0
@ -833,10 +795,7 @@ impl Window {
attribs: WindowAttributes, attribs: WindowAttributes,
) -> Result<Self, RootOsError> { ) -> Result<Self, RootOsError> {
let window = Arc::new(UnownedWindow::new(event_loop, attribs)?); let window = Arc::new(UnownedWindow::new(event_loop, attribs)?);
event_loop event_loop.windows.borrow_mut().insert(window.id(), Arc::downgrade(&window));
.windows
.borrow_mut()
.insert(window.id(), Arc::downgrade(&window));
Ok(Window(window)) Ok(Window(window))
} }
} }
@ -846,10 +805,7 @@ impl Drop for Window {
let window = self.deref(); let window = self.deref();
let xconn = &window.xconn; let xconn = &window.xconn;
if let Ok(c) = xconn if let Ok(c) = xconn.xcb_connection().destroy_window(window.id().0 as xproto::Window) {
.xcb_connection()
.destroy_window(window.id().0 as xproto::Window)
{
c.ignore_error(); c.ignore_error();
} }
} }
@ -909,15 +865,11 @@ impl fmt::Display for X11Error {
), ),
X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {}", s), X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {}", s),
X11Error::NoSuchVisual(visualid) => { X11Error::NoSuchVisual(visualid) => {
write!( write!(f, "Could not find a matching X11 visual for ID `{:x}`", visualid)
f, },
"Could not find a matching X11 visual for ID `{:x}`",
visualid
)
}
X11Error::XsettingsParse(err) => { X11Error::XsettingsParse(err) => {
write!(f, "Failed to parse xsettings: {:?}", err) write!(f, "Failed to parse xsettings: {:?}", err)
} },
} }
} }
} }
@ -1053,27 +1005,21 @@ impl Device {
let ty = unsafe { (*class_ptr)._type }; let ty = unsafe { (*class_ptr)._type };
if ty == ffi::XIScrollClass { if ty == ffi::XIScrollClass {
let info = unsafe { &*(class_ptr as *const ffi::XIScrollClassInfo) }; let info = unsafe { &*(class_ptr as *const ffi::XIScrollClassInfo) };
scroll_axes.push(( scroll_axes.push((info.number, ScrollAxis {
info.number, increment: info.increment,
ScrollAxis { orientation: match info.scroll_type {
increment: info.increment, ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
orientation: match info.scroll_type { ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal, _ => unreachable!(),
ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
_ => unreachable!(),
},
position: 0.0,
}, },
)); position: 0.0,
}));
} }
} }
} }
let mut device = Device { let mut device =
_name: name.into_owned(), Device { _name: name.into_owned(), scroll_axes, attachment: info.attachment };
scroll_axes,
attachment: info.attachment,
};
device.reset_scroll_position(info); device.reset_scroll_position(info);
device device
} }
@ -1084,10 +1030,8 @@ impl Device {
let ty = unsafe { (*class_ptr)._type }; let ty = unsafe { (*class_ptr)._type };
if ty == ffi::XIValuatorClass { if ty == ffi::XIValuatorClass {
let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) }; let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) };
if let Some(&mut (_, ref mut axis)) = self if let Some(&mut (_, ref mut axis)) =
.scroll_axes self.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == info.number)
.iter_mut()
.find(|&&mut (axis, _)| axis == info.number)
{ {
axis.position = info.value; axis.position = info.value;
} }

View file

@ -1,15 +1,9 @@
use super::{util, X11Error, XConnection}; use super::{util, X11Error, XConnection};
use crate::{ use crate::dpi::{PhysicalPosition, PhysicalSize};
dpi::{PhysicalPosition, PhysicalSize}, use crate::platform_impl::VideoModeHandle as PlatformVideoModeHandle;
platform_impl::VideoModeHandle as PlatformVideoModeHandle, use x11rb::connection::RequestConnection;
}; use x11rb::protocol::randr::{self, ConnectionExt as _};
use x11rb::{ use x11rb::protocol::xproto;
connection::RequestConnection,
protocol::{
randr::{self, ConnectionExt as _},
xproto,
},
};
// Used for testing. This should always be committed as false. // Used for testing. This should always be committed as false.
const DISABLE_MONITOR_LIST_CACHING: bool = false; const DISABLE_MONITOR_LIST_CACHING: bool = false;
@ -240,18 +234,12 @@ impl XConnection {
// Pipeline all of the get-crtc requests. // Pipeline all of the get-crtc requests.
let mut crtc_cookies = Vec::with_capacity(resources.crtcs().len()); let mut crtc_cookies = Vec::with_capacity(resources.crtcs().len());
for &crtc in resources.crtcs() { for &crtc in resources.crtcs() {
crtc_cookies.push( crtc_cookies
self.xcb_connection() .push(self.xcb_connection().randr_get_crtc_info(crtc, x11rb::CURRENT_TIME)?);
.randr_get_crtc_info(crtc, x11rb::CURRENT_TIME)?,
);
} }
// Do this here so we do all of our requests in one shot. // Do this here so we do all of our requests in one shot.
let primary = self let primary = self.xcb_connection().randr_get_output_primary(root.root)?.reply()?.output;
.xcb_connection()
.randr_get_output_primary(root.root)?
.reply()?
.output;
let mut crtc_infos = Vec::with_capacity(crtc_cookies.len()); let mut crtc_infos = Vec::with_capacity(crtc_cookies.len());
for cookie in crtc_cookies { for cookie in crtc_cookies {
@ -293,7 +281,7 @@ impl XConnection {
*monitors_lock = Some(monitors.clone()); *monitors_lock = Some(monitors.clone());
} }
Ok(monitors) Ok(monitors)
} },
} }
} }
@ -347,9 +335,7 @@ impl ScreenResources {
(major_version, minor_version): (u32, u32), (major_version, minor_version): (u32, u32),
) -> Result<Self, X11Error> { ) -> Result<Self, X11Error> {
if (major_version == 1 && minor_version >= 3) || major_version > 1 { if (major_version == 1 && minor_version >= 3) || major_version > 1 {
let reply = conn let reply = conn.randr_get_screen_resources_current(root.root)?.reply()?;
.randr_get_screen_resources_current(root.root)?
.reply()?;
Ok(Self::from_get_screen_resources_current_reply(reply)) Ok(Self::from_get_screen_resources_current_reply(reply))
} else { } else {
let reply = conn.randr_get_screen_resources(root.root)?.reply()?; let reply = conn.randr_get_screen_resources(root.root)?.reply()?;
@ -358,18 +344,12 @@ impl ScreenResources {
} }
pub(crate) fn from_get_screen_resources_reply(reply: randr::GetScreenResourcesReply) -> Self { pub(crate) fn from_get_screen_resources_reply(reply: randr::GetScreenResourcesReply) -> Self {
Self { Self { modes: reply.modes, crtcs: reply.crtcs }
modes: reply.modes,
crtcs: reply.crtcs,
}
} }
pub(crate) fn from_get_screen_resources_current_reply( pub(crate) fn from_get_screen_resources_current_reply(
reply: randr::GetScreenResourcesCurrentReply, reply: randr::GetScreenResourcesCurrentReply,
) -> Self { ) -> Self {
Self { Self { modes: reply.modes, crtcs: reply.crtcs }
modes: reply.modes,
crtcs: reply.crtcs,
}
} }
} }

View file

@ -1,13 +1,12 @@
use std::{ use std::ffi::CString;
ffi::CString, use std::hash::{Hash, Hasher};
hash::{Hash, Hasher}, use std::sync::Arc;
iter, slice, use std::{iter, slice};
sync::Arc,
};
use x11rb::connection::Connection; use x11rb::connection::Connection;
use crate::{platform_impl::PlatformCustomCursorSource, window::CursorIcon}; use crate::platform_impl::PlatformCustomCursorSource;
use crate::window::CursorIcon;
use super::super::ActiveEventLoop; use super::super::ActiveEventLoop;
use super::*; use super::*;
@ -21,13 +20,11 @@ impl XConnection {
.entry(cursor) .entry(cursor)
.or_insert_with(|| self.get_cursor(cursor)); .or_insert_with(|| self.get_cursor(cursor));
self.update_cursor(window, cursor) self.update_cursor(window, cursor).expect("Failed to set cursor");
.expect("Failed to set cursor");
} }
pub(crate) fn set_custom_cursor(&self, window: xproto::Window, cursor: &CustomCursor) { pub(crate) fn set_custom_cursor(&self, window: xproto::Window, cursor: &CustomCursor) {
self.update_cursor(window, cursor.inner.cursor) self.update_cursor(window, cursor.inner.cursor).expect("Failed to set cursor");
.expect("Failed to set cursor");
} }
fn create_empty_cursor(&self) -> ffi::Cursor { fn create_empty_cursor(&self) -> ffi::Cursor {
@ -151,12 +148,7 @@ impl CustomCursor {
let cursor = let cursor =
(event_loop.xconn.xcursor.XcursorImageLoadCursor)(event_loop.xconn.display, ximage); (event_loop.xconn.xcursor.XcursorImageLoadCursor)(event_loop.xconn.display, ximage);
(event_loop.xconn.xcursor.XcursorImageDestroy)(ximage); (event_loop.xconn.xcursor.XcursorImageDestroy)(ximage);
Self { Self { inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }) }
inner: Arc::new(CustomCursorInner {
xconn: event_loop.xconn.clone(),
cursor,
}),
}
} }
} }
} }

View file

@ -15,12 +15,7 @@ impl AaRect {
pub fn new((x, y): (i32, i32), (width, height): (u32, u32)) -> Self { pub fn new((x, y): (i32, i32), (width, height): (u32, u32)) -> Self {
let (x, y) = (x as i64, y as i64); let (x, y) = (x as i64, y as i64);
let (width, height) = (width as i64, height as i64); let (width, height) = (width as i64, height as i64);
AaRect { AaRect { x, y, width, height }
x,
y,
width,
height,
}
} }
pub fn contains_point(&self, x: i64, y: i64) -> bool { pub fn contains_point(&self, x: i64, y: i64) -> bool {
@ -50,12 +45,7 @@ pub struct FrameExtents {
impl FrameExtents { impl FrameExtents {
pub fn new(left: u32, right: u32, top: u32, bottom: u32) -> Self { pub fn new(left: u32, right: u32, top: u32, bottom: u32) -> Self {
FrameExtents { FrameExtents { left, right, top, bottom }
left,
right,
top,
bottom,
}
} }
pub fn from_border(border: u32) -> Self { pub fn from_border(border: u32) -> Self {
@ -80,10 +70,7 @@ impl FrameExtentsHeuristic {
pub fn inner_pos_to_outer(&self, x: i32, y: i32) -> (i32, i32) { pub fn inner_pos_to_outer(&self, x: i32, y: i32) -> (i32, i32) {
use self::FrameExtentsHeuristicPath::*; use self::FrameExtentsHeuristicPath::*;
if self.heuristic_path != UnsupportedBordered { if self.heuristic_path != UnsupportedBordered {
( (x - self.frame_extents.left as i32, y - self.frame_extents.top as i32)
x - self.frame_extents.left as i32,
y - self.frame_extents.top as i32,
)
} else { } else {
(x, y) (x, y)
} }
@ -92,14 +79,10 @@ impl FrameExtentsHeuristic {
pub fn inner_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) { pub fn inner_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) {
( (
width.saturating_add( width.saturating_add(
self.frame_extents self.frame_extents.left.saturating_add(self.frame_extents.right) as _
.left
.saturating_add(self.frame_extents.right) as _,
), ),
height.saturating_add( height.saturating_add(
self.frame_extents self.frame_extents.top.saturating_add(self.frame_extents.bottom) as _
.top
.saturating_add(self.frame_extents.bottom) as _,
), ),
) )
} }
@ -112,10 +95,7 @@ impl XConnection {
window: xproto::Window, window: xproto::Window,
root: xproto::Window, root: xproto::Window,
) -> Result<xproto::TranslateCoordinatesReply, X11Error> { ) -> Result<xproto::TranslateCoordinatesReply, X11Error> {
self.xcb_connection() self.xcb_connection().translate_coordinates(window, root, 0, 0)?.reply().map_err(Into::into)
.translate_coordinates(window, root, 0, 0)?
.reply()
.map_err(Into::into)
} }
// This is adequate for inner_size // This is adequate for inner_size
@ -123,10 +103,7 @@ impl XConnection {
&self, &self,
window: xproto::Window, window: xproto::Window,
) -> Result<xproto::GetGeometryReply, X11Error> { ) -> Result<xproto::GetGeometryReply, X11Error> {
self.xcb_connection() self.xcb_connection().get_geometry(window)?.reply().map_err(Into::into)
.get_geometry(window)?
.reply()
.map_err(Into::into)
} }
fn get_frame_extents(&self, window: xproto::Window) -> Option<FrameExtents> { fn get_frame_extents(&self, window: xproto::Window) -> Option<FrameExtents> {
@ -141,11 +118,7 @@ impl XConnection {
// support this. As this is part of EWMH (Extended Window Manager Hints), it's likely to // support this. As this is part of EWMH (Extended Window Manager Hints), it's likely to
// be unsupported by many smaller WMs. // be unsupported by many smaller WMs.
let extents: Option<Vec<u32>> = self let extents: Option<Vec<u32>> = self
.get_property( .get_property(window, extents_atom, xproto::Atom::from(xproto::AtomEnum::CARDINAL))
window,
extents_atom,
xproto::Atom::from(xproto::AtomEnum::CARDINAL),
)
.ok(); .ok();
extents.and_then(|extents| { extents.and_then(|extents| {
@ -171,11 +144,7 @@ impl XConnection {
} }
let client_list: Option<Vec<xproto::Window>> = self let client_list: Option<Vec<xproto::Window>> = self
.get_property( .get_property(root, client_list_atom, xproto::Atom::from(xproto::AtomEnum::WINDOW))
root,
client_list_atom,
xproto::Atom::from(xproto::AtomEnum::WINDOW),
)
.ok(); .ok();
client_list.map(|client_list| client_list.contains(&(window as xproto::Window))) client_list.map(|client_list| client_list.contains(&(window as xproto::Window)))
@ -221,14 +190,9 @@ impl XConnection {
}; };
let (width, height, border) = { let (width, height, border) = {
let inner_geometry = self let inner_geometry =
.get_geometry(window) self.get_geometry(window).expect("Failed to get inner window geometry");
.expect("Failed to get inner window geometry"); (inner_geometry.width, inner_geometry.height, inner_geometry.border_width)
(
inner_geometry.width,
inner_geometry.height,
inner_geometry.border_width,
)
}; };
// The first condition is only false for un-nested windows, but isn't always false for // The first condition is only false for un-nested windows, but isn't always false for
@ -253,39 +217,29 @@ impl XConnection {
// known discrepancies: // known discrepancies:
// * Mutter/Muffin/Budgie gives decorated windows a margin of 9px (only 7px on top) in // * Mutter/Muffin/Budgie gives decorated windows a margin of 9px (only 7px on top) in
// addition to a 1px semi-transparent border. The margin can be easily observed by // addition to a 1px semi-transparent border. The margin can be easily observed by
// using a screenshot tool to get a screenshot of a selected window, and is // using a screenshot tool to get a screenshot of a selected window, and is presumably
// presumably used for drawing drop shadows. Getting window geometry information // used for drawing drop shadows. Getting window geometry information via
// via hierarchy-climbing results in this margin being included in both the // hierarchy-climbing results in this margin being included in both the position and
// position and outer size, so a window positioned at (0, 0) would be reported as // outer size, so a window positioned at (0, 0) would be reported as having a position
// having a position (-10, -8). // (-10, -8).
// * Compiz has a drop shadow margin just like Mutter/Muffin/Budgie, though it's 10px // * Compiz has a drop shadow margin just like Mutter/Muffin/Budgie, though it's 10px on
// on all sides, and there's no additional border. // all sides, and there's no additional border.
// * Enlightenment otherwise gets a y position equivalent to inner_y_rel_root. // * Enlightenment otherwise gets a y position equivalent to inner_y_rel_root. Without
// Without decorations, there's no difference. This is presumably related to // decorations, there's no difference. This is presumably related to Enlightenment's
// Enlightenment's fairly unique concept of window position; it interprets // fairly unique concept of window position; it interprets positions given to
// positions given to XMoveWindow as a client area position rather than a position // XMoveWindow as a client area position rather than a position of the overall window.
// of the overall window.
FrameExtentsHeuristic { FrameExtentsHeuristic { frame_extents, heuristic_path: Supported }
frame_extents,
heuristic_path: Supported,
}
} else if nested { } else if nested {
// If the position value we have is for a nested window used as the client area, we'll // If the position value we have is for a nested window used as the client area, we'll
// just climb up the hierarchy and get the geometry of the outermost window we're // just climb up the hierarchy and get the geometry of the outermost window we're
// nested in. // nested in.
let outer_window = self let outer_window =
.climb_hierarchy(window, root) self.climb_hierarchy(window, root).expect("Failed to climb window hierarchy");
.expect("Failed to climb window hierarchy");
let (outer_y, outer_width, outer_height) = { let (outer_y, outer_width, outer_height) = {
let outer_geometry = self let outer_geometry =
.get_geometry(outer_window) self.get_geometry(outer_window).expect("Failed to get outer window geometry");
.expect("Failed to get outer window geometry"); (outer_geometry.y, outer_geometry.width, outer_geometry.height)
(
outer_geometry.y,
outer_geometry.width,
outer_geometry.height,
)
}; };
// Since we have the geometry of the outermost window and the geometry of the client // Since we have the geometry of the outermost window and the geometry of the client
@ -300,18 +254,12 @@ impl XConnection {
let bottom = diff_y.saturating_sub(offset_y); let bottom = diff_y.saturating_sub(offset_y);
let frame_extents = FrameExtents::new(left, right, top, bottom); let frame_extents = FrameExtents::new(left, right, top, bottom);
FrameExtentsHeuristic { FrameExtentsHeuristic { frame_extents, heuristic_path: UnsupportedNested }
frame_extents,
heuristic_path: UnsupportedNested,
}
} else { } else {
// This is the case for xmonad and dwm, AKA the only WMs tested that supplied a // This is the case for xmonad and dwm, AKA the only WMs tested that supplied a
// border value. This is convenient, since we can use it to get an accurate frame. // border value. This is convenient, since we can use it to get an accurate frame.
let frame_extents = FrameExtents::from_border(border.into()); let frame_extents = FrameExtents::from_border(border.into());
FrameExtentsHeuristic { FrameExtentsHeuristic { frame_extents, heuristic_path: UnsupportedBordered }
frame_extents,
heuristic_path: UnsupportedBordered,
}
} }
} }
} }

View file

@ -76,13 +76,7 @@ mod mwm {
impl MotifHints { impl MotifHints {
pub fn new() -> MotifHints { pub fn new() -> MotifHints {
MotifHints { MotifHints {
hints: MwmHints { hints: MwmHints { flags: 0, functions: 0, decorations: 0, input_mode: 0, status: 0 },
flags: 0,
functions: 0,
decorations: 0,
input_mode: 0,
status: 0,
},
} }
} }

View file

@ -1,8 +1,6 @@
use std::{slice, str}; use std::{slice, str};
use x11rb::protocol::{ use x11rb::protocol::xinput::{self, ConnectionExt as _};
xinput::{self, ConnectionExt as _}, use x11rb::protocol::xkb;
xkb,
};
use super::*; use super::*;
@ -22,13 +20,10 @@ impl XConnection {
mask: xinput::XIEventMask, mask: xinput::XIEventMask,
) -> Result<VoidCookie<'_>, X11Error> { ) -> Result<VoidCookie<'_>, X11Error> {
self.xcb_connection() self.xcb_connection()
.xinput_xi_select_events( .xinput_xi_select_events(window, &[xinput::EventMask {
window, deviceid: device_id,
&[xinput::EventMask { mask: vec![mask],
deviceid: device_id, }])
mask: vec![mask],
}],
)
.map_err(Into::into) .map_err(Into::into)
} }

View file

@ -1,4 +1,5 @@
use std::{iter::Enumerate, slice::Iter}; use std::iter::Enumerate;
use std::slice::Iter;
use super::*; use super::*;
@ -14,17 +15,13 @@ pub struct KeymapIter<'a> {
impl Keymap { impl Keymap {
pub fn iter(&self) -> KeymapIter<'_> { pub fn iter(&self) -> KeymapIter<'_> {
KeymapIter { KeymapIter { iter: self.keys.iter().enumerate(), index: 0, item: None }
iter: self.keys.iter().enumerate(),
index: 0,
item: None,
}
} }
} }
impl<'a> IntoIterator for &'a Keymap { impl<'a> IntoIterator for &'a Keymap {
type Item = ffi::KeyCode;
type IntoIter = KeymapIter<'a>; type IntoIter = KeymapIter<'a>;
type Item = ffi::KeyCode;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
self.iter() self.iter()

View file

@ -1,11 +1,9 @@
// Welcome to the util module, where we try to keep you from shooting yourself in the foot. // Welcome to the util module, where we try to keep you from shooting yourself in the foot.
// *results may vary // *results may vary
use std::{ use std::mem::{self, MaybeUninit};
mem::{self, MaybeUninit}, use std::ops::BitAnd;
ops::BitAnd, use std::os::raw::*;
os::raw::*,
};
mod client_msg; mod client_msg;
pub mod cookie; pub mod cookie;
@ -22,12 +20,17 @@ mod window_property;
mod wm; mod wm;
mod xmodmap; mod xmodmap;
pub use self::{ pub use self::cursor::*;
cursor::*, geometry::*, hint::*, input::*, mouse::*, window_property::*, wm::*, pub use self::geometry::*;
xmodmap::ModifierKeymap, pub use self::hint::*;
}; pub use self::input::*;
pub use self::mouse::*;
pub use self::window_property::*;
pub use self::wm::*;
pub use self::xmodmap::ModifierKeymap;
use super::{atoms::*, ffi, VoidCookie, X11Error, XConnection, XError}; use super::atoms::*;
use super::{ffi, VoidCookie, X11Error, XConnection, XError};
use x11rb::protocol::xproto::{self, ConnectionExt as _}; use x11rb::protocol::xproto::{self, ConnectionExt as _};
pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool { pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool {
@ -54,12 +57,13 @@ impl XConnection {
// 1. `XPending`, `XNextEvent`, and `XWindowEvent` flush "as needed" // 1. `XPending`, `XNextEvent`, and `XWindowEvent` flush "as needed"
// 2. `XFlush` explicitly flushes // 2. `XFlush` explicitly flushes
// 3. `XSync` flushes and blocks until all requests are responded to // 3. `XSync` flushes and blocks until all requests are responded to
// 4. Calls that have a return dependent on a response (i.e. `XGetWindowProperty`) sync internally. // 4. Calls that have a return dependent on a response (i.e. `XGetWindowProperty`) sync
// When in doubt, check the X11 source; if a function calls `_XReply`, it flushes and waits. // internally. When in doubt, check the X11 source; if a function calls `_XReply`, it flushes
// and waits.
// All util functions that abstract an async function will return a `Flusher`. // All util functions that abstract an async function will return a `Flusher`.
pub fn flush_requests(&self) -> Result<(), XError> { pub fn flush_requests(&self) -> Result<(), XError> {
unsafe { (self.xlib.XFlush)(self.display) }; unsafe { (self.xlib.XFlush)(self.display) };
//println!("XFlush"); // println!("XFlush");
// This isn't necessarily a useful time to check for errors (since our request hasn't // This isn't necessarily a useful time to check for errors (since our request hasn't
// necessarily been processed yet) // necessarily been processed yet)
self.check_errors() self.check_errors()
@ -67,7 +71,7 @@ impl XConnection {
pub fn sync_with_server(&self) -> Result<(), XError> { pub fn sync_with_server(&self) -> Result<(), XError> {
unsafe { (self.xlib.XSync)(self.display, ffi::False) }; unsafe { (self.xlib.XSync)(self.display, ffi::False) };
//println!("XSync"); // println!("XSync");
self.check_errors() self.check_errors()
} }
} }

View file

@ -8,10 +8,7 @@ pub struct Delta<T> {
impl<T: Default> Default for Delta<T> { impl<T: Default> Default for Delta<T> {
fn default() -> Self { fn default() -> Self {
Self { Self { x: Default::default(), y: Default::default() }
x: Default::default(),
y: Default::default(),
}
} }
} }

View file

@ -1,8 +1,9 @@
use std::{env, str, str::FromStr}; use std::str::FromStr;
use std::{env, str};
use super::*; use super::*;
use crate::platform_impl::platform::x11::monitor; use crate::dpi::validate_scale_factor;
use crate::{dpi::validate_scale_factor, platform_impl::platform::x11::VideoModeHandle}; use crate::platform_impl::platform::x11::{monitor, VideoModeHandle};
use tracing::warn; use tracing::warn;
use x11rb::protocol::randr::{self, ConnectionExt as _}; use x11rb::protocol::randr::{self, ConnectionExt as _};
@ -42,16 +43,14 @@ impl XConnection {
if let Some(xsettings_screen) = self.xsettings_screen() { if let Some(xsettings_screen) = self.xsettings_screen() {
match self.xsettings_dpi(xsettings_screen) { match self.xsettings_dpi(xsettings_screen) {
Ok(Some(dpi)) => return Some(dpi), Ok(Some(dpi)) => return Some(dpi),
Ok(None) => {} Ok(None) => {},
Err(err) => { Err(err) => {
tracing::warn!("failed to fetch XSettings: {err}"); tracing::warn!("failed to fetch XSettings: {err}");
} },
} }
} }
self.database() self.database().get_string("Xft.dpi", "").and_then(|s| f64::from_str(s).ok())
.get_string("Xft.dpi", "")
.and_then(|s| f64::from_str(s).ok())
} }
pub fn get_output_info( pub fn get_output_info(
@ -69,7 +68,7 @@ impl XConnection {
Err(err) => { Err(err) => {
warn!("Failed to get output info: {:?}", err); warn!("Failed to get output info: {:?}", err);
return None; return None;
} },
}; };
let bit_depth = self.default_root().root_depth; let bit_depth = self.default_root().root_depth;
@ -100,14 +99,15 @@ impl XConnection {
Err(err) => { Err(err) => {
warn!("Failed to get output name: {:?}", err); warn!("Failed to get output name: {:?}", err);
return None; return None;
} },
}; };
// Override DPI if `WINIT_X11_SCALE_FACTOR` variable is set // Override DPI if `WINIT_X11_SCALE_FACTOR` variable is set
let deprecated_dpi_override = env::var("WINIT_HIDPI_FACTOR").ok(); let deprecated_dpi_override = env::var("WINIT_HIDPI_FACTOR").ok();
if deprecated_dpi_override.is_some() { if deprecated_dpi_override.is_some() {
warn!( warn!(
"The WINIT_HIDPI_FACTOR environment variable is deprecated; use WINIT_X11_SCALE_FACTOR" "The WINIT_HIDPI_FACTOR environment variable is deprecated; use \
) WINIT_X11_SCALE_FACTOR"
)
} }
let dpi_env = env::var("WINIT_X11_SCALE_FACTOR").ok().map_or_else( let dpi_env = env::var("WINIT_X11_SCALE_FACTOR").ok().map_or_else(
|| EnvVarDPI::NotSet, || EnvVarDPI::NotSet,
@ -120,7 +120,8 @@ impl XConnection {
EnvVarDPI::NotSet EnvVarDPI::NotSet
} else { } else {
panic!( panic!(
"`WINIT_X11_SCALE_FACTOR` invalid; DPI factors must be either normal floats greater than 0, or `randr`. Got `{var}`" "`WINIT_X11_SCALE_FACTOR` invalid; DPI factors must be either normal \
floats greater than 0, or `randr`. Got `{var}`"
); );
} }
}, },
@ -134,11 +135,12 @@ impl XConnection {
EnvVarDPI::Scale(dpi_override) => { EnvVarDPI::Scale(dpi_override) => {
if !validate_scale_factor(dpi_override) { if !validate_scale_factor(dpi_override) {
panic!( panic!(
"`WINIT_X11_SCALE_FACTOR` invalid; DPI factors must be either normal floats greater than 0, or `randr`. Got `{dpi_override}`", "`WINIT_X11_SCALE_FACTOR` invalid; DPI factors must be either normal \
floats greater than 0, or `randr`. Got `{dpi_override}`",
); );
} }
dpi_override dpi_override
} },
EnvVarDPI::NotSet => { EnvVarDPI::NotSet => {
if let Some(dpi) = self.get_xft_dpi() { if let Some(dpi) = self.get_xft_dpi() {
dpi / 96. dpi / 96.
@ -148,7 +150,7 @@ impl XConnection {
(output_info.mm_width as _, output_info.mm_height as _), (output_info.mm_width as _, output_info.mm_height as _),
) )
} }
} },
}; };
Some((name, scale_factor, modes)) Some((name, scale_factor, modes))
@ -159,10 +161,8 @@ impl XConnection {
crtc_id: randr::Crtc, crtc_id: randr::Crtc,
mode_id: randr::Mode, mode_id: randr::Mode,
) -> Result<(), X11Error> { ) -> Result<(), X11Error> {
let crtc = self let crtc =
.xcb_connection() self.xcb_connection().randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?.reply()?;
.randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?
.reply()?;
self.xcb_connection() self.xcb_connection()
.randr_set_crtc_config( .randr_set_crtc_config(
@ -181,10 +181,6 @@ impl XConnection {
} }
pub fn get_crtc_mode(&self, crtc_id: randr::Crtc) -> Result<randr::Mode, X11Error> { pub fn get_crtc_mode(&self, crtc_id: randr::Crtc) -> Result<randr::Mode, X11Error> {
Ok(self Ok(self.xcb_connection().randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?.reply()?.mode)
.xcb_connection()
.randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?
.reply()?
.mode)
} }
} }

View file

@ -87,10 +87,7 @@ impl XConnection {
property, property,
property_type, property_type,
(mem::size_of::<T>() * 8) as u8, (mem::size_of::<T>() * 8) as u8,
new_value new_value.len().try_into().expect("too many items for property"),
.len()
.try_into()
.expect("too many items for property"),
bytemuck::cast_slice::<T, u8>(new_value), bytemuck::cast_slice::<T, u8>(new_value),
) )
.map_err(Into::into) .map_err(Into::into)

View file

@ -38,12 +38,8 @@ impl XConnection {
fn get_supported_hints(&self, root: xproto::Window) -> Vec<xproto::Atom> { fn get_supported_hints(&self, root: xproto::Window) -> Vec<xproto::Atom> {
let atoms = self.atoms(); let atoms = self.atoms();
let supported_atom = atoms[_NET_SUPPORTED]; let supported_atom = atoms[_NET_SUPPORTED];
self.get_property( self.get_property(root, supported_atom, xproto::Atom::from(xproto::AtomEnum::ATOM))
root, .unwrap_or_else(|_| Vec::with_capacity(0))
supported_atom,
xproto::Atom::from(xproto::AtomEnum::ATOM),
)
.unwrap_or_else(|_| Vec::with_capacity(0))
} }
#[allow(clippy::useless_conversion)] #[allow(clippy::useless_conversion)]
@ -57,22 +53,22 @@ impl XConnection {
// inavailability of time machines, we'll just try to get _NET_SUPPORTING_WM_CHECK // inavailability of time machines, we'll just try to get _NET_SUPPORTING_WM_CHECK
// regardless of whether or not the WM claims to support it. // regardless of whether or not the WM claims to support it.
// //
// Blackbox 0.70 also incorrectly reports not supporting this, though that appears to be fixed // Blackbox 0.70 also incorrectly reports not supporting this, though that appears to be
// in 0.72. // fixed in 0.72.
/*if !supported_hints.contains(&check_atom) { // if !supported_hints.contains(&check_atom) {
return None; // return None;
}*/ // }
// IceWM (1.3.x and earlier) doesn't report supporting _NET_WM_NAME, but will nonetheless // IceWM (1.3.x and earlier) doesn't report supporting _NET_WM_NAME, but will nonetheless
// provide us with a value for it. Note that the unofficial 1.4 fork of IceWM works fine. // provide us with a value for it. Note that the unofficial 1.4 fork of IceWM works fine.
/*if !supported_hints.contains(&wm_name_atom) { // if !supported_hints.contains(&wm_name_atom) {
return None; // return None;
}*/ // }
// Of the WMs tested, only xmonad and dwm fail to provide a WM name. // Of the WMs tested, only xmonad and dwm fail to provide a WM name.
// Querying this property on the root window will give us the ID of a child window created by // Querying this property on the root window will give us the ID of a child window created
// the WM. // by the WM.
let root_window_wm_check = { let root_window_wm_check = {
let result = self.get_property::<xproto::Window>( let result = self.get_property::<xproto::Window>(
root, root,

View file

@ -1,50 +1,40 @@
use std::{ use std::ffi::CString;
cmp, env, use std::mem::replace;
ffi::CString, use std::os::raw::*;
mem::replace, use std::path::Path;
os::raw::*, use std::sync::{Arc, Mutex, MutexGuard};
path::Path, use std::{cmp, env};
sync::{Arc, Mutex, MutexGuard},
};
use tracing::{debug, info, warn}; use tracing::{debug, info, warn};
use x11rb::{ use x11rb::connection::Connection;
connection::Connection, use x11rb::properties::{WmHints, WmSizeHints, WmSizeHintsSpecification};
properties::{WmHints, WmSizeHints, WmSizeHintsSpecification}, use x11rb::protocol::shape::SK;
protocol::{ use x11rb::protocol::xfixes::{ConnectionExt, RegionWrapper};
randr, use x11rb::protocol::xproto::{self, ConnectionExt as _, Rectangle};
shape::SK, use x11rb::protocol::{randr, xinput};
xfixes::{ConnectionExt, RegionWrapper},
xinput, use crate::cursor::{Cursor, CustomCursor as RootCustomCursor};
xproto::{self, ConnectionExt as _, Rectangle}, use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
}, use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
}; use crate::event::{Event, InnerSizeWriter, WindowEvent};
use crate::event_loop::AsyncRequestSerial;
use crate::{ use crate::platform::x11::WindowType;
cursor::{Cursor, CustomCursor as RootCustomCursor}, use crate::platform_impl::x11::atoms::*;
dpi::{PhysicalPosition, PhysicalSize, Position, Size}, use crate::platform_impl::x11::{
error::{ExternalError, NotSupportedError, OsError as RootOsError}, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error,
event::{Event, InnerSizeWriter, WindowEvent}, };
event_loop::AsyncRequestSerial, use crate::platform_impl::{
platform::x11::WindowType, Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor,
platform_impl::{ PlatformIcon, VideoModeHandle as PlatformVideoModeHandle,
x11::{ };
atoms::*, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, use crate::window::{
X11Error, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
}, WindowButtons, WindowLevel,
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor,
PlatformIcon, VideoModeHandle as PlatformVideoModeHandle,
},
window::{
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
WindowButtons, WindowLevel,
},
}; };
use super::util::{self, SelectedCursor};
use super::{ use super::{
ffi, ffi, ActiveEventLoop, CookieResultExt, ImeRequest, ImeSender, VoidCookie, WindowId, XConnection,
util::{self, SelectedCursor},
ActiveEventLoop, CookieResultExt, ImeRequest, ImeSender, VoidCookie, WindowId, XConnection,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -86,11 +76,8 @@ pub enum Visibility {
impl SharedState { impl SharedState {
fn new(last_monitor: X11MonitorHandle, window_attributes: &WindowAttributes) -> Mutex<Self> { fn new(last_monitor: X11MonitorHandle, window_attributes: &WindowAttributes) -> Mutex<Self> {
let visibility = if window_attributes.visible { let visibility =
Visibility::YesWait if window_attributes.visible { Visibility::YesWait } else { Visibility::No };
} else {
Visibility::No
};
Mutex::new(SharedState { Mutex::new(SharedState {
last_monitor, last_monitor,
@ -191,16 +178,13 @@ impl UnownedWindow {
info!("Guessed window scale factor: {}", scale_factor); info!("Guessed window scale factor: {}", scale_factor);
let max_inner_size: Option<(u32, u32)> = window_attrs let max_inner_size: Option<(u32, u32)> =
.max_inner_size window_attrs.max_inner_size.map(|size| size.to_physical::<u32>(scale_factor).into());
.map(|size| size.to_physical::<u32>(scale_factor).into()); let min_inner_size: Option<(u32, u32)> =
let min_inner_size: Option<(u32, u32)> = window_attrs window_attrs.min_inner_size.map(|size| size.to_physical::<u32>(scale_factor).into());
.min_inner_size
.map(|size| size.to_physical::<u32>(scale_factor).into());
let position = window_attrs let position =
.position window_attrs.position.map(|position| position.to_physical::<i32>(scale_factor));
.map(|position| position.to_physical::<i32>(scale_factor));
let dimensions = { let dimensions = {
// x11 only applies constraints when the window is actively resized // x11 only applies constraints when the window is actively resized
@ -219,10 +203,7 @@ impl UnownedWindow {
dimensions.0 = cmp::max(dimensions.0, min.0); dimensions.0 = cmp::max(dimensions.0, min.0);
dimensions.1 = cmp::max(dimensions.1, min.1); dimensions.1 = cmp::max(dimensions.1, min.1);
} }
debug!( debug!("Calculated physical dimensions: {}x{}", dimensions.0, dimensions.1);
"Calculated physical dimensions: {}x{}",
dimensions.0, dimensions.1
);
dimensions dimensions
}; };
@ -238,41 +219,37 @@ impl UnownedWindow {
.roots .roots
.iter() .iter()
.flat_map(|root| &root.allowed_depths) .flat_map(|root| &root.allowed_depths)
.flat_map(|depth| { .flat_map(|depth| depth.visuals.iter().map(move |visual| (visual, depth.depth)));
depth
.visuals
.iter()
.map(move |visual| (visual, depth.depth))
});
// creating // creating
let (visualtype, depth, require_colormap) = match window_attrs let (visualtype, depth, require_colormap) =
.platform_specific match window_attrs.platform_specific.x11.visual_id {
.x11 Some(vi) => {
.visual_id // Find this specific visual.
{ let (visualtype, depth) =
Some(vi) => { all_visuals.find(|(visual, _)| visual.visual_id == vi).ok_or_else(
// Find this specific visual. || os_error!(OsError::XError(X11Error::NoSuchVisual(vi).into())),
let (visualtype, depth) = all_visuals )?;
.find(|(visual, _)| visual.visual_id == vi)
.ok_or_else(|| os_error!(OsError::XError(X11Error::NoSuchVisual(vi).into())))?;
(Some(visualtype), depth, true) (Some(visualtype), depth, true)
} },
None if window_attrs.transparent => { None if window_attrs.transparent => {
// Find a suitable visual, true color with 32 bits of depth. // Find a suitable visual, true color with 32 bits of depth.
all_visuals all_visuals
.find_map(|(visual, depth)| { .find_map(|(visual, depth)| {
(depth == 32 && visual.class == xproto::VisualClass::TRUE_COLOR) (depth == 32 && visual.class == xproto::VisualClass::TRUE_COLOR)
.then_some((Some(visual), depth, true)) .then_some((Some(visual), depth, true))
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
debug!("Could not set transparency, because XMatchVisualInfo returned zero for the required parameters"); debug!(
(None as _, x11rb::COPY_FROM_PARENT as _, false) "Could not set transparency, because XMatchVisualInfo returned \
}) zero for the required parameters"
} );
_ => (None, x11rb::COPY_FROM_PARENT as _, false), (None as _, x11rb::COPY_FROM_PARENT as _, false)
}; })
},
_ => (None, x11rb::COPY_FROM_PARENT as _, false),
};
let mut visual = visualtype.map_or(x11rb::COPY_FROM_PARENT, |v| v.visual_id); let mut visual = visualtype.map_or(x11rb::COPY_FROM_PARENT, |v| v.visual_id);
let window_attributes = { let window_attributes = {
@ -320,11 +297,7 @@ impl UnownedWindow {
}; };
// Figure out the window's parent. // Figure out the window's parent.
let parent = window_attrs let parent = window_attrs.platform_specific.x11.embed_window.unwrap_or(root);
.platform_specific
.x11
.embed_window
.unwrap_or(root);
// finally creating the window // finally creating the window
let xwindow = { let xwindow = {
@ -419,9 +392,7 @@ impl UnownedWindow {
.map(|bin_name| bin_name.to_owned()) .map(|bin_name| bin_name.to_owned())
.unwrap_or_else(|| window_attrs.title.clone()); .unwrap_or_else(|| window_attrs.title.clone());
// This environment variable is extraordinarily unlikely to actually be used... // This environment variable is extraordinarily unlikely to actually be used...
let instance = env::var("RESOURCE_NAME") let instance = env::var("RESOURCE_NAME").ok().unwrap_or_else(|| class.clone());
.ok()
.unwrap_or_else(|| class.clone());
(instance, class) (instance, class)
}; };
@ -444,12 +415,10 @@ impl UnownedWindow {
.ignore_error(); .ignore_error();
// Set size hints. // Set size hints.
let mut min_inner_size = window_attrs let mut min_inner_size =
.min_inner_size window_attrs.min_inner_size.map(|size| size.to_physical::<u32>(scale_factor));
.map(|size| size.to_physical::<u32>(scale_factor)); let mut max_inner_size =
let mut max_inner_size = window_attrs window_attrs.max_inner_size.map(|size| size.to_physical::<u32>(scale_factor));
.max_inner_size
.map(|size| size.to_physical::<u32>(scale_factor));
if !window_attrs.resizable { if !window_attrs.resizable {
if util::wm_name_is_one_of(&["Xfwm4"]) { if util::wm_name_is_one_of(&["Xfwm4"]) {
@ -534,9 +503,7 @@ impl UnownedWindow {
&mut supported_ptr, &mut supported_ptr,
); );
if supported_ptr == ffi::False { if supported_ptr == ffi::False {
return Err(os_error!(OsError::Misc( return Err(os_error!(OsError::Misc("`XkbSetDetectableAutoRepeat` failed")));
"`XkbSetDetectableAutoRepeat` failed"
)));
} }
} }
@ -556,9 +523,7 @@ impl UnownedWindow {
// Try to create input context for the window. // Try to create input context for the window.
if let Some(ime) = event_loop.ime.as_ref() { if let Some(ime) = event_loop.ime.as_ref() {
let result = ime let result = ime.borrow_mut().create_context(window.xwindow as ffi::Window, false);
.borrow_mut()
.create_context(window.xwindow as ffi::Window, false);
leap!(result); leap!(result);
} }
@ -647,10 +612,7 @@ impl UnownedWindow {
fn set_window_types(&self, window_types: Vec<WindowType>) -> Result<VoidCookie<'_>, X11Error> { fn set_window_types(&self, window_types: Vec<WindowType>) -> Result<VoidCookie<'_>, X11Error> {
let atoms = self.xconn.atoms(); let atoms = self.xconn.atoms();
let hint_atom = atoms[_NET_WM_WINDOW_TYPE]; let hint_atom = atoms[_NET_WM_WINDOW_TYPE];
let atoms: Vec<_> = window_types let atoms: Vec<_> = window_types.iter().map(|t| t.as_atom(&self.xconn)).collect();
.iter()
.map(|t| t.as_atom(&self.xconn))
.collect();
self.xconn.change_property( self.xconn.change_property(
self.xwindow, self.xwindow,
@ -682,13 +644,9 @@ impl UnownedWindow {
#[inline] #[inline]
pub fn set_theme(&self, theme: Option<Theme>) { pub fn set_theme(&self, theme: Option<Theme>) {
self.set_theme_inner(theme) self.set_theme_inner(theme).expect("Failed to change window theme").ignore_error();
.expect("Failed to change window theme")
.ignore_error();
self.xconn self.xconn.flush_requests().expect("Failed to change window theme");
.flush_requests()
.expect("Failed to change window theme");
} }
fn set_netwm( fn set_netwm(
@ -703,13 +661,7 @@ impl UnownedWindow {
self.root, self.root,
state_atom, state_atom,
Some(xproto::EventMask::SUBSTRUCTURE_REDIRECT | xproto::EventMask::SUBSTRUCTURE_NOTIFY), Some(xproto::EventMask::SUBSTRUCTURE_REDIRECT | xproto::EventMask::SUBSTRUCTURE_NOTIFY),
[ [operation as u32, properties.0, properties.1, properties.2, properties.3],
operation as u32,
properties.0,
properties.1,
properties.2,
properties.3,
],
) )
} }
@ -723,11 +675,7 @@ impl UnownedWindow {
// locking up the user's display. // locking up the user's display.
self.xconn self.xconn
.xcb_connection() .xcb_connection()
.set_input_focus( .set_input_focus(xproto::InputFocus::PARENT, self.xwindow, x11rb::CURRENT_TIME)?
xproto::InputFocus::PARENT,
self.xwindow,
x11rb::CURRENT_TIME,
)?
.ignore_error(); .ignore_error();
} }
@ -745,7 +693,7 @@ impl UnownedWindow {
Visibility::No | Visibility::YesWait => { Visibility::No | Visibility::YesWait => {
shared_state_lock.desired_fullscreen = Some(fullscreen); shared_state_lock.desired_fullscreen = Some(fullscreen);
return Ok(None); return Ok(None);
} },
Visibility::Yes => (), Visibility::Yes => (),
} }
@ -768,11 +716,9 @@ impl UnownedWindow {
let monitor = video_mode.monitor.as_ref().unwrap(); let monitor = video_mode.monitor.as_ref().unwrap();
shared_state_lock.desktop_video_mode = Some(( shared_state_lock.desktop_video_mode = Some((
monitor.id, monitor.id,
self.xconn self.xconn.get_crtc_mode(monitor.id).expect("Failed to get desktop video mode"),
.get_crtc_mode(monitor.id)
.expect("Failed to get desktop video mode"),
)); ));
} },
// Restore desktop video mode upon exiting exclusive fullscreen // Restore desktop video mode upon exiting exclusive fullscreen
(&Some(Fullscreen::Exclusive(_)), &None) (&Some(Fullscreen::Exclusive(_)), &None)
| (&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Borderless(_))) => { | (&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Borderless(_))) => {
@ -780,7 +726,7 @@ impl UnownedWindow {
self.xconn self.xconn
.set_crtc_config(monitor_id, mode_id) .set_crtc_config(monitor_id, mode_id)
.expect("failed to restore desktop video mode"); .expect("failed to restore desktop video mode");
} },
_ => (), _ => (),
} }
@ -796,18 +742,18 @@ impl UnownedWindow {
.expect_then_ignore_error("Failed to restore window position"); .expect_then_ignore_error("Failed to restore window position");
} }
flusher.map(Some) flusher.map(Some)
} },
Some(fullscreen) => { Some(fullscreen) => {
let (video_mode, monitor) = match fullscreen { let (video_mode, monitor) = match fullscreen {
Fullscreen::Exclusive(PlatformVideoModeHandle::X(ref video_mode)) => { Fullscreen::Exclusive(PlatformVideoModeHandle::X(ref video_mode)) => {
(Some(video_mode), video_mode.monitor.clone().unwrap()) (Some(video_mode), video_mode.monitor.clone().unwrap())
} },
Fullscreen::Borderless(Some(PlatformMonitorHandle::X(monitor))) => { Fullscreen::Borderless(Some(PlatformMonitorHandle::X(monitor))) => {
(None, monitor) (None, monitor)
} },
Fullscreen::Borderless(None) => { Fullscreen::Borderless(None) => {
(None, self.shared_state_lock().last_monitor.clone()) (None, self.shared_state_lock().last_monitor.clone())
} },
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
_ => unreachable!(), _ => unreachable!(),
}; };
@ -854,7 +800,7 @@ impl UnownedWindow {
self.set_position_inner(monitor_origin.0, monitor_origin.1) self.set_position_inner(monitor_origin.0, monitor_origin.1)
.expect_then_ignore_error("Failed to set window position"); .expect_then_ignore_error("Failed to set window position");
self.set_fullscreen_hint(true).map(Some) self.set_fullscreen_hint(true).map(Some)
} },
} }
} }
@ -862,21 +808,15 @@ impl UnownedWindow {
pub(crate) fn fullscreen(&self) -> Option<Fullscreen> { pub(crate) fn fullscreen(&self) -> Option<Fullscreen> {
let shared_state = self.shared_state_lock(); let shared_state = self.shared_state_lock();
shared_state shared_state.desired_fullscreen.clone().unwrap_or_else(|| shared_state.fullscreen.clone())
.desired_fullscreen
.clone()
.unwrap_or_else(|| shared_state.fullscreen.clone())
} }
#[inline] #[inline]
pub(crate) fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) { pub(crate) fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
if let Some(flusher) = self if let Some(flusher) =
.set_fullscreen_inner(fullscreen) self.set_fullscreen_inner(fullscreen).expect("Failed to change window fullscreen state")
.expect("Failed to change window fullscreen state")
{ {
flusher flusher.check().expect("Failed to change window fullscreen state");
.check()
.expect("Failed to change window fullscreen state");
self.invalidate_cached_frame_extents(); self.invalidate_cached_frame_extents();
} }
} }
@ -899,7 +839,7 @@ impl UnownedWindow {
drop(shared_state); drop(shared_state);
self.set_fullscreen(fullscreen); self.set_fullscreen(fullscreen);
} }
} },
} }
} }
@ -908,17 +848,11 @@ impl UnownedWindow {
} }
pub fn available_monitors(&self) -> Vec<X11MonitorHandle> { pub fn available_monitors(&self) -> Vec<X11MonitorHandle> {
self.xconn self.xconn.available_monitors().expect("Failed to get available monitors")
.available_monitors()
.expect("Failed to get available monitors")
} }
pub fn primary_monitor(&self) -> Option<X11MonitorHandle> { pub fn primary_monitor(&self) -> Option<X11MonitorHandle> {
Some( Some(self.xconn.primary_monitor().expect("Failed to get primary monitor"))
self.xconn
.primary_monitor()
.expect("Failed to get primary monitor"),
)
} }
#[inline] #[inline]
@ -933,9 +867,9 @@ impl UnownedWindow {
let hidden_atom = atoms[_NET_WM_STATE_HIDDEN]; let hidden_atom = atoms[_NET_WM_STATE_HIDDEN];
Some(match state { Some(match state {
Ok(atoms) => atoms Ok(atoms) => {
.iter() atoms.iter().any(|atom: &xproto::Atom| *atom as xproto::Atom == hidden_atom)
.any(|atom: &xproto::Atom| *atom as xproto::Atom == hidden_atom), },
_ => false, _ => false,
}) })
} }
@ -1020,9 +954,7 @@ impl UnownedWindow {
self.set_minimized_inner(minimized) self.set_minimized_inner(minimized)
.expect_then_ignore_error("Failed to change window minimization"); .expect_then_ignore_error("Failed to change window minimization");
self.xconn self.xconn.flush_requests().expect("Failed to change window minimization");
.flush_requests()
.expect("Failed to change window minimization");
} }
#[inline] #[inline]
@ -1041,7 +973,7 @@ impl UnownedWindow {
let horz_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == horz_atom); let horz_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == horz_atom);
let vert_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == vert_atom); let vert_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == vert_atom);
horz_maximized && vert_maximized horz_maximized && vert_maximized
} },
_ => false, _ => false,
} }
} }
@ -1058,9 +990,7 @@ impl UnownedWindow {
pub fn set_maximized(&self, maximized: bool) { pub fn set_maximized(&self, maximized: bool) {
self.set_maximized_inner(maximized) self.set_maximized_inner(maximized)
.expect_then_ignore_error("Failed to change window maximization"); .expect_then_ignore_error("Failed to change window maximization");
self.xconn self.xconn.flush_requests().expect("Failed to change window maximization");
.flush_requests()
.expect("Failed to change window maximization");
self.invalidate_cached_frame_extents(); self.invalidate_cached_frame_extents();
} }
@ -1088,12 +1018,9 @@ impl UnownedWindow {
#[inline] #[inline]
pub fn set_title(&self, title: &str) { pub fn set_title(&self, title: &str) {
self.set_title_inner(title) self.set_title_inner(title).expect_then_ignore_error("Failed to set window title");
.expect_then_ignore_error("Failed to set window title");
self.xconn self.xconn.flush_requests().expect("Failed to set window title");
.flush_requests()
.expect("Failed to set window title");
} }
#[inline] #[inline]
@ -1115,9 +1042,7 @@ impl UnownedWindow {
pub fn set_decorations(&self, decorations: bool) { pub fn set_decorations(&self, decorations: bool) {
self.set_decorations_inner(decorations) self.set_decorations_inner(decorations)
.expect_then_ignore_error("Failed to set decoration state"); .expect_then_ignore_error("Failed to set decoration state");
self.xconn self.xconn.flush_requests().expect("Failed to set decoration state");
.flush_requests()
.expect("Failed to set decoration state");
self.invalidate_cached_frame_extents(); self.invalidate_cached_frame_extents();
} }
@ -1141,8 +1066,7 @@ impl UnownedWindow {
} }
fn set_window_level_inner(&self, level: WindowLevel) -> Result<VoidCookie<'_>, X11Error> { fn set_window_level_inner(&self, level: WindowLevel) -> Result<VoidCookie<'_>, X11Error> {
self.toggle_atom(_NET_WM_STATE_ABOVE, level == WindowLevel::AlwaysOnTop)? self.toggle_atom(_NET_WM_STATE_ABOVE, level == WindowLevel::AlwaysOnTop)?.ignore_error();
.ignore_error();
self.toggle_atom(_NET_WM_STATE_BELOW, level == WindowLevel::AlwaysOnBottom) self.toggle_atom(_NET_WM_STATE_BELOW, level == WindowLevel::AlwaysOnBottom)
} }
@ -1150,9 +1074,7 @@ impl UnownedWindow {
pub fn set_window_level(&self, level: WindowLevel) { pub fn set_window_level(&self, level: WindowLevel) {
self.set_window_level_inner(level) self.set_window_level_inner(level)
.expect_then_ignore_error("Failed to set window-level state"); .expect_then_ignore_error("Failed to set window-level state");
self.xconn self.xconn.flush_requests().expect("Failed to set window-level state");
.flush_requests()
.expect("Failed to set window-level state");
} }
fn set_icon_inner(&self, icon: PlatformIcon) -> Result<VoidCookie<'_>, X11Error> { fn set_icon_inner(&self, icon: PlatformIcon) -> Result<VoidCookie<'_>, X11Error> {
@ -1199,7 +1121,7 @@ impl UnownedWindow {
match (visible, shared_state.visibility) { match (visible, shared_state.visibility) {
(true, Visibility::Yes) | (true, Visibility::YesWait) | (false, Visibility::No) => { (true, Visibility::Yes) | (true, Visibility::YesWait) | (false, Visibility::No) => {
return return
} },
_ => (), _ => (),
} }
@ -1215,18 +1137,14 @@ impl UnownedWindow {
&xproto::ConfigureWindowAux::new().stack_mode(xproto::StackMode::ABOVE), &xproto::ConfigureWindowAux::new().stack_mode(xproto::StackMode::ABOVE),
) )
.expect_then_ignore_error("Failed to call `xcb_configure_window`"); .expect_then_ignore_error("Failed to call `xcb_configure_window`");
self.xconn self.xconn.flush_requests().expect("Failed to call XMapRaised");
.flush_requests()
.expect("Failed to call XMapRaised");
shared_state.visibility = Visibility::YesWait; shared_state.visibility = Visibility::YesWait;
} else { } else {
self.xconn self.xconn
.xcb_connection() .xcb_connection()
.unmap_window(self.xwindow) .unmap_window(self.xwindow)
.expect_then_ignore_error("Failed to call `xcb_unmap_window`"); .expect_then_ignore_error("Failed to call `xcb_unmap_window`");
self.xconn self.xconn.flush_requests().expect("Failed to call XUnmapWindow");
.flush_requests()
.expect("Failed to call XUnmapWindow");
shared_state.visibility = Visibility::No; shared_state.visibility = Visibility::No;
} }
} }
@ -1237,9 +1155,7 @@ impl UnownedWindow {
} }
fn update_cached_frame_extents(&self) { fn update_cached_frame_extents(&self) {
let extents = self let extents = self.xconn.get_frame_extents_heuristic(self.xwindow, self.root);
.xconn
.get_frame_extents_heuristic(self.xwindow, self.root);
self.shared_state_lock().frame_extents = Some(extents); self.shared_state_lock().frame_extents = Some(extents);
} }
@ -1309,8 +1225,7 @@ impl UnownedWindow {
} }
pub(crate) fn set_position_physical(&self, x: i32, y: i32) { pub(crate) fn set_position_physical(&self, x: i32, y: i32) {
self.set_position_inner(x, y) self.set_position_inner(x, y).expect_then_ignore_error("Failed to call `XMoveWindow`");
.expect_then_ignore_error("Failed to call `XMoveWindow`");
} }
#[inline] #[inline]
@ -1350,14 +1265,10 @@ impl UnownedWindow {
.xcb_connection() .xcb_connection()
.configure_window( .configure_window(
self.xwindow, self.xwindow,
&xproto::ConfigureWindowAux::new() &xproto::ConfigureWindowAux::new().width(width).height(height),
.width(width)
.height(height),
) )
.expect_then_ignore_error("Failed to call `xcb_configure_window`"); .expect_then_ignore_error("Failed to call `xcb_configure_window`");
self.xconn self.xconn.flush_requests().expect("Failed to call XResizeWindow");
.flush_requests()
.expect("Failed to call XResizeWindow");
// cursor_hittest needs to be reapplied after each window resize. // cursor_hittest needs to be reapplied after each window resize.
if self.shared_state_lock().cursor_hittest.unwrap_or(false) { if self.shared_state_lock().cursor_hittest.unwrap_or(false) {
let _ = self.set_cursor_hittest(true); let _ = self.set_cursor_hittest(true);
@ -1488,19 +1399,17 @@ impl UnownedWindow {
pub fn set_resizable(&self, resizable: bool) { pub fn set_resizable(&self, resizable: bool) {
if util::wm_name_is_one_of(&["Xfwm4"]) { if util::wm_name_is_one_of(&["Xfwm4"]) {
// Making the window unresizable on Xfwm prevents further changes to `WM_NORMAL_HINTS` from being detected. // Making the window unresizable on Xfwm prevents further changes to `WM_NORMAL_HINTS`
// This makes it impossible for resizing to be re-enabled, and also breaks DPI scaling. As such, we choose // from being detected. This makes it impossible for resizing to be
// the lesser of two evils and do nothing. // re-enabled, and also breaks DPI scaling. As such, we choose the lesser of
// two evils and do nothing.
warn!("To avoid a WM bug, disabling resizing has no effect on Xfwm4"); warn!("To avoid a WM bug, disabling resizing has no effect on Xfwm4");
return; return;
} }
let (min_size, max_size) = if resizable { let (min_size, max_size) = if resizable {
let shared_state_lock = self.shared_state_lock(); let shared_state_lock = self.shared_state_lock();
( (shared_state_lock.min_inner_size, shared_state_lock.max_inner_size)
shared_state_lock.min_inner_size,
shared_state_lock.max_inner_size,
)
} else { } else {
let window_size = Some(Size::from(self.inner_size())); let window_size = Some(Size::from(self.inner_size()));
(window_size, window_size) (window_size, window_size)
@ -1559,21 +1468,19 @@ impl UnownedWindow {
{ {
self.xconn.set_cursor_icon(self.xwindow, Some(icon)); self.xconn.set_cursor_icon(self.xwindow, Some(icon));
} }
} },
Cursor::Custom(RootCustomCursor { Cursor::Custom(RootCustomCursor { inner: PlatformCustomCursor::X(cursor) }) => {
inner: PlatformCustomCursor::X(cursor),
}) => {
#[allow(clippy::mutex_atomic)] #[allow(clippy::mutex_atomic)]
if *self.cursor_visible.lock().unwrap() { if *self.cursor_visible.lock().unwrap() {
self.xconn.set_custom_cursor(self.xwindow, &cursor); self.xconn.set_custom_cursor(self.xwindow, &cursor);
} }
*self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(cursor); *self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(cursor);
} },
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
Cursor::Custom(RootCustomCursor { Cursor::Custom(RootCustomCursor { inner: PlatformCustomCursor::Wayland(_) }) => {
inner: PlatformCustomCursor::Wayland(_), tracing::error!("passed a Wayland cursor to X11 backend")
}) => tracing::error!("passed a Wayland cursor to X11 backend"), },
} }
} }
@ -1629,23 +1536,23 @@ impl UnownedWindow {
xproto::GrabStatus::SUCCESS => Ok(()), xproto::GrabStatus::SUCCESS => Ok(()),
xproto::GrabStatus::ALREADY_GRABBED => { xproto::GrabStatus::ALREADY_GRABBED => {
Err("Cursor could not be confined: already confined by another client") Err("Cursor could not be confined: already confined by another client")
} },
xproto::GrabStatus::INVALID_TIME => { xproto::GrabStatus::INVALID_TIME => {
Err("Cursor could not be confined: invalid time") Err("Cursor could not be confined: invalid time")
} },
xproto::GrabStatus::NOT_VIEWABLE => { xproto::GrabStatus::NOT_VIEWABLE => {
Err("Cursor could not be confined: confine location not viewable") Err("Cursor could not be confined: confine location not viewable")
} },
xproto::GrabStatus::FROZEN => { xproto::GrabStatus::FROZEN => {
Err("Cursor could not be confined: frozen by another client") Err("Cursor could not be confined: frozen by another client")
} },
_ => unreachable!(), _ => unreachable!(),
} }
.map_err(|err| ExternalError::Os(os_error!(OsError::Misc(err)))) .map_err(|err| ExternalError::Os(os_error!(OsError::Misc(err))))
} },
CursorGrabMode::Locked => { CursorGrabMode::Locked => {
return Err(ExternalError::NotSupported(NotSupportedError::new())); return Err(ExternalError::NotSupported(NotSupportedError::new()));
} },
}; };
if result.is_ok() { if result.is_ok() {
@ -1662,23 +1569,20 @@ impl UnownedWindow {
if visible == *visible_lock { if visible == *visible_lock {
return; return;
} }
let cursor = if visible { let cursor =
Some((*self.selected_cursor.lock().unwrap()).clone()) if visible { Some((*self.selected_cursor.lock().unwrap()).clone()) } else { None };
} else {
None
};
*visible_lock = visible; *visible_lock = visible;
drop(visible_lock); drop(visible_lock);
match cursor { match cursor {
Some(SelectedCursor::Custom(cursor)) => { Some(SelectedCursor::Custom(cursor)) => {
self.xconn.set_custom_cursor(self.xwindow, &cursor); self.xconn.set_custom_cursor(self.xwindow, &cursor);
} },
Some(SelectedCursor::Named(cursor)) => { Some(SelectedCursor::Named(cursor)) => {
self.xconn.set_cursor_icon(self.xwindow, Some(cursor)); self.xconn.set_cursor_icon(self.xwindow, Some(cursor));
} },
None => { None => {
self.xconn.set_cursor_icon(self.xwindow, None); self.xconn.set_cursor_icon(self.xwindow, None);
} },
} }
} }
@ -1831,8 +1735,7 @@ impl UnownedWindow {
let state_atom = atoms[WM_STATE]; let state_atom = atoms[WM_STATE];
let state_type_atom = atoms[CARD32]; let state_type_atom = atoms[CARD32];
let is_minimized = if let Ok(state) = let is_minimized = if let Ok(state) =
self.xconn self.xconn.get_property::<u32>(self.xwindow, state_atom, state_type_atom)
.get_property::<u32>(self.xwindow, state_atom, state_type_atom)
{ {
state.contains(&super::ICONIC_STATE) state.contains(&super::ICONIC_STATE)
} else { } else {
@ -1915,9 +1818,7 @@ impl UnownedWindow {
#[inline] #[inline]
pub fn request_redraw(&self) { pub fn request_redraw(&self) {
self.redraw_sender self.redraw_sender.send(WindowId(self.xwindow as _)).unwrap();
.send(WindowId(self.xwindow as _))
.unwrap();
} }
#[inline] #[inline]
@ -2001,10 +1902,7 @@ fn cast_dimension_to_hint(val: u32) -> i32 {
/// Use the above strategy to cast a physical size into a hinted size. /// Use the above strategy to cast a physical size into a hinted size.
fn cast_physical_size_to_hint(size: PhysicalSize<u32>) -> (i32, i32) { fn cast_physical_size_to_hint(size: PhysicalSize<u32>) -> (i32, i32) {
let PhysicalSize { width, height } = size; let PhysicalSize { width, height } = size;
( (cast_dimension_to_hint(width), cast_dimension_to_hint(height))
cast_dimension_to_hint(width),
cast_dimension_to_hint(height),
)
} }
/// Use the above strategy to cast a size into a hinted size. /// Use the above strategy to cast a size into a hinted size.

View file

@ -1,25 +1,19 @@
use std::{ use std::collections::HashMap;
collections::HashMap, use std::error::Error;
error::Error, use std::sync::atomic::{AtomicU32, Ordering};
fmt, ptr, use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard};
sync::{ use std::{fmt, ptr};
atomic::{AtomicU32, Ordering},
Arc, Mutex, RwLock, RwLockReadGuard,
},
};
use crate::window::CursorIcon; use crate::window::CursorIcon;
use super::{atoms::Atoms, ffi, monitor::MonitorHandle}; use super::atoms::Atoms;
use x11rb::{ use super::ffi;
connection::Connection, use super::monitor::MonitorHandle;
protocol::{ use x11rb::connection::Connection;
randr::ConnectionExt as _, use x11rb::protocol::randr::ConnectionExt as _;
xproto::{self, ConnectionExt}, use x11rb::protocol::xproto::{self, ConnectionExt};
}, use x11rb::resource_manager;
resource_manager, use x11rb::xcb_ffi::XCBConnection;
xcb_ffi::XCBConnection,
};
/// A connection to an X server. /// A connection to an X server.
pub struct XConnection { pub struct XConnection {
@ -158,14 +152,9 @@ impl XConnection {
.atom; .atom;
// Get PropertyNotify events from the XSETTINGS window. // Get PropertyNotify events from the XSETTINGS window.
// TODO: The XSETTINGS window here can change. In the future, listen for DestroyNotify on this window // TODO: The XSETTINGS window here can change. In the future, listen for DestroyNotify on
// in order to accommodate for a changed window here. // this window in order to accommodate for a changed window here.
let selector_window = xcb let selector_window = xcb.get_selection_owner(xsettings_screen).ok()?.reply().ok()?.owner;
.get_selection_owner(xsettings_screen)
.ok()?
.reply()
.ok()?
.owner;
xcb.change_window_attributes( xcb.change_window_attributes(
selector_window, selector_window,
@ -198,9 +187,7 @@ impl XConnection {
/// Get the underlying XCB connection. /// Get the underlying XCB connection.
#[inline] #[inline]
pub fn xcb_connection(&self) -> &XCBConnection { pub fn xcb_connection(&self) -> &XCBConnection {
self.xcb self.xcb.as_ref().expect("xcb_connection somehow called after drop?")
.as_ref()
.expect("xcb_connection somehow called after drop?")
} }
/// Get the list of atoms. /// Get the list of atoms.

View file

@ -9,7 +9,8 @@ use std::num::NonZeroUsize;
use x11rb::protocol::xproto::{self, ConnectionExt}; use x11rb::protocol::xproto::{self, ConnectionExt};
use super::{atoms::*, XConnection}; use super::atoms::*;
use super::XConnection;
type Result<T> = core::result::Result<T, ParserError>; type Result<T> = core::result::Result<T, ParserError>;
@ -27,17 +28,11 @@ impl XConnection {
let atoms = self.atoms(); let atoms = self.atoms();
// Get the current owner of the screen's settings. // Get the current owner of the screen's settings.
let owner = self let owner = self.xcb_connection().get_selection_owner(xsettings_screen)?.reply()?;
.xcb_connection()
.get_selection_owner(xsettings_screen)?
.reply()?;
// Read the _XSETTINGS_SETTINGS property. // Read the _XSETTINGS_SETTINGS property.
let data: Vec<u8> = self.get_property( let data: Vec<u8> =
owner.owner, self.get_property(owner.owner, atoms[_XSETTINGS_SETTINGS], atoms[_XSETTINGS_SETTINGS])?;
atoms[_XSETTINGS_SETTINGS],
atoms[_XSETTINGS_SETTINGS],
)?;
// Parse the property. // Parse the property.
let dpi_setting = read_settings(&data)? let dpi_setting = read_settings(&data)?
@ -48,10 +43,10 @@ impl XConnection {
SettingData::Integer(dpi) => dpi as f64, SettingData::Integer(dpi) => dpi as f64,
SettingData::String(_) => { SettingData::String(_) => {
return Err(ParserError::BadType(SettingType::String).into()) return Err(ParserError::BadType(SettingType::String).into())
} },
SettingData::Color(_) => { SettingData::Color(_) => {
return Err(ParserError::BadType(SettingType::Color).into()) return Err(ParserError::BadType(SettingType::Color).into())
} },
}; };
Ok(Some(base_dpi / DPI_MULTIPLIER)) Ok(Some(base_dpi / DPI_MULTIPLIER))
@ -111,7 +106,7 @@ impl<'a> Setting<'a> {
SettingType::Integer => { SettingType::Integer => {
// Read a 32-bit integer. // Read a 32-bit integer.
SettingData::Integer(parser.i32()?) SettingData::Integer(parser.i32()?)
} },
SettingType::String => { SettingType::String => {
// Read the data. // Read the data.
@ -120,7 +115,7 @@ impl<'a> Setting<'a> {
parser.pad(data.len(), 4)?; parser.pad(data.len(), 4)?;
SettingData::String(data) SettingData::String(data)
} },
SettingType::Color => { SettingType::Color => {
// Read i16's of color. // Read i16's of color.
@ -128,7 +123,7 @@ impl<'a> Setting<'a> {
(parser.i16()?, parser.i16()?, parser.i16()?, parser.i16()?); (parser.i16()?, parser.i16()?, parser.i16()?, parser.i16()?);
SettingData::Color([red, blue, green, alpha]) SettingData::Color([red, blue, green, alpha])
} },
}; };
Ok(Setting { name, data }) Ok(Setting { name, data })
@ -164,9 +159,7 @@ struct Parser<'a> {
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
/// Create a new parser. /// Create a new parser.
fn new(bytes: &'a [u8]) -> Result<Self> { fn new(bytes: &'a [u8]) -> Result<Self> {
let (endianness, bytes) = bytes let (endianness, bytes) = bytes.split_first().ok_or_else(|| ParserError::ran_out(1, 0))?;
.split_first()
.ok_or_else(|| ParserError::ran_out(1, 0))?;
let endianness = match *endianness { let endianness = match *endianness {
BIG_ENDIAN => Endianness::Big, BIG_ENDIAN => Endianness::Big,
LITTLE_ENDIAN => Endianness::Little, LITTLE_ENDIAN => Endianness::Little,
@ -175,9 +168,7 @@ impl<'a> Parser<'a> {
Ok(Self { Ok(Self {
// Ignore three bytes of padding and the four-byte serial. // Ignore three bytes of padding and the four-byte serial.
bytes: bytes bytes: bytes.get(7..).ok_or_else(|| ParserError::ran_out(7, bytes.len()))?,
.get(7..)
.ok_or_else(|| ParserError::ran_out(7, bytes.len()))?,
endianness, endianness,
}) })
} }
@ -255,10 +246,7 @@ impl Endianness {
#[derive(Debug)] #[derive(Debug)]
pub enum ParserError { pub enum ParserError {
/// Ran out of bytes. /// Ran out of bytes.
NoMoreBytes { NoMoreBytes { expected: NonZeroUsize, found: usize },
expected: NonZeroUsize,
found: usize,
},
/// Invalid type. /// Invalid type.
InvalidType(i8), InvalidType(i8),
@ -291,7 +279,7 @@ mod tests {
ParserError::NoMoreBytes { expected, found } => { ParserError::NoMoreBytes { expected, found } => {
assert_eq!(expected.get(), 1); assert_eq!(expected.get(), 1);
assert_eq!(found, 0); assert_eq!(found, 0);
} },
_ => panic!(), _ => panic!(),
} }
@ -308,10 +296,7 @@ mod tests {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let settings = read_settings(&data) let settings = read_settings(&data).unwrap().collect::<Result<Vec<_>>>().unwrap();
.unwrap()
.collect::<Result<Vec<_>>>()
.unwrap();
let dpi = settings.iter().find(|s| s.name == b"Xft/DPI").unwrap(); let dpi = settings.iter().find(|s| s.name == b"Xft/DPI").unwrap();
assert_int(&dpi.data, 96 * 1024); assert_int(&dpi.data, 96 * 1024);
@ -320,10 +305,7 @@ mod tests {
let rgba = settings.iter().find(|s| s.name == b"Xft/RGBA").unwrap(); let rgba = settings.iter().find(|s| s.name == b"Xft/RGBA").unwrap();
assert_string(&rgba.data, "rgb"); assert_string(&rgba.data, "rgb");
let lcd = settings let lcd = settings.iter().find(|s| s.name == b"Xft/Lcdfilter").unwrap();
.iter()
.find(|s| s.name == b"Xft/Lcdfilter")
.unwrap();
assert_string(&lcd.data, "lcddefault"); assert_string(&lcd.data, "lcddefault");
} }

View file

@ -58,37 +58,29 @@ fn maybe_dispatch_device_event(delegate: &ApplicationDelegate, event: &NSEvent)
let delta_y = unsafe { event.deltaY() } as f64; let delta_y = unsafe { event.deltaY() } as f64;
if delta_x != 0.0 { if delta_x != 0.0 {
delegate.queue_device_event(DeviceEvent::Motion { delegate.queue_device_event(DeviceEvent::Motion { axis: 0, value: delta_x });
axis: 0,
value: delta_x,
});
} }
if delta_y != 0.0 { if delta_y != 0.0 {
delegate.queue_device_event(DeviceEvent::Motion { delegate.queue_device_event(DeviceEvent::Motion { axis: 1, value: delta_y })
axis: 1,
value: delta_y,
})
} }
if delta_x != 0.0 || delta_y != 0.0 { if delta_x != 0.0 || delta_y != 0.0 {
delegate.queue_device_event(DeviceEvent::MouseMotion { delegate.queue_device_event(DeviceEvent::MouseMotion { delta: (delta_x, delta_y) });
delta: (delta_x, delta_y),
});
} }
} },
NSEventType::LeftMouseDown | NSEventType::RightMouseDown | NSEventType::OtherMouseDown => { NSEventType::LeftMouseDown | NSEventType::RightMouseDown | NSEventType::OtherMouseDown => {
delegate.queue_device_event(DeviceEvent::Button { delegate.queue_device_event(DeviceEvent::Button {
button: unsafe { event.buttonNumber() } as u32, button: unsafe { event.buttonNumber() } as u32,
state: ElementState::Pressed, state: ElementState::Pressed,
}); });
} },
NSEventType::LeftMouseUp | NSEventType::RightMouseUp | NSEventType::OtherMouseUp => { NSEventType::LeftMouseUp | NSEventType::RightMouseUp | NSEventType::OtherMouseUp => {
delegate.queue_device_event(DeviceEvent::Button { delegate.queue_device_event(DeviceEvent::Button {
button: unsafe { event.buttonNumber() } as u32, button: unsafe { event.buttonNumber() } as u32,
state: ElementState::Released, state: ElementState::Released,
}); });
} },
_ => (), _ => (),
} }
} }

View file

@ -240,10 +240,7 @@ impl ApplicationDelegate {
} }
pub fn queue_device_event(&self, event: DeviceEvent) { pub fn queue_device_event(&self, event: DeviceEvent) {
self.ivars() self.ivars().pending_events.borrow_mut().push_back(QueuedEvent::DeviceEvent(event));
.pending_events
.borrow_mut()
.push_back(QueuedEvent::DeviceEvent(event));
} }
pub fn queue_static_scale_factor_changed_event( pub fn queue_static_scale_factor_changed_event(
@ -252,14 +249,11 @@ impl ApplicationDelegate {
suggested_size: PhysicalSize<u32>, suggested_size: PhysicalSize<u32>,
scale_factor: f64, scale_factor: f64,
) { ) {
self.ivars() self.ivars().pending_events.borrow_mut().push_back(QueuedEvent::ScaleFactorChanged {
.pending_events window,
.borrow_mut() suggested_size,
.push_back(QueuedEvent::ScaleFactorChanged { scale_factor,
window, });
suggested_size,
scale_factor,
});
} }
pub fn handle_redraw(&self, window_id: WindowId) { pub fn handle_redraw(&self, window_id: WindowId) {
@ -272,8 +266,9 @@ impl ApplicationDelegate {
event: WindowEvent::RedrawRequested, event: WindowEvent::RedrawRequested,
}); });
// `pump_events` will request to stop immediately _after_ dispatching RedrawRequested events // `pump_events` will request to stop immediately _after_ dispatching RedrawRequested
// as a way to ensure that `pump_events` can't block an external loop indefinitely // events as a way to ensure that `pump_events` can't block an external loop
// indefinitely
if self.ivars().stop_on_redraw.get() { if self.ivars().stop_on_redraw.get() {
let app = NSApplication::sharedApplication(mtm); let app = NSApplication::sharedApplication(mtm);
stop_app_immediately(&app); stop_app_immediately(&app);
@ -290,9 +285,7 @@ impl ApplicationDelegate {
} }
fn handle_event(&self, event: Event<HandlePendingUserEvents>) { fn handle_event(&self, event: Event<HandlePendingUserEvents>) {
self.ivars() self.ivars().event_handler.handle_event(event, &ActiveEventLoop::new_root(self.retain()))
.event_handler
.handle_event(event, &ActiveEventLoop::new_root(self.retain()))
} }
/// dispatch `NewEvents(Init)` + `Resumed` /// dispatch `NewEvents(Init)` + `Resumed`
@ -323,23 +316,14 @@ impl ApplicationDelegate {
let start = self.ivars().start_time.get().unwrap(); let start = self.ivars().start_time.get().unwrap();
let cause = match self.control_flow() { let cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll, ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled { ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
start,
requested_resume: None,
},
ControlFlow::WaitUntil(requested_resume) => { ControlFlow::WaitUntil(requested_resume) => {
if Instant::now() >= requested_resume { if Instant::now() >= requested_resume {
StartCause::ResumeTimeReached { StartCause::ResumeTimeReached { start, requested_resume }
start,
requested_resume,
}
} else { } else {
StartCause::WaitCancelled { StartCause::WaitCancelled { start, requested_resume: Some(requested_resume) }
start,
requested_resume: Some(requested_resume),
}
} }
} },
}; };
self.handle_event(Event::NewEvents(cause)); self.handle_event(Event::NewEvents(cause));
@ -369,18 +353,11 @@ impl ApplicationDelegate {
window_id: RootWindowId(window_id), window_id: RootWindowId(window_id),
event, event,
}); });
} },
QueuedEvent::DeviceEvent(event) => { QueuedEvent::DeviceEvent(event) => {
self.handle_event(Event::DeviceEvent { self.handle_event(Event::DeviceEvent { device_id: DEVICE_ID, event });
device_id: DEVICE_ID, },
event, QueuedEvent::ScaleFactorChanged { window, suggested_size, scale_factor } => {
});
}
QueuedEvent::ScaleFactorChanged {
window,
suggested_size,
scale_factor,
} => {
let new_inner_size = Arc::new(Mutex::new(suggested_size)); let new_inner_size = Arc::new(Mutex::new(suggested_size));
let scale_factor_changed_event = Event::WindowEvent { let scale_factor_changed_event = Event::WindowEvent {
window_id: RootWindowId(window.id()), window_id: RootWindowId(window.id()),
@ -405,7 +382,7 @@ impl ApplicationDelegate {
event: WindowEvent::Resized(physical_size), event: WindowEvent::Resized(physical_size),
}; };
self.handle_event(resized_event); self.handle_event(resized_event);
} },
} }
} }
@ -435,10 +412,7 @@ impl ApplicationDelegate {
ControlFlow::Poll => Some(Instant::now()), ControlFlow::Poll => Some(Instant::now()),
ControlFlow::WaitUntil(instant) => Some(instant), ControlFlow::WaitUntil(instant) => Some(instant),
}; };
self.ivars() self.ivars().waker.borrow_mut().start_at(min_timeout(wait_timeout, app_timeout));
.waker
.borrow_mut()
.start_at(min_timeout(wait_timeout, app_timeout));
} }
} }
@ -460,9 +434,7 @@ pub(crate) struct HandlePendingUserEvents;
/// equates to an infinite timeout, not a zero timeout (so can't just use /// equates to an infinite timeout, not a zero timeout (so can't just use
/// `Option::min`) /// `Option::min`)
fn min_timeout(a: Option<Instant>, b: Option<Instant>) -> Option<Instant> { fn min_timeout(a: Option<Instant>, b: Option<Instant>) -> Option<Instant> {
a.map_or(b, |a_timeout| { a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))
})
} }
/// A hack to make activation of multiple windows work when creating them before /// A hack to make activation of multiple windows work when creating them before

View file

@ -11,8 +11,7 @@ use objc2_foundation::{
NSString, NSString,
}; };
use crate::cursor::CursorImage; use crate::cursor::{CursorImage, OnlyCursorImageSource};
use crate::cursor::OnlyCursorImageSource;
use crate::window::CursorIcon; use crate::window::CursorIcon;
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -118,7 +117,10 @@ unsafe fn load_webkit_cursor(name: &NSString) -> Id<NSCursor> {
// cursors, and will seem completely standard to macOS users. // cursors, and will seem completely standard to macOS users.
// //
// https://stackoverflow.com/a/21786835/5435443 // https://stackoverflow.com/a/21786835/5435443
let root = ns_string!("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors"); let root = ns_string!(
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/\
HIServices.framework/Versions/A/Resources/cursors"
);
let cursor_path = root.stringByAppendingPathComponent(name); let cursor_path = root.stringByAppendingPathComponent(name);
let pdf_path = cursor_path.stringByAppendingPathComponent(ns_string!("cursor.pdf")); let pdf_path = cursor_path.stringByAppendingPathComponent(ns_string!("cursor.pdf"));
@ -166,10 +168,10 @@ pub(crate) fn invisible_cursor() -> Id<NSCursor> {
// You can reproduce this via ImageMagick. // You can reproduce this via ImageMagick.
// $ convert -size 16x16 xc:none cursor.gif // $ convert -size 16x16 xc:none cursor.gif
static CURSOR_BYTES: &[u8] = &[ static CURSOR_BYTES: &[u8] = &[
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x10, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x10, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x0E, 0x84, 0x8F, 0xA9, 0xCB, 0xED, 0x0F, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x0e, 0x84, 0x8f, 0xa9, 0xcb, 0xed, 0x0f,
0xA3, 0x9C, 0xB4, 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B, 0xa3, 0x9c, 0xb4, 0xda, 0x8b, 0xb3, 0x3e, 0x05, 0x00, 0x3b,
]; ];
fn new_invisible() -> Id<NSCursor> { fn new_invisible() -> Id<NSCursor> {
@ -182,10 +184,7 @@ pub(crate) fn invisible_cursor() -> Id<NSCursor> {
// Cache this for efficiency // Cache this for efficiency
static CURSOR: OnceLock<CustomCursor> = OnceLock::new(); static CURSOR: OnceLock<CustomCursor> = OnceLock::new();
CURSOR CURSOR.get_or_init(|| CustomCursor(new_invisible())).0.clone()
.get_or_init(|| CustomCursor(new_invisible()))
.0
.clone()
} }
pub(crate) fn cursor_from_icon(icon: CursorIcon) -> Id<NSCursor> { pub(crate) fn cursor_from_icon(icon: CursorIcon) -> Id<NSCursor> {

View file

@ -1,22 +1,18 @@
use std::ffi::c_void; use std::ffi::c_void;
use core_foundation::{ use core_foundation::base::CFRelease;
base::CFRelease, use core_foundation::data::{CFDataGetBytePtr, CFDataRef};
data::{CFDataGetBytePtr, CFDataRef},
};
use objc2::rc::Id; use objc2::rc::Id;
use objc2_app_kit::{NSEvent, NSEventModifierFlags, NSEventSubtype, NSEventType}; use objc2_app_kit::{NSEvent, NSEventModifierFlags, NSEventSubtype, NSEventType};
use objc2_foundation::{run_on_main, NSPoint}; use objc2_foundation::{run_on_main, NSPoint};
use smol_str::SmolStr; use smol_str::SmolStr;
use crate::{ use crate::event::{ElementState, KeyEvent, Modifiers};
event::{ElementState, KeyEvent, Modifiers}, use crate::keyboard::{
keyboard::{ Key, KeyCode, KeyLocation, ModifiersKeys, ModifiersState, NamedKey, NativeKey, NativeKeyCode,
Key, KeyCode, KeyLocation, ModifiersKeys, ModifiersState, NamedKey, NativeKey, PhysicalKey,
NativeKeyCode, PhysicalKey,
},
platform_impl::platform::ffi,
}; };
use crate::platform_impl::platform::ffi;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KeyEventExtra { pub struct KeyEventExtra {
@ -67,10 +63,7 @@ pub fn get_modifierless_char(scancode: u16) -> Key {
CFRelease(input_source as *mut c_void); CFRelease(input_source as *mut c_void);
} }
if translate_result != 0 { if translate_result != 0 {
tracing::error!( tracing::error!("`UCKeyTranslate` returned with the non-zero value: {}", translate_result);
"`UCKeyTranslate` returned with the non-zero value: {}",
translate_result
);
return Key::Unidentified(NativeKey::MacOS(scancode)); return Key::Unidentified(NativeKey::MacOS(scancode));
} }
if result_len == 0 { if result_len == 0 {
@ -121,9 +114,8 @@ pub(crate) fn create_key_event(
let text_with_all_modifiers: Option<SmolStr> = if key_override.is_some() { let text_with_all_modifiers: Option<SmolStr> = if key_override.is_some() {
None None
} else { } else {
let characters = unsafe { ns_event.characters() } let characters =
.map(|s| s.to_string()) unsafe { ns_event.characters() }.map(|s| s.to_string()).unwrap_or_default();
.unwrap_or_default();
if characters.is_empty() { if characters.is_empty() {
None None
} else { } else {
@ -153,7 +145,7 @@ pub(crate) fn create_key_event(
Some(text) if !has_ctrl && !has_cmd => { Some(text) if !has_ctrl && !has_cmd => {
// Character heeding both SHIFT and ALT. // Character heeding both SHIFT and ALT.
Key::Character(text.clone()) Key::Character(text.clone())
} },
_ => match key_without_modifiers.as_ref() { _ => match key_without_modifiers.as_ref() {
// Character heeding just SHIFT, ignoring ALT. // Character heeding just SHIFT, ignoring ALT.
@ -169,11 +161,7 @@ pub(crate) fn create_key_event(
(key_from_code.clone(), key_from_code) (key_from_code.clone(), key_from_code)
}; };
let text = if is_press { let text = if is_press { logical_key.to_text().map(SmolStr::new) } else { None };
logical_key.to_text().map(SmolStr::new)
} else {
None
};
let location = code_to_location(physical_key); let location = code_to_location(physical_key);
@ -184,10 +172,7 @@ pub(crate) fn create_key_event(
repeat: is_repeat, repeat: is_repeat,
state, state,
text, text,
platform_specific: KeyEventExtra { platform_specific: KeyEventExtra { text_with_all_modifiers, key_without_modifiers },
text_with_all_modifiers,
key_without_modifiers,
},
} }
} }
@ -341,58 +326,31 @@ pub(super) fn event_mods(event: &NSEvent) -> Modifiers {
ModifiersState::SHIFT, ModifiersState::SHIFT,
flags_contains(flags, NSEventModifierFlags::NSEventModifierFlagShift), flags_contains(flags, NSEventModifierFlags::NSEventModifierFlagShift),
); );
pressed_mods.set( pressed_mods.set(ModifiersKeys::LSHIFT, flags_contains(flags, NX_DEVICELSHIFTKEYMASK));
ModifiersKeys::LSHIFT, pressed_mods.set(ModifiersKeys::RSHIFT, flags_contains(flags, NX_DEVICERSHIFTKEYMASK));
flags_contains(flags, NX_DEVICELSHIFTKEYMASK),
);
pressed_mods.set(
ModifiersKeys::RSHIFT,
flags_contains(flags, NX_DEVICERSHIFTKEYMASK),
);
state.set( state.set(
ModifiersState::CONTROL, ModifiersState::CONTROL,
flags_contains(flags, NSEventModifierFlags::NSEventModifierFlagControl), flags_contains(flags, NSEventModifierFlags::NSEventModifierFlagControl),
); );
pressed_mods.set( pressed_mods.set(ModifiersKeys::LCONTROL, flags_contains(flags, NX_DEVICELCTLKEYMASK));
ModifiersKeys::LCONTROL, pressed_mods.set(ModifiersKeys::RCONTROL, flags_contains(flags, NX_DEVICERCTLKEYMASK));
flags_contains(flags, NX_DEVICELCTLKEYMASK),
);
pressed_mods.set(
ModifiersKeys::RCONTROL,
flags_contains(flags, NX_DEVICERCTLKEYMASK),
);
state.set( state.set(
ModifiersState::ALT, ModifiersState::ALT,
flags_contains(flags, NSEventModifierFlags::NSEventModifierFlagOption), flags_contains(flags, NSEventModifierFlags::NSEventModifierFlagOption),
); );
pressed_mods.set( pressed_mods.set(ModifiersKeys::LALT, flags_contains(flags, NX_DEVICELALTKEYMASK));
ModifiersKeys::LALT, pressed_mods.set(ModifiersKeys::RALT, flags_contains(flags, NX_DEVICERALTKEYMASK));
flags_contains(flags, NX_DEVICELALTKEYMASK),
);
pressed_mods.set(
ModifiersKeys::RALT,
flags_contains(flags, NX_DEVICERALTKEYMASK),
);
state.set( state.set(
ModifiersState::SUPER, ModifiersState::SUPER,
flags_contains(flags, NSEventModifierFlags::NSEventModifierFlagCommand), flags_contains(flags, NSEventModifierFlags::NSEventModifierFlagCommand),
); );
pressed_mods.set( pressed_mods.set(ModifiersKeys::LSUPER, flags_contains(flags, NX_DEVICELCMDKEYMASK));
ModifiersKeys::LSUPER, pressed_mods.set(ModifiersKeys::RSUPER, flags_contains(flags, NX_DEVICERCMDKEYMASK));
flags_contains(flags, NX_DEVICELCMDKEYMASK),
);
pressed_mods.set(
ModifiersKeys::RSUPER,
flags_contains(flags, NX_DEVICERCMDKEYMASK),
);
Modifiers { Modifiers { state, pressed_mods }
state,
pressed_mods,
}
} }
pub(super) fn dummy_event() -> Option<Id<NSEvent>> { pub(super) fn dummy_event() -> Option<Id<NSEvent>> {
@ -545,7 +503,7 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0x07 => KeyCode::KeyX, 0x07 => KeyCode::KeyX,
0x08 => KeyCode::KeyC, 0x08 => KeyCode::KeyC,
0x09 => KeyCode::KeyV, 0x09 => KeyCode::KeyV,
//0x0a => World 1, // 0x0a => World 1,
0x0b => KeyCode::KeyB, 0x0b => KeyCode::KeyB,
0x0c => KeyCode::KeyQ, 0x0c => KeyCode::KeyQ,
0x0d => KeyCode::KeyW, 0x0d => KeyCode::KeyW,
@ -587,7 +545,7 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0x31 => KeyCode::Space, 0x31 => KeyCode::Space,
0x32 => KeyCode::Backquote, 0x32 => KeyCode::Backquote,
0x33 => KeyCode::Backspace, 0x33 => KeyCode::Backspace,
//0x34 => unknown, // 0x34 => unknown,
0x35 => KeyCode::Escape, 0x35 => KeyCode::Escape,
0x36 => KeyCode::SuperRight, 0x36 => KeyCode::SuperRight,
0x37 => KeyCode::SuperLeft, 0x37 => KeyCode::SuperLeft,
@ -601,22 +559,23 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0x3f => KeyCode::Fn, 0x3f => KeyCode::Fn,
0x40 => KeyCode::F17, 0x40 => KeyCode::F17,
0x41 => KeyCode::NumpadDecimal, 0x41 => KeyCode::NumpadDecimal,
//0x42 -> unknown, // 0x42 -> unknown,
0x43 => KeyCode::NumpadMultiply, 0x43 => KeyCode::NumpadMultiply,
//0x44 => unknown, // 0x44 => unknown,
0x45 => KeyCode::NumpadAdd, 0x45 => KeyCode::NumpadAdd,
//0x46 => unknown, // 0x46 => unknown,
0x47 => KeyCode::NumLock, 0x47 => KeyCode::NumLock,
//0x48 => KeyCode::NumpadClear, // 0x48 => KeyCode::NumpadClear,
// TODO: (Artur) for me, kVK_VolumeUp is 0x48 // TODO: (Artur) for me, kVK_VolumeUp is 0x48
// macOS 10.11 // macOS 10.11
// /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h // /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/
// Versions/A/Headers/Events.h
0x49 => KeyCode::AudioVolumeUp, 0x49 => KeyCode::AudioVolumeUp,
0x4a => KeyCode::AudioVolumeDown, 0x4a => KeyCode::AudioVolumeDown,
0x4b => KeyCode::NumpadDivide, 0x4b => KeyCode::NumpadDivide,
0x4c => KeyCode::NumpadEnter, 0x4c => KeyCode::NumpadEnter,
//0x4d => unknown, // 0x4d => unknown,
0x4e => KeyCode::NumpadSubtract, 0x4e => KeyCode::NumpadSubtract,
0x4f => KeyCode::F18, 0x4f => KeyCode::F18,
0x50 => KeyCode::F19, 0x50 => KeyCode::F19,
@ -633,25 +592,25 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0x5b => KeyCode::Numpad8, 0x5b => KeyCode::Numpad8,
0x5c => KeyCode::Numpad9, 0x5c => KeyCode::Numpad9,
0x5d => KeyCode::IntlYen, 0x5d => KeyCode::IntlYen,
//0x5e => JIS Ro, // 0x5e => JIS Ro,
//0x5f => unknown, // 0x5f => unknown,
0x60 => KeyCode::F5, 0x60 => KeyCode::F5,
0x61 => KeyCode::F6, 0x61 => KeyCode::F6,
0x62 => KeyCode::F7, 0x62 => KeyCode::F7,
0x63 => KeyCode::F3, 0x63 => KeyCode::F3,
0x64 => KeyCode::F8, 0x64 => KeyCode::F8,
0x65 => KeyCode::F9, 0x65 => KeyCode::F9,
//0x66 => JIS Eisuu (macOS), // 0x66 => JIS Eisuu (macOS),
0x67 => KeyCode::F11, 0x67 => KeyCode::F11,
//0x68 => JIS Kanna (macOS), // 0x68 => JIS Kanna (macOS),
0x69 => KeyCode::F13, 0x69 => KeyCode::F13,
0x6a => KeyCode::F16, 0x6a => KeyCode::F16,
0x6b => KeyCode::F14, 0x6b => KeyCode::F14,
//0x6c => unknown, // 0x6c => unknown,
0x6d => KeyCode::F10, 0x6d => KeyCode::F10,
//0x6e => unknown, // 0x6e => unknown,
0x6f => KeyCode::F12, 0x6f => KeyCode::F12,
//0x70 => unknown, // 0x70 => unknown,
0x71 => KeyCode::F15, 0x71 => KeyCode::F15,
0x72 => KeyCode::Insert, 0x72 => KeyCode::Insert,
0x73 => KeyCode::Home, 0x73 => KeyCode::Home,
@ -666,7 +625,7 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0x7c => KeyCode::ArrowRight, 0x7c => KeyCode::ArrowRight,
0x7d => KeyCode::ArrowDown, 0x7d => KeyCode::ArrowDown,
0x7e => KeyCode::ArrowUp, 0x7e => KeyCode::ArrowUp,
//0x7f => unknown, // 0x7f => unknown,
// 0xA is the caret (^) an macOS's German QERTZ layout. This key is at the same location as // 0xA is the caret (^) an macOS's German QERTZ layout. This key is at the same location as
// backquote (`) on Windows' US layout. // backquote (`) on Windows' US layout.

View file

@ -1,6 +1,5 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt; use std::{fmt, mem};
use std::mem;
use super::app_delegate::HandlePendingUserEvents; use super::app_delegate::HandlePendingUserEvents;
use crate::event::Event; use crate::event::Event;
@ -53,13 +52,13 @@ impl EventHandler {
match self.inner.try_borrow_mut().as_deref_mut() { match self.inner.try_borrow_mut().as_deref_mut() {
Ok(Some(_)) => { Ok(Some(_)) => {
unreachable!("tried to set handler while another was already set"); unreachable!("tried to set handler while another was already set");
} },
Ok(data @ None) => { Ok(data @ None) => {
*data = Some(EventHandlerData { handler }); *data = Some(EventHandlerData { handler });
} },
Err(_) => { Err(_) => {
unreachable!("tried to set handler that is currently in use"); unreachable!("tried to set handler that is currently in use");
} },
} }
struct ClearOnDrop<'a>(&'a EventHandler); struct ClearOnDrop<'a>(&'a EventHandler);
@ -69,10 +68,10 @@ impl EventHandler {
match self.0.inner.try_borrow_mut().as_deref_mut() { match self.0.inner.try_borrow_mut().as_deref_mut() {
Ok(data @ Some(_)) => { Ok(data @ Some(_)) => {
*data = None; *data = None;
} },
Ok(None) => { Ok(None) => {
tracing::error!("tried to clear handler, but no handler was set"); tracing::error!("tried to clear handler, but no handler was set");
} },
Err(_) => { Err(_) => {
// Note: This is not expected to ever happen, this // Note: This is not expected to ever happen, this
// module generally controls the `RefCell`, and // module generally controls the `RefCell`, and
@ -83,7 +82,7 @@ impl EventHandler {
// weren't able to unset the handler. // weren't able to unset the handler.
eprintln!("tried to clear handler that is currently in use"); eprintln!("tried to clear handler that is currently in use");
std::process::abort(); std::process::abort();
} },
} }
} }
} }
@ -120,17 +119,17 @@ impl EventHandler {
// If the handler unwinds, the `RefMut` will ensure that the // If the handler unwinds, the `RefMut` will ensure that the
// handler is no longer borrowed. // handler is no longer borrowed.
(handler)(event, event_loop); (handler)(event, event_loop);
} },
Ok(None) => { Ok(None) => {
// `NSApplication`, our app delegate and this handler are all // `NSApplication`, our app delegate and this handler are all
// global state and so it's not impossible that we could get // global state and so it's not impossible that we could get
// an event after the application has exited the `EventLoop`. // an event after the application has exited the `EventLoop`.
tracing::error!("tried to run event handler, but no handler was set"); tracing::error!("tried to run event handler, but no handler was set");
} },
Err(_) => { Err(_) => {
// Prevent re-entrancy. // Prevent re-entrancy.
panic!("tried to handle event while another event is currently being handled"); panic!("tried to handle event while another event is currently being handled");
} },
} }
} }
} }

View file

@ -1,44 +1,39 @@
use std::{ use std::any::Any;
any::Any, use std::cell::Cell;
cell::Cell, use std::collections::VecDeque;
collections::VecDeque, use std::marker::PhantomData;
marker::PhantomData, use std::os::raw::c_void;
os::raw::c_void, use std::panic::{catch_unwind, resume_unwind, RefUnwindSafe, UnwindSafe};
panic::{catch_unwind, resume_unwind, RefUnwindSafe, UnwindSafe}, use std::ptr;
ptr, use std::rc::{Rc, Weak};
rc::{Rc, Weak}, use std::sync::mpsc;
sync::mpsc, use std::time::{Duration, Instant};
time::{Duration, Instant},
};
use core_foundation::base::{CFIndex, CFRelease}; use core_foundation::base::{CFIndex, CFRelease};
use core_foundation::runloop::{ use core_foundation::runloop::{
kCFRunLoopCommonModes, CFRunLoopAddSource, CFRunLoopGetMain, CFRunLoopSourceContext, kCFRunLoopCommonModes, CFRunLoopAddSource, CFRunLoopGetMain, CFRunLoopSourceContext,
CFRunLoopSourceCreate, CFRunLoopSourceRef, CFRunLoopSourceSignal, CFRunLoopWakeUp, CFRunLoopSourceCreate, CFRunLoopSourceRef, CFRunLoopSourceSignal, CFRunLoopWakeUp,
}; };
use objc2::rc::{autoreleasepool, Id};
use objc2::runtime::ProtocolObject;
use objc2::{msg_send_id, ClassType}; use objc2::{msg_send_id, ClassType};
use objc2::{
rc::{autoreleasepool, Id},
runtime::ProtocolObject,
};
use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSWindow}; use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSWindow};
use objc2_foundation::{MainThreadMarker, NSObjectProtocol}; use objc2_foundation::{MainThreadMarker, NSObjectProtocol};
use super::app::WinitApplication;
use super::app_delegate::{ApplicationDelegate, HandlePendingUserEvents};
use super::event::dummy_event; use super::event::dummy_event;
use super::{ use super::monitor::{self, MonitorHandle};
app::WinitApplication, use super::observer::setup_control_flow_observers;
app_delegate::{ApplicationDelegate, HandlePendingUserEvents}, use crate::error::EventLoopError;
monitor::{self, MonitorHandle}, use crate::event::Event;
observer::setup_control_flow_observers, use crate::event_loop::{
ActiveEventLoop as RootWindowTarget, ControlFlow, DeviceEvents, EventLoopClosed,
}; };
use crate::platform::macos::ActivationPolicy;
use crate::platform::pump_events::PumpStatus;
use crate::platform_impl::platform::cursor::CustomCursor; use crate::platform_impl::platform::cursor::CustomCursor;
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource}; use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource};
use crate::{
error::EventLoopError,
event::Event,
event_loop::{ActiveEventLoop as RootWindowTarget, ControlFlow, DeviceEvents, EventLoopClosed},
platform::{macos::ActivationPolicy, pump_events::PumpStatus},
};
#[derive(Default)] #[derive(Default)]
pub struct PanicInfo { pub struct PanicInfo {
@ -57,12 +52,14 @@ impl PanicInfo {
self.inner.set(inner); self.inner.set(inner);
result result
} }
/// Overwrites the curret state if the current state is not panicking /// Overwrites the curret state if the current state is not panicking
pub fn set_panic(&self, p: Box<dyn Any + Send + 'static>) { pub fn set_panic(&self, p: Box<dyn Any + Send + 'static>) {
if !self.is_panicking() { if !self.is_panicking() {
self.inner.set(Some(p)); self.inner.set(Some(p));
} }
} }
pub fn take(&self) -> Option<Box<dyn Any + Send + 'static>> { pub fn take(&self) -> Option<Box<dyn Any + Send + 'static>> {
self.inner.take() self.inner.take()
} }
@ -78,16 +75,11 @@ impl ActiveEventLoop {
pub(super) fn new_root(delegate: Id<ApplicationDelegate>) -> RootWindowTarget { pub(super) fn new_root(delegate: Id<ApplicationDelegate>) -> RootWindowTarget {
let mtm = MainThreadMarker::from(&*delegate); let mtm = MainThreadMarker::from(&*delegate);
let p = Self { delegate, mtm }; let p = Self { delegate, mtm };
RootWindowTarget { RootWindowTarget { p, _marker: PhantomData }
p,
_marker: PhantomData,
}
} }
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor { pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
RootCustomCursor { RootCustomCursor { inner: CustomCursor::new(source.inner) }
inner: CustomCursor::new(source.inner),
}
} }
#[inline] #[inline]
@ -115,9 +107,7 @@ impl ActiveEventLoop {
pub fn raw_display_handle_rwh_06( pub fn raw_display_handle_rwh_06(
&self, &self,
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> { ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
Ok(rwh_06::RawDisplayHandle::AppKit( Ok(rwh_06::RawDisplayHandle::AppKit(rwh_06::AppKitDisplayHandle::new()))
rwh_06::AppKitDisplayHandle::new(),
))
} }
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) { pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
@ -173,7 +163,7 @@ fn map_user_event<T: 'static>(
for event in receiver.try_iter() { for event in receiver.try_iter() {
(handler)(Event::UserEvent(event), window_target); (handler)(Event::UserEvent(event), window_target);
} }
} },
} }
} }
@ -225,7 +215,10 @@ impl<T> EventLoop<T> {
unsafe { msg_send_id![WinitApplication::class(), sharedApplication] }; unsafe { msg_send_id![WinitApplication::class(), sharedApplication] };
if !app.is_kind_of::<WinitApplication>() { if !app.is_kind_of::<WinitApplication>() {
panic!("`winit` requires control over the principal class. You must create the event loop before other parts of your application initialize NSApplication"); panic!(
"`winit` requires control over the principal class. You must create the event \
loop before other parts of your application initialize NSApplication"
);
} }
let activation_policy = match attributes.activation_policy { let activation_policy = match attributes.activation_policy {
@ -323,8 +316,8 @@ impl<T> EventLoop<T> {
self.delegate.set_event_handler(handler, || { self.delegate.set_event_handler(handler, || {
autoreleasepool(|_| { autoreleasepool(|_| {
// As a special case, if the application hasn't been launched yet then we at least run // As a special case, if the application hasn't been launched yet then we at least
// the loop until it has fully launched. // run the loop until it has fully launched.
if !self.delegate.is_launched() { if !self.delegate.is_launched() {
debug_assert!(!self.delegate.is_running()); debug_assert!(!self.delegate.is_running());
@ -332,31 +325,34 @@ impl<T> EventLoop<T> {
// SAFETY: We do not run the application re-entrantly // SAFETY: We do not run the application re-entrantly
unsafe { self.app.run() }; unsafe { self.app.run() };
// Note: we dispatch `NewEvents(Init)` + `Resumed` events after the application has launched // Note: we dispatch `NewEvents(Init)` + `Resumed` events after the application
// has launched
} else if !self.delegate.is_running() { } else if !self.delegate.is_running() {
// Even though the application may have been launched, it's possible we aren't running // Even though the application may have been launched, it's possible we aren't
// if the `EventLoop` was run before and has since exited. This indicates that // running if the `EventLoop` was run before and has since
// we just starting to re-run the same `EventLoop` again. // exited. This indicates that we just starting to re-run
// the same `EventLoop` again.
self.delegate.set_is_running(true); self.delegate.set_is_running(true);
self.delegate.dispatch_init_events(); self.delegate.dispatch_init_events();
} else { } else {
// Only run for as long as the given `Duration` allows so we don't block the external loop. // Only run for as long as the given `Duration` allows so we don't block the
// external loop.
match timeout { match timeout {
Some(Duration::ZERO) => { Some(Duration::ZERO) => {
self.delegate.set_wait_timeout(None); self.delegate.set_wait_timeout(None);
self.delegate.set_stop_before_wait(true); self.delegate.set_stop_before_wait(true);
} },
Some(duration) => { Some(duration) => {
self.delegate.set_stop_before_wait(false); self.delegate.set_stop_before_wait(false);
let timeout = Instant::now() + duration; let timeout = Instant::now() + duration;
self.delegate.set_wait_timeout(Some(timeout)); self.delegate.set_wait_timeout(Some(timeout));
self.delegate.set_stop_after_wait(true); self.delegate.set_stop_after_wait(true);
} },
None => { None => {
self.delegate.set_wait_timeout(None); self.delegate.set_wait_timeout(None);
self.delegate.set_stop_before_wait(false); self.delegate.set_stop_before_wait(false);
self.delegate.set_stop_after_wait(true); self.delegate.set_stop_after_wait(true);
} },
} }
self.delegate.set_stop_on_redraw(true); self.delegate.set_stop_on_redraw(true);
// SAFETY: We do not run the application re-entrantly // SAFETY: We do not run the application re-entrantly
@ -437,7 +433,7 @@ pub fn stop_app_on_panic<F: FnOnce() -> R + UnwindSafe, R>(
let app = NSApplication::sharedApplication(mtm); let app = NSApplication::sharedApplication(mtm);
stop_app_immediately(&app); stop_app_immediately(&app);
None None
} },
} }
} }
@ -494,9 +490,7 @@ impl<T> EventLoopProxy<T> {
} }
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
self.sender self.sender.send(event).map_err(|mpsc::SendError(x)| EventLoopClosed(x))?;
.send(event)
.map_err(|mpsc::SendError(x)| EventLoopClosed(x))?;
unsafe { unsafe {
// let the main thread know there's a new event // let the main thread know there's a new event
CFRunLoopSourceSignal(self.source); CFRunLoopSourceSignal(self.source);

View file

@ -4,14 +4,14 @@
use std::ffi::c_void; use std::ffi::c_void;
use core_foundation::{ use core_foundation::array::CFArrayRef;
array::CFArrayRef, dictionary::CFDictionaryRef, string::CFStringRef, uuid::CFUUIDRef, use core_foundation::dictionary::CFDictionaryRef;
}; use core_foundation::string::CFStringRef;
use core_graphics::{ use core_foundation::uuid::CFUUIDRef;
base::CGError, use core_graphics::base::CGError;
display::{CGDirectDisplayID, CGDisplayConfigRef}, use core_graphics::display::{CGDirectDisplayID, CGDisplayConfigRef};
}; use objc2::ffi::NSInteger;
use objc2::{ffi::NSInteger, runtime::AnyObject}; use objc2::runtime::AnyObject;
pub type CGDisplayFadeInterval = f32; pub type CGDisplayFadeInterval = f32;
pub type CGDisplayReservationInterval = f32; pub type CGDisplayReservationInterval = f32;

View file

@ -20,12 +20,8 @@ pub fn initialize(app: &NSApplication) {
// About menu item // About menu item
let about_item_title = ns_string!("About ").stringByAppendingString(&process_name); let about_item_title = ns_string!("About ").stringByAppendingString(&process_name);
let about_item = menu_item( let about_item =
mtm, menu_item(mtm, &about_item_title, Some(sel!(orderFrontStandardAboutPanel:)), None);
&about_item_title,
Some(sel!(orderFrontStandardAboutPanel:)),
None,
);
// Services menu item // Services menu item
let services_menu = NSMenu::new(mtm); let services_menu = NSMenu::new(mtm);
@ -41,10 +37,7 @@ pub fn initialize(app: &NSApplication) {
mtm, mtm,
&hide_item_title, &hide_item_title,
Some(sel!(hide:)), Some(sel!(hide:)),
Some(KeyEquivalent { Some(KeyEquivalent { key: ns_string!("h"), masks: None }),
key: ns_string!("h"),
masks: None,
}),
); );
// Hide other applications menu item // Hide other applications menu item
@ -64,12 +57,8 @@ pub fn initialize(app: &NSApplication) {
// Show applications menu item // Show applications menu item
let show_all_item_title = ns_string!("Show All"); let show_all_item_title = ns_string!("Show All");
let show_all_item = menu_item( let show_all_item =
mtm, menu_item(mtm, show_all_item_title, Some(sel!(unhideAllApplications:)), None);
show_all_item_title,
Some(sel!(unhideAllApplications:)),
None,
);
// Separator menu item // Separator menu item
let sep = NSMenuItem::separatorItem(mtm); let sep = NSMenuItem::separatorItem(mtm);
@ -80,10 +69,7 @@ pub fn initialize(app: &NSApplication) {
mtm, mtm,
&quit_item_title, &quit_item_title,
Some(sel!(terminate:)), Some(sel!(terminate:)),
Some(KeyEquivalent { Some(KeyEquivalent { key: ns_string!("q"), masks: None }),
key: ns_string!("q"),
masks: None,
}),
); );
app_menu.addItem(&about_item); app_menu.addItem(&about_item);

View file

@ -17,16 +17,14 @@ mod window_delegate;
use std::fmt; use std::fmt;
pub(crate) use self::{ pub(crate) use self::event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra};
event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra}, pub(crate) use self::event_loop::{
event_loop::{ ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes,
PlatformSpecificEventLoopAttributes,
},
monitor::{MonitorHandle, VideoModeHandle},
window::WindowId,
window_delegate::PlatformSpecificWindowAttributes,
}; };
pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
pub(crate) use self::window::WindowId;
pub(crate) use self::window_delegate::PlatformSpecificWindowAttributes;
use crate::event::DeviceId as RootDeviceId; use crate::event::DeviceId as RootDeviceId;
pub(crate) use self::cursor::CustomCursor as PlatformCustomCursor; pub(crate) use self::cursor::CustomCursor as PlatformCustomCursor;

View file

@ -1,16 +1,16 @@
#![allow(clippy::unnecessary_cast)] #![allow(clippy::unnecessary_cast)]
use std::{collections::VecDeque, fmt}; use std::collections::VecDeque;
use std::fmt;
use core_foundation::{ use core_foundation::array::{CFArrayGetCount, CFArrayGetValueAtIndex};
array::{CFArrayGetCount, CFArrayGetValueAtIndex}, use core_foundation::base::{CFRelease, TCFType};
base::{CFRelease, TCFType}, use core_foundation::string::CFString;
string::CFString,
};
use core_graphics::display::{ use core_graphics::display::{
CGDirectDisplayID, CGDisplay, CGDisplayBounds, CGDisplayCopyDisplayMode, CGDirectDisplayID, CGDisplay, CGDisplayBounds, CGDisplayCopyDisplayMode,
}; };
use objc2::{rc::Id, runtime::AnyObject}; use objc2::rc::Id;
use objc2::runtime::AnyObject;
use objc2_app_kit::NSScreen; use objc2_app_kit::NSScreen;
use objc2_foundation::{ns_string, run_on_main, MainThreadMarker, NSNumber, NSPoint, NSRect}; use objc2_foundation::{ns_string, run_on_main, MainThreadMarker, NSNumber, NSPoint, NSRect};
@ -233,9 +233,7 @@ impl MonitorHandle {
return None; return None;
} }
(time.time_scale as i64) (time.time_scale as i64).checked_div(time.time_value).map(|v| (v * 1000) as u32)
.checked_div(time.time_value)
.map(|v| (v * 1000) as u32)
} }
} }

Some files were not shown because too many files have changed in this diff Show more