mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 22:53:15 -04:00
Compare commits
20 Commits
split-exam
...
dpi_v0.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06f4e28de9 | ||
|
|
249d5d8bff | ||
|
|
66df2c22ba | ||
|
|
359a38844b | ||
|
|
563b0bf5e3 | ||
|
|
b2f9fad654 | ||
|
|
4ade1a7518 | ||
|
|
e06ecf4d72 | ||
|
|
4a8050289d | ||
|
|
99e238065e | ||
|
|
d123cd2f8e | ||
|
|
fc8a008b25 | ||
|
|
f6f1c45a72 | ||
|
|
388c40b1e0 | ||
|
|
7a40aa43dc | ||
|
|
944347696a | ||
|
|
96172693fe | ||
|
|
32004405ee | ||
|
|
22e932b5ab | ||
|
|
3d4c53459a |
25
.github/workflows/ci.yml
vendored
25
.github/workflows/ci.yml
vendored
@@ -17,6 +17,24 @@ jobs:
|
|||||||
- name: Check Formatting
|
- name: Check Formatting
|
||||||
run: cargo fmt -- --check
|
run: cargo fmt -- --check
|
||||||
|
|
||||||
|
typos:
|
||||||
|
name: Check for typos
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: taiki-e/install-action@v2
|
||||||
|
with:
|
||||||
|
tool: typos-cli
|
||||||
|
- name: run typos
|
||||||
|
run: typos
|
||||||
|
- name: Typos info
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo 'To fix typos, please run `typos -w`'
|
||||||
|
echo 'To check for a diff, run `typos`'
|
||||||
|
echo 'You can find typos here: https://crates.io/crates/typos'
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
name: Test ${{ matrix.toolchain }} ${{ matrix.platform.name }}
|
name: Test ${{ matrix.toolchain }} ${{ matrix.platform.name }}
|
||||||
runs-on: ${{ matrix.platform.os }}
|
runs-on: ${{ matrix.platform.os }}
|
||||||
@@ -127,6 +145,13 @@ jobs:
|
|||||||
- name: Build crate
|
- name: Build crate
|
||||||
run: cargo $CMD build $OPTIONS
|
run: cargo $CMD build $OPTIONS
|
||||||
|
|
||||||
|
# Test only on Linux x86_64, so we avoid spending unnecessary CI hours.
|
||||||
|
- name: Test dpi crate
|
||||||
|
if: >
|
||||||
|
contains(matrix.platform.name, 'Linux 64bit') &&
|
||||||
|
matrix.toolchain != '1.70.0'
|
||||||
|
run: cargo test -p dpi
|
||||||
|
|
||||||
- name: Build tests
|
- name: Build tests
|
||||||
if: >
|
if: >
|
||||||
!contains(matrix.platform.target, 'redox') &&
|
!contains(matrix.platform.target, 'redox') &&
|
||||||
|
|||||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -11,6 +11,10 @@ Unreleased` header.
|
|||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Deprecate `EventLoop::run` in favor of `EventLoop::run_app`.
|
||||||
|
- Deprecate `EventLoopExtRunOnDemand::run_on_demand` in favor of `EventLoop::run_app_on_demand`.
|
||||||
|
- Deprecate `EventLoopExtPumpEvents::pump_events` in favor of `EventLoopExtPumpEvents::pump_app_events`.
|
||||||
|
- Add `ApplicationHandler<T>` trait which mimics `Event<T>`.
|
||||||
- Move `dpi` types to its own crate, and re-export it from the root crate.
|
- Move `dpi` types to its own crate, and re-export it from the root crate.
|
||||||
- Implement `Sync` for `EventLoopProxy<T: Send>`.
|
- Implement `Sync` for `EventLoopProxy<T: Send>`.
|
||||||
- **Breaking:** Move `Window::new` to `ActiveEventLoop::create_window` and `EventLoop::create_window` (with the latter being deprecated).
|
- **Breaking:** Move `Window::new` to `ActiveEventLoop::create_window` and `EventLoop::create_window` (with the latter being deprecated).
|
||||||
@@ -46,6 +50,23 @@ Unreleased` header.
|
|||||||
- **Breaking:** Changed the signature of `EventLoop::with_user_event` to return a builder.
|
- **Breaking:** Changed the signature of `EventLoop::with_user_event` to return a builder.
|
||||||
- **Breaking:** Removed `EventLoopBuilder::with_user_event`, the functionality is now available in `EventLoop::with_user_event`.
|
- **Breaking:** Removed `EventLoopBuilder::with_user_event`, the functionality is now available in `EventLoop::with_user_event`.
|
||||||
- Add `Window::default_attributes` to get default `WindowAttributes`.
|
- Add `Window::default_attributes` to get default `WindowAttributes`.
|
||||||
|
- `log` has been replaced with `tracing`. The old behavior can be emulated by setting the `log` feature on the `tracing` crate.
|
||||||
|
- On X11, fix crash due to xsettings query on systems with incomplete xsettings.
|
||||||
|
|
||||||
|
# 0.29.14
|
||||||
|
|
||||||
|
- On X11/Wayland, fix `text` and `text_with_all_modifiers` not being `None` during compose.
|
||||||
|
- On Wayland, don't reapply cursor grab when unchanged.
|
||||||
|
- On X11, fix a bug where some mouse events would be unexpectedly filtered out.
|
||||||
|
|
||||||
|
# 0.29.13
|
||||||
|
|
||||||
|
- On Web, fix possible crash with `ControlFlow::Wait` and `ControlFlow::WaitUntil`.
|
||||||
|
|
||||||
|
# 0.29.12
|
||||||
|
|
||||||
|
- On X11, fix use after free during xinput2 handling.
|
||||||
|
- On X11, filter close to zero values in mouse device events
|
||||||
|
|
||||||
# 0.29.11
|
# 0.29.11
|
||||||
|
|
||||||
|
|||||||
6
CODE_OF_CONDUCT.md
Normal file
6
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Code of Conduct
|
||||||
|
|
||||||
|
The `rust-windowing` project adheres to the [Rust Code of Conduct]. This
|
||||||
|
describes the minimum behavior expected from all contributors.
|
||||||
|
|
||||||
|
[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
version = "0.29.11"
|
version = "0.29.14"
|
||||||
authors = ["The winit contributors", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
authors = ["The winit contributors", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
||||||
description = "Cross-platform window creation library."
|
description = "Cross-platform window creation library."
|
||||||
keywords = ["windowing"]
|
keywords = ["windowing"]
|
||||||
@@ -64,17 +64,18 @@ cfg_aliases = "0.2.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "2"
|
bitflags = "2"
|
||||||
cursor-icon = "1.1.0"
|
cursor-icon = "1.1.0"
|
||||||
log = "0.4"
|
|
||||||
rwh_04 = { package = "raw-window-handle", version = "0.4", optional = true }
|
rwh_04 = { package = "raw-window-handle", version = "0.4", optional = true }
|
||||||
rwh_05 = { package = "raw-window-handle", version = "0.5.2", features = ["std"], optional = true }
|
rwh_05 = { package = "raw-window-handle", version = "0.5.2", features = ["std"], optional = true }
|
||||||
rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"], optional = true }
|
rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"], optional = true }
|
||||||
serde = { workspace = true, optional = true }
|
serde = { workspace = true, optional = true }
|
||||||
smol_str = "0.2.0"
|
smol_str = "0.2.0"
|
||||||
dpi = { path = "dpi" }
|
dpi = { path = "dpi" }
|
||||||
|
tracing = { version = "0.1.40", default_features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
image = { version = "0.24.0", default-features = false, features = ["png"] }
|
image = { version = "0.24.0", default-features = false, features = ["png"] }
|
||||||
simple_logger = { version = "4.2.0", default_features = false }
|
tracing = { version = "0.1.40", default_features = false, features = ["log"] }
|
||||||
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
winit = { path = ".", features = ["rwh_05"] }
|
winit = { path = ".", features = ["rwh_05"] }
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dev-dependencies]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dev-dependencies]
|
||||||
@@ -187,7 +188,7 @@ wayland-backend = { version = "0.3.0", default_features = false, features = ["cl
|
|||||||
wayland-client = { version = "0.31.1", optional = true }
|
wayland-client = { version = "0.31.1", optional = true }
|
||||||
wayland-protocols = { version = "0.31.0", features = [ "staging"], optional = true }
|
wayland-protocols = { version = "0.31.0", features = [ "staging"], optional = true }
|
||||||
wayland-protocols-plasma = { version = "0.2.0", features = [ "client" ], optional = true }
|
wayland-protocols-plasma = { version = "0.2.0", features = [ "client" ], optional = true }
|
||||||
x11-dl = { version = "2.18.5", optional = true }
|
x11-dl = { version = "2.19.1", optional = true }
|
||||||
x11rb = { version = "0.13.0", default-features = false, features = ["allow-unsafe-code", "dl-libxcb", "randr", "resource_manager", "xinput", "xkb"], optional = true }
|
x11rb = { version = "0.13.0", default-features = false, features = ["allow-unsafe-code", "dl-libxcb", "randr", "resource_manager", "xinput", "xkb"], optional = true }
|
||||||
xkbcommon-dl = "0.4.2"
|
xkbcommon-dl = "0.4.2"
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
winit = "0.29.11"
|
winit = "0.29.14"
|
||||||
```
|
```
|
||||||
|
|
||||||
## [Documentation](https://docs.rs/winit)
|
## [Documentation](https://docs.rs/winit)
|
||||||
|
|||||||
16
dpi/CHANGELOG.md
Normal file
16
dpi/CHANGELOG.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
Please keep one empty line before and after all headers. (This is required for
|
||||||
|
`git` to produce a conflict when a release is made while a PR is open and the
|
||||||
|
PR's changelog entry would go into the wrong section).
|
||||||
|
|
||||||
|
And please only add new entries to the top of this list, right below the `#
|
||||||
|
Unreleased` header.
|
||||||
|
|
||||||
|
# Unreleased
|
||||||
|
|
||||||
|
# 0.1.0
|
||||||
|
|
||||||
|
- Add `LogicalUnit`, `PhysicalUnit` and `PixelUnit` types and related functions.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "dpi"
|
name = "dpi"
|
||||||
version = "0.0.0"
|
version = "0.1.0"
|
||||||
description = "Types for handling UI scaling"
|
description = "Types for handling UI scaling"
|
||||||
keywords = ["DPI", "HiDPI", "scale-factor"]
|
keywords = ["DPI", "HiDPI", "scale-factor"]
|
||||||
categories = ["gui"]
|
categories = ["gui"]
|
||||||
|
|||||||
273
dpi/src/lib.rs
273
dpi/src/lib.rs
@@ -35,8 +35,8 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Position and Size types
|
//! ### Position and Size types
|
||||||
//!
|
//!
|
||||||
//! The [`PhysicalPosition`] / [`PhysicalSize`] types correspond with the actual pixels on the
|
//! The [`PhysicalPosition`] / [`PhysicalSize`] / [`PhysicalUnit`] types correspond with the actual pixels on the
|
||||||
//! device, and the [`LogicalPosition`] / [`LogicalSize`] types correspond to the physical pixels
|
//! device, and the [`LogicalPosition`] / [`LogicalSize`] / [`LogicalUnit`] types correspond to the physical pixels
|
||||||
//! divided by the scale factor.
|
//! 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
|
||||||
@@ -128,6 +128,238 @@ 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A logical pixel unit.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub struct LogicalUnit<P>(pub P);
|
||||||
|
|
||||||
|
impl<P> LogicalUnit<P> {
|
||||||
|
/// Represents a minimum logical unit of [`f64::MAX`].
|
||||||
|
pub const MIN: LogicalUnit<f64> = LogicalUnit::new(f64::MIN);
|
||||||
|
/// Represents a logical unit of `0_f64`.
|
||||||
|
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]
|
||||||
|
pub const fn new(v: P) -> Self {
|
||||||
|
LogicalUnit(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> LogicalUnit<P> {
|
||||||
|
#[inline]
|
||||||
|
pub fn from_physical<T: Into<PhysicalUnit<X>>, X: Pixel>(
|
||||||
|
physical: T,
|
||||||
|
scale_factor: f64,
|
||||||
|
) -> Self {
|
||||||
|
physical.into().to_logical(scale_factor)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalUnit<X> {
|
||||||
|
assert!(validate_scale_factor(scale_factor));
|
||||||
|
PhysicalUnit::new(self.0.into() * scale_factor).cast()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cast<X: Pixel>(&self) -> LogicalUnit<X> {
|
||||||
|
LogicalUnit(self.0.cast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel, X: Pixel> From<X> for LogicalUnit<P> {
|
||||||
|
fn from(v: X) -> LogicalUnit<P> {
|
||||||
|
LogicalUnit::new(v.cast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for u8 {
|
||||||
|
fn from(v: LogicalUnit<P>) -> u8 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for u16 {
|
||||||
|
fn from(v: LogicalUnit<P>) -> u16 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for u32 {
|
||||||
|
fn from(v: LogicalUnit<P>) -> u32 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for i8 {
|
||||||
|
fn from(v: LogicalUnit<P>) -> i8 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for i16 {
|
||||||
|
fn from(v: LogicalUnit<P>) -> i16 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for i32 {
|
||||||
|
fn from(v: LogicalUnit<P>) -> i32 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for f32 {
|
||||||
|
fn from(v: LogicalUnit<P>) -> f32 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for f64 {
|
||||||
|
fn from(v: LogicalUnit<P>) -> f64 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A physical pixel unit.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub struct PhysicalUnit<P>(pub P);
|
||||||
|
|
||||||
|
impl<P> PhysicalUnit<P> {
|
||||||
|
/// Represents a minimum physical unit of [`f64::MAX`].
|
||||||
|
pub const MIN: LogicalUnit<f64> = LogicalUnit::new(f64::MIN);
|
||||||
|
/// Represents a physical unit of `0_f64`.
|
||||||
|
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]
|
||||||
|
pub const fn new(v: P) -> Self {
|
||||||
|
PhysicalUnit(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> PhysicalUnit<P> {
|
||||||
|
#[inline]
|
||||||
|
pub fn from_logical<T: Into<LogicalUnit<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self {
|
||||||
|
logical.into().to_physical(scale_factor)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalUnit<X> {
|
||||||
|
assert!(validate_scale_factor(scale_factor));
|
||||||
|
LogicalUnit::new(self.0.into() / scale_factor).cast()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cast<X: Pixel>(&self) -> PhysicalUnit<X> {
|
||||||
|
PhysicalUnit(self.0.cast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel, X: Pixel> From<X> for PhysicalUnit<P> {
|
||||||
|
fn from(v: X) -> PhysicalUnit<P> {
|
||||||
|
PhysicalUnit::new(v.cast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for u8 {
|
||||||
|
fn from(v: PhysicalUnit<P>) -> u8 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for u16 {
|
||||||
|
fn from(v: PhysicalUnit<P>) -> u16 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for u32 {
|
||||||
|
fn from(v: PhysicalUnit<P>) -> u32 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for i8 {
|
||||||
|
fn from(v: PhysicalUnit<P>) -> i8 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for i16 {
|
||||||
|
fn from(v: PhysicalUnit<P>) -> i16 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for i32 {
|
||||||
|
fn from(v: PhysicalUnit<P>) -> i32 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for f32 {
|
||||||
|
fn from(v: PhysicalUnit<P>) -> f32 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for f64 {
|
||||||
|
fn from(v: PhysicalUnit<P>) -> f64 {
|
||||||
|
v.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A pixel unit that's either physical or logical.
|
||||||
|
pub enum PixelUnit {
|
||||||
|
Physical(PhysicalUnit<i32>),
|
||||||
|
Logical(LogicalUnit<f64>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PixelUnit {
|
||||||
|
/// Represents a minimum logical unit of [`f64::MAX`].
|
||||||
|
pub const MIN: PixelUnit = PixelUnit::Logical(LogicalUnit::new(f64::MIN));
|
||||||
|
/// Represents a logical unit of `0_f64`.
|
||||||
|
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 {
|
||||||
|
unit.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalUnit<P> {
|
||||||
|
match *self {
|
||||||
|
PixelUnit::Physical(unit) => unit.to_logical(scale_factor),
|
||||||
|
PixelUnit::Logical(unit) => unit.cast(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalUnit<P> {
|
||||||
|
match *self {
|
||||||
|
PixelUnit::Physical(unit) => unit.cast(),
|
||||||
|
PixelUnit::Logical(unit) => unit.to_physical(scale_factor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<PhysicalUnit<P>> for PixelUnit {
|
||||||
|
#[inline]
|
||||||
|
fn from(unit: PhysicalUnit<P>) -> PixelUnit {
|
||||||
|
PixelUnit::Physical(unit.cast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pixel> From<LogicalUnit<P>> for PixelUnit {
|
||||||
|
#[inline]
|
||||||
|
fn from(unit: LogicalUnit<P>) -> PixelUnit {
|
||||||
|
PixelUnit::Logical(unit.cast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A position represented in logical pixels.
|
/// A position represented in logical pixels.
|
||||||
///
|
///
|
||||||
/// The position is stored as floats, so please be careful. Casting floats to integers truncates the
|
/// The position is stored as floats, so please be careful. Casting floats to integers truncates the
|
||||||
@@ -730,6 +962,43 @@ mod tests {
|
|||||||
assert!(!validate_scale_factor(f64::NEG_INFINITY));
|
assert!(!validate_scale_factor(f64::NEG_INFINITY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_logical_unity() {
|
||||||
|
let log_unit = LogicalUnit::new(1.0);
|
||||||
|
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.cast::<u32>(), LogicalUnit::new(1));
|
||||||
|
assert_eq!(
|
||||||
|
log_unit,
|
||||||
|
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));
|
||||||
|
|
||||||
|
let x: f64 = log_unit.into();
|
||||||
|
assert_eq!(x, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_physical_unit() {
|
||||||
|
assert_eq!(
|
||||||
|
PhysicalUnit::from_logical(LogicalUnit::new(1.0), 1.0),
|
||||||
|
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));
|
||||||
|
|
||||||
|
let x: f64 = PhysicalUnit::new(1).into();
|
||||||
|
assert_eq!(x, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_logical_position() {
|
fn test_logical_position() {
|
||||||
let log_pos = LogicalPosition::new(1.0, 2.0);
|
let log_pos = LogicalPosition::new(1.0, 2.0);
|
||||||
|
|||||||
@@ -3,32 +3,32 @@
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
#[cfg(not(web_platform))]
|
#[cfg(not(web_platform))]
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
#[cfg(web_platform)]
|
#[cfg(web_platform)]
|
||||||
use web_time as time;
|
use web_time as time;
|
||||||
|
|
||||||
use simple_logger::SimpleLogger;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::{
|
use winit::event::{ElementState, KeyEvent, StartCause, WindowEvent};
|
||||||
event::{ElementState, Event, KeyEvent, WindowEvent},
|
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
|
||||||
event_loop::{ControlFlow, EventLoop},
|
use winit::keyboard::{Key, NamedKey};
|
||||||
keyboard::{Key, NamedKey},
|
use winit::window::{Window, WindowId};
|
||||||
window::Window,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[path = "util/fill.rs"]
|
#[path = "util/fill.rs"]
|
||||||
mod fill;
|
mod fill;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
const WAIT_TIME: time::Duration = time::Duration::from_millis(100);
|
||||||
|
const POLL_SLEEP_TIME: time::Duration = time::Duration::from_millis(100);
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum Mode {
|
enum Mode {
|
||||||
|
#[default]
|
||||||
Wait,
|
Wait,
|
||||||
WaitUntil,
|
WaitUntil,
|
||||||
Poll,
|
Poll,
|
||||||
}
|
}
|
||||||
|
|
||||||
const WAIT_TIME: time::Duration = time::Duration::from_millis(100);
|
|
||||||
const POLL_SLEEP_TIME: time::Duration = time::Duration::from_millis(100);
|
|
||||||
|
|
||||||
fn main() -> Result<(), impl std::error::Error> {
|
fn main() -> Result<(), impl std::error::Error> {
|
||||||
SimpleLogger::new().init().unwrap();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
println!("Press '1' to switch to Wait mode.");
|
println!("Press '1' to switch to Wait mode.");
|
||||||
println!("Press '2' to switch to WaitUntil mode.");
|
println!("Press '2' to switch to WaitUntil mode.");
|
||||||
@@ -38,96 +38,110 @@ fn main() -> Result<(), impl std::error::Error> {
|
|||||||
|
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let mut mode = Mode::Wait;
|
let mut app = ControlFlowDemo::default();
|
||||||
let mut request_redraw = false;
|
event_loop.run_app(&mut app)
|
||||||
let mut wait_cancelled = false;
|
}
|
||||||
let mut close_requested = false;
|
|
||||||
|
|
||||||
let mut window = None;
|
#[derive(Default)]
|
||||||
event_loop.run(move |event, event_loop| {
|
struct ControlFlowDemo {
|
||||||
use winit::event::StartCause;
|
mode: Mode,
|
||||||
|
request_redraw: bool,
|
||||||
|
wait_cancelled: bool,
|
||||||
|
close_requested: bool,
|
||||||
|
window: Option<Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler for ControlFlowDemo {
|
||||||
|
fn new_events(&mut self, _event_loop: &ActiveEventLoop, cause: StartCause) {
|
||||||
|
println!("new_events: {cause:?}");
|
||||||
|
|
||||||
|
self.wait_cancelled = match cause {
|
||||||
|
StartCause::WaitCancelled { .. } => self.mode == Mode::WaitUntil,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let window_attributes = Window::default_attributes().with_title(
|
||||||
|
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
|
||||||
|
);
|
||||||
|
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
_event_loop: &ActiveEventLoop,
|
||||||
|
_window_id: WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
println!("{event:?}");
|
println!("{event:?}");
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::NewEvents(start_cause) => {
|
WindowEvent::CloseRequested => {
|
||||||
wait_cancelled = match start_cause {
|
self.close_requested = true;
|
||||||
StartCause::WaitCancelled { .. } => mode == Mode::WaitUntil,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Event::Resumed => {
|
WindowEvent::KeyboardInput {
|
||||||
let window_attributes = Window::default_attributes().with_title(
|
event:
|
||||||
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
|
KeyEvent {
|
||||||
);
|
logical_key: key,
|
||||||
window = Some(event_loop.create_window(window_attributes).unwrap());
|
state: ElementState::Pressed,
|
||||||
}
|
..
|
||||||
Event::WindowEvent { event, .. } => match event {
|
},
|
||||||
WindowEvent::CloseRequested => {
|
..
|
||||||
close_requested = true;
|
} => match key.as_ref() {
|
||||||
|
// WARNING: Consider using `key_without_modifiers()` if available on your platform.
|
||||||
|
// See the `key_binding` example
|
||||||
|
Key::Character("1") => {
|
||||||
|
self.mode = Mode::Wait;
|
||||||
|
println!("\nmode: {:?}\n", self.mode);
|
||||||
}
|
}
|
||||||
WindowEvent::KeyboardInput {
|
Key::Character("2") => {
|
||||||
event:
|
self.mode = Mode::WaitUntil;
|
||||||
KeyEvent {
|
println!("\nmode: {:?}\n", self.mode);
|
||||||
logical_key: key,
|
}
|
||||||
state: ElementState::Pressed,
|
Key::Character("3") => {
|
||||||
..
|
self.mode = Mode::Poll;
|
||||||
},
|
println!("\nmode: {:?}\n", self.mode);
|
||||||
..
|
}
|
||||||
} => match key.as_ref() {
|
Key::Character("r") => {
|
||||||
// WARNING: Consider using `key_without_modifiers()` if available on your platform.
|
self.request_redraw = !self.request_redraw;
|
||||||
// See the `key_binding` example
|
println!("\nrequest_redraw: {}\n", self.request_redraw);
|
||||||
Key::Character("1") => {
|
}
|
||||||
mode = Mode::Wait;
|
Key::Named(NamedKey::Escape) => {
|
||||||
println!("\nmode: {mode:?}\n");
|
self.close_requested = true;
|
||||||
}
|
|
||||||
Key::Character("2") => {
|
|
||||||
mode = Mode::WaitUntil;
|
|
||||||
println!("\nmode: {mode:?}\n");
|
|
||||||
}
|
|
||||||
Key::Character("3") => {
|
|
||||||
mode = Mode::Poll;
|
|
||||||
println!("\nmode: {mode:?}\n");
|
|
||||||
}
|
|
||||||
Key::Character("r") => {
|
|
||||||
request_redraw = !request_redraw;
|
|
||||||
println!("\nrequest_redraw: {request_redraw}\n");
|
|
||||||
}
|
|
||||||
Key::Named(NamedKey::Escape) => {
|
|
||||||
close_requested = true;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
WindowEvent::RedrawRequested => {
|
|
||||||
let window = window.as_ref().unwrap();
|
|
||||||
window.pre_present_notify();
|
|
||||||
fill::fill_window(window);
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
Event::AboutToWait => {
|
WindowEvent::RedrawRequested => {
|
||||||
if request_redraw && !wait_cancelled && !close_requested {
|
let window = self.window.as_ref().unwrap();
|
||||||
window.as_ref().unwrap().request_redraw();
|
window.pre_present_notify();
|
||||||
}
|
fill::fill_window(window);
|
||||||
|
|
||||||
match mode {
|
|
||||||
Mode::Wait => event_loop.set_control_flow(ControlFlow::Wait),
|
|
||||||
Mode::WaitUntil => {
|
|
||||||
if !wait_cancelled {
|
|
||||||
event_loop.set_control_flow(ControlFlow::WaitUntil(
|
|
||||||
time::Instant::now() + WAIT_TIME,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Mode::Poll => {
|
|
||||||
thread::sleep(POLL_SLEEP_TIME);
|
|
||||||
event_loop.set_control_flow(ControlFlow::Poll);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if close_requested {
|
|
||||||
event_loop.exit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
if self.request_redraw && !self.wait_cancelled && !self.close_requested {
|
||||||
|
self.window.as_ref().unwrap().request_redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.mode {
|
||||||
|
Mode::Wait => event_loop.set_control_flow(ControlFlow::Wait),
|
||||||
|
Mode::WaitUntil => {
|
||||||
|
if !self.wait_cancelled {
|
||||||
|
event_loop
|
||||||
|
.set_control_flow(ControlFlow::WaitUntil(time::Instant::now() + WAIT_TIME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mode::Poll => {
|
||||||
|
thread::sleep(POLL_SLEEP_TIME);
|
||||||
|
event_loop.set_control_flow(ControlFlow::Poll);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.close_requested {
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,51 +11,59 @@
|
|||||||
fn main() -> std::process::ExitCode {
|
fn main() -> std::process::ExitCode {
|
||||||
use std::{process::ExitCode, thread::sleep, time::Duration};
|
use std::{process::ExitCode, thread::sleep, time::Duration};
|
||||||
|
|
||||||
use simple_logger::SimpleLogger;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::{
|
use winit::event::WindowEvent;
|
||||||
event::{Event, WindowEvent},
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
event_loop::EventLoop,
|
use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
|
||||||
platform::pump_events::{EventLoopExtPumpEvents, PumpStatus},
|
use winit::window::{Window, WindowId};
|
||||||
window::Window,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[path = "util/fill.rs"]
|
#[path = "util/fill.rs"]
|
||||||
mod fill;
|
mod fill;
|
||||||
|
|
||||||
let mut event_loop = EventLoop::new().unwrap();
|
#[derive(Default)]
|
||||||
|
struct PumpDemo {
|
||||||
|
window: Option<Window>,
|
||||||
|
}
|
||||||
|
|
||||||
SimpleLogger::new().init().unwrap();
|
impl ApplicationHandler for PumpDemo {
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let window_attributes = Window::default_attributes().with_title("A fantastic window!");
|
||||||
|
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
let mut window = None;
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
_window_id: WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
|
println!("{event:?}");
|
||||||
|
|
||||||
loop {
|
let window = match self.window.as_ref() {
|
||||||
let timeout = Some(Duration::ZERO);
|
Some(window) => window,
|
||||||
let status = event_loop.pump_events(timeout, |event, event_loop| {
|
None => return,
|
||||||
if let Event::WindowEvent { event, .. } = &event {
|
};
|
||||||
// Print only Window events to reduce noise
|
|
||||||
println!("{event:?}");
|
|
||||||
}
|
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::Resumed => {
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
let window_attributes =
|
WindowEvent::RedrawRequested => {
|
||||||
Window::default_attributes().with_title("A fantastic window!");
|
fill::fill_window(window);
|
||||||
window = Some(event_loop.create_window(window_attributes).unwrap());
|
window.request_redraw();
|
||||||
}
|
|
||||||
Event::WindowEvent { event, .. } => {
|
|
||||||
let window = window.as_ref().unwrap();
|
|
||||||
match event {
|
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
|
||||||
WindowEvent::RedrawRequested => fill::fill_window(window),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::AboutToWait => {
|
|
||||||
window.as_ref().unwrap().request_redraw();
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
let mut app = PumpDemo::default();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let timeout = Some(Duration::ZERO);
|
||||||
|
let status = event_loop.pump_app_events(timeout, &mut app);
|
||||||
|
|
||||||
if let PumpStatus::Exit(exit_code) = status {
|
if let PumpStatus::Exit(exit_code) = status {
|
||||||
break ExitCode::from(exit_code as u8);
|
break ExitCode::from(exit_code as u8);
|
||||||
|
|||||||
@@ -2,88 +2,94 @@
|
|||||||
|
|
||||||
// Limit this example to only compatible platforms.
|
// Limit this example to only compatible platforms.
|
||||||
#[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform,))]
|
#[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform,))]
|
||||||
fn main() -> Result<(), impl std::error::Error> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use simple_logger::SimpleLogger;
|
use winit::application::ApplicationHandler;
|
||||||
|
use winit::event::WindowEvent;
|
||||||
use winit::{
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
error::EventLoopError,
|
use winit::platform::run_on_demand::EventLoopExtRunOnDemand;
|
||||||
event::{Event, WindowEvent},
|
use winit::window::{Window, WindowId};
|
||||||
event_loop::EventLoop,
|
|
||||||
platform::run_on_demand::EventLoopExtRunOnDemand,
|
|
||||||
window::{Window, WindowId},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[path = "util/fill.rs"]
|
#[path = "util/fill.rs"]
|
||||||
mod fill;
|
mod fill;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct App {
|
struct App {
|
||||||
|
idx: usize,
|
||||||
window_id: Option<WindowId>,
|
window_id: Option<WindowId>,
|
||||||
window: Option<Window>,
|
window: Option<Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleLogger::new().init().unwrap();
|
impl ApplicationHandler for App {
|
||||||
let mut event_loop = EventLoop::new().unwrap();
|
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
|
||||||
|
if let Some(window) = self.window.as_ref() {
|
||||||
fn run_app(event_loop: &mut EventLoop<()>, idx: usize) -> Result<(), EventLoopError> {
|
window.request_redraw();
|
||||||
let mut app = App::default();
|
|
||||||
|
|
||||||
event_loop.run_on_demand(move |event, event_loop| {
|
|
||||||
println!("Run {idx}: {:?}", event);
|
|
||||||
|
|
||||||
if let Some(window) = &app.window {
|
|
||||||
match event {
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
window_id,
|
|
||||||
} if window.id() == window_id => {
|
|
||||||
println!("--------------------------------------------------------- Window {idx} CloseRequested");
|
|
||||||
fill::cleanup_window(window);
|
|
||||||
app.window = None;
|
|
||||||
}
|
|
||||||
Event::AboutToWait => window.request_redraw(),
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::RedrawRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
fill::fill_window(window);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
} else if let Some(id) = app.window_id {
|
|
||||||
match event {
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Destroyed,
|
|
||||||
window_id,
|
|
||||||
} if id == window_id => {
|
|
||||||
println!("--------------------------------------------------------- Window {idx} Destroyed");
|
|
||||||
app.window_id = None;
|
|
||||||
event_loop.exit();
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
} else if let Event::Resumed = event {
|
|
||||||
let window_attributes = Window::default_attributes()
|
|
||||||
.with_title("Fantastic window number one!")
|
|
||||||
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0));
|
|
||||||
let window = event_loop.create_window(window_attributes).unwrap();
|
|
||||||
app.window_id = Some(window.id());
|
|
||||||
app.window = Some(window);
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let window_attributes = Window::default_attributes()
|
||||||
|
.with_title("Fantastic window number one!")
|
||||||
|
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0));
|
||||||
|
let window = event_loop.create_window(window_attributes).unwrap();
|
||||||
|
self.window_id = Some(window.id());
|
||||||
|
self.window = Some(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
window_id: WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
|
if event == WindowEvent::Destroyed && self.window_id == Some(window_id) {
|
||||||
|
println!(
|
||||||
|
"--------------------------------------------------------- Window {} Destroyed",
|
||||||
|
self.idx
|
||||||
|
);
|
||||||
|
self.window_id = None;
|
||||||
|
event_loop.exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let window = match self.window.as_mut() {
|
||||||
|
Some(window) => window,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => {
|
||||||
|
println!("--------------------------------------------------------- Window {} CloseRequested", self.idx);
|
||||||
|
fill::cleanup_window(window);
|
||||||
|
self.window = None;
|
||||||
|
}
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
fill::fill_window(window);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run_app(&mut event_loop, 1)?;
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
let mut event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
|
let mut app = App {
|
||||||
|
idx: 1,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
event_loop.run_app_on_demand(&mut app)?;
|
||||||
|
|
||||||
println!("--------------------------------------------------------- Finished first loop");
|
println!("--------------------------------------------------------- Finished first loop");
|
||||||
println!("--------------------------------------------------------- Waiting 5 seconds");
|
println!("--------------------------------------------------------- Waiting 5 seconds");
|
||||||
std::thread::sleep(Duration::from_secs(5));
|
std::thread::sleep(Duration::from_secs(5));
|
||||||
|
|
||||||
let ret = run_app(&mut event_loop, 2);
|
app.idx += 1;
|
||||||
|
event_loop.run_app_on_demand(&mut app)?;
|
||||||
println!("--------------------------------------------------------- Finished second loop");
|
println!("--------------------------------------------------------- Finished second loop");
|
||||||
ret
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(windows_platform, macos_platform, x11_platform, wayland_platform,)))]
|
#[cfg(not(any(windows_platform, macos_platform, x11_platform, wayland_platform,)))]
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ use rwh_05::HasRawDisplayHandle;
|
|||||||
#[cfg(not(any(android_platform, ios_platform)))]
|
#[cfg(not(any(android_platform, ios_platform)))]
|
||||||
use softbuffer::{Context, Surface};
|
use softbuffer::{Context, Surface};
|
||||||
|
|
||||||
|
use winit::application::ApplicationHandler;
|
||||||
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
||||||
use winit::event::{DeviceEvent, DeviceId, Event, Ime, WindowEvent};
|
use winit::event::{DeviceEvent, DeviceId, Ime, WindowEvent};
|
||||||
use winit::event::{MouseButton, MouseScrollDelta};
|
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};
|
||||||
@@ -53,38 +54,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
let mut state = Application::new(&event_loop);
|
let mut state = Application::new(&event_loop);
|
||||||
|
|
||||||
event_loop.run(move |event, event_loop| match event {
|
event_loop.run_app(&mut state).map_err(Into::into)
|
||||||
Event::NewEvents(_) => (),
|
|
||||||
Event::Resumed => {
|
|
||||||
println!("Resumed the event loop");
|
|
||||||
state.dump_monitors(event_loop);
|
|
||||||
|
|
||||||
// Create initial window.
|
|
||||||
state
|
|
||||||
.create_window(event_loop, None)
|
|
||||||
.expect("failed to create initial window");
|
|
||||||
|
|
||||||
state.print_help();
|
|
||||||
}
|
|
||||||
Event::AboutToWait => {
|
|
||||||
if state.windows.is_empty() {
|
|
||||||
println!("No windows left, exiting...");
|
|
||||||
event_loop.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::WindowEvent { window_id, event } => {
|
|
||||||
state.handle_window_event(event_loop, window_id, event)
|
|
||||||
}
|
|
||||||
Event::DeviceEvent { device_id, event } => {
|
|
||||||
state.handle_device_event(event_loop, device_id, event)
|
|
||||||
}
|
|
||||||
Event::UserEvent(event) => {
|
|
||||||
println!("User event: {event:?}");
|
|
||||||
}
|
|
||||||
Event::Suspended | Event::LoopExiting | Event::MemoryWarning => (),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -104,15 +74,14 @@ struct Application {
|
|||||||
///
|
///
|
||||||
/// With OpenGL it could be EGLDisplay.
|
/// With OpenGL it could be EGLDisplay.
|
||||||
#[cfg(not(any(android_platform, ios_platform)))]
|
#[cfg(not(any(android_platform, ios_platform)))]
|
||||||
context: Context,
|
context: Option<Context>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application {
|
impl Application {
|
||||||
fn new<T>(event_loop: &EventLoop<T>) -> Self {
|
fn new<T>(event_loop: &EventLoop<T>) -> Self {
|
||||||
// SAFETY: the context is dropped inside the loop, since the state we're using
|
// SAFETY: we drop the context right before the event loop is stopped, thus making it safe.
|
||||||
// is moved inside the closure.
|
|
||||||
#[cfg(not(any(android_platform, ios_platform)))]
|
#[cfg(not(any(android_platform, ios_platform)))]
|
||||||
let context = unsafe { Context::from_raw(event_loop.raw_display_handle()).unwrap() };
|
let context = Some(unsafe { Context::from_raw(event_loop.raw_display_handle()).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 varies
|
||||||
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px,
|
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px,
|
||||||
@@ -227,7 +196,97 @@ impl Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_window_event(
|
fn dump_monitors(&self, event_loop: &ActiveEventLoop) {
|
||||||
|
println!("Monitors information");
|
||||||
|
let primary_monitor = event_loop.primary_monitor();
|
||||||
|
for monitor in event_loop.available_monitors() {
|
||||||
|
let intro = if primary_monitor.as_ref() == Some(&monitor) {
|
||||||
|
"Primary monitor"
|
||||||
|
} else {
|
||||||
|
"Monitor"
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(name) = monitor.name() {
|
||||||
|
println!("{intro}: {name}");
|
||||||
|
} else {
|
||||||
|
println!("{intro}: [no name]");
|
||||||
|
}
|
||||||
|
|
||||||
|
let PhysicalSize { width, height } = monitor.size();
|
||||||
|
print!(" Current mode: {width}x{height}");
|
||||||
|
if let Some(m_hz) = monitor.refresh_rate_millihertz() {
|
||||||
|
println!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000);
|
||||||
|
} else {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
|
let PhysicalPosition { x, y } = monitor.position();
|
||||||
|
println!(" Position: {x},{y}");
|
||||||
|
|
||||||
|
println!(" Scale factor: {}", monitor.scale_factor());
|
||||||
|
|
||||||
|
println!(" Available modes (width x height x bit-depth):");
|
||||||
|
for mode in monitor.video_modes() {
|
||||||
|
let PhysicalSize { width, height } = mode.size();
|
||||||
|
let bits = mode.bit_depth();
|
||||||
|
let m_hz = mode.refresh_rate_millihertz();
|
||||||
|
println!(
|
||||||
|
" {width}x{height}x{bits} @ {}.{} Hz",
|
||||||
|
m_hz / 1000,
|
||||||
|
m_hz % 1000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process the key binding.
|
||||||
|
fn process_key_binding(key: &str, mods: &ModifiersState) -> Option<Action> {
|
||||||
|
KEY_BINDINGS.iter().find_map(|binding| {
|
||||||
|
binding
|
||||||
|
.is_triggered_by(&key, mods)
|
||||||
|
.then_some(binding.action)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process mouse binding.
|
||||||
|
fn process_mouse_binding(button: MouseButton, mods: &ModifiersState) -> Option<Action> {
|
||||||
|
MOUSE_BINDINGS.iter().find_map(|binding| {
|
||||||
|
binding
|
||||||
|
.is_triggered_by(&button, mods)
|
||||||
|
.then_some(binding.action)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_help(&self) {
|
||||||
|
println!("Keyboard bindings:");
|
||||||
|
for binding in KEY_BINDINGS {
|
||||||
|
println!(
|
||||||
|
"{}{:<10} - {} ({})",
|
||||||
|
modifiers_to_string(binding.mods),
|
||||||
|
binding.trigger,
|
||||||
|
binding.action,
|
||||||
|
binding.action.help(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("Mouse bindings:");
|
||||||
|
for binding in MOUSE_BINDINGS {
|
||||||
|
println!(
|
||||||
|
"{}{:<10} - {} ({})",
|
||||||
|
modifiers_to_string(binding.mods),
|
||||||
|
mouse_button_to_string(binding.trigger),
|
||||||
|
binding.action,
|
||||||
|
binding.action.help(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler<UserEvent> for Application {
|
||||||
|
fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: UserEvent) {
|
||||||
|
println!("User event: {event:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
event_loop: &ActiveEventLoop,
|
event_loop: &ActiveEventLoop,
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
@@ -333,7 +392,7 @@ impl Application {
|
|||||||
println!("Preedit: {}, with caret at {:?}", text, caret_pos);
|
println!("Preedit: {}, with caret at {:?}", text, caret_pos);
|
||||||
}
|
}
|
||||||
Ime::Commit(text) => {
|
Ime::Commit(text) => {
|
||||||
println!("Commited: {}", text);
|
println!("Committed: {}", text);
|
||||||
}
|
}
|
||||||
Ime::Disabled => println!("IME disabled for Window={window_id:?}"),
|
Ime::Disabled => println!("IME disabled for Window={window_id:?}"),
|
||||||
},
|
},
|
||||||
@@ -371,92 +430,37 @@ impl Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_device_event(&mut self, _: &ActiveEventLoop, _: DeviceId, event: DeviceEvent) {
|
fn device_event(
|
||||||
println!("Device event: {event:?}");
|
&mut self,
|
||||||
|
_event_loop: &ActiveEventLoop,
|
||||||
|
device_id: DeviceId,
|
||||||
|
event: DeviceEvent,
|
||||||
|
) {
|
||||||
|
println!("Device {device_id:?} event: {event:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump_monitors(&self, event_loop: &ActiveEventLoop) {
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
println!("Monitors information");
|
println!("Resumed the event loop");
|
||||||
let primary_monitor = event_loop.primary_monitor();
|
self.dump_monitors(event_loop);
|
||||||
for monitor in event_loop.available_monitors() {
|
|
||||||
let intro = if primary_monitor.as_ref() == Some(&monitor) {
|
|
||||||
"Primary monitor"
|
|
||||||
} else {
|
|
||||||
"Monitor"
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(name) = monitor.name() {
|
// Create initial window.
|
||||||
println!("{intro}: {name}");
|
self.create_window(event_loop, None)
|
||||||
} else {
|
.expect("failed to create initial window");
|
||||||
println!("{intro}: [no name]");
|
|
||||||
}
|
|
||||||
|
|
||||||
let PhysicalSize { width, height } = monitor.size();
|
self.print_help();
|
||||||
print!(" Current mode: {width}x{height}");
|
}
|
||||||
if let Some(m_hz) = monitor.refresh_rate_millihertz() {
|
|
||||||
println!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000);
|
|
||||||
} else {
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
|
|
||||||
let PhysicalPosition { x, y } = monitor.position();
|
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
println!(" Position: {x},{y}");
|
if self.windows.is_empty() {
|
||||||
|
println!("No windows left, exiting...");
|
||||||
println!(" Scale factor: {}", monitor.scale_factor());
|
event_loop.exit();
|
||||||
|
|
||||||
println!(" Available modes (width x height x bit-depth):");
|
|
||||||
for mode in monitor.video_modes() {
|
|
||||||
let PhysicalSize { width, height } = mode.size();
|
|
||||||
let bits = mode.bit_depth();
|
|
||||||
let m_hz = mode.refresh_rate_millihertz();
|
|
||||||
println!(
|
|
||||||
" {width}x{height}x{bits} @ {}.{} Hz",
|
|
||||||
m_hz / 1000,
|
|
||||||
m_hz % 1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process the key binding.
|
#[cfg(not(any(android_platform, ios_platform)))]
|
||||||
fn process_key_binding(key: &str, mods: &ModifiersState) -> Option<Action> {
|
fn exiting(&mut self, _event_loop: &ActiveEventLoop) {
|
||||||
KEY_BINDINGS.iter().find_map(|binding| {
|
// We must drop the context here.
|
||||||
binding
|
self.context = None;
|
||||||
.is_triggered_by(&key, mods)
|
|
||||||
.then_some(binding.action)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process mouse binding.
|
|
||||||
fn process_mouse_binding(button: MouseButton, mods: &ModifiersState) -> Option<Action> {
|
|
||||||
MOUSE_BINDINGS.iter().find_map(|binding| {
|
|
||||||
binding
|
|
||||||
.is_triggered_by(&button, mods)
|
|
||||||
.then_some(binding.action)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_help(&self) {
|
|
||||||
println!("Keyboard bindings:");
|
|
||||||
for binding in KEY_BINDINGS {
|
|
||||||
println!(
|
|
||||||
"{}{:<10} - {} ({})",
|
|
||||||
modifiers_to_string(binding.mods),
|
|
||||||
binding.trigger,
|
|
||||||
binding.action,
|
|
||||||
binding.action.help(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
println!("Mouse bindings:");
|
|
||||||
for binding in MOUSE_BINDINGS {
|
|
||||||
println!(
|
|
||||||
"{}{:<10} - {} ({})",
|
|
||||||
modifiers_to_string(binding.mods),
|
|
||||||
mouse_button_to_string(binding.trigger),
|
|
||||||
binding.action,
|
|
||||||
binding.action.help(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,11 +500,11 @@ struct WindowState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WindowState {
|
impl WindowState {
|
||||||
fn new(application: &Application, window: Window) -> Result<Self, Box<dyn Error>> {
|
fn new(app: &Application, window: Window) -> Result<Self, Box<dyn Error>> {
|
||||||
// SAFETY: the surface is dropped before the `window` which provided it with handle, thus
|
// SAFETY: the surface is dropped before the `window` which provided it with handle, thus
|
||||||
// it doesn't outlive it.
|
// it doesn't outlive it.
|
||||||
#[cfg(not(any(android_platform, ios_platform)))]
|
#[cfg(not(any(android_platform, ios_platform)))]
|
||||||
let surface = unsafe { Surface::new(&application.context, &window)? };
|
let surface = unsafe { Surface::new(app.context.as_ref().unwrap(), &window)? };
|
||||||
|
|
||||||
let theme = window.theme().unwrap_or(Theme::Dark);
|
let theme = window.theme().unwrap_or(Theme::Dark);
|
||||||
println!("Theme: {theme:?}");
|
println!("Theme: {theme:?}");
|
||||||
@@ -515,7 +519,7 @@ impl WindowState {
|
|||||||
let mut state = Self {
|
let mut state = Self {
|
||||||
#[cfg(macos_platform)]
|
#[cfg(macos_platform)]
|
||||||
option_as_alt: window.option_as_alt(),
|
option_as_alt: window.option_as_alt(),
|
||||||
custom_idx: application.custom_cursors.len() - 1,
|
custom_idx: app.custom_cursors.len() - 1,
|
||||||
cursor_grab: CursorGrabMode::None,
|
cursor_grab: CursorGrabMode::None,
|
||||||
named_idx,
|
named_idx,
|
||||||
#[cfg(not(any(android_platform, ios_platform)))]
|
#[cfg(not(any(android_platform, ios_platform)))]
|
||||||
|
|||||||
@@ -3,40 +3,37 @@ use std::error::Error;
|
|||||||
|
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
use simple_logger::SimpleLogger;
|
use winit::application::ApplicationHandler;
|
||||||
|
use winit::event::WindowEvent;
|
||||||
use winit::{
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
event::{Event, WindowEvent},
|
use winit::platform::x11::WindowAttributesExtX11;
|
||||||
event_loop::EventLoop,
|
use winit::window::{Window, WindowId};
|
||||||
platform::x11::WindowAttributesExtX11,
|
|
||||||
window::Window,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[path = "util/fill.rs"]
|
#[path = "util/fill.rs"]
|
||||||
mod fill;
|
mod fill;
|
||||||
|
|
||||||
// First argument should be a 32-bit X11 window ID.
|
pub struct XEmbedDemo {
|
||||||
let parent_window_id = std::env::args()
|
parent_window_id: u32,
|
||||||
.nth(1)
|
window: Option<Window>,
|
||||||
.ok_or("Expected a 32-bit X11 window ID as the first argument.")?
|
}
|
||||||
.parse::<u32>()?;
|
|
||||||
|
|
||||||
SimpleLogger::new().init().unwrap();
|
impl ApplicationHandler for XEmbedDemo {
|
||||||
let event_loop = EventLoop::new()?;
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
|
||||||
let mut window = None;
|
|
||||||
event_loop.run(move |event, event_loop| match event {
|
|
||||||
Event::Resumed => {
|
|
||||||
let window_attributes = Window::default_attributes()
|
let window_attributes = Window::default_attributes()
|
||||||
.with_title("An embedded window!")
|
.with_title("An embedded window!")
|
||||||
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
|
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
|
||||||
.with_embed_parent_window(parent_window_id);
|
.with_embed_parent_window(self.parent_window_id);
|
||||||
|
|
||||||
window = Some(event_loop.create_window(window_attributes).unwrap());
|
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||||
}
|
}
|
||||||
Event::WindowEvent { event, .. } => {
|
|
||||||
let window = window.as_ref().unwrap();
|
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
_window_id: WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
|
let window = self.window.as_ref().unwrap();
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
@@ -46,13 +43,26 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::AboutToWait => {
|
|
||||||
window.as_ref().unwrap().request_redraw();
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
|
||||||
|
self.window.as_ref().unwrap().request_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// First argument should be a 32-bit X11 window ID.
|
||||||
|
let parent_window_id = std::env::args()
|
||||||
|
.nth(1)
|
||||||
|
.ok_or("Expected a 32-bit X11 window ID as the first argument.")?
|
||||||
|
.parse::<u32>()?;
|
||||||
|
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
let event_loop = EventLoop::new()?;
|
||||||
|
|
||||||
|
let mut app = XEmbedDemo {
|
||||||
|
parent_window_id,
|
||||||
|
window: None,
|
||||||
|
};
|
||||||
|
event_loop.run_app(&mut app).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(x11_platform))]
|
#[cfg(not(x11_platform))]
|
||||||
|
|||||||
221
src/application.rs
Normal file
221
src/application.rs
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
//! End user application handling.
|
||||||
|
|
||||||
|
use crate::event::{DeviceEvent, DeviceId, StartCause, WindowEvent};
|
||||||
|
use crate::event_loop::ActiveEventLoop;
|
||||||
|
use crate::window::WindowId;
|
||||||
|
|
||||||
|
/// The handler of the application events.
|
||||||
|
pub trait ApplicationHandler<T: 'static = ()> {
|
||||||
|
/// Emitted when new events arrive from the OS to be processed.
|
||||||
|
///
|
||||||
|
/// This is a useful place to put code that should be done before you start processing
|
||||||
|
/// events, such as updating frame timing information for benchmarking or checking the
|
||||||
|
/// [`StartCause`] to see if a timer set by
|
||||||
|
/// [`ControlFlow::WaitUntil`](crate::event_loop::ControlFlow::WaitUntil) has elapsed.
|
||||||
|
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
|
||||||
|
let _ = (event_loop, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emitted when the application has been resumed.
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
/// the `Resumed` event is always emitted after the [`NewEvents(StartCause::Init)`][StartCause::Init]
|
||||||
|
/// event.
|
||||||
|
///
|
||||||
|
/// # Portability
|
||||||
|
///
|
||||||
|
/// It's recommended that applications should only initialize their graphics context and create
|
||||||
|
/// a window after they have received their first `Resumed` event. Some systems
|
||||||
|
/// (specifically Android) won't allow applications to create a render surface until they are
|
||||||
|
/// resumed.
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// Also see [`Suspended`] notes.
|
||||||
|
///
|
||||||
|
/// ## Android
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
/// be a discrepancy.
|
||||||
|
///
|
||||||
|
/// [`onResume`]: https://developer.android.com/reference/android/app/Activity#onResume()
|
||||||
|
///
|
||||||
|
/// Applications that need to run on Android must wait until they have been `Resumed`
|
||||||
|
/// before they will be able to create a render surface (such as an `EGLSurface`,
|
||||||
|
/// [`VkSurfaceKHR`] or [`wgpu::Surface`]) which depend on having a
|
||||||
|
/// [`SurfaceView`]. Applications must also assume that if they are [`Suspended`], then their
|
||||||
|
/// render surfaces are invalid and should be dropped.
|
||||||
|
///
|
||||||
|
/// Also see [`Suspended`] notes.
|
||||||
|
///
|
||||||
|
/// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
|
||||||
|
/// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
|
||||||
|
/// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
|
||||||
|
/// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
|
||||||
|
///
|
||||||
|
/// ## iOS
|
||||||
|
///
|
||||||
|
/// On iOS, the `Resumed` event is emitted in response to an [`applicationDidBecomeActive`]
|
||||||
|
/// callback which means the application is "active" (according to the
|
||||||
|
/// [iOS application lifecycle]).
|
||||||
|
///
|
||||||
|
/// [`applicationDidBecomeActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive
|
||||||
|
/// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
|
||||||
|
///
|
||||||
|
/// ## Web
|
||||||
|
///
|
||||||
|
/// On Web, the `Resumed` event is emitted in response to a [`pageshow`] event
|
||||||
|
/// with the property [`persisted`] being true, which means that the page is being
|
||||||
|
/// restored from the [`bfcache`] (back/forward cache) - an in-memory cache that
|
||||||
|
/// stores a complete snapshot of a page (including the JavaScript heap) as the
|
||||||
|
/// user is navigating away.
|
||||||
|
///
|
||||||
|
/// [`pageshow`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
|
||||||
|
/// [`persisted`]: https://developer.mozilla.org/en-US/docs/Web/API/PageTransitionEvent/persisted
|
||||||
|
/// [`bfcache`]: https://web.dev/bfcache/
|
||||||
|
/// [`Suspended`]: Self::suspended
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop);
|
||||||
|
|
||||||
|
/// Emitted when an event is sent from [`EventLoopProxy::send_event`].
|
||||||
|
///
|
||||||
|
/// [`EventLoopProxy::send_event`]: crate::event_loop::EventLoopProxy::send_event
|
||||||
|
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: T) {
|
||||||
|
let _ = (event_loop, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emitted when the OS sends an event to a winit window.
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
window_id: WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Emitted when the OS sends an event to a device.
|
||||||
|
fn device_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
device_id: DeviceId,
|
||||||
|
event: DeviceEvent,
|
||||||
|
) {
|
||||||
|
let _ = (event_loop, device_id, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
/// 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
|
||||||
|
/// ups and also lots of corresponding `AboutToWait` events.
|
||||||
|
///
|
||||||
|
/// This is not an ideal event to drive application rendering from and instead applications
|
||||||
|
/// should render in response to [`WindowEvent::RedrawRequested`] events.
|
||||||
|
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let _ = event_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emitted when the application has been suspended.
|
||||||
|
///
|
||||||
|
/// # Portability
|
||||||
|
///
|
||||||
|
/// Not all platforms support the notion of suspending applications, and there may be no
|
||||||
|
/// technical way to guarantee being able to emit a `Suspended` event if the OS has
|
||||||
|
/// no formal application lifecycle (currently only Android, iOS, and Web do). For this reason,
|
||||||
|
/// Winit does not currently try to emit pseudo `Suspended` events before the application
|
||||||
|
/// quits on platforms without an application lifecycle.
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// Also see [`Resumed`] notes.
|
||||||
|
///
|
||||||
|
/// ## Android
|
||||||
|
///
|
||||||
|
/// On Android, the `Suspended` event is only sent when the application's associated
|
||||||
|
/// [`SurfaceView`] is destroyed. This is expected to closely correlate with the [`onPause`]
|
||||||
|
/// lifecycle event but there may technically be a discrepancy.
|
||||||
|
///
|
||||||
|
/// [`onPause`]: https://developer.android.com/reference/android/app/Activity#onPause()
|
||||||
|
///
|
||||||
|
/// Applications that need to run on Android should assume their [`SurfaceView`] has been
|
||||||
|
/// destroyed, which indirectly invalidates any existing render surfaces that may have been
|
||||||
|
/// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]).
|
||||||
|
///
|
||||||
|
/// 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`].
|
||||||
|
///
|
||||||
|
/// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
|
||||||
|
/// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
|
||||||
|
/// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
|
||||||
|
/// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
|
||||||
|
///
|
||||||
|
/// ## iOS
|
||||||
|
///
|
||||||
|
/// On iOS, the `Suspended` event is currently emitted in response to an
|
||||||
|
/// [`applicationWillResignActive`] callback which means that the application is
|
||||||
|
/// about to transition from the active to inactive state (according to the
|
||||||
|
/// [iOS application lifecycle]).
|
||||||
|
///
|
||||||
|
/// [`applicationWillResignActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622950-applicationwillresignactive
|
||||||
|
/// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
|
||||||
|
///
|
||||||
|
/// ## Web
|
||||||
|
///
|
||||||
|
/// On Web, the `Suspended` event is emitted in response to a [`pagehide`] event
|
||||||
|
/// with the property [`persisted`] being true, which means that the page is being
|
||||||
|
/// put in the [`bfcache`] (back/forward cache) - an in-memory cache that stores a
|
||||||
|
/// complete snapshot of a page (including the JavaScript heap) as the user is
|
||||||
|
/// navigating away.
|
||||||
|
///
|
||||||
|
/// [`pagehide`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
|
||||||
|
/// [`persisted`]: https://developer.mozilla.org/en-US/docs/Web/API/PageTransitionEvent/persisted
|
||||||
|
/// [`bfcache`]: https://web.dev/bfcache/
|
||||||
|
/// [`Resumed`]: Self::resumed
|
||||||
|
fn suspended(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let _ = event_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emitted when the event loop is being shut down.
|
||||||
|
///
|
||||||
|
/// This is irreversible - if this method is called, it is guaranteed that the event loop
|
||||||
|
/// will exist right after.
|
||||||
|
fn exiting(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let _ = event_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emitted when the application has received a memory warning.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// ### Android
|
||||||
|
///
|
||||||
|
/// On Android, the `MemoryWarning` event is sent when [`onLowMemory`] was called. The application
|
||||||
|
/// must [release memory] or risk being killed.
|
||||||
|
///
|
||||||
|
/// [`onLowMemory`]: https://developer.android.com/reference/android/app/Application.html#onLowMemory()
|
||||||
|
/// [release memory]: https://developer.android.com/topic/performance/memory#release
|
||||||
|
///
|
||||||
|
/// ### iOS
|
||||||
|
///
|
||||||
|
/// On iOS, the `MemoryWarning` event is emitted in response to an [`applicationDidReceiveMemoryWarning`]
|
||||||
|
/// callback. The application must free as much memory as possible or risk being terminated, see
|
||||||
|
/// [how to respond to memory warnings].
|
||||||
|
///
|
||||||
|
/// [`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
|
||||||
|
///
|
||||||
|
/// ### Others
|
||||||
|
///
|
||||||
|
/// - **macOS / Orbital / Wayland / Web / Windows:** Unsupported.
|
||||||
|
fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let _ = event_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,6 +88,15 @@ 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!(
|
||||||
|
"winit::Cursor::from_rgba",
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
hotspot_x,
|
||||||
|
hotspot_y
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
|
|
||||||
Ok(CustomCursorSource {
|
Ok(CustomCursorSource {
|
||||||
inner: PlatformCustomCursorSource::from_rgba(
|
inner: PlatformCustomCursorSource::from_rgba(
|
||||||
rgba.into(),
|
rgba.into(),
|
||||||
@@ -186,6 +195,7 @@ impl OnlyCursorImageSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Platforms export this directly as `PlatformCustomCursor` if they don't implement caching.
|
/// Platforms export this directly as `PlatformCustomCursor` if they don't implement caching.
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct OnlyCursorImage(pub(crate) Arc<CursorImage>);
|
pub(crate) struct OnlyCursorImage(pub(crate) Arc<CursorImage>);
|
||||||
|
|
||||||
|
|||||||
232
src/event.rs
232
src/event.rs
@@ -1,36 +1,37 @@
|
|||||||
//! The [`Event`] enum and assorted supporting types.
|
//! The [`Event`] enum and assorted supporting types.
|
||||||
//!
|
//!
|
||||||
//! These are sent to the closure given to [`EventLoop::run(...)`], 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(...)`] like this:
|
//! approximate the basic ordering loop of [`EventLoop::run_app(...)`] like this:
|
||||||
//!
|
//!
|
||||||
//! ```rust,ignore
|
//! ```rust,ignore
|
||||||
//! let mut start_cause = StartCause::Init;
|
//! let mut start_cause = StartCause::Init;
|
||||||
//!
|
//!
|
||||||
//! while !elwt.exiting() {
|
//! while !elwt.exiting() {
|
||||||
//! event_handler(NewEvents(start_cause), elwt);
|
//! app.new_events(event_loop, start_cause);
|
||||||
//!
|
//!
|
||||||
//! for e in (window events, user events, device events) {
|
//! for event in (window events, user events, device events) {
|
||||||
//! event_handler(e, elwt);
|
//! // This will pick the right method on the application based on the event.
|
||||||
|
//! app.handle_event(event_loop, event);
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! for w in (redraw windows) {
|
//! for window_id in (redraw windows) {
|
||||||
//! event_handler(RedrawRequested(w), elwt);
|
//! app.window_event(event_loop, window_id, RedrawRequested);
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! event_handler(AboutToWait, elwt);
|
//! app.about_to_wait(event_loop);
|
||||||
//! start_cause = wait_if_necessary();
|
//! start_cause = wait_if_necessary();
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! event_handler(LoopExiting, elwt);
|
//! app.exiting(event_loop);
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! This leaves out timing details like [`ControlFlow::WaitUntil`] but hopefully
|
//! This leaves out timing details like [`ControlFlow::WaitUntil`] but hopefully
|
||||||
//! describes what happens in what order.
|
//! describes what happens in what order.
|
||||||
//!
|
//!
|
||||||
//! [`EventLoop::run(...)`]: crate::event_loop::EventLoop::run
|
//! [`EventLoop::run_app(...)`]: crate::event_loop::EventLoop::run_app
|
||||||
//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
|
//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Mutex, Weak};
|
use std::sync::{Mutex, Weak};
|
||||||
@@ -59,199 +60,55 @@ use crate::{
|
|||||||
/// See the module-level docs for more information on the event loop manages each event.
|
/// See the module-level docs for more information on the event loop manages each event.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Event<T: 'static> {
|
pub enum Event<T: 'static> {
|
||||||
/// Emitted when new events arrive from the OS to be processed.
|
/// See [`ApplicationHandler::new_events`] for details.
|
||||||
///
|
///
|
||||||
/// This event type is useful as a place to put code that should be done before you start
|
/// [`ApplicationHandler::new_events`]: crate::application::ApplicationHandler::new_events
|
||||||
/// processing events, such as updating frame timing information for benchmarking or checking
|
|
||||||
/// the [`StartCause`] to see if a timer set by
|
|
||||||
/// [`ControlFlow::WaitUntil`](crate::event_loop::ControlFlow::WaitUntil) has elapsed.
|
|
||||||
NewEvents(StartCause),
|
NewEvents(StartCause),
|
||||||
|
|
||||||
/// Emitted when the OS sends an event to a winit window.
|
/// See [`ApplicationHandler::window_event`] for details.
|
||||||
|
///
|
||||||
|
/// [`ApplicationHandler::window_event`]: crate::application::ApplicationHandler::window_event
|
||||||
WindowEvent {
|
WindowEvent {
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
event: WindowEvent,
|
event: WindowEvent,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Emitted when the OS sends an event to a device.
|
/// See [`ApplicationHandler::device_event`] for details.
|
||||||
|
///
|
||||||
|
/// [`ApplicationHandler::device_event`]: crate::application::ApplicationHandler::device_event
|
||||||
DeviceEvent {
|
DeviceEvent {
|
||||||
device_id: DeviceId,
|
device_id: DeviceId,
|
||||||
event: DeviceEvent,
|
event: DeviceEvent,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Emitted when an event is sent from [`EventLoopProxy::send_event`](crate::event_loop::EventLoopProxy::send_event)
|
/// See [`ApplicationHandler::user_event`] for details.
|
||||||
|
///
|
||||||
|
/// [`ApplicationHandler::user_event`]: crate::application::ApplicationHandler::user_event
|
||||||
UserEvent(T),
|
UserEvent(T),
|
||||||
|
|
||||||
/// Emitted when the application has been suspended.
|
/// See [`ApplicationHandler::suspended`] for details.
|
||||||
///
|
///
|
||||||
/// # Portability
|
/// [`ApplicationHandler::suspended`]: crate::application::ApplicationHandler::suspended
|
||||||
///
|
|
||||||
/// Not all platforms support the notion of suspending applications, and there may be no
|
|
||||||
/// technical way to guarantee being able to emit a `Suspended` event if the OS has
|
|
||||||
/// no formal application lifecycle (currently only Android, iOS, and Web do). For this reason,
|
|
||||||
/// Winit does not currently try to emit pseudo `Suspended` events before the application
|
|
||||||
/// quits on platforms without an application lifecycle.
|
|
||||||
///
|
|
||||||
/// 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
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// Also see [`Resumed`] notes.
|
|
||||||
///
|
|
||||||
/// ## Android
|
|
||||||
///
|
|
||||||
/// On Android, the `Suspended` event is only sent when the application's associated
|
|
||||||
/// [`SurfaceView`] is destroyed. This is expected to closely correlate with the [`onPause`]
|
|
||||||
/// lifecycle event but there may technically be a discrepancy.
|
|
||||||
///
|
|
||||||
/// [`onPause`]: https://developer.android.com/reference/android/app/Activity#onPause()
|
|
||||||
///
|
|
||||||
/// Applications that need to run on Android should assume their [`SurfaceView`] has been
|
|
||||||
/// destroyed, which indirectly invalidates any existing render surfaces that may have been
|
|
||||||
/// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]).
|
|
||||||
///
|
|
||||||
/// 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`].
|
|
||||||
///
|
|
||||||
/// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
|
|
||||||
/// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
|
|
||||||
/// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
|
|
||||||
/// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
|
|
||||||
///
|
|
||||||
/// ## iOS
|
|
||||||
///
|
|
||||||
/// On iOS, the `Suspended` event is currently emitted in response to an
|
|
||||||
/// [`applicationWillResignActive`] callback which means that the application is
|
|
||||||
/// about to transition from the active to inactive state (according to the
|
|
||||||
/// [iOS application lifecycle]).
|
|
||||||
///
|
|
||||||
/// [`applicationWillResignActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622950-applicationwillresignactive
|
|
||||||
/// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
|
|
||||||
///
|
|
||||||
/// ## Web
|
|
||||||
///
|
|
||||||
/// On Web, the `Suspended` event is emitted in response to a [`pagehide`] event
|
|
||||||
/// with the property [`persisted`] being true, which means that the page is being
|
|
||||||
/// put in the [`bfcache`] (back/forward cache) - an in-memory cache that stores a
|
|
||||||
/// complete snapshot of a page (including the JavaScript heap) as the user is
|
|
||||||
/// navigating away.
|
|
||||||
///
|
|
||||||
/// [`pagehide`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
|
|
||||||
/// [`persisted`]: https://developer.mozilla.org/en-US/docs/Web/API/PageTransitionEvent/persisted
|
|
||||||
/// [`bfcache`]: https://web.dev/bfcache/
|
|
||||||
///
|
|
||||||
/// [`Resumed`]: Self::Resumed
|
|
||||||
Suspended,
|
Suspended,
|
||||||
|
|
||||||
/// Emitted when the application has been resumed.
|
/// See [`ApplicationHandler::resumed`] for details.
|
||||||
///
|
///
|
||||||
/// For consistency, all platforms emit a `Resumed` event even if they don't themselves have a
|
/// [`ApplicationHandler::resumed`]: crate::application::ApplicationHandler::resumed
|
||||||
/// formal suspend/resume lifecycle. For systems without a standard suspend/resume lifecycle
|
|
||||||
/// the `Resumed` event is always emitted after the [`NewEvents(StartCause::Init)`][StartCause::Init]
|
|
||||||
/// event.
|
|
||||||
///
|
|
||||||
/// # Portability
|
|
||||||
///
|
|
||||||
/// It's recommended that applications should only initialize their graphics context and create
|
|
||||||
/// a window after they have received their first `Resumed` event. Some systems
|
|
||||||
/// (specifically Android) won't allow applications to create a render surface until they are
|
|
||||||
/// resumed.
|
|
||||||
///
|
|
||||||
/// 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
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// Also see [`Suspended`] notes.
|
|
||||||
///
|
|
||||||
/// ## Android
|
|
||||||
///
|
|
||||||
/// 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
|
|
||||||
/// be a discrepancy.
|
|
||||||
///
|
|
||||||
/// [`onResume`]: https://developer.android.com/reference/android/app/Activity#onResume()
|
|
||||||
///
|
|
||||||
/// Applications that need to run on Android must wait until they have been `Resumed`
|
|
||||||
/// before they will be able to create a render surface (such as an `EGLSurface`,
|
|
||||||
/// [`VkSurfaceKHR`] or [`wgpu::Surface`]) which depend on having a
|
|
||||||
/// [`SurfaceView`]. Applications must also assume that if they are [`Suspended`], then their
|
|
||||||
/// render surfaces are invalid and should be dropped.
|
|
||||||
///
|
|
||||||
/// Also see [`Suspended`] notes.
|
|
||||||
///
|
|
||||||
/// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
|
|
||||||
/// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
|
|
||||||
/// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
|
|
||||||
/// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
|
|
||||||
///
|
|
||||||
/// ## iOS
|
|
||||||
///
|
|
||||||
/// On iOS, the `Resumed` event is emitted in response to an [`applicationDidBecomeActive`]
|
|
||||||
/// callback which means the application is "active" (according to the
|
|
||||||
/// [iOS application lifecycle]).
|
|
||||||
///
|
|
||||||
/// [`applicationDidBecomeActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive
|
|
||||||
/// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
|
|
||||||
///
|
|
||||||
/// ## Web
|
|
||||||
///
|
|
||||||
/// On Web, the `Resumed` event is emitted in response to a [`pageshow`] event
|
|
||||||
/// with the property [`persisted`] being true, which means that the page is being
|
|
||||||
/// restored from the [`bfcache`] (back/forward cache) - an in-memory cache that
|
|
||||||
/// stores a complete snapshot of a page (including the JavaScript heap) as the
|
|
||||||
/// user is navigating away.
|
|
||||||
///
|
|
||||||
/// [`pageshow`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
|
|
||||||
/// [`persisted`]: https://developer.mozilla.org/en-US/docs/Web/API/PageTransitionEvent/persisted
|
|
||||||
/// [`bfcache`]: https://web.dev/bfcache/
|
|
||||||
///
|
|
||||||
/// [`Suspended`]: Self::Suspended
|
|
||||||
Resumed,
|
Resumed,
|
||||||
|
|
||||||
/// Emitted when the event loop is about to block and wait for new events.
|
/// See [`ApplicationHandler::about_to_wait`] for details.
|
||||||
///
|
///
|
||||||
/// Most applications shouldn't need to hook into this event since there is no real relationship
|
/// [`ApplicationHandler::about_to_wait`]: crate::application::ApplicationHandler::about_to_wait
|
||||||
/// 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
|
|
||||||
/// ups and also lots of corresponding `AboutToWait` events.
|
|
||||||
///
|
|
||||||
/// This is not an ideal event to drive application rendering from and instead applications
|
|
||||||
/// should render in response to [`WindowEvent::RedrawRequested`] events.
|
|
||||||
AboutToWait,
|
AboutToWait,
|
||||||
|
|
||||||
/// Emitted when the event loop is being shut down.
|
/// See [`ApplicationHandler::exiting`] for details.
|
||||||
///
|
///
|
||||||
/// This is irreversible - if this event is emitted, it is guaranteed to be the last event that
|
/// [`ApplicationHandler::exiting`]: crate::application::ApplicationHandler::exiting
|
||||||
/// gets emitted. You generally want to treat this as a "do on quit" event.
|
|
||||||
LoopExiting,
|
LoopExiting,
|
||||||
|
|
||||||
/// Emitted when the application has received a memory warning.
|
/// See [`ApplicationHandler::memory_warning`] for details.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// [`ApplicationHandler::memory_warning`]: crate::application::ApplicationHandler::memory_warning
|
||||||
///
|
|
||||||
/// ### Android
|
|
||||||
///
|
|
||||||
/// On Android, the `MemoryWarning` event is sent when [`onLowMemory`] was called. The application
|
|
||||||
/// must [release memory] or risk being killed.
|
|
||||||
///
|
|
||||||
/// [`onLowMemory`]: https://developer.android.com/reference/android/app/Application.html#onLowMemory()
|
|
||||||
/// [release memory]: https://developer.android.com/topic/performance/memory#release
|
|
||||||
///
|
|
||||||
/// ### iOS
|
|
||||||
///
|
|
||||||
/// On iOS, the `MemoryWarning` event is emitted in response to an [`applicationDidReceiveMemoryWarning`]
|
|
||||||
/// callback. The application must free as much memory as possible or risk being terminated, see
|
|
||||||
/// [how to respond to memory warnings].
|
|
||||||
///
|
|
||||||
/// [`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
|
|
||||||
///
|
|
||||||
/// ### Others
|
|
||||||
///
|
|
||||||
/// - **macOS / Wayland / Windows / Orbital:** Unsupported.
|
|
||||||
MemoryWarning,
|
MemoryWarning,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,6 +638,31 @@ pub struct KeyEvent {
|
|||||||
/// 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 if
|
||||||
/// this event is the result of one of those repeats.
|
/// this event is the result of one of those repeats.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// In games, you often want to ignore repated key events - this can be
|
||||||
|
/// done by ignoring events where this property is set.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use winit::event::{WindowEvent, KeyEvent, ElementState};
|
||||||
|
/// use winit::keyboard::{KeyCode, PhysicalKey};
|
||||||
|
/// # let window_event = WindowEvent::RedrawRequested; // To make the example compile
|
||||||
|
/// match window_event {
|
||||||
|
/// WindowEvent::KeyboardInput {
|
||||||
|
/// event: KeyEvent {
|
||||||
|
/// physical_key: PhysicalKey::Code(KeyCode::KeyW),
|
||||||
|
/// state: ElementState::Pressed,
|
||||||
|
/// repeat: false,
|
||||||
|
/// ..
|
||||||
|
/// },
|
||||||
|
/// ..
|
||||||
|
/// } => {
|
||||||
|
/// // The physical key `W` was pressed, and it was not a repeat
|
||||||
|
/// }
|
||||||
|
/// _ => {} // Handle other events
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub repeat: bool,
|
pub repeat: bool,
|
||||||
|
|
||||||
/// Platform-specific key event information.
|
/// Platform-specific key event information.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use std::time::{Duration, Instant};
|
|||||||
#[cfg(web_platform)]
|
#[cfg(web_platform)]
|
||||||
use web_time::{Duration, Instant};
|
use web_time::{Duration, Instant};
|
||||||
|
|
||||||
|
use crate::application::ApplicationHandler;
|
||||||
use crate::error::{EventLoopError, OsError};
|
use crate::error::{EventLoopError, OsError};
|
||||||
use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
|
use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
|
||||||
use crate::{event::Event, monitor::MonitorHandle, platform_impl};
|
use crate::{event::Event, monitor::MonitorHandle, platform_impl};
|
||||||
@@ -109,6 +110,8 @@ impl<T> EventLoopBuilder<T> {
|
|||||||
)]
|
)]
|
||||||
#[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();
|
||||||
|
|
||||||
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
||||||
return Err(EventLoopError::RecreationAttempt);
|
return Err(EventLoopError::RecreationAttempt);
|
||||||
}
|
}
|
||||||
@@ -213,8 +216,22 @@ impl<T> EventLoop<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the event loop in the calling thread and calls the given `event_handler` closure
|
/// See [`run_app`].
|
||||||
/// to dispatch any pending events.
|
///
|
||||||
|
/// [`run_app`]: Self::run_app
|
||||||
|
#[inline]
|
||||||
|
#[deprecated = "use `EventLoop::run_app` instead"]
|
||||||
|
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
||||||
|
pub fn run<F>(self, event_handler: F) -> Result<(), EventLoopError>
|
||||||
|
where
|
||||||
|
F: FnMut(Event<T>, &ActiveEventLoop),
|
||||||
|
{
|
||||||
|
let _span = tracing::debug_span!("winit::EventLoop::run").entered();
|
||||||
|
|
||||||
|
self.event_loop.run(event_handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the application with the event loop on the calling thread.
|
||||||
///
|
///
|
||||||
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
||||||
///
|
///
|
||||||
@@ -229,10 +246,10 @@ impl<T> EventLoop<T> {
|
|||||||
/// Web applications are recommended to use
|
/// Web applications are recommended to use
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
web_platform,
|
web_platform,
|
||||||
doc = "[`EventLoopExtWebSys::spawn()`][crate::platform::web::EventLoopExtWebSys::spawn()]"
|
doc = "[`EventLoopExtWebSys::spawn_app()`][crate::platform::web::EventLoopExtWebSys::spawn_app()]"
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(not(web_platform), doc = "`EventLoopExtWebSys::spawn()`")]
|
#[cfg_attr(not(web_platform), doc = "`EventLoopExtWebSys::spawn()`")]
|
||||||
/// [^1] instead of [`run()`] to avoid the need
|
/// [^1] instead of [`run_app()`] to avoid the need
|
||||||
/// for the Javascript exception trick, and to make it clearer that the event loop runs
|
/// for the Javascript exception trick, and to make it clearer that the event loop runs
|
||||||
/// asynchronously (via the browser's own, internal, event loop) and doesn't block the
|
/// asynchronously (via the browser's own, internal, event loop) and doesn't block the
|
||||||
/// current thread of execution like it does on other platforms.
|
/// current thread of execution like it does on other platforms.
|
||||||
@@ -240,15 +257,13 @@ impl<T> EventLoop<T> {
|
|||||||
/// This function won't be available with `target_feature = "exception-handling"`.
|
/// This function won't be available with `target_feature = "exception-handling"`.
|
||||||
///
|
///
|
||||||
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
||||||
/// [`run()`]: Self::run()
|
/// [`run_app()`]: Self::run_app()
|
||||||
/// [^1]: `EventLoopExtWebSys::spawn()` is only available on Web.
|
/// [^1]: `EventLoopExtWebSys::spawn_app()` is only available on Web.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
||||||
pub fn run<F>(self, event_handler: F) -> Result<(), EventLoopError>
|
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
where
|
self.event_loop
|
||||||
F: FnMut(Event<T>, &ActiveEventLoop),
|
.run(|event, event_loop| dispatch_event_for_app(app, event_loop, event))
|
||||||
{
|
|
||||||
self.event_loop.run(event_handler)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
|
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
|
||||||
@@ -274,6 +289,12 @@ impl<T> EventLoop<T> {
|
|||||||
///
|
///
|
||||||
/// [`DeviceEvent`]: crate::event::DeviceEvent
|
/// [`DeviceEvent`]: crate::event::DeviceEvent
|
||||||
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::EventLoop::listen_device_events",
|
||||||
|
allowed = ?allowed
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
|
|
||||||
self.event_loop
|
self.event_loop
|
||||||
.window_target()
|
.window_target()
|
||||||
.p
|
.p
|
||||||
@@ -295,6 +316,12 @@ impl<T> EventLoop<T> {
|
|||||||
#[deprecated = "use `ActiveEventLoop::create_window` instead"]
|
#[deprecated = "use `ActiveEventLoop::create_window` instead"]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn create_window(&self, window_attributes: WindowAttributes) -> Result<Window, OsError> {
|
pub fn create_window(&self, window_attributes: WindowAttributes) -> Result<Window, OsError> {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::EventLoop::create_window",
|
||||||
|
window_attributes = ?window_attributes
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
|
|
||||||
let window =
|
let window =
|
||||||
platform_impl::Window::new(&self.event_loop.window_target().p, window_attributes)?;
|
platform_impl::Window::new(&self.event_loop.window_target().p, window_attributes)?;
|
||||||
Ok(Window { window })
|
Ok(Window { window })
|
||||||
@@ -328,11 +355,11 @@ unsafe impl<T> rwh_05::HasRawDisplayHandle for EventLoop<T> {
|
|||||||
impl<T> AsFd for EventLoop<T> {
|
impl<T> AsFd for EventLoop<T> {
|
||||||
/// Get the underlying [EventLoop]'s `fd` which you can register
|
/// Get the underlying [EventLoop]'s `fd` which you can register
|
||||||
/// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
|
/// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
|
||||||
/// loop must be polled with the [`pump_events`] API.
|
/// loop must be polled with the [`pump_app_events`] API.
|
||||||
///
|
///
|
||||||
/// [`calloop`]: https://crates.io/crates/calloop
|
/// [`calloop`]: https://crates.io/crates/calloop
|
||||||
/// [`mio`]: https://crates.io/crates/mio
|
/// [`mio`]: https://crates.io/crates/mio
|
||||||
/// [`pump_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_events
|
/// [`pump_app_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_app_events
|
||||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||||
self.event_loop.as_fd()
|
self.event_loop.as_fd()
|
||||||
}
|
}
|
||||||
@@ -342,11 +369,11 @@ impl<T> AsFd for EventLoop<T> {
|
|||||||
impl<T> AsRawFd for EventLoop<T> {
|
impl<T> AsRawFd for EventLoop<T> {
|
||||||
/// Get the underlying [EventLoop]'s raw `fd` which you can register
|
/// Get the underlying [EventLoop]'s raw `fd` which you can register
|
||||||
/// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
|
/// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
|
||||||
/// loop must be polled with the [`pump_events`] API.
|
/// loop must be polled with the [`pump_app_events`] API.
|
||||||
///
|
///
|
||||||
/// [`calloop`]: https://crates.io/crates/calloop
|
/// [`calloop`]: https://crates.io/crates/calloop
|
||||||
/// [`mio`]: https://crates.io/crates/mio
|
/// [`mio`]: https://crates.io/crates/mio
|
||||||
/// [`pump_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_events
|
/// [`pump_app_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_app_events
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.event_loop.as_raw_fd()
|
self.event_loop.as_raw_fd()
|
||||||
}
|
}
|
||||||
@@ -363,18 +390,28 @@ impl ActiveEventLoop {
|
|||||||
/// see the web platform module for more information.
|
/// see the web platform module for more information.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn create_window(&self, window_attributes: WindowAttributes) -> Result<Window, OsError> {
|
pub fn create_window(&self, window_attributes: WindowAttributes) -> Result<Window, OsError> {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::ActiveEventLoop::create_window",
|
||||||
|
window_attributes = ?window_attributes
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
|
|
||||||
let window = platform_impl::Window::new(&self.p, window_attributes)?;
|
let window = platform_impl::Window::new(&self.p, window_attributes)?;
|
||||||
Ok(Window { window })
|
Ok(Window { window })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 {
|
||||||
|
let _span = tracing::debug_span!("winit::ActiveEventLoop::create_custom_cursor",).entered();
|
||||||
|
|
||||||
self.p.create_custom_cursor(custom_cursor)
|
self.p.create_custom_cursor(custom_cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of all the monitors available on the system.
|
/// Returns the list of all the monitors available on the system.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
||||||
|
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()
|
.available_monitors()
|
||||||
@@ -391,6 +428,8 @@ impl ActiveEventLoop {
|
|||||||
/// **Wayland / Web:** Always returns `None`.
|
/// **Wayland / Web:** Always returns `None`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
||||||
|
let _span = tracing::debug_span!("winit::ActiveEventLoop::primary_monitor",).entered();
|
||||||
|
|
||||||
self.p
|
self.p
|
||||||
.primary_monitor()
|
.primary_monitor()
|
||||||
.map(|inner| MonitorHandle { inner })
|
.map(|inner| MonitorHandle { inner })
|
||||||
@@ -408,6 +447,12 @@ impl ActiveEventLoop {
|
|||||||
///
|
///
|
||||||
/// [`DeviceEvent`]: crate::event::DeviceEvent
|
/// [`DeviceEvent`]: crate::event::DeviceEvent
|
||||||
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::ActiveEventLoop::listen_device_events",
|
||||||
|
allowed = ?allowed
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
|
|
||||||
self.p.listen_device_events(allowed);
|
self.p.listen_device_events(allowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,6 +470,8 @@ impl ActiveEventLoop {
|
|||||||
///
|
///
|
||||||
/// See [`LoopExiting`](Event::LoopExiting).
|
/// See [`LoopExiting`](Event::LoopExiting).
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
|
let _span = tracing::debug_span!("winit::ActiveEventLoop::exit",).entered();
|
||||||
|
|
||||||
self.p.exit()
|
self.p.exit()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,6 +577,8 @@ impl<T: 'static> EventLoopProxy<T> {
|
|||||||
///
|
///
|
||||||
/// [`UserEvent(event)`]: Event::UserEvent
|
/// [`UserEvent(event)`]: Event::UserEvent
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
||||||
|
let _span = tracing::debug_span!("winit::EventLoopProxy::send_event",).entered();
|
||||||
|
|
||||||
self.event_loop_proxy.send_event(event)
|
self.event_loop_proxy.send_event(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -592,3 +641,23 @@ impl AsyncRequestSerial {
|
|||||||
Self { serial }
|
Self { serial }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shim for various run APIs.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn dispatch_event_for_app<T: 'static, A: ApplicationHandler<T>>(
|
||||||
|
app: &mut A,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
event: Event<T>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
Event::NewEvents(cause) => app.new_events(event_loop, cause),
|
||||||
|
Event::WindowEvent { window_id, event } => app.window_event(event_loop, window_id, event),
|
||||||
|
Event::DeviceEvent { device_id, event } => app.device_event(event_loop, device_id, event),
|
||||||
|
Event::UserEvent(event) => app.user_event(event_loop, event),
|
||||||
|
Event::Suspended => app.suspended(event_loop),
|
||||||
|
Event::Resumed => app.resumed(event_loop),
|
||||||
|
Event::AboutToWait => app.about_to_wait(event_loop),
|
||||||
|
Event::LoopExiting => app.exiting(event_loop),
|
||||||
|
Event::MemoryWarning => app.memory_warning(event_loop),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -118,6 +118,8 @@ impl Icon {
|
|||||||
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
|
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
|
||||||
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
|
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
|
||||||
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();
|
||||||
|
|
||||||
Ok(Icon {
|
Ok(Icon {
|
||||||
inner: PlatformIcon::from_rgba(rgba, width, height)?,
|
inner: PlatformIcon::from_rgba(rgba, width, height)?,
|
||||||
})
|
})
|
||||||
|
|||||||
96
src/lib.rs
96
src/lib.rs
@@ -21,7 +21,7 @@
|
|||||||
//! 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()`]. 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`].
|
||||||
//!
|
//!
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
x11_platform,
|
x11_platform,
|
||||||
wayland_platform
|
wayland_platform
|
||||||
),
|
),
|
||||||
doc = "[`EventLoopExtPumpEvents::pump_events()`][platform::pump_events::EventLoopExtPumpEvents::pump_events()]"
|
doc = "[`EventLoopExtPumpEvents::pump_app_events()`][platform::pump_events::EventLoopExtPumpEvents::pump_app_events()]"
|
||||||
)]
|
)]
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
not(any(
|
not(any(
|
||||||
@@ -46,18 +46,54 @@
|
|||||||
x11_platform,
|
x11_platform,
|
||||||
wayland_platform
|
wayland_platform
|
||||||
)),
|
)),
|
||||||
doc = "`EventLoopExtPumpEvents::pump_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
|
||||||
//! it's discouraged beyond compatibility reasons.
|
//! it's discouraged beyond compatibility reasons.
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use winit::{
|
//! use winit::application::ApplicationHandler;
|
||||||
//! event::{Event, WindowEvent},
|
//! use winit::event::WindowEvent;
|
||||||
//! event_loop::{ControlFlow, EventLoop},
|
//! use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
|
||||||
//! window::Window,
|
//! use winit::window::{Window, WindowId};
|
||||||
//! };
|
//!
|
||||||
|
//! #[derive(Default)]
|
||||||
|
//! struct App {
|
||||||
|
//! window: Option<Window>,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! impl ApplicationHandler for App {
|
||||||
|
//! fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
//! self.window = Some(event_loop.create_window(Window::default_attributes()).unwrap());
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
|
||||||
|
//! match event {
|
||||||
|
//! WindowEvent::CloseRequested => {
|
||||||
|
//! println!("The close button was pressed; stopping");
|
||||||
|
//! event_loop.exit();
|
||||||
|
//! },
|
||||||
|
//! WindowEvent::RedrawRequested => {
|
||||||
|
//! // Redraw the application.
|
||||||
|
//! //
|
||||||
|
//! // It's preferable for applications that do not render continuously to render in
|
||||||
|
//! // this event rather than in AboutToWait, since rendering in here allows
|
||||||
|
//! // the program to gracefully handle redraws requested by the OS.
|
||||||
|
//!
|
||||||
|
//! // Draw.
|
||||||
|
//!
|
||||||
|
//! // Queue a RedrawRequested event.
|
||||||
|
//! //
|
||||||
|
//! // You only need to call this if you've determined that you need to redraw in
|
||||||
|
//! // applications which do not always need to. Applications that redraw continuously
|
||||||
|
//! // can render here instead.
|
||||||
|
//! self.window.as_ref().unwrap().request_redraw();
|
||||||
|
//! }
|
||||||
|
//! _ => (),
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
//!
|
//!
|
||||||
//! let event_loop = EventLoop::new().unwrap();
|
//! let event_loop = EventLoop::new().unwrap();
|
||||||
//!
|
//!
|
||||||
@@ -70,43 +106,8 @@
|
|||||||
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
|
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
|
||||||
//! event_loop.set_control_flow(ControlFlow::Wait);
|
//! event_loop.set_control_flow(ControlFlow::Wait);
|
||||||
//!
|
//!
|
||||||
//! let mut window = None;
|
//! let mut app = App::default();
|
||||||
//!
|
//! event_loop.run_app(&mut app);
|
||||||
//! event_loop.run(move |event, event_loop| {
|
|
||||||
//! match event {
|
|
||||||
//! Event::Resumed => {
|
|
||||||
//! window = Some(event_loop.create_window(Window::default_attributes()).unwrap());
|
|
||||||
//! }
|
|
||||||
//! Event::WindowEvent {
|
|
||||||
//! event: WindowEvent::CloseRequested,
|
|
||||||
//! ..
|
|
||||||
//! } => {
|
|
||||||
//! println!("The close button was pressed; stopping");
|
|
||||||
//! event_loop.exit();
|
|
||||||
//! },
|
|
||||||
//! Event::AboutToWait => {
|
|
||||||
//! // Application update code.
|
|
||||||
//!
|
|
||||||
//! // Queue a RedrawRequested event.
|
|
||||||
//! //
|
|
||||||
//! // You only need to call this if you've determined that you need to redraw in
|
|
||||||
//! // applications which do not always need to. Applications that redraw continuously
|
|
||||||
//! // can render here instead.
|
|
||||||
//! window.as_ref().unwrap().request_redraw();
|
|
||||||
//! },
|
|
||||||
//! Event::WindowEvent {
|
|
||||||
//! event: WindowEvent::RedrawRequested,
|
|
||||||
//! ..
|
|
||||||
//! } => {
|
|
||||||
//! // Redraw the application.
|
|
||||||
//! //
|
|
||||||
//! // It's preferable for applications that do not render continuously to render in
|
|
||||||
//! // this event rather than in AboutToWait, since rendering in here allows
|
|
||||||
//! // the program to gracefully handle redraws requested by the OS.
|
|
||||||
//! },
|
|
||||||
//! _ => ()
|
|
||||||
//! }
|
|
||||||
//! });
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! [`WindowEvent`] has a [`WindowId`] member. In multi-window environments, it should be
|
//! [`WindowEvent`] has a [`WindowId`] member. In multi-window environments, it should be
|
||||||
@@ -164,7 +165,7 @@
|
|||||||
//!
|
//!
|
||||||
//! [`EventLoop`]: event_loop::EventLoop
|
//! [`EventLoop`]: event_loop::EventLoop
|
||||||
//! [`EventLoop::new()`]: event_loop::EventLoop::new
|
//! [`EventLoop::new()`]: event_loop::EventLoop::new
|
||||||
//! [`EventLoop::run()`]: event_loop::EventLoop::run
|
//! [`EventLoop::run_app()`]: event_loop::EventLoop::run_app
|
||||||
//! [`exit()`]: event_loop::ActiveEventLoop::exit
|
//! [`exit()`]: event_loop::ActiveEventLoop::exit
|
||||||
//! [`Window`]: window::Window
|
//! [`Window`]: window::Window
|
||||||
//! [`WindowId`]: window::WindowId
|
//! [`WindowId`]: window::WindowId
|
||||||
@@ -178,7 +179,7 @@
|
|||||||
//! [`Event::LoopExiting`]: event::Event::LoopExiting
|
//! [`Event::LoopExiting`]: event::Event::LoopExiting
|
||||||
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
|
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
|
||||||
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
|
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
|
||||||
//! [^1]: `EventLoopExtPumpEvents::pump_events()` is only available on Windows, macOS, Android, X11 and Wayland.
|
//! [^1]: `EventLoopExtPumpEvents::pump_app_events()` is only available on Windows, macOS, Android, X11 and Wayland.
|
||||||
|
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms)]
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
#![deny(rustdoc::broken_intra_doc_links)]
|
||||||
@@ -200,6 +201,7 @@ pub use rwh_06 as raw_window_handle;
|
|||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use dpi;
|
pub use dpi;
|
||||||
|
|
||||||
|
pub mod application;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
//!
|
//!
|
||||||
//! 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.11", features = [ "android-native-activity" ] }`
|
//! 2. Enable the `"android-native-activity"` feature for Winit: `winit = { version = "0.29.14", features = [ "android-native-activity" ] }`
|
||||||
//! 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).
|
//! 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).
|
//! 4. Pass a clone of the `AndroidApp` that your application receives to Winit when building your event loop (as shown above).
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::{
|
use crate::application::ApplicationHandler;
|
||||||
event::Event,
|
use crate::event::Event;
|
||||||
event_loop::{ActiveEventLoop, EventLoop},
|
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
|
||||||
};
|
|
||||||
|
|
||||||
/// The return status for `pump_events`
|
|
||||||
pub enum PumpStatus {
|
|
||||||
/// Continue running external loop.
|
|
||||||
Continue,
|
|
||||||
/// Exit external loop.
|
|
||||||
Exit(i32),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional methods on [`EventLoop`] for pumping events within an external event loop
|
/// Additional methods on [`EventLoop`] for pumping events within an external event loop
|
||||||
pub trait EventLoopExtPumpEvents {
|
pub trait EventLoopExtPumpEvents {
|
||||||
/// A type provided by the user that can be passed through [`Event::UserEvent`].
|
/// A type provided by the user that can be passed through [`Event::UserEvent`].
|
||||||
type UserEvent;
|
type UserEvent: 'static;
|
||||||
|
|
||||||
/// Pump the `EventLoop` to check for and dispatch pending events.
|
/// Pump the `EventLoop` to check for and dispatch pending events.
|
||||||
///
|
///
|
||||||
@@ -113,6 +104,21 @@ pub trait EventLoopExtPumpEvents {
|
|||||||
/// If you render outside of Winit you are likely to see window resizing artifacts
|
/// If you render outside of Winit you are likely to see window resizing artifacts
|
||||||
/// since MacOS expects applications to render synchronously during any `drawRect`
|
/// since MacOS expects applications to render synchronously during any `drawRect`
|
||||||
/// callback.
|
/// callback.
|
||||||
|
fn pump_app_events<A: ApplicationHandler<Self::UserEvent>>(
|
||||||
|
&mut self,
|
||||||
|
timeout: Option<Duration>,
|
||||||
|
app: &mut A,
|
||||||
|
) -> PumpStatus {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
self.pump_events(timeout, |event, event_loop| {
|
||||||
|
event_loop::dispatch_event_for_app(app, event_loop, event)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`pump_app_events`].
|
||||||
|
///
|
||||||
|
/// [`pump_app_events`]: Self::pump_app_events
|
||||||
|
#[deprecated = "use EventLoopExtPumpEvents::pump_app_events"]
|
||||||
fn pump_events<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus
|
fn pump_events<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus
|
||||||
where
|
where
|
||||||
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
|
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
|
||||||
@@ -128,3 +134,11 @@ impl<T> EventLoopExtPumpEvents for EventLoop<T> {
|
|||||||
self.event_loop.pump_events(timeout, event_handler)
|
self.event_loop.pump_events(timeout, event_handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The return status for `pump_events`
|
||||||
|
pub enum PumpStatus {
|
||||||
|
/// Continue running external loop.
|
||||||
|
Continue,
|
||||||
|
/// Exit external loop.
|
||||||
|
Exit(i32),
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use crate::{
|
use crate::application::ApplicationHandler;
|
||||||
error::EventLoopError,
|
use crate::error::EventLoopError;
|
||||||
event::Event,
|
use crate::event::Event;
|
||||||
event_loop::{ActiveEventLoop, EventLoop},
|
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
|
use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
|
||||||
@@ -10,12 +9,19 @@ use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
|
|||||||
/// Additional methods on [`EventLoop`] to return control flow to the caller.
|
/// Additional methods on [`EventLoop`] to return control flow to the caller.
|
||||||
pub trait EventLoopExtRunOnDemand {
|
pub trait EventLoopExtRunOnDemand {
|
||||||
/// A type provided by the user that can be passed through [`Event::UserEvent`].
|
/// A type provided by the user that can be passed through [`Event::UserEvent`].
|
||||||
type UserEvent;
|
type UserEvent: 'static;
|
||||||
|
|
||||||
/// Runs the event loop in the calling thread and calls the given `event_handler` closure
|
/// See [`run_app_on_demand`].
|
||||||
/// to dispatch any window system events.
|
|
||||||
///
|
///
|
||||||
/// Unlike [`EventLoop::run`], this function accepts non-`'static` (i.e. non-`move`) closures
|
/// [`run_app_on_demand`]: Self::run_app_on_demand
|
||||||
|
#[deprecated = "use EventLoopExtRunOnDemand::run_app_on_demand"]
|
||||||
|
fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
|
||||||
|
where
|
||||||
|
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
|
||||||
|
|
||||||
|
/// 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
|
||||||
/// and it is possible to return control back to the caller without
|
/// 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.
|
||||||
@@ -26,11 +32,10 @@ pub trait EventLoopExtRunOnDemand {
|
|||||||
///
|
///
|
||||||
/// This API is not designed to run an event loop in bursts that you can exit from and return
|
/// This API is not designed to run an event loop in bursts that you can exit from and return
|
||||||
/// to while maintaining the full state of your application. (If you need something like this
|
/// to while maintaining the full state of your application. (If you need something like this
|
||||||
/// you can look at the [`EventLoopExtPumpEvents::pump_events()`] API)
|
/// you can look at the [`EventLoopExtPumpEvents::pump_app_events()`] API)
|
||||||
///
|
///
|
||||||
/// Each time `run_on_demand` is called the `event_handler` can expect to receive a
|
/// Each time `run_app_on_demand` is called the startup sequence of `init`, followed by
|
||||||
/// `NewEvents(Init)` and `Resumed` event (even on platforms that have no suspend/resume
|
/// `resume` is being preserved.
|
||||||
/// lifecycle) - which can be used to consistently initialize application state.
|
|
||||||
///
|
///
|
||||||
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
||||||
///
|
///
|
||||||
@@ -40,8 +45,8 @@ pub trait EventLoopExtRunOnDemand {
|
|||||||
/// backend it is possible to use `EventLoopExtWebSys::spawn()`[^1] more than once instead).
|
/// backend it is possible to use `EventLoopExtWebSys::spawn()`[^1] more than once instead).
|
||||||
/// - No [`Window`] state can be carried between separate runs of the event loop.
|
/// - No [`Window`] state can be carried between separate runs of the event loop.
|
||||||
///
|
///
|
||||||
/// You are strongly encouraged to use [`EventLoop::run()`] for portability, unless you specifically need
|
/// You are strongly encouraged to use [`EventLoop::run_app()`] for portability, unless you
|
||||||
/// the ability to re-run a single event loop more than once
|
/// specifically need the ability to re-run a single event loop more than once
|
||||||
///
|
///
|
||||||
/// # Supported Platforms
|
/// # Supported Platforms
|
||||||
/// - Windows
|
/// - Windows
|
||||||
@@ -64,9 +69,15 @@ pub trait EventLoopExtRunOnDemand {
|
|||||||
///
|
///
|
||||||
/// [`exit()`]: ActiveEventLoop::exit()
|
/// [`exit()`]: ActiveEventLoop::exit()
|
||||||
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
||||||
fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
|
fn run_app_on_demand<A: ApplicationHandler<Self::UserEvent>>(
|
||||||
where
|
&mut self,
|
||||||
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
|
app: &mut A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
self.run_on_demand(|event, event_loop| {
|
||||||
|
event_loop::dispatch_event_for_app(app, event_loop, event)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
|
impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
|
||||||
|
|||||||
@@ -53,9 +53,10 @@ use std::time::Duration;
|
|||||||
#[cfg(web_platform)]
|
#[cfg(web_platform)]
|
||||||
use web_sys::HtmlCanvasElement;
|
use web_sys::HtmlCanvasElement;
|
||||||
|
|
||||||
|
use crate::application::ApplicationHandler;
|
||||||
use crate::cursor::CustomCursorSource;
|
use crate::cursor::CustomCursorSource;
|
||||||
use crate::event::Event;
|
use crate::event::Event;
|
||||||
use crate::event_loop::{ActiveEventLoop, EventLoop};
|
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
|
||||||
#[cfg(web_platform)]
|
#[cfg(web_platform)]
|
||||||
use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture;
|
use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture;
|
||||||
use crate::platform_impl::PlatformCustomCursorSource;
|
use crate::platform_impl::PlatformCustomCursorSource;
|
||||||
@@ -160,18 +161,18 @@ impl WindowAttributesExtWebSys for WindowAttributes {
|
|||||||
/// Additional methods on `EventLoop` that are specific to the web.
|
/// Additional methods on `EventLoop` that are specific to the web.
|
||||||
pub trait EventLoopExtWebSys {
|
pub trait EventLoopExtWebSys {
|
||||||
/// A type provided by the user that can be passed through `Event::UserEvent`.
|
/// A type provided by the user that can be passed through `Event::UserEvent`.
|
||||||
type UserEvent;
|
type UserEvent: 'static;
|
||||||
|
|
||||||
/// Initializes the winit event loop.
|
/// Initializes the winit event loop.
|
||||||
///
|
///
|
||||||
/// Unlike
|
/// Unlike
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
all(web_platform, target_feature = "exception-handling"),
|
all(web_platform, target_feature = "exception-handling"),
|
||||||
doc = "`run()`"
|
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()`]"
|
doc = "[`run_app()`]"
|
||||||
)]
|
)]
|
||||||
/// [^1], this returns immediately, and doesn't throw an exception in order to
|
/// [^1], this returns immediately, and doesn't throw an exception in order to
|
||||||
/// satisfy its [`!`] return type.
|
/// satisfy its [`!`] return type.
|
||||||
@@ -183,9 +184,15 @@ pub trait EventLoopExtWebSys {
|
|||||||
///
|
///
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
not(all(web_platform, target_feature = "exception-handling")),
|
not(all(web_platform, target_feature = "exception-handling")),
|
||||||
doc = "[`run()`]: EventLoop::run()"
|
doc = "[`run_app()`]: EventLoop::run_app()"
|
||||||
)]
|
)]
|
||||||
/// [^1]: `run()` is _not_ available on WASM when the target supports `exception-handling`.
|
/// [^1]: `run_app()` is _not_ available on WASM when the target supports `exception-handling`.
|
||||||
|
fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, app: A);
|
||||||
|
|
||||||
|
/// See [`spawn_app`].
|
||||||
|
///
|
||||||
|
/// [`spawn_app`]: Self::spawn_app
|
||||||
|
#[deprecated = "use EventLoopExtWebSys::spawn_app"]
|
||||||
fn spawn<F>(self, event_handler: F)
|
fn spawn<F>(self, event_handler: F)
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
|
F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
|
||||||
@@ -194,6 +201,12 @@ pub trait EventLoopExtWebSys {
|
|||||||
impl<T> EventLoopExtWebSys for EventLoop<T> {
|
impl<T> EventLoopExtWebSys for EventLoop<T> {
|
||||||
type UserEvent = T;
|
type UserEvent = T;
|
||||||
|
|
||||||
|
fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, mut app: A) {
|
||||||
|
self.event_loop.spawn(move |event, event_loop| {
|
||||||
|
event_loop::dispatch_event_for_app(&mut app, event_loop, event)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn spawn<F>(self, event_handler: F)
|
fn spawn<F>(self, event_handler: F)
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop),
|
F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop),
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ pub fn character_map_and_combine_key(
|
|||||||
let key_map = match app.device_key_character_map(device_id) {
|
let key_map = match app.device_key_character_map(device_id) {
|
||||||
Ok(key_map) => key_map,
|
Ok(key_map) => key_map,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -188,7 +188,7 @@ 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) => {
|
||||||
log::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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@ pub fn character_map_and_combine_key(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use android_activity::input::{InputEvent, KeyAction, Keycode, MotionAction};
|
|||||||
use android_activity::{
|
use android_activity::{
|
||||||
AndroidApp, AndroidAppWaker, ConfigurationRef, InputStatus, MainEvent, Rect,
|
AndroidApp, AndroidAppWaker, ConfigurationRef, InputStatus, MainEvent, Rect,
|
||||||
};
|
};
|
||||||
use log::{debug, trace, warn};
|
use tracing::{debug, trace, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cursor::Cursor,
|
cursor::Cursor,
|
||||||
@@ -330,7 +330,7 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Failed to get input events iterator: {err:?}");
|
tracing::warn!("Failed to get input events iterator: {err:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,7 +1014,7 @@ 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 {
|
||||||
log::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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -622,9 +622,9 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
|
|||||||
match wrapper {
|
match wrapper {
|
||||||
EventWrapper::StaticEvent(event) => {
|
EventWrapper::StaticEvent(event) => {
|
||||||
if !processing_redraws && event.is_redraw() {
|
if !processing_redraws && event.is_redraw() {
|
||||||
log::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() {
|
||||||
log::warn!(
|
tracing::warn!(
|
||||||
"processing non `RedrawRequested` event after the main event loop: {:#?}",
|
"processing non `RedrawRequested` event after the main event loop: {:#?}",
|
||||||
event
|
event
|
||||||
);
|
);
|
||||||
@@ -676,9 +676,9 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
|
|||||||
match wrapper {
|
match wrapper {
|
||||||
EventWrapper::StaticEvent(event) => {
|
EventWrapper::StaticEvent(event) => {
|
||||||
if !processing_redraws && event.is_redraw() {
|
if !processing_redraws && event.is_redraw() {
|
||||||
log::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() {
|
||||||
log::warn!(
|
tracing::warn!(
|
||||||
"processing non-`RedrawRequested` event after the main event loop: {:#?}",
|
"processing non-`RedrawRequested` event after the main event loop: {:#?}",
|
||||||
event
|
event
|
||||||
);
|
);
|
||||||
@@ -911,7 +911,7 @@ macro_rules! os_capabilities {
|
|||||||
impl OSCapabilities {$(
|
impl OSCapabilities {$(
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
pub fn $error_name(&self, extra_msg: &str) {
|
pub fn $error_name(&self, extra_msg: &str) {
|
||||||
log::warn!(
|
tracing::warn!(
|
||||||
concat!("`", $objc_call, "` requires iOS {}.{}+. This device is running iOS {}.{}.{}. {}"),
|
concat!("`", $objc_call, "` requires iOS {}.{}+. This device is running iOS {}.{}.{}. {}"),
|
||||||
$major, $minor, self.os_version.majorVersion, self.os_version.minorVersion, self.os_version.patchVersion,
|
$major, $minor, self.os_version.majorVersion, self.os_version.minorVersion, self.os_version.patchVersion,
|
||||||
extra_msg
|
extra_msg
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ impl ActiveEventLoop {
|
|||||||
pub(crate) fn exit(&self) {
|
pub(crate) fn exit(&self) {
|
||||||
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
|
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
|
||||||
// it is not possible to quit an iOS app gracefully and programmatically
|
// it is not possible to quit an iOS app gracefully and programmatically
|
||||||
log::warn!("`ControlFlow::Exit` ignored on iOS");
|
tracing::warn!("`ControlFlow::Exit` ignored on iOS");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn exiting(&self) -> bool {
|
pub(crate) fn exiting(&self) -> bool {
|
||||||
@@ -182,7 +182,7 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
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\n\
|
||||||
Note: `EventLoop::run` calls `UIApplicationMain` on iOS",
|
Note: `EventLoop::run_app` calls `UIApplicationMain` on iOS",
|
||||||
);
|
);
|
||||||
|
|
||||||
let handler = map_user_event(handler, self.receiver);
|
let handler = map_user_event(handler, self.receiver);
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use icrate::Foundation::{CGFloat, CGPoint, CGRect, CGSize, MainThreadBound, MainThreadMarker};
|
use icrate::Foundation::{CGFloat, CGPoint, CGRect, CGSize, MainThreadBound, MainThreadMarker};
|
||||||
use log::{debug, warn};
|
|
||||||
use objc2::rc::Id;
|
use objc2::rc::Id;
|
||||||
use objc2::runtime::{AnyObject, NSObject};
|
use objc2::runtime::{AnyObject, NSObject};
|
||||||
use objc2::{class, declare_class, msg_send, msg_send_id, mutability, ClassType, DeclaredClass};
|
use objc2::{class, declare_class, msg_send, msg_send_id, mutability, ClassType, DeclaredClass};
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
use super::app_state::EventWrapper;
|
use super::app_state::EventWrapper;
|
||||||
use super::uikit::{
|
use super::uikit::{
|
||||||
@@ -689,7 +689,7 @@ 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` on iOS",
|
"`Window::get_inner_position` cannot be called before `EventLoop::run_app` on iOS",
|
||||||
);
|
);
|
||||||
app.statusBarFrame()
|
app.statusBarFrame()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use std::ptr::{self, NonNull};
|
|||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use crate::utils::Lazy;
|
use crate::utils::Lazy;
|
||||||
use log::warn;
|
|
||||||
use smol_str::SmolStr;
|
use smol_str::SmolStr;
|
||||||
#[cfg(wayland_platform)]
|
#[cfg(wayland_platform)]
|
||||||
use std::os::unix::io::OwnedFd;
|
use std::os::unix::io::OwnedFd;
|
||||||
|
use tracing::warn;
|
||||||
use xkbcommon_dl::{
|
use xkbcommon_dl::{
|
||||||
self as xkb, xkb_compose_status, xkb_context, xkb_context_flags, xkbcommon_compose_handle,
|
self as xkb, xkb_compose_status, xkb_context, xkb_context_flags, xkbcommon_compose_handle,
|
||||||
xkbcommon_handle, XkbCommon, XkbCommonCompose,
|
xkbcommon_handle, XkbCommon, XkbCommonCompose,
|
||||||
@@ -373,10 +373,15 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
|
|||||||
|
|
||||||
fn composed_text(&mut self) -> Result<Option<SmolStr>, ()> {
|
fn composed_text(&mut self) -> Result<Option<SmolStr>, ()> {
|
||||||
match self.compose {
|
match self.compose {
|
||||||
ComposeStatus::Accepted(xkb_compose_status::XKB_COMPOSE_COMPOSED) => {
|
ComposeStatus::Accepted(status) => match status {
|
||||||
let state = self.context.compose_state1.as_mut().unwrap();
|
xkb_compose_status::XKB_COMPOSE_COMPOSED => {
|
||||||
Ok(state.get_string(self.context.scratch_buffer))
|
let state = self.context.compose_state1.as_mut().unwrap();
|
||||||
}
|
Ok(state.get_string(self.context.scratch_buffer))
|
||||||
|
}
|
||||||
|
xkb_compose_status::XKB_COMPOSE_COMPOSING
|
||||||
|
| xkb_compose_status::XKB_COMPOSE_CANCELLED => Ok(None),
|
||||||
|
xkb_compose_status::XKB_COMPOSE_NOTHING => Err(()),
|
||||||
|
},
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,7 +456,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| {
|
||||||
log::warn!(
|
tracing::warn!(
|
||||||
"UTF-8 received from libxkbcommon ({:?}) was invalid: {e}",
|
"UTF-8 received from libxkbcommon ({:?}) was invalid: {e}",
|
||||||
bytes
|
bytes
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -687,7 +687,7 @@ unsafe extern "C" fn x_error_callback(
|
|||||||
|
|
||||||
// Don't log error.
|
// Don't log error.
|
||||||
if !error_handled {
|
if !error_handled {
|
||||||
log::error!("X11 error: {:#?}", error);
|
tracing::error!("X11 error: {:#?}", error);
|
||||||
// XXX only update the error, if it wasn't handled by any of the hooks.
|
// XXX only update the error, if it wasn't handled by any of the hooks.
|
||||||
*xconn.latest_error.lock().unwrap() = Some(error);
|
*xconn.latest_error.lock().unwrap() = Some(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -584,7 +584,7 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.event_loop.dispatch(timeout, state).map_err(|error| {
|
self.event_loop.dispatch(timeout, state).map_err(|error| {
|
||||||
log::error!("Error dispatching event loop: {}", error);
|
tracing::error!("Error dispatching event loop: {}", error);
|
||||||
error.into()
|
error.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use calloop::timer::{TimeoutAction, Timer};
|
use calloop::timer::{TimeoutAction, Timer};
|
||||||
use calloop::{LoopHandle, RegistrationToken};
|
use calloop::{LoopHandle, RegistrationToken};
|
||||||
use log::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use sctk::reexports::client::protocol::wl_keyboard::WlKeyboard;
|
use sctk::reexports::client::protocol::wl_keyboard::WlKeyboard;
|
||||||
use sctk::reexports::client::protocol::wl_keyboard::{
|
use sctk::reexports::client::protocol::wl_keyboard::{
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ impl WinitState {
|
|||||||
) {
|
) {
|
||||||
Ok(c) => Some(c),
|
Ok(c) => Some(c),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Subcompositor protocol not available, ignoring CSD: {e:?}");
|
tracing::warn!("Subcompositor protocol not available, ignoring CSD: {e:?}");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use sctk::shell::xdg::window::Window as SctkWindow;
|
|||||||
use sctk::shell::xdg::window::WindowDecorations;
|
use sctk::shell::xdg::window::WindowDecorations;
|
||||||
use sctk::shell::WaylandSurface;
|
use sctk::shell::WaylandSurface;
|
||||||
|
|
||||||
use log::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
|
use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
|
||||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::sync::{Arc, Mutex, Weak};
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use ahash::HashSet;
|
use ahash::HashSet;
|
||||||
use log::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use sctk::reexports::client::backend::ObjectId;
|
use sctk::reexports::client::backend::ObjectId;
|
||||||
use sctk::reexports::client::protocol::wl_seat::WlSeat;
|
use sctk::reexports::client::protocol::wl_seat::WlSeat;
|
||||||
@@ -727,7 +727,7 @@ impl WindowState {
|
|||||||
RootCustomCursor {
|
RootCustomCursor {
|
||||||
inner: PlatformCustomCursor::X(_),
|
inner: PlatformCustomCursor::X(_),
|
||||||
} => {
|
} => {
|
||||||
log::error!("passed a X11 cursor to Wayland backend");
|
tracing::error!("passed a X11 cursor to Wayland backend");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -826,9 +826,14 @@ impl WindowState {
|
|||||||
|
|
||||||
/// Set the cursor grabbing state on the top-level.
|
/// Set the cursor grabbing state on the top-level.
|
||||||
pub fn set_cursor_grab(&mut self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
pub fn set_cursor_grab(&mut self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
||||||
// Replace the user grabbing mode.
|
if self.cursor_grab_mode.user_grab_mode == mode {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_cursor_grab_inner(mode)?;
|
||||||
|
// Update user grab on success.
|
||||||
self.cursor_grab_mode.user_grab_mode = mode;
|
self.cursor_grab_mode.user_grab_mode = mode;
|
||||||
self.set_cursor_grab_inner(mode)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reload the hints for minimum and maximum sizes.
|
/// Reload the hints for minimum and maximum sizes.
|
||||||
|
|||||||
@@ -33,9 +33,10 @@ 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::util::cookie::GenericEventCookie;
|
||||||
use crate::platform_impl::x11::{
|
use crate::platform_impl::x11::{
|
||||||
atoms::*, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState,
|
atoms::*, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState,
|
||||||
GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
|
ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The maximum amount of X modifiers to replay.
|
/// The maximum amount of X modifiers to replay.
|
||||||
@@ -184,14 +185,15 @@ impl EventProcessor {
|
|||||||
}
|
}
|
||||||
xlib::GenericEvent => {
|
xlib::GenericEvent => {
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let xev = match GenericEventCookie::from_event(&wt.xconn, *xev) {
|
let xev: GenericEventCookie =
|
||||||
Some(xev) if xev.cookie.extension as u8 == self.xi2ext.major_opcode => {
|
match GenericEventCookie::from_event(wt.xconn.clone(), *xev) {
|
||||||
xev.cookie
|
Some(xev) if xev.extension() == self.xi2ext.major_opcode => xev,
|
||||||
}
|
_ => return,
|
||||||
_ => return,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
match xev.evtype {
|
let evtype = xev.evtype();
|
||||||
|
|
||||||
|
match evtype {
|
||||||
ty @ xinput2::XI_ButtonPress | ty @ xinput2::XI_ButtonRelease => {
|
ty @ xinput2::XI_ButtonPress | ty @ xinput2::XI_ButtonRelease => {
|
||||||
let state = if ty == xinput2::XI_ButtonPress {
|
let state = if ty == xinput2::XI_ButtonPress {
|
||||||
ElementState::Pressed
|
ElementState::Pressed
|
||||||
@@ -199,7 +201,7 @@ impl EventProcessor {
|
|||||||
ElementState::Released
|
ElementState::Released
|
||||||
};
|
};
|
||||||
|
|
||||||
let xev: &XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIDeviceEvent = unsafe { xev.as_event() };
|
||||||
self.update_mods_from_xinput2_event(
|
self.update_mods_from_xinput2_event(
|
||||||
&xev.mods,
|
&xev.mods,
|
||||||
&xev.group,
|
&xev.group,
|
||||||
@@ -209,7 +211,7 @@ impl EventProcessor {
|
|||||||
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.data as *const _) };
|
let xev: &XIDeviceEvent = unsafe { xev.as_event() };
|
||||||
self.update_mods_from_xinput2_event(
|
self.update_mods_from_xinput2_event(
|
||||||
&xev.mods,
|
&xev.mods,
|
||||||
&xev.group,
|
&xev.group,
|
||||||
@@ -219,11 +221,11 @@ impl EventProcessor {
|
|||||||
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.data as *const _) };
|
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.data as *const _) };
|
let xev: &XILeaveEvent = unsafe { xev.as_event() };
|
||||||
self.update_mods_from_xinput2_event(
|
self.update_mods_from_xinput2_event(
|
||||||
&xev.mods,
|
&xev.mods,
|
||||||
&xev.group,
|
&xev.group,
|
||||||
@@ -233,51 +235,51 @@ impl EventProcessor {
|
|||||||
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.data as *const _) };
|
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.data as *const _) };
|
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 xev.evtype {
|
let phase = match evtype {
|
||||||
xinput2::XI_TouchBegin => TouchPhase::Started,
|
xinput2::XI_TouchBegin => TouchPhase::Started,
|
||||||
xinput2::XI_TouchUpdate => TouchPhase::Moved,
|
xinput2::XI_TouchUpdate => TouchPhase::Moved,
|
||||||
xinput2::XI_TouchEnd => TouchPhase::Ended,
|
xinput2::XI_TouchEnd => TouchPhase::Ended,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xev: &XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
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 xev.evtype {
|
let state = match evtype {
|
||||||
xinput2::XI_RawButtonPress => ElementState::Pressed,
|
xinput2::XI_RawButtonPress => ElementState::Pressed,
|
||||||
xinput2::XI_RawButtonRelease => ElementState::Released,
|
xinput2::XI_RawButtonRelease => ElementState::Released,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xev: &XIRawEvent = unsafe { &*(xev.data as *const _) };
|
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.data as *const _) };
|
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 xev.evtype {
|
let state = match evtype {
|
||||||
xinput2::XI_RawKeyPress => ElementState::Pressed,
|
xinput2::XI_RawKeyPress => ElementState::Pressed,
|
||||||
xinput2::XI_RawKeyRelease => ElementState::Released,
|
xinput2::XI_RawKeyRelease => ElementState::Released,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xev: &xinput2::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
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.data as *const _) };
|
let xev: &XIHierarchyEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_hierarchy_changed(xev, &mut callback);
|
self.xinput2_hierarchy_changed(xev, &mut callback);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -979,7 +981,7 @@ impl EventProcessor {
|
|||||||
|
|
||||||
// Always update the modifiers when we're not replaying.
|
// Always update the modifiers when we're not replaying.
|
||||||
if !replay {
|
if !replay {
|
||||||
self.udpate_mods_from_core_event(window_id, xev.state as u16, &mut callback);
|
self.update_mods_from_core_event(window_id, xev.state as u16, &mut callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
if keycode != 0 && !self.is_composing {
|
if keycode != 0 && !self.is_composing {
|
||||||
@@ -1518,8 +1520,8 @@ impl EventProcessor {
|
|||||||
let mask =
|
let mask =
|
||||||
unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
|
unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
|
||||||
let mut value = xev.raw_values;
|
let mut value = xev.raw_values;
|
||||||
let mut mouse_delta = (0.0, 0.0);
|
let mut mouse_delta = util::Delta::default();
|
||||||
let mut scroll_delta = (0.0, 0.0);
|
let mut scroll_delta = util::Delta::default();
|
||||||
for i in 0..xev.valuators.mask_len * 8 {
|
for i in 0..xev.valuators.mask_len * 8 {
|
||||||
if !xinput2::XIMaskIsSet(mask, i) {
|
if !xinput2::XIMaskIsSet(mask, i) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1529,10 +1531,10 @@ impl EventProcessor {
|
|||||||
// We assume that every XInput2 device with analog axes is a pointing device emitting
|
// We assume that every XInput2 device with analog axes is a pointing device emitting
|
||||||
// relative coordinates.
|
// relative coordinates.
|
||||||
match i {
|
match i {
|
||||||
0 => mouse_delta.0 = x,
|
0 => mouse_delta.set_x(x),
|
||||||
1 => mouse_delta.1 = x,
|
1 => mouse_delta.set_y(x),
|
||||||
2 => scroll_delta.0 = x as f32,
|
2 => scroll_delta.set_x(x as f32),
|
||||||
3 => scroll_delta.1 = x as f32,
|
3 => scroll_delta.set_y(x as f32),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1548,7 +1550,7 @@ impl EventProcessor {
|
|||||||
value = unsafe { value.offset(1) };
|
value = unsafe { value.offset(1) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if mouse_delta != (0.0, 0.0) {
|
if let Some(mouse_delta) = mouse_delta.consume() {
|
||||||
let event = Event::DeviceEvent {
|
let event = Event::DeviceEvent {
|
||||||
device_id: did,
|
device_id: did,
|
||||||
event: DeviceEvent::MouseMotion { delta: mouse_delta },
|
event: DeviceEvent::MouseMotion { delta: mouse_delta },
|
||||||
@@ -1556,7 +1558,7 @@ impl EventProcessor {
|
|||||||
callback(&self.target, event);
|
callback(&self.target, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if scroll_delta != (0.0, 0.0) {
|
if let Some(scroll_delta) = scroll_delta.consume() {
|
||||||
let event = Event::DeviceEvent {
|
let event = Event::DeviceEvent {
|
||||||
device_id: did,
|
device_id: did,
|
||||||
event: DeviceEvent::MouseWheel {
|
event: DeviceEvent::MouseWheel {
|
||||||
@@ -1776,7 +1778,7 @@ impl EventProcessor {
|
|||||||
self.send_modifiers(window_id, mods.into(), true, &mut callback)
|
self.send_modifiers(window_id, mods.into(), true, &mut callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn udpate_mods_from_core_event<T: 'static, F>(
|
pub fn update_mods_from_core_event<T: 'static, F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_id: crate::window::WindowId,
|
window_id: crate::window::WindowId,
|
||||||
state: u16,
|
state: u16,
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ extern "C" fn preedit_draw_callback(
|
|||||||
let chg_range =
|
let chg_range =
|
||||||
call_data.chg_first as usize..(call_data.chg_first + call_data.chg_length) as usize;
|
call_data.chg_first as usize..(call_data.chg_first + call_data.chg_length) as usize;
|
||||||
if chg_range.start > client_data.text.len() || chg_range.end > client_data.text.len() {
|
if chg_range.start > client_data.text.len() || chg_range.end > client_data.text.len() {
|
||||||
log::warn!(
|
tracing::warn!(
|
||||||
"invalid chg range: buffer length={}, but chg_first={} chg_lengthg={}",
|
"invalid chg range: buffer length={}, but chg_first={} chg_lengthg={}",
|
||||||
client_data.text.len(),
|
client_data.text.len(),
|
||||||
call_data.chg_first,
|
call_data.chg_first,
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ use std::sync::{
|
|||||||
Arc,
|
Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::debug;
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use super::{ffi, util, XConnection, XError};
|
use super::{ffi, util, XConnection, XError};
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use calloop::generic::Generic;
|
|||||||
use calloop::EventLoop as Loop;
|
use calloop::EventLoop as Loop;
|
||||||
use calloop::{ping::Ping, Readiness};
|
use calloop::{ping::Ping, Readiness};
|
||||||
use libc::{setlocale, LC_CTYPE};
|
use libc::{setlocale, LC_CTYPE};
|
||||||
use log::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use x11rb::connection::RequestConnection;
|
use x11rb::connection::RequestConnection;
|
||||||
use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError};
|
use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError};
|
||||||
@@ -66,6 +66,9 @@ const ALL_DEVICES: u16 = 0;
|
|||||||
const ALL_MASTER_DEVICES: u16 = 1;
|
const ALL_MASTER_DEVICES: u16 = 1;
|
||||||
const ICONIC_STATE: u32 = 3;
|
const ICONIC_STATE: u32 = 3;
|
||||||
|
|
||||||
|
/// The underlying x11rb connection that we are using.
|
||||||
|
type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
|
||||||
|
|
||||||
type X11Source = Generic<BorrowedFd<'static>>;
|
type X11Source = Generic<BorrowedFd<'static>>;
|
||||||
|
|
||||||
struct WakeSender<T> {
|
struct WakeSender<T> {
|
||||||
@@ -480,7 +483,7 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
.dispatch(timeout, &mut self.state)
|
.dispatch(timeout, &mut self.state)
|
||||||
.map_err(std::io::Error::from)
|
.map_err(std::io::Error::from)
|
||||||
{
|
{
|
||||||
log::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);
|
||||||
self.set_exit_code(exit_code);
|
self.set_exit_code(exit_code);
|
||||||
return;
|
return;
|
||||||
@@ -564,7 +567,7 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
callback(event, &self.event_processor.target)
|
callback(event, &self.event_processor.target)
|
||||||
}
|
}
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => {
|
||||||
log::error!("Failed to get activation token: {}", e);
|
tracing::error!("Failed to get activation token: {}", e);
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
@@ -884,6 +887,9 @@ pub enum X11Error {
|
|||||||
|
|
||||||
/// Unable to parse xsettings.
|
/// Unable to parse xsettings.
|
||||||
XsettingsParse(xsettings::ParserError),
|
XsettingsParse(xsettings::ParserError),
|
||||||
|
|
||||||
|
/// Failed to get property.
|
||||||
|
GetProperty(util::GetPropertyError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for X11Error {
|
impl fmt::Display for X11Error {
|
||||||
@@ -893,6 +899,7 @@ impl fmt::Display for X11Error {
|
|||||||
X11Error::Connect(e) => write!(f, "X11 connection error: {}", e),
|
X11Error::Connect(e) => write!(f, "X11 connection error: {}", e),
|
||||||
X11Error::Connection(e) => write!(f, "X11 connection error: {}", e),
|
X11Error::Connection(e) => write!(f, "X11 connection error: {}", e),
|
||||||
X11Error::XidsExhausted(e) => write!(f, "XID range exhausted: {}", e),
|
X11Error::XidsExhausted(e) => write!(f, "XID range exhausted: {}", e),
|
||||||
|
X11Error::GetProperty(e) => write!(f, "Failed to get X property {}", e),
|
||||||
X11Error::X11(e) => write!(f, "X11 error: {:?}", e),
|
X11Error::X11(e) => write!(f, "X11 error: {:?}", e),
|
||||||
X11Error::UnexpectedNull(s) => write!(f, "Xlib function returned null: {}", s),
|
X11Error::UnexpectedNull(s) => write!(f, "Xlib function returned null: {}", s),
|
||||||
X11Error::InvalidActivationToken(s) => write!(
|
X11Error::InvalidActivationToken(s) => write!(
|
||||||
@@ -985,8 +992,11 @@ impl From<xsettings::ParserError> for X11Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The underlying x11rb connection that we are using.
|
impl From<util::GetPropertyError> for X11Error {
|
||||||
type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
|
fn from(value: util::GetPropertyError) -> Self {
|
||||||
|
Self::GetProperty(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Type alias for a void cookie.
|
/// Type alias for a void cookie.
|
||||||
type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
|
type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
|
||||||
@@ -1003,34 +1013,6 @@ impl<'a, E: fmt::Debug> CookieResultExt for Result<VoidCookie<'a>, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// XEvents of type GenericEvent store their actual data in an XGenericEventCookie data structure. This is a wrapper to
|
|
||||||
/// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
|
|
||||||
struct GenericEventCookie<'a> {
|
|
||||||
xconn: &'a XConnection,
|
|
||||||
cookie: ffi::XGenericEventCookie,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> GenericEventCookie<'a> {
|
|
||||||
fn from_event(xconn: &XConnection, event: ffi::XEvent) -> Option<GenericEventCookie<'_>> {
|
|
||||||
unsafe {
|
|
||||||
let mut cookie: ffi::XGenericEventCookie = From::from(event);
|
|
||||||
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True {
|
|
||||||
Some(GenericEventCookie { xconn, cookie })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Drop for GenericEventCookie<'a> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
(self.xconn.xlib.XFreeEventData)(self.xconn.display, &mut self.cookie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mkwid(w: xproto::Window) -> crate::window::WindowId {
|
fn mkwid(w: xproto::Window) -> crate::window::WindowId {
|
||||||
crate::window::WindowId(crate::platform_impl::platform::WindowId(w as _))
|
crate::window::WindowId(crate::platform_impl::platform::WindowId(w as _))
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/platform_impl/linux/x11/util/cookie.rs
Normal file
55
src/platform_impl/linux/x11/util/cookie.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use std::ffi::c_int;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use x11_dl::xlib::{self, XEvent, XGenericEventCookie};
|
||||||
|
|
||||||
|
use crate::platform_impl::x11::XConnection;
|
||||||
|
|
||||||
|
/// XEvents of type GenericEvent store their actual data in an XGenericEventCookie data structure.
|
||||||
|
/// This is a wrapper to extract the cookie from a GenericEvent XEvent and release the cookie data
|
||||||
|
/// once it has been processed
|
||||||
|
pub struct GenericEventCookie {
|
||||||
|
cookie: XGenericEventCookie,
|
||||||
|
xconn: Arc<XConnection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenericEventCookie {
|
||||||
|
pub fn from_event(xconn: Arc<XConnection>, event: XEvent) -> Option<GenericEventCookie> {
|
||||||
|
unsafe {
|
||||||
|
let mut cookie: XGenericEventCookie = From::from(event);
|
||||||
|
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == xlib::True {
|
||||||
|
Some(GenericEventCookie { cookie, xconn })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn extension(&self) -> u8 {
|
||||||
|
self.cookie.extension as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn evtype(&self) -> c_int {
|
||||||
|
self.cookie.evtype
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Borrow inner event data as `&T`.
|
||||||
|
///
|
||||||
|
/// ## SAFETY
|
||||||
|
///
|
||||||
|
/// The caller must ensure that the event has the `T` inside of it.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn as_event<T>(&self) -> &T {
|
||||||
|
unsafe { &*(self.cookie.data as *const _) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for GenericEventCookie {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
(self.xconn.xlib.XFreeEventData)(self.xconn.display, &mut self.cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ impl XConnection {
|
|||||||
self.flush_requests()?;
|
self.flush_requests()?;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
log::error!("Could not select XKB events: The XKB extension is not initialized!");
|
tracing::error!("Could not select XKB events: The XKB extension is not initialized!");
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
mod client_msg;
|
mod client_msg;
|
||||||
|
pub mod cookie;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
mod hint;
|
mod hint;
|
||||||
@@ -15,13 +16,15 @@ mod icon;
|
|||||||
mod input;
|
mod input;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub(crate) mod memory;
|
pub(crate) mod memory;
|
||||||
|
mod mouse;
|
||||||
mod randr;
|
mod randr;
|
||||||
mod window_property;
|
mod window_property;
|
||||||
mod wm;
|
mod wm;
|
||||||
mod xmodmap;
|
mod xmodmap;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
cursor::*, geometry::*, hint::*, input::*, window_property::*, wm::*, xmodmap::ModifierKeymap,
|
cursor::*, geometry::*, hint::*, input::*, mouse::*, window_property::*, wm::*,
|
||||||
|
xmodmap::ModifierKeymap,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{atoms::*, ffi, VoidCookie, X11Error, XConnection, XError};
|
use super::{atoms::*, ffi, VoidCookie, X11Error, XConnection, XError};
|
||||||
|
|||||||
52
src/platform_impl/linux/x11/util/mouse.rs
Normal file
52
src/platform_impl/linux/x11/util/mouse.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
//! Utilities for handling mouse events.
|
||||||
|
|
||||||
|
/// Recorded mouse delta designed to filter out noise.
|
||||||
|
pub struct Delta<T> {
|
||||||
|
x: T,
|
||||||
|
y: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default> Default for Delta<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
x: Default::default(),
|
||||||
|
y: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default> Delta<T> {
|
||||||
|
pub(crate) fn set_x(&mut self, x: T) {
|
||||||
|
self.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_y(&mut self, y: T) {
|
||||||
|
self.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! consume {
|
||||||
|
($this:expr, $ty:ty) => {{
|
||||||
|
let this = $this;
|
||||||
|
let (x, y) = match (this.x.abs() < <$ty>::EPSILON, this.y.abs() < <$ty>::EPSILON) {
|
||||||
|
(true, true) => return None,
|
||||||
|
(false, true) => (this.x, 0.0),
|
||||||
|
(true, false) => (0.0, this.y),
|
||||||
|
(false, false) => (this.x, this.y),
|
||||||
|
};
|
||||||
|
|
||||||
|
Some((x, y))
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Delta<f32> {
|
||||||
|
pub(crate) fn consume(self) -> Option<(f32, f32)> {
|
||||||
|
consume!(self, f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Delta<f64> {
|
||||||
|
pub(crate) fn consume(self) -> Option<(f64, f64)> {
|
||||||
|
consume!(self, f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ use super::*;
|
|||||||
use crate::platform_impl::platform::x11::monitor;
|
use crate::platform_impl::platform::x11::monitor;
|
||||||
use crate::{dpi::validate_scale_factor, platform_impl::platform::x11::VideoModeHandle};
|
use crate::{dpi::validate_scale_factor, platform_impl::platform::x11::VideoModeHandle};
|
||||||
|
|
||||||
use log::warn;
|
use tracing::warn;
|
||||||
use x11rb::protocol::randr::{self, ConnectionExt as _};
|
use x11rb::protocol::randr::{self, ConnectionExt as _};
|
||||||
|
|
||||||
/// Represents values of `WINIT_HIDPI_FACTOR`.
|
/// Represents values of `WINIT_HIDPI_FACTOR`.
|
||||||
@@ -44,7 +44,7 @@ impl XConnection {
|
|||||||
Ok(Some(dpi)) => return Some(dpi),
|
Ok(Some(dpi)) => return Some(dpi),
|
||||||
Ok(None) => {}
|
Ok(None) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("failed to fetch XSettings: {err}");
|
tracing::warn!("failed to fetch XSettings: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,6 +53,7 @@ impl XConnection {
|
|||||||
.get_string("Xft.dpi", "")
|
.get_string("Xft.dpi", "")
|
||||||
.and_then(|s| f64::from_str(s).ok())
|
.and_then(|s| f64::from_str(s).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_output_info(
|
pub fn get_output_info(
|
||||||
&self,
|
&self,
|
||||||
resources: &monitor::ScreenResources,
|
resources: &monitor::ScreenResources,
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
use super::*;
|
use std::error::Error;
|
||||||
use bytemuck::{NoUninit, Pod};
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bytemuck::{NoUninit, Pod};
|
||||||
|
|
||||||
use x11rb::connection::Connection;
|
use x11rb::connection::Connection;
|
||||||
use x11rb::errors::ReplyError;
|
use x11rb::errors::ReplyError;
|
||||||
|
|
||||||
pub type Cardinal = u32;
|
use super::*;
|
||||||
|
|
||||||
pub const CARDINAL_SIZE: usize = mem::size_of::<u32>();
|
pub const CARDINAL_SIZE: usize = mem::size_of::<u32>();
|
||||||
|
|
||||||
|
pub type Cardinal = u32;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum GetPropertyError {
|
pub enum GetPropertyError {
|
||||||
X11rbError(Arc<ReplyError>),
|
X11rbError(Arc<ReplyError>),
|
||||||
@@ -15,12 +20,6 @@ pub enum GetPropertyError {
|
|||||||
FormatMismatch(c_int),
|
FormatMismatch(c_int),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<ReplyError>> From<T> for GetPropertyError {
|
|
||||||
fn from(e: T) -> Self {
|
|
||||||
Self::X11rbError(Arc::new(e.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetPropertyError {
|
impl GetPropertyError {
|
||||||
pub fn is_actual_property_type(&self, t: xproto::Atom) -> bool {
|
pub fn is_actual_property_type(&self, t: xproto::Atom) -> bool {
|
||||||
if let GetPropertyError::TypeMismatch(actual_type) = *self {
|
if let GetPropertyError::TypeMismatch(actual_type) = *self {
|
||||||
@@ -31,6 +30,24 @@ impl GetPropertyError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Into<ReplyError>> From<T> for GetPropertyError {
|
||||||
|
fn from(e: T) -> Self {
|
||||||
|
Self::X11rbError(Arc::new(e.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GetPropertyError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
GetPropertyError::X11rbError(err) => err.fmt(f),
|
||||||
|
GetPropertyError::TypeMismatch(err) => write!(f, "type mismatch: {err}"),
|
||||||
|
GetPropertyError::FormatMismatch(err) => write!(f, "format mismatch: {err}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for GetPropertyError {}
|
||||||
|
|
||||||
// Number of 32-bit chunks to retrieve per iteration of get_property's inner loop.
|
// Number of 32-bit chunks to retrieve per iteration of get_property's inner loop.
|
||||||
// To test if `get_property` works correctly, set this to 1.
|
// To test if `get_property` works correctly, set this to 1.
|
||||||
const PROPERTY_BUFFER_SIZE: u32 = 1024; // 4k of RAM ought to be enough for anyone!
|
const PROPERTY_BUFFER_SIZE: u32 = 1024; // 4k of RAM ought to be enough for anyone!
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const NUM_MODS: usize = 8;
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ModifierKeymap {
|
pub struct ModifierKeymap {
|
||||||
// Maps keycodes to modifiers
|
// Maps keycodes to modifiers
|
||||||
modifers: HashSet<XKeyCode>,
|
modifiers: HashSet<XKeyCode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModifierKeymap {
|
impl ModifierKeymap {
|
||||||
@@ -25,7 +25,7 @@ impl ModifierKeymap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_modifier(&self, keycode: XKeyCode) -> bool {
|
pub fn is_modifier(&self, keycode: XKeyCode) -> bool {
|
||||||
self.modifers.contains(&keycode)
|
self.modifiers.contains(&keycode)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reload_from_x_connection(&mut self, xconn: &super::XConnection) {
|
pub fn reload_from_x_connection(&mut self, xconn: &super::XConnection) {
|
||||||
@@ -48,9 +48,9 @@ impl ModifierKeymap {
|
|||||||
let keys = unsafe {
|
let keys = unsafe {
|
||||||
slice::from_raw_parts(keymap.modifiermap as *const _, keys_per_mod * NUM_MODS)
|
slice::from_raw_parts(keymap.modifiermap as *const _, keys_per_mod * NUM_MODS)
|
||||||
};
|
};
|
||||||
self.modifers.clear();
|
self.modifiers.clear();
|
||||||
for key in keys {
|
for key in keys {
|
||||||
self.modifers.insert(*key);
|
self.modifiers.insert(*key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::{
|
|||||||
sync::{Arc, Mutex, MutexGuard},
|
sync::{Arc, Mutex, MutexGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
use x11rb::{
|
use x11rb::{
|
||||||
connection::Connection,
|
connection::Connection,
|
||||||
properties::{WmHints, WmSizeHints, WmSizeHintsSpecification},
|
properties::{WmHints, WmSizeHints, WmSizeHintsSpecification},
|
||||||
@@ -1573,7 +1573,7 @@ impl UnownedWindow {
|
|||||||
#[cfg(wayland_platform)]
|
#[cfg(wayland_platform)]
|
||||||
Cursor::Custom(RootCustomCursor {
|
Cursor::Custom(RootCustomCursor {
|
||||||
inner: PlatformCustomCursor::Wayland(_),
|
inner: PlatformCustomCursor::Wayland(_),
|
||||||
}) => log::error!("passed a Wayland cursor to X11 backend"),
|
}) => tracing::error!("passed a Wayland cursor to X11 backend"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1857,7 +1857,7 @@ impl UnownedWindow {
|
|||||||
)
|
)
|
||||||
.expect_then_ignore_error("Failed to send client message");
|
.expect_then_ignore_error("Failed to send client message");
|
||||||
if let Err(e) = self.xconn.flush_requests() {
|
if let Err(e) = self.xconn.flush_requests() {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"`flush` returned an error when focusing the window. Error was: {}",
|
"`flush` returned an error when focusing the window. Error was: {}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ impl XConnection {
|
|||||||
|
|
||||||
let xsettings_screen = Self::new_xsettings_screen(&xcb, default_screen);
|
let xsettings_screen = Self::new_xsettings_screen(&xcb, default_screen);
|
||||||
if xsettings_screen.is_none() {
|
if xsettings_screen.is_none() {
|
||||||
log::warn!("error setting XSETTINGS; Xft options won't reload automatically")
|
tracing::warn!("error setting XSETTINGS; Xft options won't reload automatically")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch atoms.
|
// Fetch atoms.
|
||||||
@@ -159,7 +159,7 @@ impl XConnection {
|
|||||||
|
|
||||||
// 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 this window
|
||||||
// in order to accomodate for a changed window here.
|
// in order to accommodate for a changed window here.
|
||||||
let selector_window = xcb
|
let selector_window = xcb
|
||||||
.get_selection_owner(xsettings_screen)
|
.get_selection_owner(xsettings_screen)
|
||||||
.ok()?
|
.ok()?
|
||||||
|
|||||||
@@ -33,13 +33,11 @@ impl XConnection {
|
|||||||
.reply()?;
|
.reply()?;
|
||||||
|
|
||||||
// Read the _XSETTINGS_SETTINGS property.
|
// Read the _XSETTINGS_SETTINGS property.
|
||||||
let data: Vec<u8> = self
|
let data: Vec<u8> = self.get_property(
|
||||||
.get_property(
|
owner.owner,
|
||||||
owner.owner,
|
atoms[_XSETTINGS_SETTINGS],
|
||||||
atoms[_XSETTINGS_SETTINGS],
|
atoms[_XSETTINGS_SETTINGS],
|
||||||
atoms[_XSETTINGS_SETTINGS],
|
)?;
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Parse the property.
|
// Parse the property.
|
||||||
let dpi_setting = read_settings(&data)?
|
let dpi_setting = read_settings(&data)?
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ declare_class!(
|
|||||||
self.set_is_running(true);
|
self.set_is_running(true);
|
||||||
self.dispatch_init_events();
|
self.dispatch_init_events();
|
||||||
|
|
||||||
// If the application is being launched via `EventLoop::pump_events()` then we'll
|
// If the application is being launched via `EventLoop::pump_app_events()` then we'll
|
||||||
// want to stop the app once it is launched (and return to the external loop)
|
// want to stop the app once it is launched (and return to the external loop)
|
||||||
//
|
//
|
||||||
// In this case we still want to consider Winit's `EventLoop` to be "running",
|
// In this case we still want to consider Winit's `EventLoop` to be "running",
|
||||||
@@ -471,10 +471,10 @@ fn window_activation_hack(app: &NSApplication) {
|
|||||||
// This way we preserve the user's desired initial visibility status
|
// This way we preserve the user's desired initial visibility status
|
||||||
// TODO: Also filter on the type/"level" of the window, and maybe other things?
|
// TODO: Also filter on the type/"level" of the window, and maybe other things?
|
||||||
if window.isVisible() {
|
if window.isVisible() {
|
||||||
log::trace!("Activating visible window");
|
tracing::trace!("Activating visible window");
|
||||||
window.makeKeyAndOrderFront(None);
|
window.makeKeyAndOrderFront(None);
|
||||||
} else {
|
} else {
|
||||||
log::trace!("Skipping activating invisible window");
|
tracing::trace!("Skipping activating invisible window");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ unsafe fn try_cursor_from_selector(sel: Sel) -> Option<Id<NSCursor>> {
|
|||||||
let cursor: Id<NSCursor> = unsafe { msg_send_id![cls, performSelector: sel] };
|
let cursor: Id<NSCursor> = unsafe { msg_send_id![cls, performSelector: sel] };
|
||||||
Some(cursor)
|
Some(cursor)
|
||||||
} else {
|
} else {
|
||||||
log::warn!("cursor `{sel}` appears to be invalid");
|
tracing::warn!("cursor `{sel}` appears to be invalid");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,14 +36,14 @@ pub fn get_modifierless_char(scancode: u16) -> Key {
|
|||||||
unsafe {
|
unsafe {
|
||||||
input_source = ffi::TISCopyCurrentKeyboardLayoutInputSource();
|
input_source = ffi::TISCopyCurrentKeyboardLayoutInputSource();
|
||||||
if input_source.is_null() {
|
if input_source.is_null() {
|
||||||
log::error!("`TISCopyCurrentKeyboardLayoutInputSource` returned null ptr");
|
tracing::error!("`TISCopyCurrentKeyboardLayoutInputSource` returned null ptr");
|
||||||
return Key::Unidentified(NativeKey::MacOS(scancode));
|
return Key::Unidentified(NativeKey::MacOS(scancode));
|
||||||
}
|
}
|
||||||
let layout_data =
|
let layout_data =
|
||||||
ffi::TISGetInputSourceProperty(input_source, ffi::kTISPropertyUnicodeKeyLayoutData);
|
ffi::TISGetInputSourceProperty(input_source, ffi::kTISPropertyUnicodeKeyLayoutData);
|
||||||
if layout_data.is_null() {
|
if layout_data.is_null() {
|
||||||
CFRelease(input_source as *mut c_void);
|
CFRelease(input_source as *mut c_void);
|
||||||
log::error!("`TISGetInputSourceProperty` returned null ptr");
|
tracing::error!("`TISGetInputSourceProperty` returned null ptr");
|
||||||
return Key::Unidentified(NativeKey::MacOS(scancode));
|
return Key::Unidentified(NativeKey::MacOS(scancode));
|
||||||
}
|
}
|
||||||
layout = CFDataGetBytePtr(layout_data as CFDataRef) as *const ffi::UCKeyboardLayout;
|
layout = CFDataGetBytePtr(layout_data as CFDataRef) as *const ffi::UCKeyboardLayout;
|
||||||
@@ -71,7 +71,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 {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"`UCKeyTranslate` returned with the non-zero value: {}",
|
"`UCKeyTranslate` returned with the non-zero value: {}",
|
||||||
translate_result
|
translate_result
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ impl EventHandler {
|
|||||||
*data = None;
|
*data = None;
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
log::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
|
||||||
@@ -125,7 +125,7 @@ impl EventHandler {
|
|||||||
// `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`.
|
||||||
log::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.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use icrate::Foundation::{NSNotFound, NSRange, NSUInteger};
|
use icrate::Foundation::{NSNotFound, NSRange, NSUInteger};
|
||||||
use log::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
pub const EMPTY_RANGE: NSRange = NSRange {
|
pub const EMPTY_RANGE: NSRange = NSRange {
|
||||||
location: NSNotFound as NSUInteger,
|
location: NSNotFound as NSUInteger,
|
||||||
@@ -20,7 +20,7 @@ pub(crate) struct TraceGuard {
|
|||||||
impl TraceGuard {
|
impl TraceGuard {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new(module_path: &'static str, called_from_fn: &'static str) -> Self {
|
pub(crate) fn new(module_path: &'static str, called_from_fn: &'static str) -> Self {
|
||||||
trace!(target: module_path, "Triggered `{}`", called_from_fn);
|
trace!(target = module_path, "Triggered `{}`", called_from_fn);
|
||||||
Self {
|
Self {
|
||||||
module_path,
|
module_path,
|
||||||
called_from_fn,
|
called_from_fn,
|
||||||
@@ -31,6 +31,10 @@ impl TraceGuard {
|
|||||||
impl Drop for TraceGuard {
|
impl Drop for TraceGuard {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
trace!(target: self.module_path, "Completed `{}`", self.called_from_fn);
|
trace!(
|
||||||
|
target = self.module_path,
|
||||||
|
"Completed `{}`",
|
||||||
|
self.called_from_fn
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ declare_class!(
|
|||||||
// Leave the Preedit self.ivars()
|
// Leave the Preedit self.ivars()
|
||||||
self.ivars().ime_state.set(ImeState::Ground);
|
self.ivars().ime_state.set(ImeState::Ground);
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Expected to have IME enabled when receiving unmarkText");
|
tracing::warn!("Expected to have IME enabled when receiving unmarkText");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -537,7 +537,7 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
log::warn!("unhandled event: {:?}", other);
|
tracing::warn!("unhandled event: {:?}", other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,7 +301,9 @@ impl CursorHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
ImageState::Failed(error) => {
|
ImageState::Failed(error) => {
|
||||||
log::error!("trying to load custom cursor that has failed to load: {error}")
|
tracing::error!(
|
||||||
|
"trying to load custom cursor that has failed to load: {error}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ImageState::Image(_) => {
|
ImageState::Image(_) => {
|
||||||
drop(state);
|
drop(state);
|
||||||
@@ -413,7 +415,7 @@ impl Inner {
|
|||||||
self.set_style();
|
self.set_style();
|
||||||
}
|
}
|
||||||
ImageState::Failed(error) => {
|
ImageState::Failed(error) => {
|
||||||
log::error!("custom cursor failed to load: {error}");
|
tracing::error!("custom cursor failed to load: {error}");
|
||||||
self.cursor = previous.into()
|
self.cursor = previous.into()
|
||||||
}
|
}
|
||||||
ImageState::Loading { .. } => unreachable!("notified without being ready"),
|
ImageState::Loading { .. } => unreachable!("notified without being ready"),
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ enum RunnerEnum {
|
|||||||
Pending,
|
Pending,
|
||||||
/// The `EventLoop` is being run.
|
/// The `EventLoop` is being run.
|
||||||
Running(Runner),
|
Running(Runner),
|
||||||
/// The `EventLoop` is exited after being started with `EventLoop::run`. Since
|
/// The `EventLoop` is exited after being started with `EventLoop::run_app`. Since
|
||||||
/// `EventLoop::run` takes ownership of the `EventLoop`, we can be certain
|
/// `EventLoop::run_app` takes ownership of the `EventLoop`, we can be certain
|
||||||
/// that this event loop will never be run again.
|
/// that this event loop will never be run again.
|
||||||
Destroyed,
|
Destroyed,
|
||||||
}
|
}
|
||||||
@@ -735,7 +735,7 @@ impl Shared {
|
|||||||
// * `self`, i.e. the item which triggered this event loop wakeup, which
|
// * `self`, i.e. the item which triggered this event loop wakeup, which
|
||||||
// is usually a `wasm-bindgen` `Closure`, which will be dropped after
|
// is usually a `wasm-bindgen` `Closure`, which will be dropped after
|
||||||
// returning to the JS glue code.
|
// returning to the JS glue code.
|
||||||
// * The `ActiveEventLoop` leaked inside `EventLoop::run` due to the
|
// * The `ActiveEventLoop` leaked inside `EventLoop::run_app` due to the
|
||||||
// JS exception thrown at the end.
|
// JS exception thrown at the end.
|
||||||
// * For each undropped `Window`:
|
// * For each undropped `Window`:
|
||||||
// * The `register_redraw_request` closure.
|
// * The `register_redraw_request` closure.
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ pub fn key_location(event: &KeyboardEvent) -> KeyLocation {
|
|||||||
KeyboardEvent::DOM_KEY_LOCATION_NUMPAD => KeyLocation::Numpad,
|
KeyboardEvent::DOM_KEY_LOCATION_NUMPAD => KeyLocation::Numpad,
|
||||||
KeyboardEvent::DOM_KEY_LOCATION_STANDARD => KeyLocation::Standard,
|
KeyboardEvent::DOM_KEY_LOCATION_STANDARD => KeyLocation::Standard,
|
||||||
location => {
|
location => {
|
||||||
log::warn!("Unexpected key location: {location}");
|
tracing::warn!("Unexpected key location: {location}");
|
||||||
KeyLocation::Standard
|
KeyLocation::Standard
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use js_sys::{Array, Object};
|
use js_sys::{Array, Object};
|
||||||
use log::warn;
|
use tracing::warn;
|
||||||
use wasm_bindgen::prelude::{wasm_bindgen, Closure};
|
use wasm_bindgen::prelude::{wasm_bindgen, Closure};
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
use web_sys::{
|
use web_sys::{
|
||||||
|
|||||||
@@ -117,9 +117,7 @@ impl Schedule {
|
|||||||
let channel = MessageChannel::new().unwrap();
|
let channel = MessageChannel::new().unwrap();
|
||||||
let closure = Closure::new(f);
|
let closure = Closure::new(f);
|
||||||
let port_1 = channel.port1();
|
let port_1 = channel.port1();
|
||||||
port_1
|
port_1.set_onmessage(Some(closure.as_ref().unchecked_ref()));
|
||||||
.add_event_listener_with_callback("message", closure.as_ref().unchecked_ref())
|
|
||||||
.expect("Failed to set message handler");
|
|
||||||
port_1.start();
|
port_1.start();
|
||||||
|
|
||||||
let port_2 = channel.port2();
|
let port_2 = channel.port2();
|
||||||
@@ -178,6 +176,7 @@ impl Drop for Schedule {
|
|||||||
} => {
|
} => {
|
||||||
window.clear_timeout_with_handle(*handle);
|
window.clear_timeout_with_handle(*handle);
|
||||||
port.close();
|
port.close();
|
||||||
|
port.set_onmessage(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use windows_sys::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::platform_impl::platform::{
|
use crate::platform_impl::platform::{
|
||||||
definitions::{IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknownVtbl},
|
definitions::{IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknownVtbl},
|
||||||
|
|||||||
@@ -536,7 +536,7 @@ impl ActiveEventLoop {
|
|||||||
let inner = match WinCursor::new(&source.inner.0) {
|
let inner = match WinCursor::new(&source.inner.0) {
|
||||||
Ok(cursor) => cursor,
|
Ok(cursor) => cursor,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Failed to create custom cursor: {err}");
|
tracing::warn!("Failed to create custom cursor: {err}");
|
||||||
WinCursor::Failed
|
WinCursor::Failed
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ impl ImeContext {
|
|||||||
let mut boundary_before_char = 0;
|
let mut boundary_before_char = 0;
|
||||||
|
|
||||||
for (attr, chr) in attrs.into_iter().zip(text.chars()) {
|
for (attr, chr) in attrs.into_iter().zip(text.chars()) {
|
||||||
let char_is_targetted =
|
let char_is_targeted =
|
||||||
attr as u32 == ATTR_TARGET_CONVERTED || attr as u32 == ATTR_TARGET_NOTCONVERTED;
|
attr as u32 == ATTR_TARGET_CONVERTED || attr as u32 == ATTR_TARGET_NOTCONVERTED;
|
||||||
|
|
||||||
if first.is_none() && char_is_targetted {
|
if first.is_none() && char_is_targeted {
|
||||||
first = Some(boundary_before_char);
|
first = Some(boundary_before_char);
|
||||||
} else if first.is_some() && last.is_none() && !char_is_targetted {
|
} else if first.is_some() && last.is_none() && !char_is_targeted {
|
||||||
last = Some(boundary_before_char);
|
last = Some(boundary_before_char);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ use windows_sys::Win32::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::{trace, warn};
|
|
||||||
use smol_str::SmolStr;
|
use smol_str::SmolStr;
|
||||||
|
use tracing::{trace, warn};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ impl MonitorHandle {
|
|||||||
let monitor_info = match get_monitor_info(self.0) {
|
let monitor_info = match get_monitor_info(self.0) {
|
||||||
Ok(monitor_info) => monitor_info,
|
Ok(monitor_info) => monitor_info,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::warn!("Error from get_monitor_info: {error}");
|
tracing::warn!("Error from get_monitor_info: {error}");
|
||||||
return modes.into_iter().map(mod_map);
|
return modes.into_iter().map(mod_map);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ use windows_sys::Win32::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cursor::Cursor,
|
cursor::Cursor,
|
||||||
|
|||||||
163
src/window.rs
163
src/window.rs
@@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
///
|
///
|
||||||
/// The window is closed when dropped.
|
/// The window is closed when dropped.
|
||||||
///
|
///
|
||||||
/// # Threading
|
/// ## Threading
|
||||||
///
|
///
|
||||||
/// This is `Send + Sync`, meaning that it can be freely used from other
|
/// This is `Send + Sync`, meaning that it can be freely used from other
|
||||||
/// threads.
|
/// threads.
|
||||||
@@ -30,37 +30,6 @@ use serde::{Deserialize, Serialize};
|
|||||||
/// window from a thread other than the main, the code is scheduled to run on
|
/// window from a thread other than the main, the code is scheduled to run on
|
||||||
/// the main thread, and your thread may be blocked until that completes.
|
/// the main thread, and your thread may be blocked until that completes.
|
||||||
///
|
///
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// use winit::{
|
|
||||||
/// event::{Event, WindowEvent},
|
|
||||||
/// event_loop::{ControlFlow, EventLoop},
|
|
||||||
/// window::Window,
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// let mut event_loop = EventLoop::new().unwrap();
|
|
||||||
/// event_loop.set_control_flow(ControlFlow::Wait);
|
|
||||||
/// let mut windows = Vec::new();
|
|
||||||
///
|
|
||||||
/// event_loop.run(move |event, event_loop| {
|
|
||||||
/// match event {
|
|
||||||
/// Event::Resumed => {
|
|
||||||
/// let window = event_loop.create_window(Window::default_attributes()).unwrap();
|
|
||||||
/// windows.push(window);
|
|
||||||
/// }
|
|
||||||
/// Event::WindowEvent {
|
|
||||||
/// event: WindowEvent::CloseRequested,
|
|
||||||
/// ..
|
|
||||||
/// } => {
|
|
||||||
/// windows.clear();
|
|
||||||
/// event_loop.exit();
|
|
||||||
/// }
|
|
||||||
/// _ => (),
|
|
||||||
/// }
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
/// **Web:** The [`Window`], which is represented by a `HTMLElementCanvas`, can
|
/// **Web:** The [`Window`], which is represented by a `HTMLElementCanvas`, can
|
||||||
@@ -528,6 +497,8 @@ impl Window {
|
|||||||
/// Returns an identifier unique to the window.
|
/// Returns an identifier unique to the window.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn id(&self) -> WindowId {
|
pub fn id(&self) -> WindowId {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::id",).entered();
|
||||||
|
|
||||||
self.window.maybe_wait_on_main(|w| WindowId(w.id()))
|
self.window.maybe_wait_on_main(|w| WindowId(w.id()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,6 +562,8 @@ impl Window {
|
|||||||
/// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
|
/// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_factor(&self) -> f64 {
|
pub fn scale_factor(&self) -> f64 {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::scale_factor",).entered();
|
||||||
|
|
||||||
self.window.maybe_wait_on_main(|w| w.scale_factor())
|
self.window.maybe_wait_on_main(|w| w.scale_factor())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,6 +595,8 @@ impl Window {
|
|||||||
/// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested
|
/// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request_redraw(&self) {
|
pub fn request_redraw(&self) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::request_redraw",).entered();
|
||||||
|
|
||||||
self.window.maybe_queue_on_main(|w| w.request_redraw())
|
self.window.maybe_queue_on_main(|w| w.request_redraw())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,6 +633,8 @@ impl Window {
|
|||||||
/// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested
|
/// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pre_present_notify(&self) {
|
pub fn pre_present_notify(&self) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::pre_present_notify",).entered();
|
||||||
|
|
||||||
self.window.maybe_queue_on_main(|w| w.pre_present_notify());
|
self.window.maybe_queue_on_main(|w| w.pre_present_notify());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,6 +651,8 @@ impl Window {
|
|||||||
// at least, then this function should be provided through a platform specific
|
// at least, then this function should be provided through a platform specific
|
||||||
// extension trait
|
// extension trait
|
||||||
pub fn reset_dead_keys(&self) {
|
pub fn reset_dead_keys(&self) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::reset_dead_keys",).entered();
|
||||||
|
|
||||||
self.window.maybe_queue_on_main(|w| w.reset_dead_keys())
|
self.window.maybe_queue_on_main(|w| w.reset_dead_keys())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -696,6 +675,8 @@ impl Window {
|
|||||||
/// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
|
/// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::inner_position",).entered();
|
||||||
|
|
||||||
self.window.maybe_wait_on_main(|w| w.inner_position())
|
self.window.maybe_wait_on_main(|w| w.inner_position())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,6 +698,8 @@ impl Window {
|
|||||||
/// - **Android / Wayland:** Always returns [`NotSupportedError`].
|
/// - **Android / Wayland:** Always returns [`NotSupportedError`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::outer_position",).entered();
|
||||||
|
|
||||||
self.window.maybe_wait_on_main(|w| w.outer_position())
|
self.window.maybe_wait_on_main(|w| w.outer_position())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,6 +732,12 @@ impl Window {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_outer_position<P: Into<Position>>(&self, position: P) {
|
pub fn set_outer_position<P: Into<Position>>(&self, position: P) {
|
||||||
let position = position.into();
|
let position = position.into();
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_outer_position",
|
||||||
|
position = ?position
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
|
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_outer_position(position))
|
.maybe_queue_on_main(move |w| w.set_outer_position(position))
|
||||||
}
|
}
|
||||||
@@ -767,6 +756,8 @@ impl Window {
|
|||||||
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::inner_size",).entered();
|
||||||
|
|
||||||
self.window.maybe_wait_on_main(|w| w.inner_size())
|
self.window.maybe_wait_on_main(|w| w.inner_size())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -808,6 +799,11 @@ impl Window {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn request_inner_size<S: Into<Size>>(&self, size: S) -> Option<PhysicalSize<u32>> {
|
pub fn request_inner_size<S: Into<Size>>(&self, size: S) -> Option<PhysicalSize<u32>> {
|
||||||
let size = size.into();
|
let size = size.into();
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::request_inner_size",
|
||||||
|
size = ?size
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_wait_on_main(|w| w.request_inner_size(size))
|
.maybe_wait_on_main(|w| w.request_inner_size(size))
|
||||||
}
|
}
|
||||||
@@ -825,6 +821,7 @@ impl Window {
|
|||||||
/// [`Window::inner_size`]._
|
/// [`Window::inner_size`]._
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::outer_size",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.outer_size())
|
self.window.maybe_wait_on_main(|w| w.outer_size())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,6 +845,11 @@ impl Window {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_min_inner_size<S: Into<Size>>(&self, min_size: Option<S>) {
|
pub fn set_min_inner_size<S: Into<Size>>(&self, min_size: Option<S>) {
|
||||||
let min_size = min_size.map(|s| s.into());
|
let min_size = min_size.map(|s| s.into());
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_min_inner_size",
|
||||||
|
min_size = ?min_size
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_min_inner_size(min_size))
|
.maybe_queue_on_main(move |w| w.set_min_inner_size(min_size))
|
||||||
}
|
}
|
||||||
@@ -872,6 +874,11 @@ impl Window {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_max_inner_size<S: Into<Size>>(&self, max_size: Option<S>) {
|
pub fn set_max_inner_size<S: Into<Size>>(&self, max_size: Option<S>) {
|
||||||
let max_size = max_size.map(|s| s.into());
|
let max_size = max_size.map(|s| s.into());
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::max_size",
|
||||||
|
max_size = ?max_size
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_max_inner_size(max_size))
|
.maybe_queue_on_main(move |w| w.set_max_inner_size(max_size))
|
||||||
}
|
}
|
||||||
@@ -883,6 +890,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web / Wayland / Windows / Orbital:** Always returns [`None`].
|
/// - **iOS / Android / Web / Wayland / Windows / Orbital:** Always returns [`None`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
|
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::resize_increments",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.resize_increments())
|
self.window.maybe_wait_on_main(|w| w.resize_increments())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -899,6 +907,11 @@ impl Window {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_resize_increments<S: Into<Size>>(&self, increments: Option<S>) {
|
pub fn set_resize_increments<S: Into<Size>>(&self, increments: Option<S>) {
|
||||||
let increments = increments.map(Into::into);
|
let increments = increments.map(Into::into);
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_resize_increments",
|
||||||
|
increments = ?increments
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_resize_increments(increments))
|
.maybe_queue_on_main(move |w| w.set_resize_increments(increments))
|
||||||
}
|
}
|
||||||
@@ -913,6 +926,7 @@ impl Window {
|
|||||||
/// - **iOS / Android:** Unsupported.
|
/// - **iOS / Android:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_title(&self, title: &str) {
|
pub fn set_title(&self, title: &str) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_title", title).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.set_title(title))
|
self.window.maybe_wait_on_main(|w| w.set_title(title))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,6 +945,7 @@ impl Window {
|
|||||||
/// - **X11:** Can only be set while building the window, with [`WindowAttributes::with_transparent`].
|
/// - **X11:** Can only be set while building the window, with [`WindowAttributes::with_transparent`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_transparent(&self, transparent: bool) {
|
pub fn set_transparent(&self, transparent: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_transparent", transparent).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_transparent(transparent))
|
.maybe_queue_on_main(move |w| w.set_transparent(transparent))
|
||||||
}
|
}
|
||||||
@@ -945,6 +960,7 @@ impl Window {
|
|||||||
/// - **Wayland:** Only works with org_kde_kwin_blur_manager protocol.
|
/// - **Wayland:** Only works with org_kde_kwin_blur_manager protocol.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_blur(&self, blur: bool) {
|
pub fn set_blur(&self, blur: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_blur", blur).entered();
|
||||||
self.window.maybe_queue_on_main(move |w| w.set_blur(blur))
|
self.window.maybe_queue_on_main(move |w| w.set_blur(blur))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -958,6 +974,7 @@ impl Window {
|
|||||||
/// - **iOS:** Can only be called on the main thread.
|
/// - **iOS:** Can only be called on the main thread.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_visible(&self, visible: bool) {
|
pub fn set_visible(&self, visible: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_visible", visible).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_visible(visible))
|
.maybe_queue_on_main(move |w| w.set_visible(visible))
|
||||||
}
|
}
|
||||||
@@ -972,6 +989,7 @@ impl Window {
|
|||||||
/// - **Wayland / iOS / Android / Web:** Unsupported.
|
/// - **Wayland / iOS / Android / Web:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_visible(&self) -> Option<bool> {
|
pub fn is_visible(&self) -> Option<bool> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::is_visible",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.is_visible())
|
self.window.maybe_wait_on_main(|w| w.is_visible())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,6 +1009,7 @@ impl Window {
|
|||||||
/// [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized
|
/// [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_resizable(&self, resizable: bool) {
|
pub fn set_resizable(&self, resizable: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_resizable", resizable).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_resizable(resizable))
|
.maybe_queue_on_main(move |w| w.set_resizable(resizable))
|
||||||
}
|
}
|
||||||
@@ -1003,6 +1022,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web:** Unsupported.
|
/// - **iOS / Android / Web:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_resizable(&self) -> bool {
|
pub fn is_resizable(&self) -> bool {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::is_resizable",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.is_resizable())
|
self.window.maybe_wait_on_main(|w| w.is_resizable())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1013,6 +1033,11 @@ impl Window {
|
|||||||
/// - **Wayland / X11 / Orbital:** Not implemented.
|
/// - **Wayland / X11 / Orbital:** Not implemented.
|
||||||
/// - **Web / iOS / Android:** Unsupported.
|
/// - **Web / iOS / Android:** Unsupported.
|
||||||
pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
|
pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_enabled_buttons",
|
||||||
|
buttons = ?buttons
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_enabled_buttons(buttons))
|
.maybe_queue_on_main(move |w| w.set_enabled_buttons(buttons))
|
||||||
}
|
}
|
||||||
@@ -1024,6 +1049,7 @@ impl Window {
|
|||||||
/// - **Wayland / X11 / Orbital:** Not implemented. Always returns [`WindowButtons::all`].
|
/// - **Wayland / X11 / Orbital:** Not implemented. Always returns [`WindowButtons::all`].
|
||||||
/// - **Web / iOS / Android:** Unsupported. Always returns [`WindowButtons::all`].
|
/// - **Web / iOS / Android:** Unsupported. Always returns [`WindowButtons::all`].
|
||||||
pub fn enabled_buttons(&self) -> WindowButtons {
|
pub fn enabled_buttons(&self) -> WindowButtons {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::enabled_buttons",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.enabled_buttons())
|
self.window.maybe_wait_on_main(|w| w.enabled_buttons())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1035,6 +1061,7 @@ impl Window {
|
|||||||
/// - **Wayland:** Un-minimize is unsupported.
|
/// - **Wayland:** Un-minimize is unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_minimized(&self, minimized: bool) {
|
pub fn set_minimized(&self, minimized: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_minimized", minimized).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_minimized(minimized))
|
.maybe_queue_on_main(move |w| w.set_minimized(minimized))
|
||||||
}
|
}
|
||||||
@@ -1053,6 +1080,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_minimized(&self) -> Option<bool> {
|
pub fn is_minimized(&self) -> Option<bool> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::is_minimized",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.is_minimized())
|
self.window.maybe_wait_on_main(|w| w.is_minimized())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1063,6 +1091,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web:** Unsupported.
|
/// - **iOS / Android / Web:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_maximized(&self, maximized: bool) {
|
pub fn set_maximized(&self, maximized: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_maximized", maximized).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_maximized(maximized))
|
.maybe_queue_on_main(move |w| w.set_maximized(maximized))
|
||||||
}
|
}
|
||||||
@@ -1074,6 +1103,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web:** Unsupported.
|
/// - **iOS / Android / Web:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_maximized(&self) -> bool {
|
pub fn is_maximized(&self) -> bool {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::is_maximized",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.is_maximized())
|
self.window.maybe_wait_on_main(|w| w.is_maximized())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1102,6 +1132,11 @@ impl Window {
|
|||||||
/// [transient activation]: https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation
|
/// [transient activation]: https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
|
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_fullscreen",
|
||||||
|
fullscreen = ?fullscreen
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_fullscreen(fullscreen.map(|f| f.into())))
|
.maybe_queue_on_main(move |w| w.set_fullscreen(fullscreen.map(|f| f.into())))
|
||||||
}
|
}
|
||||||
@@ -1116,6 +1151,7 @@ impl Window {
|
|||||||
/// - **Web:** Can only return `None` or `Borderless(None)`.
|
/// - **Web:** Can only return `None` or `Borderless(None)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fullscreen(&self) -> Option<Fullscreen> {
|
pub fn fullscreen(&self) -> Option<Fullscreen> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::fullscreen",).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_wait_on_main(|w| w.fullscreen().map(|f| f.into()))
|
.maybe_wait_on_main(|w| w.fullscreen().map(|f| f.into()))
|
||||||
}
|
}
|
||||||
@@ -1131,6 +1167,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web:** No effect.
|
/// - **iOS / Android / Web:** No effect.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_decorations(&self, decorations: bool) {
|
pub fn set_decorations(&self, decorations: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_decorations", decorations).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_decorations(decorations))
|
.maybe_queue_on_main(move |w| w.set_decorations(decorations))
|
||||||
}
|
}
|
||||||
@@ -1145,6 +1182,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web:** Always returns `true`.
|
/// - **iOS / Android / Web:** Always returns `true`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_decorated(&self) -> bool {
|
pub fn is_decorated(&self) -> bool {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::is_decorated",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.is_decorated())
|
self.window.maybe_wait_on_main(|w| w.is_decorated())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1154,6 +1192,11 @@ impl Window {
|
|||||||
///
|
///
|
||||||
/// See [`WindowLevel`] for details.
|
/// See [`WindowLevel`] for details.
|
||||||
pub fn set_window_level(&self, level: WindowLevel) {
|
pub fn set_window_level(&self, level: WindowLevel) {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_window_level",
|
||||||
|
level = ?level
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_window_level(level))
|
.maybe_queue_on_main(move |w| w.set_window_level(level))
|
||||||
}
|
}
|
||||||
@@ -1174,6 +1217,7 @@ impl Window {
|
|||||||
/// said, it's usually in the same ballpark as on Windows.
|
/// said, it's usually in the same ballpark as on Windows.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_window_icon",).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_window_icon(window_icon))
|
.maybe_queue_on_main(move |w| w.set_window_icon(window_icon))
|
||||||
}
|
}
|
||||||
@@ -1216,6 +1260,12 @@ impl Window {
|
|||||||
pub fn set_ime_cursor_area<P: Into<Position>, S: Into<Size>>(&self, position: P, size: S) {
|
pub fn set_ime_cursor_area<P: Into<Position>, S: Into<Size>>(&self, position: P, size: S) {
|
||||||
let position = position.into();
|
let position = position.into();
|
||||||
let size = size.into();
|
let size = size.into();
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_ime_cursor_area",
|
||||||
|
position = ?position,
|
||||||
|
size = ?size,
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_ime_cursor_area(position, size))
|
.maybe_queue_on_main(move |w| w.set_ime_cursor_area(position, size))
|
||||||
}
|
}
|
||||||
@@ -1242,6 +1292,7 @@ impl Window {
|
|||||||
/// [`KeyboardInput`]: crate::event::WindowEvent::KeyboardInput
|
/// [`KeyboardInput`]: crate::event::WindowEvent::KeyboardInput
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_ime_allowed(&self, allowed: bool) {
|
pub fn set_ime_allowed(&self, allowed: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_ime_allowed", allowed).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_ime_allowed(allowed))
|
.maybe_queue_on_main(move |w| w.set_ime_allowed(allowed))
|
||||||
}
|
}
|
||||||
@@ -1253,6 +1304,11 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
|
/// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_ime_purpose(&self, purpose: ImePurpose) {
|
pub fn set_ime_purpose(&self, purpose: ImePurpose) {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_ime_purpose",
|
||||||
|
purpose = ?purpose
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_ime_purpose(purpose))
|
.maybe_queue_on_main(move |w| w.set_ime_purpose(purpose))
|
||||||
}
|
}
|
||||||
@@ -1269,6 +1325,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Wayland / Orbital:** Unsupported.
|
/// - **iOS / Android / Wayland / Orbital:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn focus_window(&self) {
|
pub fn focus_window(&self) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::focus_window",).entered();
|
||||||
self.window.maybe_queue_on_main(|w| w.focus_window())
|
self.window.maybe_queue_on_main(|w| w.focus_window())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1279,6 +1336,7 @@ impl Window {
|
|||||||
/// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused
|
/// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn has_focus(&self) -> bool {
|
pub fn has_focus(&self) -> bool {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::has_focus",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.has_focus())
|
self.window.maybe_wait_on_main(|w| w.has_focus())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1297,6 +1355,11 @@ impl Window {
|
|||||||
/// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.
|
/// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::request_user_attention",
|
||||||
|
request_type = ?request_type
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.request_user_attention(request_type))
|
.maybe_queue_on_main(move |w| w.request_user_attention(request_type))
|
||||||
}
|
}
|
||||||
@@ -1312,6 +1375,11 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_theme(&self, theme: Option<Theme>) {
|
pub fn set_theme(&self, theme: Option<Theme>) {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_theme",
|
||||||
|
theme = ?theme
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window.maybe_queue_on_main(move |w| w.set_theme(theme))
|
self.window.maybe_queue_on_main(move |w| w.set_theme(theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1323,6 +1391,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported.
|
/// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn theme(&self) -> Option<Theme> {
|
pub fn theme(&self) -> Option<Theme> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::theme",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.theme())
|
self.window.maybe_wait_on_main(|w| w.theme())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1336,6 +1405,8 @@ impl Window {
|
|||||||
///
|
///
|
||||||
/// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
|
/// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
|
||||||
pub fn set_content_protected(&self, protected: bool) {
|
pub fn set_content_protected(&self, protected: bool) {
|
||||||
|
let _span =
|
||||||
|
tracing::debug_span!("winit::Window::set_content_protected", protected).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_content_protected(protected))
|
.maybe_queue_on_main(move |w| w.set_content_protected(protected))
|
||||||
}
|
}
|
||||||
@@ -1347,6 +1418,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / x11 / Wayland / Web:** Unsupported. Always returns an empty string.
|
/// - **iOS / Android / x11 / Wayland / Web:** Unsupported. Always returns an empty string.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn title(&self) -> String {
|
pub fn title(&self) -> String {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::title",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.title())
|
self.window.maybe_wait_on_main(|w| w.title())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1363,6 +1435,7 @@ impl Window {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor(&self, cursor: impl Into<Cursor>) {
|
pub fn set_cursor(&self, cursor: impl Into<Cursor>) {
|
||||||
let cursor = cursor.into();
|
let cursor = cursor.into();
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_cursor",).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_cursor(cursor))
|
.maybe_queue_on_main(move |w| w.set_cursor(cursor))
|
||||||
}
|
}
|
||||||
@@ -1395,6 +1468,11 @@ impl Window {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_position<P: Into<Position>>(&self, position: P) -> Result<(), ExternalError> {
|
pub fn set_cursor_position<P: Into<Position>>(&self, position: P) -> Result<(), ExternalError> {
|
||||||
let position = position.into();
|
let position = position.into();
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_cursor_position",
|
||||||
|
position = ?position
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_wait_on_main(|w| w.set_cursor_position(position))
|
.maybe_wait_on_main(|w| w.set_cursor_position(position))
|
||||||
}
|
}
|
||||||
@@ -1415,6 +1493,11 @@ impl Window {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::set_cursor_grab",
|
||||||
|
mode = ?mode
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.set_cursor_grab(mode))
|
self.window.maybe_wait_on_main(|w| w.set_cursor_grab(mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1432,6 +1515,7 @@ impl Window {
|
|||||||
/// - **iOS / Android:** Unsupported.
|
/// - **iOS / Android:** Unsupported.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_visible(&self, visible: bool) {
|
pub fn set_cursor_visible(&self, visible: bool) {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_cursor_visible", visible).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.set_cursor_visible(visible))
|
.maybe_queue_on_main(move |w| w.set_cursor_visible(visible))
|
||||||
}
|
}
|
||||||
@@ -1449,6 +1533,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
|
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::drag_window",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| w.drag_window())
|
self.window.maybe_wait_on_main(|w| w.drag_window())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1463,6 +1548,11 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
|
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::drag_resize_window",
|
||||||
|
direction = ?direction
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_wait_on_main(|w| w.drag_resize_window(direction))
|
.maybe_wait_on_main(|w| w.drag_resize_window(direction))
|
||||||
}
|
}
|
||||||
@@ -1478,6 +1568,11 @@ impl Window {
|
|||||||
/// [window menu]: https://en.wikipedia.org/wiki/Common_menus_in_Microsoft_Windows#System_menu
|
/// [window menu]: https://en.wikipedia.org/wiki/Common_menus_in_Microsoft_Windows#System_menu
|
||||||
pub fn show_window_menu(&self, position: impl Into<Position>) {
|
pub fn show_window_menu(&self, position: impl Into<Position>) {
|
||||||
let position = position.into();
|
let position = position.into();
|
||||||
|
let _span = tracing::debug_span!(
|
||||||
|
"winit::Window::show_window_menu",
|
||||||
|
position = ?position
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_queue_on_main(move |w| w.show_window_menu(position))
|
.maybe_queue_on_main(move |w| w.show_window_menu(position))
|
||||||
}
|
}
|
||||||
@@ -1492,6 +1587,7 @@ impl Window {
|
|||||||
/// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
|
/// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
|
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::set_cursor_hittest", hittest).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_wait_on_main(|w| w.set_cursor_hittest(hittest))
|
.maybe_wait_on_main(|w| w.set_cursor_hittest(hittest))
|
||||||
}
|
}
|
||||||
@@ -1504,6 +1600,7 @@ impl Window {
|
|||||||
/// Returns `None` if current monitor can't be detected.
|
/// Returns `None` if current monitor can't be detected.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_monitor(&self) -> Option<MonitorHandle> {
|
pub fn current_monitor(&self) -> Option<MonitorHandle> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::current_monitor",).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_wait_on_main(|w| w.current_monitor().map(|inner| MonitorHandle { inner }))
|
.maybe_wait_on_main(|w| w.current_monitor().map(|inner| MonitorHandle { inner }))
|
||||||
}
|
}
|
||||||
@@ -1515,6 +1612,7 @@ impl Window {
|
|||||||
/// [`ActiveEventLoop::available_monitors`]: crate::event_loop::ActiveEventLoop::available_monitors
|
/// [`ActiveEventLoop::available_monitors`]: crate::event_loop::ActiveEventLoop::available_monitors
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::available_monitors",).entered();
|
||||||
self.window.maybe_wait_on_main(|w| {
|
self.window.maybe_wait_on_main(|w| {
|
||||||
w.available_monitors()
|
w.available_monitors()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -1535,6 +1633,7 @@ impl Window {
|
|||||||
/// [`ActiveEventLoop::primary_monitor`]: crate::event_loop::ActiveEventLoop::primary_monitor
|
/// [`ActiveEventLoop::primary_monitor`]: crate::event_loop::ActiveEventLoop::primary_monitor
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
||||||
|
let _span = tracing::debug_span!("winit::Window::primary_monitor",).entered();
|
||||||
self.window
|
self.window
|
||||||
.maybe_wait_on_main(|w| w.primary_monitor().map(|inner| MonitorHandle { inner }))
|
.maybe_wait_on_main(|w| w.primary_monitor().map(|inner| MonitorHandle { inner }))
|
||||||
}
|
}
|
||||||
|
|||||||
6
typos.toml
Normal file
6
typos.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# documentation: https://github.com/crate-ci/typos/blob/master/docs/reference.md
|
||||||
|
|
||||||
|
[default.extend-identifiers]
|
||||||
|
ptd = "ptd" # From winwows_sys::Win32::System::Com::FORMATETC { ptd, ..}
|
||||||
|
requestor = "requestor" # From x11_dl::xlib::XSelectionEvent { requestor ..}
|
||||||
|
XF86_Calculater = "XF86_Calculater" # From xkbcommon_dl::keysyms::XF86_Calculater
|
||||||
Reference in New Issue
Block a user