mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-27 07:03:15 -04:00
Compare commits
18 Commits
notgull/sp
...
madsmtm/ch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7b6f0c63d | ||
|
|
f40f87ff12 | ||
|
|
aa3127e460 | ||
|
|
295a789c42 | ||
|
|
a63b04385a | ||
|
|
06f4e28de9 | ||
|
|
249d5d8bff | ||
|
|
66df2c22ba | ||
|
|
359a38844b | ||
|
|
563b0bf5e3 | ||
|
|
b2f9fad654 | ||
|
|
4ade1a7518 | ||
|
|
e06ecf4d72 | ||
|
|
4a8050289d | ||
|
|
99e238065e | ||
|
|
d123cd2f8e | ||
|
|
fc8a008b25 | ||
|
|
f6f1c45a72 |
13
.cspell.json
13
.cspell.json
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
|
|
||||||
"version": "0.2",
|
|
||||||
"dictionaryDefinitions": [
|
|
||||||
{
|
|
||||||
"name": "project-words",
|
|
||||||
"path": "./project-words.txt",
|
|
||||||
"addWords": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dictionaries": ["project-words"],
|
|
||||||
"ignorePaths": ["/target", "/project-words.txt"]
|
|
||||||
}
|
|
||||||
24
.github/workflows/check-commit-msg.yml
vendored
Normal file
24
.github/workflows/check-commit-msg.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: Check Commit Messages
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
length:
|
||||||
|
name: Check that length of commit messages are <72 characters
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Fetch branch data from origin
|
||||||
|
run: git fetch origin
|
||||||
|
- run: |
|
||||||
|
COMMIT_MESSAGES=$(git log --combined --format=%s origin/$GITHUB_BASE_REF..HEAD)
|
||||||
|
echo $COMMIT_MESSAGES
|
||||||
|
for MESSAGE in $COMMIT_MESSAGES; do
|
||||||
|
LENGTH=$(echo $MESSAGE | wc -c)
|
||||||
|
if [ $LENGTH -gt 72 ]; then
|
||||||
|
echo "Commit message \"$MESSAGE\" is too long ($LENGTH characters). Please keep commit messages under 72 characters."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
fmt:
|
fmt:
|
||||||
name: Tidy Code
|
name: Check formatting
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -16,13 +16,28 @@ jobs:
|
|||||||
components: rustfmt
|
components: rustfmt
|
||||||
- name: Check Formatting
|
- name: Check Formatting
|
||||||
run: cargo fmt -- --check
|
run: cargo fmt -- --check
|
||||||
- name: Check Spelling
|
|
||||||
run: npx -y cspell --no-progress --no-summary '**/*.rs' '**/*.md'
|
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 }}
|
||||||
needs: fmt
|
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -130,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') &&
|
||||||
|
|||||||
14
CHANGELOG.md
14
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).
|
||||||
@@ -48,6 +52,16 @@ Unreleased` header.
|
|||||||
- 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.
|
- `log` has been replaced with `tracing`. The old behavior can be emulated by setting the `log` feature on the `tracing` crate.
|
||||||
|
|
||||||
|
# 0.29.15
|
||||||
|
|
||||||
|
- 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
|
# 0.29.13
|
||||||
|
|
||||||
- On Web, fix possible crash with `ControlFlow::Wait` and `ControlFlow::WaitUntil`.
|
- On Web, fix possible crash with `ControlFlow::Wait` and `ControlFlow::WaitUntil`.
|
||||||
|
|||||||
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.13"
|
version = "0.29.15"
|
||||||
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"]
|
||||||
@@ -188,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.13"
|
winit = "0.29.15"
|
||||||
```
|
```
|
||||||
|
|
||||||
## [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,29 +3,30 @@
|
|||||||
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 winit::{
|
use winit::application::ApplicationHandler;
|
||||||
event::{ElementState, Event, KeyEvent, WindowEvent},
|
use winit::event::{ElementState, KeyEvent, StartCause, WindowEvent};
|
||||||
event_loop::{ControlFlow, EventLoop},
|
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
|
||||||
keyboard::{Key, NamedKey},
|
use winit::keyboard::{Key, NamedKey};
|
||||||
window::Window,
|
use winit::window::{Window, WindowId};
|
||||||
};
|
|
||||||
|
|
||||||
#[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> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
@@ -37,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,50 +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 winit::{
|
use winit::application::ApplicationHandler;
|
||||||
event::{Event, WindowEvent},
|
use winit::event::WindowEvent;
|
||||||
event_loop::EventLoop,
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
platform::pump_events::{EventLoopExtPumpEvents, PumpStatus},
|
use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
|
||||||
window::Window,
|
use winit::window::{Window, WindowId};
|
||||||
};
|
|
||||||
|
|
||||||
#[path = "util/fill.rs"]
|
#[path = "util/fill.rs"]
|
||||||
mod fill;
|
mod fill;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct PumpDemo {
|
||||||
|
window: Option<Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
_window_id: WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
|
println!("{event:?}");
|
||||||
|
|
||||||
|
let window = match self.window.as_ref() {
|
||||||
|
Some(window) => window,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
fill::fill_window(window);
|
||||||
|
window.request_redraw();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut event_loop = EventLoop::new().unwrap();
|
let mut event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let mut window = None;
|
let mut app = PumpDemo::default();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let timeout = Some(Duration::ZERO);
|
let timeout = Some(Duration::ZERO);
|
||||||
let status = event_loop.pump_events(timeout, |event, event_loop| {
|
let status = event_loop.pump_app_events(timeout, &mut app);
|
||||||
if let Event::WindowEvent { event, .. } = &event {
|
|
||||||
// Print only Window events to reduce noise
|
|
||||||
println!("{event:?}");
|
|
||||||
}
|
|
||||||
|
|
||||||
match event {
|
|
||||||
Event::Resumed => {
|
|
||||||
let window_attributes =
|
|
||||||
Window::default_attributes().with_title("A fantastic window!");
|
|
||||||
window = Some(event_loop.create_window(window_attributes).unwrap());
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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,86 +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 winit::{
|
use winit::application::ApplicationHandler;
|
||||||
error::EventLoopError,
|
use winit::event::WindowEvent;
|
||||||
event::{Event, WindowEvent},
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
event_loop::EventLoop,
|
use winit::platform::run_on_demand::EventLoopExtRunOnDemand;
|
||||||
platform::run_on_demand::EventLoopExtRunOnDemand,
|
use winit::window::{Window, WindowId};
|
||||||
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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing_subscriber::fmt::init();
|
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,
|
||||||
@@ -244,9 +303,9 @@ impl Application {
|
|||||||
}
|
}
|
||||||
WindowEvent::Focused(focused) => {
|
WindowEvent::Focused(focused) => {
|
||||||
if focused {
|
if focused {
|
||||||
println!("Window={window_id:?} focused");
|
println!("Window={window_id:?} fosused");
|
||||||
} else {
|
} else {
|
||||||
println!("Window={window_id:?} unfocused");
|
println!("Window={window_id:?} unfosused");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
||||||
@@ -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,16 +3,52 @@ use std::error::Error;
|
|||||||
|
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
use winit::{
|
use winit::application::ApplicationHandler;
|
||||||
event::{Event, WindowEvent},
|
use winit::event::WindowEvent;
|
||||||
event_loop::EventLoop,
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
platform::x11::WindowAttributesExtX11,
|
use winit::platform::x11::WindowAttributesExtX11;
|
||||||
window::Window,
|
use winit::window::{Window, WindowId};
|
||||||
};
|
|
||||||
|
|
||||||
#[path = "util/fill.rs"]
|
#[path = "util/fill.rs"]
|
||||||
mod fill;
|
mod fill;
|
||||||
|
|
||||||
|
pub struct XEmbedDemo {
|
||||||
|
parent_window_id: u32,
|
||||||
|
window: Option<Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler for XEmbedDemo {
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let window_attributes = Window::default_attributes()
|
||||||
|
.with_title("An embedded window!")
|
||||||
|
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
|
||||||
|
.with_embed_parent_window(self.parent_window_id);
|
||||||
|
|
||||||
|
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
_window_id: WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
|
let window = self.window.as_ref().unwrap();
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
window.pre_present_notify();
|
||||||
|
fill::fill_window(window);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
// First argument should be a 32-bit X11 window ID.
|
||||||
let parent_window_id = std::env::args()
|
let parent_window_id = std::env::args()
|
||||||
.nth(1)
|
.nth(1)
|
||||||
@@ -22,35 +58,11 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
let event_loop = EventLoop::new()?;
|
let event_loop = EventLoop::new()?;
|
||||||
|
|
||||||
let mut window = None;
|
let mut app = XEmbedDemo {
|
||||||
event_loop.run(move |event, event_loop| match event {
|
parent_window_id,
|
||||||
Event::Resumed => {
|
window: None,
|
||||||
let window_attributes = Window::default_attributes()
|
};
|
||||||
.with_title("An embedded window!")
|
event_loop.run_app(&mut app).map_err(Into::into)
|
||||||
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
|
|
||||||
.with_embed_parent_window(parent_window_id);
|
|
||||||
|
|
||||||
window = Some(event_loop.create_window(window_attributes).unwrap());
|
|
||||||
}
|
|
||||||
Event::WindowEvent { event, .. } => {
|
|
||||||
let window = window.as_ref().unwrap();
|
|
||||||
|
|
||||||
match event {
|
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
|
||||||
WindowEvent::RedrawRequested => {
|
|
||||||
window.pre_present_notify();
|
|
||||||
fill::fill_window(window);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::AboutToWait => {
|
|
||||||
window.as_ref().unwrap().request_redraw();
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(x11_platform))]
|
#[cfg(not(x11_platform))]
|
||||||
|
|||||||
@@ -1,707 +0,0 @@
|
|||||||
ABNT
|
|
||||||
ACCEPTFILES
|
|
||||||
ALTERASE
|
|
||||||
APPCOMMAND
|
|
||||||
APPSTARTING
|
|
||||||
APPWINDOW
|
|
||||||
ASYNCWINDOWPOS
|
|
||||||
ATOK
|
|
||||||
AZERTY
|
|
||||||
Abortable
|
|
||||||
Artur
|
|
||||||
Autorotate
|
|
||||||
BACKTAB
|
|
||||||
BADFLAGS
|
|
||||||
BADMODE
|
|
||||||
BADPARAM
|
|
||||||
BASSBOOST
|
|
||||||
BITSPERPEL
|
|
||||||
BKSP
|
|
||||||
BLURBEHIND
|
|
||||||
BOTTOMLEFT
|
|
||||||
BOTTOMRIGHT
|
|
||||||
BRIGHTNESSDOW
|
|
||||||
BRIGHTNESSU
|
|
||||||
BYCOMMAND
|
|
||||||
Backquote
|
|
||||||
Bangou
|
|
||||||
Blackbox
|
|
||||||
CAEAGL
|
|
||||||
CANDIDATEFORM
|
|
||||||
CAPTURECHANGED
|
|
||||||
CFUUID
|
|
||||||
CLIPSIBLINGS
|
|
||||||
CLOEXEC
|
|
||||||
CLOSECD
|
|
||||||
CODEOWNERS
|
|
||||||
COLORSYNC
|
|
||||||
COMPATTR
|
|
||||||
COMPOSITIONFORM
|
|
||||||
COMPSTR
|
|
||||||
CREATESTRUCTW
|
|
||||||
CRSEL
|
|
||||||
CRTC
|
|
||||||
CTYPE
|
|
||||||
CURSORPOS
|
|
||||||
CUSEL
|
|
||||||
CXVIRTUALSCREEN
|
|
||||||
CYCLEWINDOWS
|
|
||||||
CYVIRTUALSCREEN
|
|
||||||
Calculater
|
|
||||||
Codeinput
|
|
||||||
Colormap
|
|
||||||
Compiz
|
|
||||||
Condvar
|
|
||||||
Crtc
|
|
||||||
DEADCHAR
|
|
||||||
DEFAULTSIZE
|
|
||||||
DEFAULTTONEAREST
|
|
||||||
DEFAULTTONULL
|
|
||||||
DEFAULTTOPRIMARY
|
|
||||||
DELETEFILE
|
|
||||||
DEVICEINFO
|
|
||||||
DEVICELALTKEYMASK
|
|
||||||
DEVICELCMDKEYMASK
|
|
||||||
DEVICELCTLKEYMASK
|
|
||||||
DEVICELSHIFTKEYMASK
|
|
||||||
DEVICENAME
|
|
||||||
DEVICERALTKEYMASK
|
|
||||||
DEVICERCMDKEYMASK
|
|
||||||
DEVICERCTLKEYMASK
|
|
||||||
DEVICERSHIFTKEYMASK
|
|
||||||
DEVMODEW
|
|
||||||
DEVNOTIFY
|
|
||||||
DISP
|
|
||||||
DISPLAYFREQUENCY
|
|
||||||
DPAD
|
|
||||||
DPICHANGED
|
|
||||||
DROPEFFECT
|
|
||||||
DVASPECT
|
|
||||||
DWMCOMPOSITIONCHANGED
|
|
||||||
DWMWA
|
|
||||||
Deque
|
|
||||||
Dflt
|
|
||||||
EINTR
|
|
||||||
EINVAL
|
|
||||||
EJECTCD
|
|
||||||
EJECTCLOSECD
|
|
||||||
ENDCALL
|
|
||||||
ENDCOMPOSITION
|
|
||||||
ENLW
|
|
||||||
ENTERSIZEMOVE
|
|
||||||
ERCIM
|
|
||||||
EREOF
|
|
||||||
EWMH
|
|
||||||
EXITSIZEMOVE
|
|
||||||
EXSEL
|
|
||||||
EXSTYLE
|
|
||||||
EXTENDEDKEY
|
|
||||||
Eisu
|
|
||||||
Eisuu
|
|
||||||
Endcall
|
|
||||||
Endianness
|
|
||||||
FASTFORWARD
|
|
||||||
FLASHW
|
|
||||||
FLASHWINFO
|
|
||||||
FORMATETC
|
|
||||||
FORWARDMAIL
|
|
||||||
FRAMECHANGED
|
|
||||||
FVWM
|
|
||||||
GAMEPAD
|
|
||||||
GETHIGHCONTRAST
|
|
||||||
GETMINMAXINFO
|
|
||||||
GIDC
|
|
||||||
GLES
|
|
||||||
GWLP
|
|
||||||
HANGEUL
|
|
||||||
HANJA
|
|
||||||
HCURSOR
|
|
||||||
HDROP
|
|
||||||
HEADSETHOOK
|
|
||||||
HGLOBAL
|
|
||||||
HICON
|
|
||||||
HIGHCONTRASTA
|
|
||||||
HIGHCONTRASTON
|
|
||||||
HIMC
|
|
||||||
HINSTANCE
|
|
||||||
HMODULE
|
|
||||||
HORZ
|
|
||||||
HRAWINPUT
|
|
||||||
HTBOTTOM
|
|
||||||
HTBOTTOMLEFT
|
|
||||||
HTBOTTOMRIGHT
|
|
||||||
HTCAPTION
|
|
||||||
HTCLIENT
|
|
||||||
HTLEFT
|
|
||||||
HTRIGHT
|
|
||||||
HTTOP
|
|
||||||
HTTOPLEFT
|
|
||||||
HTTOPRIGHT
|
|
||||||
HWHEEL
|
|
||||||
Hanja
|
|
||||||
Hankaku
|
|
||||||
Headsethook
|
|
||||||
Henkan
|
|
||||||
Himetric
|
|
||||||
Hotspot
|
|
||||||
IACE
|
|
||||||
IBEAM
|
|
||||||
ICCCM
|
|
||||||
ICONINFO
|
|
||||||
IMEs
|
|
||||||
IMMENABLED
|
|
||||||
INPUTSINK
|
|
||||||
INTERNALPAINT
|
|
||||||
IOYUV
|
|
||||||
Impls
|
|
||||||
Ivars
|
|
||||||
JISHO
|
|
||||||
JUNJA
|
|
||||||
Junja
|
|
||||||
KBDILLUMDOWN
|
|
||||||
KBDILLUMTOGGLE
|
|
||||||
KBDILLUMUP
|
|
||||||
KEYDOWN
|
|
||||||
KEYFIRST
|
|
||||||
KEYLAST
|
|
||||||
KEYMAP
|
|
||||||
KEYUP
|
|
||||||
KILLFOCUS
|
|
||||||
KPJPCOMMA
|
|
||||||
KPLEFTPAREN
|
|
||||||
KPPLUSMINUS
|
|
||||||
KPRIGHTPAREN
|
|
||||||
Kanna
|
|
||||||
Keymap
|
|
||||||
Koho
|
|
||||||
LALT
|
|
||||||
LBUTTON
|
|
||||||
LBUTTONDOWN
|
|
||||||
LBUTTONUP
|
|
||||||
LCONTROL
|
|
||||||
LCTRL
|
|
||||||
LEFTALIGN
|
|
||||||
LOADFROMFILE
|
|
||||||
LOGPIXELSX
|
|
||||||
LOYA
|
|
||||||
LRESULT
|
|
||||||
LSHIFT
|
|
||||||
LSUPER
|
|
||||||
LWIN
|
|
||||||
Lcdfilter
|
|
||||||
Libera
|
|
||||||
MASSHOU
|
|
||||||
MAXIMIZABLE
|
|
||||||
MAXIMIZEBOX
|
|
||||||
MBUTTON
|
|
||||||
MBUTTONDOWN
|
|
||||||
MBUTTONUP
|
|
||||||
MENUCHAR
|
|
||||||
MICMUTE
|
|
||||||
MINIMIZABLE
|
|
||||||
MINIMIZEBOX
|
|
||||||
MINMAXINFO
|
|
||||||
MODECHANGE
|
|
||||||
MONITORINFO
|
|
||||||
MONITORINFOEXW
|
|
||||||
MOUSEHWHEEL
|
|
||||||
MOUSELEAVE
|
|
||||||
MOUSEMOVE
|
|
||||||
MOUSEWHEEL
|
|
||||||
MOVERESIZE
|
|
||||||
MSDOS
|
|
||||||
MSRV
|
|
||||||
Massyo
|
|
||||||
Miniaturizable
|
|
||||||
Mmap
|
|
||||||
Modifiermap
|
|
||||||
Muhenkan
|
|
||||||
Multitouch
|
|
||||||
NCACTIVATE
|
|
||||||
NCCALCSIZE
|
|
||||||
NCDESTROY
|
|
||||||
NCHITTEST
|
|
||||||
NCLBUTTONDOWN
|
|
||||||
NEXTTRACK
|
|
||||||
NOACTIVATE
|
|
||||||
NOMOVE
|
|
||||||
NONAME
|
|
||||||
NONCONVERT
|
|
||||||
NOREMOVE
|
|
||||||
NOREPOSITION
|
|
||||||
NOSIZE
|
|
||||||
NOTCONVERTED
|
|
||||||
NOTOPMOST
|
|
||||||
NOZORDER
|
|
||||||
NTSTATUS
|
|
||||||
NUMLOCK
|
|
||||||
Nesw
|
|
||||||
Nonnull
|
|
||||||
Nunley
|
|
||||||
OSVERSIONINFOW
|
|
||||||
OVERLAPPEDWINDOW
|
|
||||||
Overscan
|
|
||||||
PAUSECD
|
|
||||||
PCSTR
|
|
||||||
PCWSTR
|
|
||||||
PELSHEIGHT
|
|
||||||
PELSWIDTH
|
|
||||||
PGDN
|
|
||||||
PGUP
|
|
||||||
PINP
|
|
||||||
PLAYCD
|
|
||||||
POINTERDOWN
|
|
||||||
POINTERUP
|
|
||||||
POINTERUPDATE
|
|
||||||
POINTL
|
|
||||||
PQRS
|
|
||||||
PREVIOUSTRACK
|
|
||||||
PROCESSKEY
|
|
||||||
Pboard
|
|
||||||
Peekable
|
|
||||||
Pels
|
|
||||||
Pictsymbols
|
|
||||||
Pixmap
|
|
||||||
Premultiply
|
|
||||||
QERTZ
|
|
||||||
QWERTZ
|
|
||||||
RALT
|
|
||||||
RAWINPUT
|
|
||||||
RAWINPUTDEVICE
|
|
||||||
RAWINPUTDEVICELIST
|
|
||||||
RAWINPUTHEADER
|
|
||||||
RAWKEYBOARD
|
|
||||||
RBUTTON
|
|
||||||
RBUTTONDOWN
|
|
||||||
RBUTTONUP
|
|
||||||
RCONTROL
|
|
||||||
RCTRL
|
|
||||||
RDWR
|
|
||||||
RESULTSTR
|
|
||||||
RETURNCMD
|
|
||||||
RFKILL
|
|
||||||
RGBA
|
|
||||||
RIDEV
|
|
||||||
RIDI
|
|
||||||
RMENU
|
|
||||||
ROYA
|
|
||||||
RRRRRGGGGGBBBBB
|
|
||||||
RRRRRRRRGGGGGGGGBBBBBBBB
|
|
||||||
RRRRRRRRRRGGGGGGGGGGBBBBBBBBBB
|
|
||||||
RSHIFT
|
|
||||||
RSUPER
|
|
||||||
RUSTDOCFLAGS
|
|
||||||
RWIN
|
|
||||||
Raii
|
|
||||||
Reentrancy
|
|
||||||
Reparent
|
|
||||||
Romaji
|
|
||||||
SCREENSAVE
|
|
||||||
SCROLLDOWN
|
|
||||||
SCROLLUP
|
|
||||||
SENDFILE
|
|
||||||
SETCONTEXT
|
|
||||||
SETCURSOR
|
|
||||||
SETFOCUS
|
|
||||||
SETICON
|
|
||||||
SETTINGCHANGE
|
|
||||||
SHOULDAPPSUSEDARKMODE
|
|
||||||
SHOWNOACTIVATE
|
|
||||||
SHOWUICOMPOSITIONWINDOW
|
|
||||||
SIGILL
|
|
||||||
SIGSEGV
|
|
||||||
SIZEALL
|
|
||||||
SIZEBOX
|
|
||||||
SIZENESW
|
|
||||||
SIZENS
|
|
||||||
SIZENWSE
|
|
||||||
SIZEWE
|
|
||||||
STARTCOMPOSITION
|
|
||||||
STATDATA
|
|
||||||
STGMEDIUM
|
|
||||||
SWITCHVIDEOMODE
|
|
||||||
SYSCHAR
|
|
||||||
SYSCOMMAND
|
|
||||||
SYSDEADCHAR
|
|
||||||
SYSKEYDOWN
|
|
||||||
SYSKEYUP
|
|
||||||
SYSMENU
|
|
||||||
Smol
|
|
||||||
Sonoma
|
|
||||||
Subcompositor
|
|
||||||
Sublayer
|
|
||||||
Subviews
|
|
||||||
Sysrq
|
|
||||||
THUMBSTICK
|
|
||||||
TIMERNOFG
|
|
||||||
TOOLWINDOW
|
|
||||||
TOPLEFT
|
|
||||||
TOPRIGHT
|
|
||||||
TOUCHEVENTF
|
|
||||||
TOUCHINPUT
|
|
||||||
TOUROKU
|
|
||||||
TRACKMOUSEEVENT
|
|
||||||
TYMED
|
|
||||||
TYPEHID
|
|
||||||
TYPEKEYBOARD
|
|
||||||
TYPEMOUSE
|
|
||||||
Thumbl
|
|
||||||
Thumbr
|
|
||||||
Tomiĉo
|
|
||||||
UNICHAR
|
|
||||||
USEDARKMODECOLORS
|
|
||||||
UXTHEME
|
|
||||||
Unadjust
|
|
||||||
Unadvise
|
|
||||||
Ungrab
|
|
||||||
Unminimizing
|
|
||||||
VKEY
|
|
||||||
VKEYS
|
|
||||||
Viewporter
|
|
||||||
Visualid
|
|
||||||
Vulkan
|
|
||||||
WINDOWCOMPOSITIONATTRIB
|
|
||||||
WINDOWCOMPOSITIONATTRIBDATA
|
|
||||||
WINDOWEDGE
|
|
||||||
WINDOWPLACEMENT
|
|
||||||
WINDOWPOS
|
|
||||||
WINDOWPOSCHANGED
|
|
||||||
WINDOWPOSCHANGING
|
|
||||||
WLAN
|
|
||||||
WNDPROC
|
|
||||||
WSCTRL
|
|
||||||
WXYZ
|
|
||||||
XBUTTONDOWN
|
|
||||||
XBUTTONUP
|
|
||||||
XEMBED
|
|
||||||
XFER
|
|
||||||
XKBCH
|
|
||||||
XKBH
|
|
||||||
XKBXH
|
|
||||||
XMODIFIERS
|
|
||||||
XSETTINGS
|
|
||||||
XVIRTUALSCREEN
|
|
||||||
Xcursor
|
|
||||||
Xdnd
|
|
||||||
Xfer
|
|
||||||
Xids
|
|
||||||
Xorg
|
|
||||||
Xutf
|
|
||||||
YVIRTUALSCREEN
|
|
||||||
Zenkaku
|
|
||||||
aarch
|
|
||||||
abortable
|
|
||||||
adwaita
|
|
||||||
ahash
|
|
||||||
altgr
|
|
||||||
apartmentthreaded
|
|
||||||
argb
|
|
||||||
armv
|
|
||||||
atleast
|
|
||||||
attribs
|
|
||||||
autoreleasepool
|
|
||||||
autoreleases
|
|
||||||
autorotate
|
|
||||||
beachball
|
|
||||||
beforeunload
|
|
||||||
behaviour
|
|
||||||
bfcache
|
|
||||||
bgra
|
|
||||||
bindgen
|
|
||||||
bitflags
|
|
||||||
bitmaprenderer
|
|
||||||
blackbox
|
|
||||||
blurregion
|
|
||||||
borderless
|
|
||||||
busybutclickable
|
|
||||||
bytemuck
|
|
||||||
bytewise
|
|
||||||
calloop
|
|
||||||
callstack
|
|
||||||
cdylib
|
|
||||||
cgfloat
|
|
||||||
clicky
|
|
||||||
clipchildren
|
|
||||||
clonable
|
|
||||||
clsctx
|
|
||||||
clsid
|
|
||||||
codepaths
|
|
||||||
coinit
|
|
||||||
colormap
|
|
||||||
contextmenu
|
|
||||||
crossfont
|
|
||||||
crtc
|
|
||||||
crtcs
|
|
||||||
curr
|
|
||||||
darkmode
|
|
||||||
dbus
|
|
||||||
deminiaturize
|
|
||||||
deviceid
|
|
||||||
dlopen
|
|
||||||
docsrs
|
|
||||||
donotround
|
|
||||||
doubletap
|
|
||||||
downscaling
|
|
||||||
dppx
|
|
||||||
dwmsbt
|
|
||||||
dwmwcp
|
|
||||||
elwt
|
|
||||||
emscripten
|
|
||||||
endianness
|
|
||||||
entrancy
|
|
||||||
entrantly
|
|
||||||
evdev
|
|
||||||
eventloop
|
|
||||||
evlp
|
|
||||||
evtype
|
|
||||||
exclam
|
|
||||||
excludefromcapture
|
|
||||||
fcitx
|
|
||||||
forcetouch
|
|
||||||
fpath
|
|
||||||
fract
|
|
||||||
fsecs
|
|
||||||
fullscreen
|
|
||||||
fullscreened
|
|
||||||
fullsize
|
|
||||||
gamepads
|
|
||||||
getpid
|
|
||||||
gettid
|
|
||||||
glutin
|
|
||||||
gotchyas
|
|
||||||
hdrop
|
|
||||||
henkan
|
|
||||||
hidpi
|
|
||||||
himc
|
|
||||||
himetric
|
|
||||||
hinstance
|
|
||||||
hittest
|
|
||||||
hiword
|
|
||||||
hmenu
|
|
||||||
hmonitor
|
|
||||||
horz
|
|
||||||
hotplug
|
|
||||||
hotspot
|
|
||||||
hotx
|
|
||||||
hredraw
|
|
||||||
hresult
|
|
||||||
htotal
|
|
||||||
hwnd
|
|
||||||
ibus
|
|
||||||
icrate
|
|
||||||
impls
|
|
||||||
initer
|
|
||||||
inputmethod
|
|
||||||
isize
|
|
||||||
ivars
|
|
||||||
kcav
|
|
||||||
kchibisov
|
|
||||||
keybdinput
|
|
||||||
keybinds
|
|
||||||
keyevent
|
|
||||||
keyeventf
|
|
||||||
keymap
|
|
||||||
keypermod
|
|
||||||
keypresses
|
|
||||||
keysym
|
|
||||||
keysyms
|
|
||||||
kunddaliya
|
|
||||||
kwin
|
|
||||||
lcddefault
|
|
||||||
lgid
|
|
||||||
libc
|
|
||||||
libwayland
|
|
||||||
libxkbcommon
|
|
||||||
lindex
|
|
||||||
lmenu
|
|
||||||
longjmp
|
|
||||||
longsolidusoverlay
|
|
||||||
lowline
|
|
||||||
loword
|
|
||||||
lparam
|
|
||||||
lpfn
|
|
||||||
lpsz
|
|
||||||
lshift
|
|
||||||
macbooks
|
|
||||||
madsmtm
|
|
||||||
mainloop
|
|
||||||
maintainership
|
|
||||||
mainwindow
|
|
||||||
mapvk
|
|
||||||
memmap
|
|
||||||
millihertz
|
|
||||||
minwindef
|
|
||||||
mkdid
|
|
||||||
mkwid
|
|
||||||
modifierless
|
|
||||||
modifiermap
|
|
||||||
msiglreith
|
|
||||||
muhenkan
|
|
||||||
multitouch
|
|
||||||
nanos
|
|
||||||
nccreate
|
|
||||||
netwm
|
|
||||||
newtype
|
|
||||||
nodename
|
|
||||||
nonminimal
|
|
||||||
noredirectionbitmap
|
|
||||||
notgull
|
|
||||||
notitle
|
|
||||||
nsec
|
|
||||||
nsscreen
|
|
||||||
nsstring
|
|
||||||
nsview
|
|
||||||
ntdll
|
|
||||||
numpad
|
|
||||||
numpads
|
|
||||||
objc
|
|
||||||
offcenter
|
|
||||||
onpointerrawupdate
|
|
||||||
opengl
|
|
||||||
oppsite
|
|
||||||
orbclient
|
|
||||||
ossi
|
|
||||||
overscan
|
|
||||||
overtyping
|
|
||||||
pagehide
|
|
||||||
pageshow
|
|
||||||
physicalkey
|
|
||||||
pixmap
|
|
||||||
pointercancel
|
|
||||||
pointermove
|
|
||||||
pointerout
|
|
||||||
pointerover
|
|
||||||
pointerrawupdate
|
|
||||||
polonius
|
|
||||||
ppmm
|
|
||||||
preedit
|
|
||||||
premultiply
|
|
||||||
primarylangid
|
|
||||||
pthread
|
|
||||||
qhandle
|
|
||||||
randr
|
|
||||||
reallocs
|
|
||||||
rects
|
|
||||||
reentrancy
|
|
||||||
reparent
|
|
||||||
reparenting
|
|
||||||
replugs
|
|
||||||
repr
|
|
||||||
resizeable
|
|
||||||
retval
|
|
||||||
rgba
|
|
||||||
rgrc
|
|
||||||
rightclick
|
|
||||||
riid
|
|
||||||
roundsmall
|
|
||||||
rshift
|
|
||||||
runloop
|
|
||||||
rustc
|
|
||||||
rustdoc
|
|
||||||
rustix
|
|
||||||
scancode
|
|
||||||
scancodes
|
|
||||||
sctk
|
|
||||||
serde
|
|
||||||
setjmp
|
|
||||||
setlocale
|
|
||||||
shcore
|
|
||||||
smithay
|
|
||||||
smol
|
|
||||||
softbuffer
|
|
||||||
sourceid
|
|
||||||
splitn
|
|
||||||
standardised
|
|
||||||
stdweb
|
|
||||||
struct
|
|
||||||
structfield
|
|
||||||
subcompositor
|
|
||||||
subframework
|
|
||||||
subsec
|
|
||||||
subviews
|
|
||||||
syms
|
|
||||||
syscall
|
|
||||||
systembackdrop
|
|
||||||
sythesize
|
|
||||||
sythesized
|
|
||||||
sythetic
|
|
||||||
tabbedwindow
|
|
||||||
tabindex
|
|
||||||
throghout
|
|
||||||
timespec
|
|
||||||
titlebar
|
|
||||||
touchpad
|
|
||||||
touchstart
|
|
||||||
trackpad
|
|
||||||
transientwindow
|
|
||||||
tymed
|
|
||||||
uapi
|
|
||||||
uiscreen
|
|
||||||
uiscreens
|
|
||||||
ulong
|
|
||||||
unaccel
|
|
||||||
unaccelerated
|
|
||||||
uncoalesced
|
|
||||||
unconfine
|
|
||||||
undropped
|
|
||||||
unfocusing
|
|
||||||
ungrab
|
|
||||||
ungrabs
|
|
||||||
uninit
|
|
||||||
uninitialize
|
|
||||||
unmark
|
|
||||||
unmaximized
|
|
||||||
unminimize
|
|
||||||
unobserve
|
|
||||||
unparameterised
|
|
||||||
unref
|
|
||||||
unresizable
|
|
||||||
usedefault
|
|
||||||
userdata
|
|
||||||
uxtheme
|
|
||||||
viewporter
|
|
||||||
visibilitychange
|
|
||||||
visualid
|
|
||||||
visualtype
|
|
||||||
vkey
|
|
||||||
vredraw
|
|
||||||
vsync
|
|
||||||
vtbl
|
|
||||||
vtotal
|
|
||||||
vulkano
|
|
||||||
wakeup
|
|
||||||
wakeups
|
|
||||||
wantpalm
|
|
||||||
wgpu
|
|
||||||
winapi
|
|
||||||
windef
|
|
||||||
winit
|
|
||||||
winuser
|
|
||||||
wndclassexw
|
|
||||||
wparam
|
|
||||||
wrongcompobj
|
|
||||||
xbutton
|
|
||||||
xconn
|
|
||||||
xconnection
|
|
||||||
xcursor
|
|
||||||
xdisplay
|
|
||||||
xevent
|
|
||||||
xext
|
|
||||||
xfiltered
|
|
||||||
xfixes
|
|
||||||
xhot
|
|
||||||
ximage
|
|
||||||
xkbcommon
|
|
||||||
xkbext
|
|
||||||
xlib
|
|
||||||
xmodifiers
|
|
||||||
xmonad
|
|
||||||
xpresent
|
|
||||||
xrandr
|
|
||||||
xrender
|
|
||||||
xresources
|
|
||||||
xscrnsaver
|
|
||||||
xsettings
|
|
||||||
xwindow
|
|
||||||
yeong
|
|
||||||
yhot
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -195,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>);
|
||||||
|
|
||||||
|
|||||||
211
src/event.rs
211
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,7 +418,7 @@ pub enum WindowEvent {
|
|||||||
/// The window has been occluded (completely hidden from view).
|
/// The window has been occluded (completely hidden from view).
|
||||||
///
|
///
|
||||||
/// This is different to window visibility as it depends on whether the window is closed,
|
/// This is different to window visibility as it depends on whether the window is closed,
|
||||||
/// minimized, set invisible, or fully occluded by another window.
|
/// minimised, set invisible, or fully occluded by another window.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
@@ -784,7 +641,7 @@ pub struct KeyEvent {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// In games, you often want to ignore repeated key events - this can be
|
/// In games, you often want to ignore repated key events - this can be
|
||||||
/// done by ignoring events where this property is set.
|
/// done by ignoring events where this property is set.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|||||||
@@ -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};
|
||||||
@@ -80,7 +81,7 @@ impl<T> EventLoopBuilder<T> {
|
|||||||
/// ***For cross-platform compatibility, the [`EventLoop`] must be created on the main thread,
|
/// ***For cross-platform compatibility, the [`EventLoop`] must be created on the main thread,
|
||||||
/// and only once per application.***
|
/// and only once per application.***
|
||||||
///
|
///
|
||||||
/// Calling this function will result in display backend initialization.
|
/// Calling this function will result in display backend initialisation.
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// ## Panics
|
||||||
///
|
///
|
||||||
@@ -215,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.
|
||||||
///
|
///
|
||||||
@@ -231,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.
|
||||||
@@ -242,17 +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))
|
||||||
{
|
|
||||||
let _span = tracing::debug_span!("winit::EventLoop::run").entered();
|
|
||||||
|
|
||||||
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
|
||||||
@@ -344,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()
|
||||||
}
|
}
|
||||||
@@ -358,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()
|
||||||
}
|
}
|
||||||
@@ -630,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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1229,7 +1229,7 @@ pub enum NamedKey {
|
|||||||
Dimmer,
|
Dimmer,
|
||||||
/// Swap video sources. (`VK_DISPLAY_SWAP`)
|
/// Swap video sources. (`VK_DISPLAY_SWAP`)
|
||||||
DisplaySwap,
|
DisplaySwap,
|
||||||
/// Select Digital Video Recorder. (`KEYCODE_DVR`)
|
/// Select Digital Video Rrecorder. (`KEYCODE_DVR`)
|
||||||
DVR,
|
DVR,
|
||||||
/// Exit the current application. (`VK_EXIT`)
|
/// Exit the current application. (`VK_EXIT`)
|
||||||
Exit,
|
Exit,
|
||||||
|
|||||||
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;
|
||||||
|
|||||||
@@ -45,13 +45,13 @@
|
|||||||
//! | Base Class | Feature Flag | Notes |
|
//! | Base Class | Feature Flag | Notes |
|
||||||
//! | :--------------: | :---------------: | :-----: |
|
//! | :--------------: | :---------------: | :-----: |
|
||||||
//! | `NativeActivity` | `android-native-activity` | Built-in to Android - it is possible to use without compiling any Java or Kotlin code. Java or Kotlin code may be needed to subclass `NativeActivity` to access some platform features. It does not derive from the [`AndroidAppCompat`] base class.|
|
//! | `NativeActivity` | `android-native-activity` | Built-in to Android - it is possible to use without compiling any Java or Kotlin code. Java or Kotlin code may be needed to subclass `NativeActivity` to access some platform features. It does not derive from the [`AndroidAppCompat`] base class.|
|
||||||
//! | [`GameActivity`] | `android-game-activity` | Derives from [`AndroidAppCompat`], a defacto standard `Activity` base class that helps support a wider range of Android versions. Requires a build system that can compile Java or Kotlin and fetch Android dependencies from a [Maven repository][android_jet] (or link with an embedded [release][android_releases] of [`GameActivity`]) |
|
//! | [`GameActivity`] | `android-game-activity` | Derives from [`AndroidAppCompat`], a defacto standard `Activity` base class that helps support a wider range of Android versions. Requires a build system that can compile Java or Kotlin and fetch Android dependencies from a [Maven repository][agdk_jetpack] (or link with an embedded [release][agdk_releases] of [`GameActivity`]) |
|
||||||
//!
|
//!
|
||||||
//! [`GameActivity`]: https://developer.android.com/games/agdk/game-activity
|
//! [`GameActivity`]: https://developer.android.com/games/agdk/game-activity
|
||||||
//! [`GameTextInput`]: https://developer.android.com/games/agdk/add-support-for-text-input
|
//! [`GameTextInput`]: https://developer.android.com/games/agdk/add-support-for-text-input
|
||||||
//! [`AndroidAppCompat`]: https://developer.android.com/reference/androidx/appcompat/app/AppCompatActivity
|
//! [`AndroidAppCompat`]: https://developer.android.com/reference/androidx/appcompat/app/AppCompatActivity
|
||||||
//! [android_jet]: https://developer.android.com/jetpack/androidx/releases/games
|
//! [agdk_jetpack]: https://developer.android.com/jetpack/androidx/releases/games
|
||||||
//! [android_releases]: https://developer.android.com/games/agdk/download#agdk-libraries
|
//! [agdk_releases]: https://developer.android.com/games/agdk/download#agdk-libraries
|
||||||
//! [Gradle]: https://developer.android.com/studio/build
|
//! [Gradle]: https://developer.android.com/studio/build
|
||||||
//!
|
//!
|
||||||
//! For more details, refer to these `android-activity` [example applications](https://github.com/rust-mobile/android-activity/tree/main/examples).
|
//! For more details, refer to these `android-activity` [example applications](https://github.com/rust-mobile/android-activity/tree/main/examples).
|
||||||
@@ -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.13", features = [ "android-native-activity" ] }`
|
//! 2. Enable the `"android-native-activity"` feature for Winit: `winit = { version = "0.29.15", 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> {
|
||||||
@@ -94,7 +105,7 @@ impl ActiveEventLoop {
|
|||||||
///
|
///
|
||||||
/// let mut event_loop = EventLoop::new().unwrap();
|
/// let mut event_loop = EventLoop::new().unwrap();
|
||||||
/// event_loop.run_on_demand(|_, _| {
|
/// event_loop.run_on_demand(|_, _| {
|
||||||
/// // Attempt to run the event loop in a re-entrant manner; this must fail.
|
/// // Attempt to run the event loop re-entrantly; this must fail.
|
||||||
/// event_loop.run_on_demand(|_, _| {});
|
/// event_loop.run_on_demand(|_, _| {});
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ pub trait PhysicalKeyExtScancode {
|
|||||||
|
|
||||||
impl PhysicalKeyExtScancode for PhysicalKey {
|
impl PhysicalKeyExtScancode for PhysicalKey {
|
||||||
fn to_scancode(self) -> Option<u32> {
|
fn to_scancode(self) -> Option<u32> {
|
||||||
crate::platform_impl::physical_key_to_scancode(self)
|
crate::platform_impl::physicalkey_to_scancode(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_scancode(scancode: u32) -> PhysicalKey {
|
fn from_scancode(scancode: u32) -> PhysicalKey {
|
||||||
crate::platform_impl::scancode_to_physical_key(scancode)
|
crate::platform_impl::scancode_to_physicalkey(scancode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! The [`ActivationToken`] is essential to ensure that your newly
|
//! The [`ActivationToken`] is essential to ensure that your newly
|
||||||
//! created window will obtain the focus, otherwise the user could
|
//! created window will obtain the focus, otherwise the user could
|
||||||
//! be required to click on the window.
|
//! be requered to click on the window.
|
||||||
//!
|
//!
|
||||||
//! Such token is usually delivered via the environment variable and
|
//! Such token is usually delivered via the environment variable and
|
||||||
//! could be read from it with the [`EventLoopExtStartupNotify::read_token_from_env`].
|
//! could be read from it with the [`EventLoopExtStartupNotify::read_token_from_env`].
|
||||||
|
|||||||
@@ -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),
|
||||||
@@ -330,7 +343,7 @@ impl fmt::Display for BadAnimation {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Empty => write!(f, "No cursors supplied"),
|
Self::Empty => write!(f, "No cursors supplied"),
|
||||||
Self::Animation => write!(f, "A supplied cursor is an animation"),
|
Self::Animation => write!(f, "A supplied cursor is an animtion"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,11 +157,11 @@ pub trait EventLoopBuilderExtWindows {
|
|||||||
/// #[cfg(target_os = "windows")]
|
/// #[cfg(target_os = "windows")]
|
||||||
/// builder.with_msg_hook(|msg|{
|
/// builder.with_msg_hook(|msg|{
|
||||||
/// let msg = msg as *const MSG;
|
/// let msg = msg as *const MSG;
|
||||||
/// # let accelerators: Vec<ACCEL> = Vec::new();
|
/// # let accels: Vec<ACCEL> = Vec::new();
|
||||||
/// let translated = unsafe {
|
/// let translated = unsafe {
|
||||||
/// TranslateAcceleratorW(
|
/// TranslateAcceleratorW(
|
||||||
/// (*msg).hwnd,
|
/// (*msg).hwnd,
|
||||||
/// CreateAcceleratorTableW(accelerators.as_ptr() as _, 1),
|
/// CreateAcceleratorTableW(accels.as_ptr() as _, 1),
|
||||||
/// msg,
|
/// msg,
|
||||||
/// ) == 1
|
/// ) == 1
|
||||||
/// };
|
/// };
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ use crate::dpi::Size;
|
|||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum WindowType {
|
pub enum WindowType {
|
||||||
/// A desktop feature. This can include a single window containing desktop icons with the same dimensions as the
|
/// A desktop feature. This can include a single window containing desktop icons with the same dimensions as the
|
||||||
/// screen, allowing the desktop environment to have full control of the desktop, without the need for proxy-ing
|
/// screen, allowing the desktop environment to have full control of the desktop, without the need for proxying
|
||||||
/// root window clicks.
|
/// root window clicks.
|
||||||
Desktop,
|
Desktop,
|
||||||
/// A dock or panel feature. Typically a Window Manager would keep such windows on top of all other windows.
|
/// A dock or panel feature. Typically a Window Manager would keep such windows on top of all other windows.
|
||||||
Dock,
|
Dock,
|
||||||
/// Toolbar windows. "Torn off" from the main application.
|
/// Toolbar windows. "Torn off" from the main application.
|
||||||
Toolbar,
|
Toolbar,
|
||||||
/// Pin-able menu windows. "Torn off" from the main application.
|
/// Pinnable menu windows. "Torn off" from the main application.
|
||||||
Menu,
|
Menu,
|
||||||
/// A small persistent utility window, such as a palette or toolbox.
|
/// A small persistent utility window, such as a palette or toolbox.
|
||||||
Utility,
|
Utility,
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
where
|
where
|
||||||
F: FnMut(event::Event<T>, &RootAEL),
|
F: FnMut(event::Event<T>, &RootAEL),
|
||||||
{
|
{
|
||||||
trace!("Main loop iteration");
|
trace!("Mainloop iteration");
|
||||||
|
|
||||||
let cause = self.cause;
|
let cause = self.cause;
|
||||||
let mut pending_redraw = self.pending_redraw;
|
let mut pending_redraw = self.pending_redraw;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ use crate::platform_impl::common::xkb::{XkbContext, XKBH};
|
|||||||
///
|
///
|
||||||
/// X11-style keycodes are offset by 8 from the keycodes the Linux kernel uses.
|
/// X11-style keycodes are offset by 8 from the keycodes the Linux kernel uses.
|
||||||
pub fn raw_keycode_to_physicalkey(keycode: u32) -> PhysicalKey {
|
pub fn raw_keycode_to_physicalkey(keycode: u32) -> PhysicalKey {
|
||||||
scancode_to_physical_key(keycode.saturating_sub(8))
|
scancode_to_physicalkey(keycode.saturating_sub(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map the linux scancode to Keycode.
|
/// Map the linux scancode to Keycode.
|
||||||
///
|
///
|
||||||
/// Both X11 and Wayland use keys with `+ 8` offset to linux scancode.
|
/// Both X11 and Wayland use keys with `+ 8` offset to linux scancode.
|
||||||
pub fn scancode_to_physical_key(scancode: u32) -> PhysicalKey {
|
pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
|
||||||
// The keycode values are taken from linux/include/uapi/linux/input-event-codes.h, as
|
// The keycode values are taken from linux/include/uapi/linux/input-event-codes.h, as
|
||||||
// libxkbcommon's documentation seems to suggest that the keycode values we're interested in
|
// libxkbcommon's documentation seems to suggest that the keycode values we're interested in
|
||||||
// are defined by the Linux kernel. If Winit programs end up being run on other Unix-likes,
|
// are defined by the Linux kernel. If Winit programs end up being run on other Unix-likes,
|
||||||
@@ -287,7 +287,7 @@ pub fn scancode_to_physical_key(scancode: u32) -> PhysicalKey {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn physical_key_to_scancode(key: PhysicalKey) -> Option<u32> {
|
pub fn physicalkey_to_scancode(key: PhysicalKey) -> Option<u32> {
|
||||||
let code = match key {
|
let code = match key {
|
||||||
PhysicalKey::Code(code) => code,
|
PhysicalKey::Code(code) => code,
|
||||||
PhysicalKey::Unidentified(code) => {
|
PhysicalKey::Unidentified(code) => {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ use keymap::XkbKeymap;
|
|||||||
|
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
pub use keymap::raw_keycode_to_physicalkey;
|
pub use keymap::raw_keycode_to_physicalkey;
|
||||||
pub use keymap::{physical_key_to_scancode, scancode_to_physical_key};
|
pub use keymap::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||||
pub use state::XkbState;
|
pub use state::XkbState;
|
||||||
|
|
||||||
// TODO: Wire this up without using a static `AtomicBool`.
|
// TODO: Wire this up without using a static `AtomicBool`.
|
||||||
@@ -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(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use self::common::xkb::{physical_key_to_scancode, scancode_to_physical_key};
|
pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||||
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
||||||
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
||||||
pub(crate) use crate::platform_impl::Fullscreen;
|
pub(crate) use crate::platform_impl::Fullscreen;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||||||
WlKeyboardEvent::Leave { surface, .. } => {
|
WlKeyboardEvent::Leave { surface, .. } => {
|
||||||
let window_id = wayland::make_wid(&surface);
|
let window_id = wayland::make_wid(&surface);
|
||||||
|
|
||||||
// NOTE: we should drop the repeat regardless whether it was for the present
|
// NOTE: we should drop the repeat regardless whethere it was for the present
|
||||||
// window of for the window which just went gone.
|
// window of for the window which just went gone.
|
||||||
let keyboard_state = seat_state.keyboard_state.as_mut().unwrap();
|
let keyboard_state = seat_state.keyboard_state.as_mut().unwrap();
|
||||||
keyboard_state.current_repeat = None;
|
keyboard_state.current_repeat = None;
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ impl PointerHandler for WinitState {
|
|||||||
pointer_data.phase = phase;
|
pointer_data.phase = phase;
|
||||||
|
|
||||||
// Mice events have both pixel and discrete delta's at the same time. So prefer
|
// Mice events have both pixel and discrete delta's at the same time. So prefer
|
||||||
// the discrete values if they are present.
|
// the descrite values if they are present.
|
||||||
let delta = if has_discrete_scroll {
|
let delta = if has_discrete_scroll {
|
||||||
// XXX Wayland sign convention is the inverse of winit.
|
// XXX Wayland sign convention is the inverse of winit.
|
||||||
MouseScrollDelta::LineDelta(
|
MouseScrollDelta::LineDelta(
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -987,7 +987,7 @@ impl EventProcessor {
|
|||||||
if keycode != 0 && !self.is_composing {
|
if keycode != 0 && !self.is_composing {
|
||||||
// Don't alter the modifiers state from replaying.
|
// Don't alter the modifiers state from replaying.
|
||||||
if replay {
|
if replay {
|
||||||
self.send_synthetic_modifier_from_core(window_id, xev.state as u16, &mut callback);
|
self.send_synthic_modifier_from_core(window_id, xev.state as u16, &mut callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut key_processor) = self.xkb_context.key_context() {
|
if let Some(mut key_processor) = self.xkb_context.key_context() {
|
||||||
@@ -1037,7 +1037,7 @@ impl EventProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_synthetic_modifier_from_core<T: 'static, F>(
|
fn send_synthic_modifier_from_core<T: 'static, F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_id: crate::window::WindowId,
|
window_id: crate::window::WindowId,
|
||||||
state: u16,
|
state: u16,
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> {
|
|||||||
pub unsafe extern "C" fn xim_instantiate_callback(
|
pub unsafe extern "C" fn xim_instantiate_callback(
|
||||||
_display: *mut ffi::Display,
|
_display: *mut ffi::Display,
|
||||||
client_data: ffi::XPointer,
|
client_data: ffi::XPointer,
|
||||||
// This field is un-supplied.
|
// This field is unsupplied.
|
||||||
_call_data: ffi::XPointer,
|
_call_data: ffi::XPointer,
|
||||||
) {
|
) {
|
||||||
let inner: *mut ImeInner = client_data as _;
|
let inner: *mut ImeInner = client_data as _;
|
||||||
@@ -193,7 +193,7 @@ pub unsafe extern "C" fn xim_instantiate_callback(
|
|||||||
pub unsafe extern "C" fn xim_destroy_callback(
|
pub unsafe extern "C" fn xim_destroy_callback(
|
||||||
_xim: ffi::XIM,
|
_xim: ffi::XIM,
|
||||||
client_data: ffi::XPointer,
|
client_data: ffi::XPointer,
|
||||||
// This field is un-supplied.
|
// This field is unsupplied.
|
||||||
_call_data: ffi::XPointer,
|
_call_data: ffi::XPointer,
|
||||||
) {
|
) {
|
||||||
let inner: *mut ImeInner = client_data as _;
|
let inner: *mut ImeInner = client_data as _;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ extern "C" fn preedit_draw_callback(
|
|||||||
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() {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"invalid chg range: buffer length={}, but chg_first={} chg_length={}",
|
"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,
|
||||||
call_data.chg_length
|
call_data.chg_length
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ impl From<util::GetPropertyError> for GetXimServersError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The root window has a property named XIM_SERVERS, which contains a list of atoms representing
|
// The root window has a property named XIM_SERVERS, which contains a list of atoms representing
|
||||||
// the available XIM servers. For instance, if you're using ibus, it would contain an atom named
|
// the availabile XIM servers. For instance, if you're using ibus, it would contain an atom named
|
||||||
// "@server=ibus". It's possible for this property to contain multiple atoms, though presumably
|
// "@server=ibus". It's possible for this property to contain multiple atoms, though presumably
|
||||||
// rare. Note that we replace "@server=" with "@im=" in order to match the format of locale
|
// rare. Note that we replace "@server=" with "@im=" in order to match the format of locale
|
||||||
// modifiers, since we don't want a user who's looking at logs to ask "am I supposed to set
|
// modifiers, since we don't want a user who's looking at logs to ask "am I supposed to set
|
||||||
|
|||||||
@@ -887,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 {
|
||||||
@@ -896,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!(
|
||||||
@@ -988,6 +992,12 @@ impl From<xsettings::ParserError> for X11Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<util::GetPropertyError> for X11Error {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ impl AaRect {
|
|||||||
pub struct Geometry {
|
pub struct Geometry {
|
||||||
pub root: xproto::Window,
|
pub root: xproto::Window,
|
||||||
// If you want positions relative to the root window, use translate_coords.
|
// If you want positions relative to the root window, use translate_coords.
|
||||||
// Note that the overwhelming majority of window managers are re-parenting WMs, thus the window
|
// Note that the overwhelming majority of window managers are reparenting WMs, thus the window
|
||||||
// ID we get from window creation is for a nested window used as the window's client area. If
|
// ID we get from window creation is for a nested window used as the window's client area. If
|
||||||
// you call get_geometry with that window ID, then you'll get the position of that client area
|
// you call get_geometry with that window ID, then you'll get the position of that client area
|
||||||
// window relative to the parent it's nested in (the frame), which isn't helpful if you want
|
// window relative to the parent it's nested in (the frame), which isn't helpful if you want
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl XConnection {
|
impl XConnection {
|
||||||
// This is important, so pay attention!
|
// This is impoartant, so pay attention!
|
||||||
// Xlib has an output buffer, and tries to hide the async nature of X from you.
|
// Xlib has an output buffer, and tries to hide the async nature of X from you.
|
||||||
// This buffer contains the requests you make, and is flushed under various circumstances:
|
// This buffer contains the requests you make, and is flushed under various circumstances:
|
||||||
// 1. `XPending`, `XNextEvent`, and `XWindowEvent` flush "as needed"
|
// 1. `XPending`, `XNextEvent`, and `XWindowEvent` flush "as needed"
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ macro_rules! consume {
|
|||||||
let this = $this;
|
let this = $this;
|
||||||
let (x, y) = match (this.x.abs() < <$ty>::EPSILON, this.y.abs() < <$ty>::EPSILON) {
|
let (x, y) = match (this.x.abs() < <$ty>::EPSILON, this.y.abs() < <$ty>::EPSILON) {
|
||||||
(true, true) => return None,
|
(true, true) => return None,
|
||||||
(true, false) => (this.x, 0.0),
|
(false, true) => (this.x, 0.0),
|
||||||
(false, true) => (0.0, this.y),
|
(true, false) => (0.0, this.y),
|
||||||
(false, false) => (this.x, this.y),
|
(false, false) => (this.x, this.y),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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!
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ impl XConnection {
|
|||||||
|
|
||||||
// Mutter/Muffin/Budgie doesn't have _NET_SUPPORTING_WM_CHECK in its _NET_SUPPORTED, despite
|
// Mutter/Muffin/Budgie doesn't have _NET_SUPPORTING_WM_CHECK in its _NET_SUPPORTED, despite
|
||||||
// it working and being supported. This has been reported upstream, but due to the
|
// it working and being supported. This has been reported upstream, but due to the
|
||||||
// unavailability of time machines, we'll just try to get _NET_SUPPORTING_WM_CHECK
|
// inavailability of time machines, we'll just try to get _NET_SUPPORTING_WM_CHECK
|
||||||
// regardless of whether or not the WM claims to support it.
|
// regardless of whether or not the WM claims to support it.
|
||||||
//
|
//
|
||||||
// Blackbox 0.70 also incorrectly reports not supporting this, though that appears to be fixed
|
// Blackbox 0.70 also incorrectly reports not supporting this, though that appears to be fixed
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ impl UnownedWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Enable drag and drop (TODO: extend API to make this toggle-able)
|
// Enable drag and drop (TODO: extend API to make this toggleable)
|
||||||
{
|
{
|
||||||
let dnd_aware_atom = atoms[XdndAware];
|
let dnd_aware_atom = atoms[XdndAware];
|
||||||
let version = &[5u32]; // Latest version; hasn't changed since 2002
|
let version = &[5u32]; // Latest version; hasn't changed since 2002
|
||||||
@@ -1038,10 +1038,9 @@ impl UnownedWindow {
|
|||||||
let vert_atom = atoms[_NET_WM_STATE_MAXIMIZED_VERT];
|
let vert_atom = atoms[_NET_WM_STATE_MAXIMIZED_VERT];
|
||||||
match state {
|
match state {
|
||||||
Ok(atoms) => {
|
Ok(atoms) => {
|
||||||
let horizontal_maximized =
|
let horz_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == horz_atom);
|
||||||
atoms.iter().any(|atom: &xproto::Atom| *atom == horz_atom);
|
|
||||||
let vert_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == vert_atom);
|
let vert_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == vert_atom);
|
||||||
horizontal_maximized && vert_maximized
|
horz_maximized && vert_maximized
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@@ -1049,10 +1048,10 @@ impl UnownedWindow {
|
|||||||
|
|
||||||
fn set_maximized_inner(&self, maximized: bool) -> Result<VoidCookie<'_>, X11Error> {
|
fn set_maximized_inner(&self, maximized: bool) -> Result<VoidCookie<'_>, X11Error> {
|
||||||
let atoms = self.xconn.atoms();
|
let atoms = self.xconn.atoms();
|
||||||
let horizontal_atom = atoms[_NET_WM_STATE_MAXIMIZED_HORZ];
|
let horz_atom = atoms[_NET_WM_STATE_MAXIMIZED_HORZ];
|
||||||
let vert_atom = atoms[_NET_WM_STATE_MAXIMIZED_VERT];
|
let vert_atom = atoms[_NET_WM_STATE_MAXIMIZED_VERT];
|
||||||
|
|
||||||
self.set_netwm(maximized.into(), (horizontal_atom, vert_atom, 0, 0))
|
self.set_netwm(maximized.into(), (horz_atom, vert_atom, 0, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -113,8 +113,7 @@ pub(crate) fn create_key_event(
|
|||||||
let state = if is_press { Pressed } else { Released };
|
let state = if is_press { Pressed } else { Released };
|
||||||
|
|
||||||
let scancode = unsafe { ns_event.keyCode() };
|
let scancode = unsafe { ns_event.keyCode() };
|
||||||
let mut physical_key =
|
let mut physical_key = key_override.unwrap_or_else(|| scancode_to_physicalkey(scancode as u32));
|
||||||
key_override.unwrap_or_else(|| scancode_to_physical_key(scancode as u32));
|
|
||||||
|
|
||||||
// NOTE: The logical key should heed both SHIFT and ALT if possible.
|
// NOTE: The logical key should heed both SHIFT and ALT if possible.
|
||||||
// For instance:
|
// For instance:
|
||||||
@@ -151,7 +150,7 @@ pub(crate) fn create_key_event(
|
|||||||
|
|
||||||
let logical_key = match text_with_all_modifiers.as_ref() {
|
let logical_key = match text_with_all_modifiers.as_ref() {
|
||||||
// Only checking for ctrl and cmd here, not checking for alt because we DO want to
|
// Only checking for ctrl and cmd here, not checking for alt because we DO want to
|
||||||
// include its effect in the key. For example if -on the Germany layout- one
|
// include its effect in the key. For example if -on the Germay layout- one
|
||||||
// presses alt+8, the logical key should be "{"
|
// presses alt+8, the logical key should be "{"
|
||||||
// Also not checking if this is a release event because then this issue would
|
// Also not checking if this is a release event because then this issue would
|
||||||
// still affect the key release.
|
// still affect the key release.
|
||||||
@@ -416,7 +415,7 @@ pub(super) fn dummy_event() -> Option<Id<NSEvent>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn physical_key_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
|
pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
|
||||||
let code = match physical_key {
|
let code = match physical_key {
|
||||||
PhysicalKey::Code(code) => code,
|
PhysicalKey::Code(code) => code,
|
||||||
PhysicalKey::Unidentified(_) => return None,
|
PhysicalKey::Unidentified(_) => return None,
|
||||||
@@ -538,7 +537,7 @@ pub(crate) fn physical_key_to_scancode(physical_key: PhysicalKey) -> Option<u32>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn scancode_to_physical_key(scancode: u32) -> PhysicalKey {
|
pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
|
||||||
PhysicalKey::Code(match scancode {
|
PhysicalKey::Code(match scancode {
|
||||||
0x00 => KeyCode::KeyA,
|
0x00 => KeyCode::KeyA,
|
||||||
0x01 => KeyCode::KeyS,
|
0x01 => KeyCode::KeyS,
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ impl PanicInfo {
|
|||||||
self.inner.set(inner);
|
self.inner.set(inner);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
/// Overwrites the current state if the current state is not panicking
|
/// Overwrites the curret state if the current state is not panicking
|
||||||
pub fn set_panic(&self, p: Box<dyn Any + Send + 'static>) {
|
pub fn set_panic(&self, p: Box<dyn Any + Send + 'static>) {
|
||||||
if !self.is_panicking() {
|
if !self.is_panicking() {
|
||||||
self.inner.set(Some(p));
|
self.inner.set(Some(p));
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ mod window_delegate;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub(crate) use self::{
|
pub(crate) use self::{
|
||||||
event::{physical_key_to_scancode, scancode_to_physical_key, KeyEventExtra},
|
event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra},
|
||||||
event_loop::{
|
event_loop::{
|
||||||
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
|
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
|
||||||
PlatformSpecificEventLoopAttributes,
|
PlatformSpecificEventLoopAttributes,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use super::app_delegate::ApplicationDelegate;
|
|||||||
use super::cursor::{default_cursor, invisible_cursor};
|
use super::cursor::{default_cursor, invisible_cursor};
|
||||||
use super::event::{
|
use super::event::{
|
||||||
code_to_key, code_to_location, create_key_event, event_mods, lalt_pressed, ralt_pressed,
|
code_to_key, code_to_location, create_key_event, event_mods, lalt_pressed, ralt_pressed,
|
||||||
scancode_to_physical_key,
|
scancode_to_physicalkey,
|
||||||
};
|
};
|
||||||
use super::window::WinitWindow;
|
use super::window::WinitWindow;
|
||||||
use super::{util, DEVICE_ID};
|
use super::{util, DEVICE_ID};
|
||||||
@@ -918,7 +918,7 @@ impl WinitView {
|
|||||||
'send_event: {
|
'send_event: {
|
||||||
if is_flags_changed_event && unsafe { ns_event.keyCode() } != 0 {
|
if is_flags_changed_event && unsafe { ns_event.keyCode() } != 0 {
|
||||||
let scancode = unsafe { ns_event.keyCode() };
|
let scancode = unsafe { ns_event.keyCode() };
|
||||||
let physical_key = scancode_to_physical_key(scancode as u32);
|
let physical_key = scancode_to_physicalkey(scancode as u32);
|
||||||
|
|
||||||
// We'll correct the `is_press` later.
|
// We'll correct the `is_press` later.
|
||||||
let mut event = create_key_event(ns_event, false, false, Some(physical_key));
|
let mut event = create_key_event(ns_event, false, false, Some(physical_key));
|
||||||
|
|||||||
@@ -594,7 +594,7 @@ fn new_window(attrs: &WindowAttributes, mtm: MainThreadMarker) -> Option<Id<Wini
|
|||||||
view.setWantsBestResolutionOpenGLSurface(!attrs.platform_specific.disallow_hidpi);
|
view.setWantsBestResolutionOpenGLSurface(!attrs.platform_specific.disallow_hidpi);
|
||||||
|
|
||||||
// On Mojave, views automatically become layer-backed shortly after being added to
|
// On Mojave, views automatically become layer-backed shortly after being added to
|
||||||
// a window. Changing the layer-backed-ness of a view breaks the association between
|
// a window. Changing the layer-backedness of a view breaks the association between
|
||||||
// the view and its associated OpenGL context. To work around this, on Mojave we
|
// the view and its associated OpenGL context. To work around this, on Mojave we
|
||||||
// explicitly make the view layer-backed up front so that AppKit doesn't do it
|
// explicitly make the view layer-backed up front so that AppKit doesn't do it
|
||||||
// itself and break the association with its context.
|
// itself and break the association with its context.
|
||||||
@@ -1012,7 +1012,7 @@ impl WindowDelegate {
|
|||||||
self.set_style_mask(mask);
|
self.set_style_mask(mask);
|
||||||
|
|
||||||
// We edit the button directly instead of using `NSResizableWindowMask`,
|
// We edit the button directly instead of using `NSResizableWindowMask`,
|
||||||
// since that mask also affect the resize ability of the window (which is
|
// since that mask also affect the resizability of the window (which is
|
||||||
// controllable by other means in `winit`).
|
// controllable by other means in `winit`).
|
||||||
if let Some(button) = self.window().standardWindowButton(NSWindowZoomButton) {
|
if let Some(button) = self.window().standardWindowButton(NSWindowZoomButton) {
|
||||||
button.setEnabled(buttons.contains(WindowButtons::MAXIMIZE));
|
button.setEnabled(buttons.contains(WindowButtons::MAXIMIZE));
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -321,8 +321,8 @@ impl Key {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PhysicalKey {
|
impl PhysicalKey {
|
||||||
pub fn from_key_code_attribute_value(k_code: &str) -> Self {
|
pub fn from_key_code_attribute_value(kcav: &str) -> Self {
|
||||||
PhysicalKey::Code(match k_code {
|
PhysicalKey::Code(match kcav {
|
||||||
"Backquote" => KeyCode::Backquote,
|
"Backquote" => KeyCode::Backquote,
|
||||||
"Backslash" => KeyCode::Backslash,
|
"Backslash" => KeyCode::Backslash,
|
||||||
"BracketLeft" => KeyCode::BracketLeft,
|
"BracketLeft" => KeyCode::BracketLeft,
|
||||||
|
|||||||
@@ -117,13 +117,13 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
|
|||||||
|
|
||||||
if let Some(set_window_composition_attribute) = *SET_WINDOW_COMPOSITION_ATTRIBUTE {
|
if let Some(set_window_composition_attribute) = *SET_WINDOW_COMPOSITION_ATTRIBUTE {
|
||||||
unsafe {
|
unsafe {
|
||||||
// SetWindowCompositionAttribute needs a big_bool (i32), not bool.
|
// SetWindowCompositionAttribute needs a bigbool (i32), not bool.
|
||||||
let mut is_dark_mode_big_bool = BOOL::from(is_dark_mode);
|
let mut is_dark_mode_bigbool = BOOL::from(is_dark_mode);
|
||||||
|
|
||||||
let mut data = WINDOWCOMPOSITIONATTRIBDATA {
|
let mut data = WINDOWCOMPOSITIONATTRIBDATA {
|
||||||
Attrib: WCA_USEDARKMODECOLORS,
|
Attrib: WCA_USEDARKMODECOLORS,
|
||||||
pvData: &mut is_dark_mode_big_bool as *mut _ as _,
|
pvData: &mut is_dark_mode_bigbool as *mut _ as _,
|
||||||
cbData: std::mem::size_of_val(&is_dark_mode_big_bool) as _,
|
cbData: std::mem::size_of_val(&is_dark_mode_bigbool) as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = set_window_composition_attribute(hwnd, &mut data);
|
let status = set_window_composition_attribute(hwnd, &mut data);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use windows_sys::{
|
|||||||
pub struct IUnknownVtbl {
|
pub struct IUnknownVtbl {
|
||||||
pub QueryInterface: unsafe extern "system" fn(
|
pub QueryInterface: unsafe extern "system" fn(
|
||||||
This: *mut IUnknown,
|
This: *mut IUnknown,
|
||||||
r_iid: *const GUID,
|
riid: *const GUID,
|
||||||
ppvObject: *mut *mut c_void,
|
ppvObject: *mut *mut c_void,
|
||||||
) -> HRESULT,
|
) -> HRESULT,
|
||||||
pub AddRef: unsafe extern "system" fn(This: *mut IUnknown) -> u32,
|
pub AddRef: unsafe extern "system" fn(This: *mut IUnknown) -> u32,
|
||||||
@@ -29,45 +29,43 @@ pub struct IDataObjectVtbl {
|
|||||||
pub parent: IUnknownVtbl,
|
pub parent: IUnknownVtbl,
|
||||||
pub GetData: unsafe extern "system" fn(
|
pub GetData: unsafe extern "system" fn(
|
||||||
This: *mut IDataObject,
|
This: *mut IDataObject,
|
||||||
p_format_etc_In: *const FORMATETC,
|
pformatetcIn: *const FORMATETC,
|
||||||
p_medium: *mut STGMEDIUM,
|
pmedium: *mut STGMEDIUM,
|
||||||
) -> HRESULT,
|
) -> HRESULT,
|
||||||
pub GetDataHere: unsafe extern "system" fn(
|
pub GetDataHere: unsafe extern "system" fn(
|
||||||
This: *mut IDataObject,
|
This: *mut IDataObject,
|
||||||
p_format_etc: *const FORMATETC,
|
pformatetc: *const FORMATETC,
|
||||||
p_medium: *mut STGMEDIUM,
|
pmedium: *mut STGMEDIUM,
|
||||||
) -> HRESULT,
|
|
||||||
QueryGetData: unsafe extern "system" fn(
|
|
||||||
This: *mut IDataObject,
|
|
||||||
p_format_etc: *const FORMATETC,
|
|
||||||
) -> HRESULT,
|
) -> HRESULT,
|
||||||
|
QueryGetData:
|
||||||
|
unsafe extern "system" fn(This: *mut IDataObject, pformatetc: *const FORMATETC) -> HRESULT,
|
||||||
pub GetCanonicalFormatEtc: unsafe extern "system" fn(
|
pub GetCanonicalFormatEtc: unsafe extern "system" fn(
|
||||||
This: *mut IDataObject,
|
This: *mut IDataObject,
|
||||||
p_format_etc_In: *const FORMATETC,
|
pformatetcIn: *const FORMATETC,
|
||||||
p_format_etc_Out: *mut FORMATETC,
|
pformatetcOut: *mut FORMATETC,
|
||||||
) -> HRESULT,
|
) -> HRESULT,
|
||||||
pub SetData: unsafe extern "system" fn(
|
pub SetData: unsafe extern "system" fn(
|
||||||
This: *mut IDataObject,
|
This: *mut IDataObject,
|
||||||
p_format_etc: *const FORMATETC,
|
pformatetc: *const FORMATETC,
|
||||||
p_format_etcOut: *const FORMATETC,
|
pformatetcOut: *const FORMATETC,
|
||||||
fRelease: BOOL,
|
fRelease: BOOL,
|
||||||
) -> HRESULT,
|
) -> HRESULT,
|
||||||
pub EnumFormatEtc: unsafe extern "system" fn(
|
pub EnumFormatEtc: unsafe extern "system" fn(
|
||||||
This: *mut IDataObject,
|
This: *mut IDataObject,
|
||||||
dwDirection: u32,
|
dwDirection: u32,
|
||||||
pp_enumFormatEtc: *mut *mut IEnumFORMATETC,
|
ppenumFormatEtc: *mut *mut IEnumFORMATETC,
|
||||||
) -> HRESULT,
|
) -> HRESULT,
|
||||||
pub DAdvise: unsafe extern "system" fn(
|
pub DAdvise: unsafe extern "system" fn(
|
||||||
This: *mut IDataObject,
|
This: *mut IDataObject,
|
||||||
p_format_etc: *const FORMATETC,
|
pformatetc: *const FORMATETC,
|
||||||
a_dvf: u32,
|
advf: u32,
|
||||||
pAdvSInk: *const IAdviseSink,
|
pAdvSInk: *const IAdviseSink,
|
||||||
pdwConnection: *mut u32,
|
pdwConnection: *mut u32,
|
||||||
) -> HRESULT,
|
) -> HRESULT,
|
||||||
pub DUnadvise: unsafe extern "system" fn(This: *mut IDataObject, dwConnection: u32) -> HRESULT,
|
pub DUnadvise: unsafe extern "system" fn(This: *mut IDataObject, dwConnection: u32) -> HRESULT,
|
||||||
pub EnumDAdvise: unsafe extern "system" fn(
|
pub EnumDAdvise: unsafe extern "system" fn(
|
||||||
This: *mut IDataObject,
|
This: *mut IDataObject,
|
||||||
pp_enumAdvise: *const *const IEnumSTATDATA,
|
ppenumAdvise: *const *const IEnumSTATDATA,
|
||||||
) -> HRESULT,
|
) -> HRESULT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1021,10 +1021,10 @@ pub(super) unsafe extern "system" fn public_window_callback(
|
|||||||
|
|
||||||
let userdata_ptr = match (userdata, msg) {
|
let userdata_ptr = match (userdata, msg) {
|
||||||
(0, WM_NCCREATE) => {
|
(0, WM_NCCREATE) => {
|
||||||
let create_struct = unsafe { &mut *(lparam as *mut CREATESTRUCTW) };
|
let createstruct = unsafe { &mut *(lparam as *mut CREATESTRUCTW) };
|
||||||
let init_data = unsafe { &mut *(create_struct.lpCreateParams as *mut InitData<'_>) };
|
let initdata = unsafe { &mut *(createstruct.lpCreateParams as *mut InitData<'_>) };
|
||||||
|
|
||||||
let result = match unsafe { init_data.on_nccreate(window) } {
|
let result = match unsafe { initdata.on_nccreate(window) } {
|
||||||
Some(userdata) => unsafe {
|
Some(userdata) => unsafe {
|
||||||
super::set_window_long(window, GWL_USERDATA, userdata as _);
|
super::set_window_long(window, GWL_USERDATA, userdata as _);
|
||||||
DefWindowProcW(window, msg, wparam, lparam)
|
DefWindowProcW(window, msg, wparam, lparam)
|
||||||
@@ -1038,11 +1038,11 @@ pub(super) unsafe extern "system" fn public_window_callback(
|
|||||||
// but we'll make window creation fail here just in case.
|
// but we'll make window creation fail here just in case.
|
||||||
(0, WM_CREATE) => return -1,
|
(0, WM_CREATE) => return -1,
|
||||||
(_, WM_CREATE) => unsafe {
|
(_, WM_CREATE) => unsafe {
|
||||||
let create_struct = &mut *(lparam as *mut CREATESTRUCTW);
|
let createstruct = &mut *(lparam as *mut CREATESTRUCTW);
|
||||||
let init_data = create_struct.lpCreateParams;
|
let initdata = createstruct.lpCreateParams;
|
||||||
let init_data = &mut *(init_data as *mut InitData<'_>);
|
let initdata = &mut *(initdata as *mut InitData<'_>);
|
||||||
|
|
||||||
init_data.on_create();
|
initdata.on_create();
|
||||||
return DefWindowProcW(window, msg, wparam, lparam);
|
return DefWindowProcW(window, msg, wparam, lparam);
|
||||||
},
|
},
|
||||||
(0, _) => return unsafe { DefWindowProcW(window, msg, wparam, lparam) },
|
(0, _) => return unsafe { DefWindowProcW(window, msg, wparam, lparam) },
|
||||||
@@ -1147,7 +1147,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
// on all 4 borders would result in the caption getting drawn by the DWM.
|
// on all 4 borders would result in the caption getting drawn by the DWM.
|
||||||
//
|
//
|
||||||
// Another option would be to allow the DWM to paint inside the client area.
|
// Another option would be to allow the DWM to paint inside the client area.
|
||||||
// Unfortunately this results in inconsistent resize behavior, where the compositor is
|
// Unfortunately this results in janky resize behavior, where the compositor is
|
||||||
// ahead of the window surface. Currently, there seems no option to achieve this
|
// ahead of the window surface. Currently, there seems no option to achieve this
|
||||||
// with the Windows API.
|
// with the Windows API.
|
||||||
params.rgrc[0].top += 1;
|
params.rgrc[0].top += 1;
|
||||||
@@ -1312,10 +1312,10 @@ unsafe fn public_window_callback_inner(
|
|||||||
WM_WINDOWPOSCHANGED => {
|
WM_WINDOWPOSCHANGED => {
|
||||||
use crate::event::WindowEvent::Moved;
|
use crate::event::WindowEvent::Moved;
|
||||||
|
|
||||||
let window_pos = lparam as *const WINDOWPOS;
|
let windowpos = lparam as *const WINDOWPOS;
|
||||||
if unsafe { (*window_pos).flags & SWP_NOMOVE != SWP_NOMOVE } {
|
if unsafe { (*windowpos).flags & SWP_NOMOVE != SWP_NOMOVE } {
|
||||||
let physical_position =
|
let physical_position =
|
||||||
unsafe { PhysicalPosition::new((*window_pos).x, (*window_pos).y) };
|
unsafe { PhysicalPosition::new((*windowpos).x, (*windowpos).y) };
|
||||||
userdata.send_event(Event::WindowEvent {
|
userdata.send_event(Event::WindowEvent {
|
||||||
window_id: RootWindowId(WindowId(window)),
|
window_id: RootWindowId(WindowId(window)),
|
||||||
event: Moved(physical_position),
|
event: Moved(physical_position),
|
||||||
@@ -1817,18 +1817,18 @@ unsafe fn public_window_callback_inner(
|
|||||||
}
|
}
|
||||||
|
|
||||||
WM_TOUCH => {
|
WM_TOUCH => {
|
||||||
let p_count = super::loword(wparam as u32) as usize;
|
let pcount = super::loword(wparam as u32) as usize;
|
||||||
let mut inputs = Vec::with_capacity(p_count);
|
let mut inputs = Vec::with_capacity(pcount);
|
||||||
let h_touch = lparam;
|
let htouch = lparam;
|
||||||
if unsafe {
|
if unsafe {
|
||||||
GetTouchInputInfo(
|
GetTouchInputInfo(
|
||||||
h_touch,
|
htouch,
|
||||||
p_count as u32,
|
pcount as u32,
|
||||||
inputs.as_mut_ptr(),
|
inputs.as_mut_ptr(),
|
||||||
mem::size_of::<TOUCHINPUT>() as i32,
|
mem::size_of::<TOUCHINPUT>() as i32,
|
||||||
) > 0
|
) > 0
|
||||||
} {
|
} {
|
||||||
unsafe { inputs.set_len(p_count) };
|
unsafe { inputs.set_len(pcount) };
|
||||||
for input in &inputs {
|
for input in &inputs {
|
||||||
let mut location = POINT {
|
let mut location = POINT {
|
||||||
x: input.x / 100,
|
x: input.x / 100,
|
||||||
@@ -1862,7 +1862,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { CloseTouchInputHandle(h_touch) };
|
unsafe { CloseTouchInputHandle(htouch) };
|
||||||
result = ProcResult::Value(0);
|
result = ProcResult::Value(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2557,7 +2557,7 @@ unsafe fn handle_raw_input(userdata: &ThreadMsgTargetData, data: RAWINPUT) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum PointerMoveKind {
|
enum PointerMoveKind {
|
||||||
/// Pointer entered to the window.
|
/// Pointer enterd to the window.
|
||||||
Enter,
|
Enter,
|
||||||
/// Pointer leaved the window client area.
|
/// Pointer leaved the window client area.
|
||||||
Leave,
|
Leave,
|
||||||
|
|||||||
@@ -399,19 +399,19 @@ impl<T> BufferedEvent<T> {
|
|||||||
match self {
|
match self {
|
||||||
Self::Event(event) => dispatch(event),
|
Self::Event(event) => dispatch(event),
|
||||||
Self::ScaleFactorChanged(window_id, scale_factor, new_inner_size) => {
|
Self::ScaleFactorChanged(window_id, scale_factor, new_inner_size) => {
|
||||||
let user_new_inner_size = Arc::new(Mutex::new(new_inner_size));
|
let user_new_innner_size = Arc::new(Mutex::new(new_inner_size));
|
||||||
dispatch(Event::WindowEvent {
|
dispatch(Event::WindowEvent {
|
||||||
window_id,
|
window_id,
|
||||||
event: WindowEvent::ScaleFactorChanged {
|
event: WindowEvent::ScaleFactorChanged {
|
||||||
scale_factor,
|
scale_factor,
|
||||||
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(
|
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(
|
||||||
&user_new_inner_size,
|
&user_new_innner_size,
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
let inner_size = *user_new_inner_size.lock().unwrap();
|
let inner_size = *user_new_innner_size.lock().unwrap();
|
||||||
|
|
||||||
drop(user_new_inner_size);
|
drop(user_new_innner_size);
|
||||||
|
|
||||||
if inner_size != new_inner_size {
|
if inner_size != new_inner_size {
|
||||||
let window_flags = unsafe {
|
let window_flags = unsafe {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ use crate::{
|
|||||||
platform_impl::platform::{
|
platform_impl::platform::{
|
||||||
event_loop::ProcResult,
|
event_loop::ProcResult,
|
||||||
keyboard_layout::{Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE},
|
keyboard_layout::{Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE},
|
||||||
loword, primary_lang_id, KeyEventExtra,
|
loword, primarylangid, KeyEventExtra,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -106,13 +106,13 @@ impl KeyEventBuilder {
|
|||||||
let mut matcher = || -> MatchResult {
|
let mut matcher = || -> MatchResult {
|
||||||
match msg_kind {
|
match msg_kind {
|
||||||
WM_SETFOCUS => {
|
WM_SETFOCUS => {
|
||||||
// synthesize key down events
|
// synthesize keydown events
|
||||||
let kbd_state = get_async_kbd_state();
|
let kbd_state = get_async_kbd_state();
|
||||||
let key_events = Self::synthesize_kbd_state(ElementState::Pressed, &kbd_state);
|
let key_events = Self::synthesize_kbd_state(ElementState::Pressed, &kbd_state);
|
||||||
MatchResult::MessagesToDispatch(self.pending.complete_multi(key_events))
|
MatchResult::MessagesToDispatch(self.pending.complete_multi(key_events))
|
||||||
}
|
}
|
||||||
WM_KILLFOCUS => {
|
WM_KILLFOCUS => {
|
||||||
// synthesize keyup events
|
// sythesize keyup events
|
||||||
let kbd_state = get_kbd_state();
|
let kbd_state = get_kbd_state();
|
||||||
let key_events = Self::synthesize_kbd_state(ElementState::Released, &kbd_state);
|
let key_events = Self::synthesize_kbd_state(ElementState::Released, &kbd_state);
|
||||||
MatchResult::MessagesToDispatch(self.pending.complete_multi(key_events))
|
MatchResult::MessagesToDispatch(self.pending.complete_multi(key_events))
|
||||||
@@ -230,7 +230,7 @@ impl KeyEventBuilder {
|
|||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if more_char_coming {
|
if more_char_coming {
|
||||||
// No need to produce an event just yet, because there are still more characters that
|
// No need to produce an event just yet, because there are still more characters that
|
||||||
// need to appended to this keyboard event
|
// need to appended to this keyobard event
|
||||||
MatchResult::TokenToRemove(pending_token)
|
MatchResult::TokenToRemove(pending_token)
|
||||||
} else {
|
} else {
|
||||||
let mut event_info = self.event_info.lock().unwrap();
|
let mut event_info = self.event_info.lock().unwrap();
|
||||||
@@ -328,7 +328,7 @@ impl KeyEventBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allowing nonminimal_bool lint because the `is_key_pressed` macro triggers this warning
|
// Allowing nominimal_bool lint because the `is_key_pressed` macro triggers this warning
|
||||||
// and I don't know of another way to resolve it and also keeping the macro
|
// and I don't know of another way to resolve it and also keeping the macro
|
||||||
#[allow(clippy::nonminimal_bool)]
|
#[allow(clippy::nonminimal_bool)]
|
||||||
fn synthesize_kbd_state(
|
fn synthesize_kbd_state(
|
||||||
@@ -454,7 +454,7 @@ impl KeyEventBuilder {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let scancode = scancode as ExScancode;
|
let scancode = scancode as ExScancode;
|
||||||
let physical_key = scancode_to_physical_key(scancode as u32);
|
let physical_key = scancode_to_physicalkey(scancode as u32);
|
||||||
let mods = if caps_lock_on {
|
let mods = if caps_lock_on {
|
||||||
WindowsModifiers::CAPS_LOCK
|
WindowsModifiers::CAPS_LOCK
|
||||||
} else {
|
} else {
|
||||||
@@ -499,7 +499,7 @@ enum PartialText {
|
|||||||
|
|
||||||
enum PartialLogicalKey {
|
enum PartialLogicalKey {
|
||||||
/// Use the text provided by the WM_CHAR messages and report that as a `Character` variant. If
|
/// Use the text provided by the WM_CHAR messages and report that as a `Character` variant. If
|
||||||
/// the text consists of multiple grapheme clusters (user-perceived characters) that means that
|
/// the text consists of multiple grapheme clusters (user-precieved characters) that means that
|
||||||
/// dead key could not be combined with the second input, and in that case we should fall back
|
/// dead key could not be combined with the second input, and in that case we should fall back
|
||||||
/// to using what would have without a dead-key input.
|
/// to using what would have without a dead-key input.
|
||||||
TextOr(Key),
|
TextOr(Key),
|
||||||
@@ -544,7 +544,7 @@ impl PartialKeyEventInfo {
|
|||||||
} else {
|
} else {
|
||||||
new_ex_scancode(lparam_struct.scancode, lparam_struct.extended)
|
new_ex_scancode(lparam_struct.scancode, lparam_struct.extended)
|
||||||
};
|
};
|
||||||
let physical_key = scancode_to_physical_key(scancode as u32);
|
let physical_key = scancode_to_physicalkey(scancode as u32);
|
||||||
let location = get_location(scancode, layout.hkl as HKL);
|
let location = get_location(scancode, layout.hkl as HKL);
|
||||||
|
|
||||||
let kbd_state = get_kbd_state();
|
let kbd_state = get_kbd_state();
|
||||||
@@ -589,7 +589,7 @@ impl PartialKeyEventInfo {
|
|||||||
// We convert dead keys into their character.
|
// We convert dead keys into their character.
|
||||||
// The reason for this is that `key_without_modifiers` is designed for key-bindings,
|
// The reason for this is that `key_without_modifiers` is designed for key-bindings,
|
||||||
// but the US International layout treats `'` (apostrophe) as a dead key and the
|
// but the US International layout treats `'` (apostrophe) as a dead key and the
|
||||||
// regular US layout treats it a character. In order for a single binding
|
// reguar US layout treats it a character. In order for a single binding
|
||||||
// configuration to work with both layouts, we forward each dead key as a character.
|
// configuration to work with both layouts, we forward each dead key as a character.
|
||||||
Key::Dead(k) => {
|
Key::Dead(k) => {
|
||||||
if let Some(ch) = k {
|
if let Some(ch) = k {
|
||||||
@@ -741,15 +741,15 @@ fn get_async_kbd_state() -> [u8; 256] {
|
|||||||
/// every AltGr key-press (and key-release). We check if the current event is a Ctrl event and if
|
/// every AltGr key-press (and key-release). We check if the current event is a Ctrl event and if
|
||||||
/// the next event is a right Alt (AltGr) event. If this is the case, the current event must be the
|
/// the next event is a right Alt (AltGr) event. If this is the case, the current event must be the
|
||||||
/// fake Ctrl event.
|
/// fake Ctrl event.
|
||||||
fn is_current_fake(current_info: &PartialKeyEventInfo, next_msg: MSG, layout: &Layout) -> bool {
|
fn is_current_fake(curr_info: &PartialKeyEventInfo, next_msg: MSG, layout: &Layout) -> bool {
|
||||||
let current_is_ctrl = matches!(
|
let curr_is_ctrl = matches!(
|
||||||
current_info.logical_key,
|
curr_info.logical_key,
|
||||||
PartialLogicalKey::This(Key::Named(NamedKey::Control))
|
PartialLogicalKey::This(Key::Named(NamedKey::Control))
|
||||||
);
|
);
|
||||||
if layout.has_alt_graph {
|
if layout.has_alt_graph {
|
||||||
let next_code = ex_scancode_from_lparam(next_msg.lParam);
|
let next_code = ex_scancode_from_lparam(next_msg.lParam);
|
||||||
let next_is_altgr = next_code == 0xE038; // 0xE038 is right alt
|
let next_is_altgr = next_code == 0xE038; // 0xE038 is right alt
|
||||||
if current_is_ctrl && next_is_altgr {
|
if curr_is_ctrl && next_is_altgr {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -942,12 +942,12 @@ fn get_location(scancode: ExScancode, hkl: HKL) -> KeyLocation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn physical_key_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
|
pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
|
||||||
// See `scancode_to_physical_key` for more info
|
// See `scancode_to_physicalkey` for more info
|
||||||
|
|
||||||
let hkl = unsafe { GetKeyboardLayout(0) };
|
let hkl = unsafe { GetKeyboardLayout(0) };
|
||||||
|
|
||||||
let primary_lang_id = primary_lang_id(loword(hkl as u32));
|
let primary_lang_id = primarylangid(loword(hkl as u32));
|
||||||
let is_korean = primary_lang_id as u32 == LANG_KOREAN;
|
let is_korean = primary_lang_id as u32 == LANG_KOREAN;
|
||||||
|
|
||||||
let code = match physical_key {
|
let code = match physical_key {
|
||||||
@@ -1124,7 +1124,7 @@ pub(crate) fn physical_key_to_scancode(physical_key: PhysicalKey) -> Option<u32>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn scancode_to_physical_key(scancode: u32) -> PhysicalKey {
|
pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
|
||||||
// See: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
|
// See: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
|
||||||
// and: https://www.w3.org/TR/uievents-code/
|
// and: https://www.w3.org/TR/uievents-code/
|
||||||
// and: The widget/NativeKeyToDOMCodeName.h file in the firefox source
|
// and: The widget/NativeKeyToDOMCodeName.h file in the firefox source
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ use windows_sys::Win32::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey},
|
keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey},
|
||||||
platform_impl::{loword, primary_lang_id, scancode_to_physical_key},
|
platform_impl::{loword, primarylangid, scancode_to_physicalkey},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) static LAYOUT_CACHE: Lazy<Mutex<LayoutCache>> =
|
pub(crate) static LAYOUT_CACHE: Lazy<Mutex<LayoutCache>> =
|
||||||
@@ -121,12 +121,12 @@ impl WindowsModifiers {
|
|||||||
let rshift = key_state[VK_RSHIFT as usize] & 0x80 != 0;
|
let rshift = key_state[VK_RSHIFT as usize] & 0x80 != 0;
|
||||||
|
|
||||||
let control = key_state[VK_CONTROL as usize] & 0x80 != 0;
|
let control = key_state[VK_CONTROL as usize] & 0x80 != 0;
|
||||||
let l_control = key_state[VK_LCONTROL as usize] & 0x80 != 0;
|
let lcontrol = key_state[VK_LCONTROL as usize] & 0x80 != 0;
|
||||||
let r_control = key_state[VK_RCONTROL as usize] & 0x80 != 0;
|
let rcontrol = key_state[VK_RCONTROL as usize] & 0x80 != 0;
|
||||||
|
|
||||||
let alt = key_state[VK_MENU as usize] & 0x80 != 0;
|
let alt = key_state[VK_MENU as usize] & 0x80 != 0;
|
||||||
let l_alt = key_state[VK_LMENU as usize] & 0x80 != 0;
|
let lalt = key_state[VK_LMENU as usize] & 0x80 != 0;
|
||||||
let r_alt = key_state[VK_RMENU as usize] & 0x80 != 0;
|
let ralt = key_state[VK_RMENU as usize] & 0x80 != 0;
|
||||||
|
|
||||||
let caps = key_state[VK_CAPITAL as usize] & 0x01 != 0;
|
let caps = key_state[VK_CAPITAL as usize] & 0x01 != 0;
|
||||||
|
|
||||||
@@ -134,10 +134,10 @@ impl WindowsModifiers {
|
|||||||
if shift || lshift || rshift {
|
if shift || lshift || rshift {
|
||||||
result.insert(WindowsModifiers::SHIFT);
|
result.insert(WindowsModifiers::SHIFT);
|
||||||
}
|
}
|
||||||
if control || l_control || r_control {
|
if control || lcontrol || rcontrol {
|
||||||
result.insert(WindowsModifiers::CONTROL);
|
result.insert(WindowsModifiers::CONTROL);
|
||||||
}
|
}
|
||||||
if alt || l_alt || r_alt {
|
if alt || lalt || ralt {
|
||||||
result.insert(WindowsModifiers::ALT);
|
result.insert(WindowsModifiers::ALT);
|
||||||
}
|
}
|
||||||
if caps {
|
if caps {
|
||||||
@@ -335,7 +335,7 @@ impl LayoutCache {
|
|||||||
if scancode == 0 {
|
if scancode == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let keycode = match scancode_to_physical_key(scancode) {
|
let keycode = match scancode_to_physicalkey(scancode) {
|
||||||
PhysicalKey::Code(code) => code,
|
PhysicalKey::Code(code) => code,
|
||||||
// TODO: validate that we can skip on unidentified keys (probably never occurs?)
|
// TODO: validate that we can skip on unidentified keys (probably never occurs?)
|
||||||
_ => continue,
|
_ => continue,
|
||||||
@@ -387,7 +387,7 @@ impl LayoutCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let native_code = NativeKey::Windows(vk as VIRTUAL_KEY);
|
let native_code = NativeKey::Windows(vk as VIRTUAL_KEY);
|
||||||
let key_code = match scancode_to_physical_key(scancode) {
|
let key_code = match scancode_to_physicalkey(scancode) {
|
||||||
PhysicalKey::Code(code) => code,
|
PhysicalKey::Code(code) => code,
|
||||||
// TODO: validate that we can skip on unidentified keys (probably never occurs?)
|
// TODO: validate that we can skip on unidentified keys (probably never occurs?)
|
||||||
_ => continue,
|
_ => continue,
|
||||||
@@ -542,7 +542,7 @@ fn is_numpad_specific(vk: VIRTUAL_KEY) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn keycode_to_vkey(keycode: KeyCode, hkl: u64) -> VIRTUAL_KEY {
|
fn keycode_to_vkey(keycode: KeyCode, hkl: u64) -> VIRTUAL_KEY {
|
||||||
let primary_lang_id = primary_lang_id(loword(hkl as u32));
|
let primary_lang_id = primarylangid(loword(hkl as u32));
|
||||||
let is_korean = primary_lang_id as u32 == LANG_KOREAN;
|
let is_korean = primary_lang_id as u32 == LANG_KOREAN;
|
||||||
let is_japanese = primary_lang_id as u32 == LANG_JAPANESE;
|
let is_japanese = primary_lang_id as u32 == LANG_JAPANESE;
|
||||||
|
|
||||||
@@ -763,7 +763,7 @@ fn vkey_to_non_char_key(
|
|||||||
// List of the Web key names and their corresponding platform-native key names:
|
// List of the Web key names and their corresponding platform-native key names:
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
|
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
|
||||||
|
|
||||||
let primary_lang_id = primary_lang_id(loword(hkl as u32));
|
let primary_lang_id = primarylangid(loword(hkl as u32));
|
||||||
let is_korean = primary_lang_id as u32 == LANG_KOREAN;
|
let is_korean = primary_lang_id as u32 == LANG_KOREAN;
|
||||||
let is_japanese = primary_lang_id as u32 == LANG_JAPANESE;
|
let is_japanese = primary_lang_id as u32 == LANG_JAPANESE;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub(crate) use self::{
|
|||||||
PlatformSpecificEventLoopAttributes,
|
PlatformSpecificEventLoopAttributes,
|
||||||
},
|
},
|
||||||
icon::{SelectedCursor, WinIcon},
|
icon::{SelectedCursor, WinIcon},
|
||||||
keyboard::{physical_key_to_scancode, scancode_to_physical_key},
|
keyboard::{physicalkey_to_scancode, scancode_to_physicalkey},
|
||||||
monitor::{MonitorHandle, VideoModeHandle},
|
monitor::{MonitorHandle, VideoModeHandle},
|
||||||
window::Window,
|
window::Window,
|
||||||
};
|
};
|
||||||
@@ -148,7 +148,7 @@ const fn get_y_lparam(x: u32) -> i16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) const fn primary_lang_id(lgid: u16) -> u16 {
|
pub(crate) const fn primarylangid(lgid: u16) -> u16 {
|
||||||
lgid & 0x3FF
|
lgid & 0x3FF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,26 +163,24 @@ const fn hiword(x: u32) -> u16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn get_window_long(hwnd: HWND, n_index: WINDOW_LONG_PTR_INDEX) -> isize {
|
unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize {
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
return unsafe {
|
return unsafe { windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(hwnd, nindex) };
|
||||||
windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(hwnd, n_index)
|
|
||||||
};
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
return unsafe {
|
return unsafe {
|
||||||
windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongW(hwnd, n_index) as isize
|
windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongW(hwnd, nindex) as isize
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn set_window_long(hwnd: HWND, n_index: WINDOW_LONG_PTR_INDEX, new_long: isize) -> isize {
|
unsafe fn set_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX, dwnewlong: isize) -> isize {
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
return unsafe {
|
return unsafe {
|
||||||
windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW(hwnd, n_index, new_long)
|
windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW(hwnd, nindex, dwnewlong)
|
||||||
};
|
};
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
return unsafe {
|
return unsafe {
|
||||||
windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongW(hwnd, n_index, new_long as i32)
|
windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongW(hwnd, nindex, dwnewlong as i32)
|
||||||
as isize
|
as isize
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use windows_sys::Win32::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::scancode_to_physical_key;
|
use super::scancode_to_physicalkey;
|
||||||
use crate::{
|
use crate::{
|
||||||
event::ElementState,
|
event::ElementState,
|
||||||
event_loop::DeviceEvents,
|
event_loop::DeviceEvents,
|
||||||
@@ -152,7 +152,7 @@ pub fn register_all_mice_and_keyboards_for_raw_input(
|
|||||||
mut window_handle: HWND,
|
mut window_handle: HWND,
|
||||||
filter: DeviceEvents,
|
filter: DeviceEvents,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// RIDEV_DEVNOTIFY: receive hot-plug events
|
// RIDEV_DEVNOTIFY: receive hotplug events
|
||||||
// RIDEV_INPUTSINK: receive events even if we're not in the foreground
|
// RIDEV_INPUTSINK: receive events even if we're not in the foreground
|
||||||
// RIDEV_REMOVE: don't receive device events (requires NULL hwndTarget)
|
// RIDEV_REMOVE: don't receive device events (requires NULL hwndTarget)
|
||||||
let flags = match filter {
|
let flags = match filter {
|
||||||
@@ -249,16 +249,16 @@ pub fn get_keyboard_physical_key(keyboard: RAWKEYBOARD) -> Option<PhysicalKey> {
|
|||||||
if scancode == 0xE11D || scancode == 0xE02A {
|
if scancode == 0xE11D || scancode == 0xE02A {
|
||||||
// At the hardware (or driver?) level, pressing the Pause key is equivalent to pressing
|
// At the hardware (or driver?) level, pressing the Pause key is equivalent to pressing
|
||||||
// Ctrl+NumLock.
|
// Ctrl+NumLock.
|
||||||
// This equivalence means that if the user presses Pause, the keyboard will emit two
|
// This equvalence means that if the user presses Pause, the keyboard will emit two
|
||||||
// subsequent key presses:
|
// subsequent keypresses:
|
||||||
// 1, 0xE11D - Which is a left Ctrl (0x1D) with an extension flag (0xE100)
|
// 1, 0xE11D - Which is a left Ctrl (0x1D) with an extension flag (0xE100)
|
||||||
// 2, 0x0045 - Which on its own can be interpreted as Pause
|
// 2, 0x0045 - Which on its own can be interpreted as Pause
|
||||||
//
|
//
|
||||||
// There's another combination which isn't quite an equivalence:
|
// There's another combination which isn't quite an equivalence:
|
||||||
// PrtSc used to be Shift+Asterisk. This means that on some keyboards, pressing
|
// PrtSc used to be Shift+Asterisk. This means that on some keyboards, presssing
|
||||||
// PrtSc (print screen) produces the following sequence:
|
// PrtSc (print screen) produces the following sequence:
|
||||||
// 1, 0xE02A - Which is a left shift (0x2A) with an extension flag (0xE000)
|
// 1, 0xE02A - Which is a left shift (0x2A) with an extension flag (0xE000)
|
||||||
// 2, 0xE037 - Which is a numpad multiply (0x37) with an extension flag (0xE000). This on
|
// 2, 0xE037 - Which is a numpad multiply (0x37) with an exteion flag (0xE000). This on
|
||||||
// its own it can be interpreted as PrtSc
|
// its own it can be interpreted as PrtSc
|
||||||
//
|
//
|
||||||
// For this reason, if we encounter the first keypress, we simply ignore it, trusting
|
// For this reason, if we encounter the first keypress, we simply ignore it, trusting
|
||||||
@@ -284,7 +284,7 @@ pub fn get_keyboard_physical_key(keyboard: RAWKEYBOARD) -> Option<PhysicalKey> {
|
|||||||
// https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503
|
// https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503
|
||||||
PhysicalKey::Code(KeyCode::NumLock)
|
PhysicalKey::Code(KeyCode::NumLock)
|
||||||
} else {
|
} else {
|
||||||
scancode_to_physical_key(scancode as u32)
|
scancode_to_physicalkey(scancode as u32)
|
||||||
};
|
};
|
||||||
if keyboard.VKey == VK_SHIFT {
|
if keyboard.VKey == VK_SHIFT {
|
||||||
if let PhysicalKey::Code(code) = physical_key {
|
if let PhysicalKey::Code(code) = physical_key {
|
||||||
|
|||||||
@@ -1406,7 +1406,7 @@ unsafe fn init(
|
|||||||
let menu = attributes.platform_specific.menu;
|
let menu = attributes.platform_specific.menu;
|
||||||
let fullscreen = attributes.fullscreen.clone();
|
let fullscreen = attributes.fullscreen.clone();
|
||||||
let maximized = attributes.maximized;
|
let maximized = attributes.maximized;
|
||||||
let mut init_data = InitData {
|
let mut initdata = InitData {
|
||||||
event_loop,
|
event_loop,
|
||||||
attributes,
|
attributes,
|
||||||
window_flags,
|
window_flags,
|
||||||
@@ -1427,7 +1427,7 @@ unsafe fn init(
|
|||||||
parent.unwrap_or(0),
|
parent.unwrap_or(0),
|
||||||
menu.unwrap_or(0),
|
menu.unwrap_or(0),
|
||||||
util::get_instance_handle(),
|
util::get_instance_handle(),
|
||||||
&mut init_data as *mut _ as *mut _,
|
&mut initdata as *mut _ as *mut _,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1442,7 +1442,7 @@ unsafe fn init(
|
|||||||
|
|
||||||
// If the handle is non-null, then window creation must have succeeded, which means
|
// If the handle is non-null, then window creation must have succeeded, which means
|
||||||
// that we *must* have populated the `InitData.window` field.
|
// that we *must* have populated the `InitData.window` field.
|
||||||
let win = init_data.window.unwrap();
|
let win = initdata.window.unwrap();
|
||||||
|
|
||||||
// Need to set FULLSCREEN or MAXIMIZED after CreateWindowEx
|
// Need to set FULLSCREEN or MAXIMIZED after CreateWindowEx
|
||||||
// This is because if the size is changed in WM_CREATE, the restored size will be stored in that size.
|
// This is because if the size is changed in WM_CREATE, the restored size will be stored in that size.
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ impl WindowFlags {
|
|||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
// This condition is necessary to avoid having an un-restorable window
|
// This condition is necessary to avoid having an unrestorable window
|
||||||
if !new.contains(WindowFlags::MINIMIZED) {
|
if !new.contains(WindowFlags::MINIMIZED) {
|
||||||
SetWindowLongW(window, GWL_STYLE, style as i32);
|
SetWindowLongW(window, GWL_STYLE, style as i32);
|
||||||
SetWindowLongW(window, GWL_EXSTYLE, style_ex as i32);
|
SetWindowLongW(window, GWL_EXSTYLE, style_ex as i32);
|
||||||
@@ -450,7 +450,7 @@ impl WindowFlags {
|
|||||||
let mut style = GetWindowLongW(hwnd, GWL_STYLE) as u32;
|
let mut style = GetWindowLongW(hwnd, GWL_STYLE) as u32;
|
||||||
let style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE) as u32;
|
let style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE) as u32;
|
||||||
|
|
||||||
// Frame-less style implemented by manually overriding the non-client area in `WM_NCCALCSIZE`.
|
// Frameless style implemented by manually overriding the non-client area in `WM_NCCALCSIZE`.
|
||||||
if !self.contains(WindowFlags::MARKER_DECORATIONS) {
|
if !self.contains(WindowFlags::MARKER_DECORATIONS) {
|
||||||
style &= !(WS_CAPTION | WS_SIZEBOX);
|
style &= !(WS_CAPTION | WS_SIZEBOX);
|
||||||
}
|
}
|
||||||
@@ -525,7 +525,7 @@ impl CursorFlags {
|
|||||||
|
|
||||||
// We do this check because calling `set_cursor_clip` incessantly will flood the event
|
// We do this check because calling `set_cursor_clip` incessantly will flood the event
|
||||||
// loop with `WM_MOUSEMOVE` events, and `refresh_os_cursor` is called by `set_cursor_flags`
|
// loop with `WM_MOUSEMOVE` events, and `refresh_os_cursor` is called by `set_cursor_flags`
|
||||||
// which at times gets called once every iteration of the event loop.
|
// which at times gets called once every iteration of the eventloop.
|
||||||
if active_cursor_clip != cursor_clip.map(rect_to_tuple) {
|
if active_cursor_clip != cursor_clip.map(rect_to_tuple) {
|
||||||
util::set_cursor_clip(cursor_clip)?;
|
util::set_cursor_clip(cursor_clip)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// A poly-fill for `lazy_cell`
|
// A poly-fill for `lazy_cell`
|
||||||
// Replace with std::sync::LazyLock when https://github.com/rust-lang/rust/issues/109736 is stabilized.
|
// Replace with std::sync::LazyLock when https://github.com/rust-lang/rust/issues/109736 is stablized.
|
||||||
|
|
||||||
// This isn't used on every platform, which can come up as dead code warnings.
|
// This isn't used on every platform, which can come up as dead code warnings.
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -70,8 +39,8 @@ pub struct Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Window {
|
impl fmt::Debug for Window {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
formatter.pad("Window { .. }")
|
fmtr.pad("Window { .. }")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1026,7 +995,7 @@ impl Window {
|
|||||||
|
|
||||||
/// Sets whether the window is resizable or not.
|
/// Sets whether the window is resizable or not.
|
||||||
///
|
///
|
||||||
/// Note that making the window un-resizable doesn't exempt you from handling [`WindowEvent::Resized`], as that
|
/// Note that making the window unresizable doesn't exempt you from handling [`WindowEvent::Resized`], as that
|
||||||
/// event can still be triggered by DPI scaling, entering fullscreen mode, etc. Also, the
|
/// event can still be triggered by DPI scaling, entering fullscreen mode, etc. Also, the
|
||||||
/// window could still be resized by calling [`Window::request_inner_size`].
|
/// window could still be resized by calling [`Window::request_inner_size`].
|
||||||
///
|
///
|
||||||
@@ -1235,7 +1204,7 @@ impl Window {
|
|||||||
/// Sets the window icon.
|
/// Sets the window icon.
|
||||||
///
|
///
|
||||||
/// On Windows and X11, this is typically the small icon in the top-left
|
/// On Windows and X11, this is typically the small icon in the top-left
|
||||||
/// corner of the title bar.
|
/// corner of the titlebar.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
@@ -1375,7 +1344,7 @@ impl Window {
|
|||||||
/// is already focused. How requesting for user attention manifests is platform dependent,
|
/// is already focused. How requesting for user attention manifests is platform dependent,
|
||||||
/// see [`UserAttentionType`] for details.
|
/// see [`UserAttentionType`] for details.
|
||||||
///
|
///
|
||||||
/// Providing `None` will unset the request for user attention. Un-setting the request for
|
/// Providing `None` will unset the request for user attention. Unsetting the request for
|
||||||
/// user attention might not be done automatically by the WM when the window receives input.
|
/// user attention might not be done automatically by the WM when the window receives input.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
|
|||||||
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