mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-27 07:03:15 -04:00
Compare commits
33 Commits
v0.20.0-al
...
v0.20.0-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce5cf97e17 | ||
|
|
3ee59696e5 | ||
|
|
f5c624bcd6 | ||
|
|
c1f314ccdc | ||
|
|
53a89f28a0 | ||
|
|
f874d76289 | ||
|
|
28775be115 | ||
|
|
7d3ff3d2d9 | ||
|
|
4a5d639d74 | ||
|
|
74a7cf55ea | ||
|
|
9393b14b01 | ||
|
|
f8bd671073 | ||
|
|
2af753f307 | ||
|
|
5bf303fd26 | ||
|
|
e37e46b155 | ||
|
|
b8192ef6f6 | ||
|
|
23354cf1a5 | ||
|
|
dd38fab2f3 | ||
|
|
ac08601b40 | ||
|
|
34db2d7d4c | ||
|
|
0e20973bdb | ||
|
|
29e2481597 | ||
|
|
3555de114a | ||
|
|
dbe6a1bcdf | ||
|
|
a195ce8146 | ||
|
|
9dd15d00d8 | ||
|
|
2442305bb7 | ||
|
|
063648368d | ||
|
|
918b2efce7 | ||
|
|
2467a997f4 | ||
|
|
f457c6a0b8 | ||
|
|
1193cada46 | ||
|
|
b0e09b8ffe |
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -2,5 +2,5 @@
|
||||
- [ ] `cargo fmt` has been run on this branch
|
||||
- [ ] Added an entry to `CHANGELOG.md` if knowledge of this change could be valuable to users
|
||||
- [ ] Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
|
||||
- [ ] Created an example program if it would help users understand this functionality
|
||||
- [ ] Updated [feature matrix](https://github.com/tomaka/winit/blob/master/FEATURES.md), if new features were added or implemented
|
||||
- [ ] Created or updated an example program if it would help users understand this functionality
|
||||
- [ ] Updated [feature matrix](https://github.com/rust-windowing/winit/blob/master/FEATURES.md), if new features were added or implemented
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "deps/apk-builder"]
|
||||
path = deps/apk-builder
|
||||
url = https://github.com/tomaka/android-rs-glue
|
||||
url = https://github.com/rust-windowing/android-rs-glue
|
||||
|
||||
@@ -45,11 +45,10 @@ matrix:
|
||||
install:
|
||||
- rustup self update
|
||||
- rustup target add $TARGET; true
|
||||
- rustup install nightly
|
||||
- rustup component add rustfmt --toolchain nightly
|
||||
- rustup component add rustfmt
|
||||
|
||||
script:
|
||||
- cargo +nightly fmt --all -- --check
|
||||
- cargo fmt --all -- --check
|
||||
- cargo build --target $TARGET --verbose
|
||||
- cargo build --target $TARGET --features serde --verbose
|
||||
# Running iOS apps on OSX requires the simulator so we skip that for now
|
||||
|
||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,6 +1,25 @@
|
||||
# Unreleased
|
||||
|
||||
# 0.20.0 Alpha 1
|
||||
# 0.20.0 Alpha 2 (2019-06-28)
|
||||
|
||||
- On X11, non-resizable windows now have maximize explicitly disabled.
|
||||
- On Windows, support paths longer than MAX_PATH (260 characters) in `WindowEvent::DroppedFile`
|
||||
and `WindowEvent::HoveredFile`.
|
||||
- On Mac, implement `DeviceEvent::Button`.
|
||||
- Change `Event::Suspended(true / false)` to `Event::Suspended` and `Event::Resumed`.
|
||||
- On X11, fix sanity check which checks that a monitor's reported width and height (in millimeters) are non-zero when calculating the DPI factor.
|
||||
- Revert the use of invisible surfaces in Wayland, which introduced graphical glitches with OpenGL (#835)
|
||||
- On X11, implement `_NET_WM_PING` to allow desktop environment to kill unresponsive programs.
|
||||
- On Windows, when a window is initially invisible, it won't take focus from the existing visible windows.
|
||||
- On Windows, fix multiple calls to `request_redraw` during `EventsCleared` sending multiple `RedrawRequested events.`
|
||||
- On Windows, fix edge case where `RedrawRequested` could be dispatched before input events in event loop iteration.
|
||||
- On Windows, fix timing issue that could cause events to be improperly dispatched after `RedrawRequested` but before `EventsCleared`.
|
||||
- On macOS, drop unused Metal dependency.
|
||||
- On Windows, fix the trail effect happening on transparent decorated windows. Borderless (or un-decorated) windows were not affected.
|
||||
- On Windows, fix `with_maximized` not properly setting window size to entire window.
|
||||
- On macOS, change `WindowExtMacOS::request_user_attention()` to take an `enum` instead of a `bool`.
|
||||
|
||||
# 0.20.0 Alpha 1 (2019-06-21)
|
||||
|
||||
- Changes below are considered **breaking**.
|
||||
- Change all occurrences of `EventsLoop` to `EventLoop`.
|
||||
@@ -53,6 +72,9 @@
|
||||
- On Windows, fix `CursorMoved(0, 0)` getting dispatched on window focus.
|
||||
- On macOS, fix command key event left and right reverse.
|
||||
- On FreeBSD, NetBSD, and OpenBSD, fix build of X11 backend.
|
||||
- On Linux, the numpad's add, subtract and divide keys are now mapped to the `Add`, `Subtract` and `Divide` virtual key codes
|
||||
- On macOS, the numpad's subtract key has been added to the `Subtract` mapping
|
||||
- On Wayland, the numpad's home, end, page up and page down keys are now mapped to the `Home`, `End`, `PageUp` and `PageDown` virtual key codes
|
||||
- On Windows, fix icon not showing up in corner of window.
|
||||
- On X11, change DPI scaling factor behavior. First, winit tries to read it from "Xft.dpi" XResource, and uses DPI calculation from xrandr dimensions as fallback behavior.
|
||||
|
||||
@@ -71,9 +93,6 @@
|
||||
- On Windows, cursor grabs used to get perpetually canceled when the grabbing window lost focus. Now, cursor grabs automatically get re-initialized when the window regains focus and the mouse moves over the client area.
|
||||
- On Windows, only vertical mouse wheel events were handled. Now, horizontal mouse wheel events are also handled.
|
||||
- On Windows, ignore the AltGr key when populating the `ModifersState` type.
|
||||
- On Linux, the numpad's add, subtract and divide keys are now mapped to the `Add`, `Subtract` and `Divide` virtual key codes
|
||||
- On macOS, the numpad's subtract key has been added to the `Subtract` mapping
|
||||
- On Wayland, the numpad's home, end, page up and page down keys are now mapped to the `Home`, `End`, `PageUp` and `PageDown` virtual key codes
|
||||
|
||||
# Version 0.18.1 (2018-12-30)
|
||||
|
||||
|
||||
12
Cargo.toml
12
Cargo.toml
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "winit"
|
||||
version = "0.20.0-alpha1"
|
||||
version = "0.20.0-alpha2"
|
||||
authors = ["The winit contributors", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
||||
description = "Cross-platform window creation library."
|
||||
edition = "2018"
|
||||
keywords = ["windowing"]
|
||||
license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/tomaka/winit"
|
||||
repository = "https://github.com/rust-windowing/winit"
|
||||
documentation = "https://docs.rs/winit"
|
||||
categories = ["gui"]
|
||||
|
||||
@@ -35,10 +35,14 @@ objc = "0.2.3"
|
||||
cocoa = "0.18.4"
|
||||
core-foundation = "0.6"
|
||||
core-graphics = "0.17.3"
|
||||
core-video-sys = "0.1.2"
|
||||
dispatch = "0.1.4"
|
||||
objc = "0.2.3"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies.core-video-sys]
|
||||
version = "0.1.3"
|
||||
default_features = false
|
||||
features = ["display_link"]
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
bitflags = "1"
|
||||
|
||||
@@ -69,7 +73,7 @@ features = [
|
||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
|
||||
wayland-client = { version = "0.23.0", features = [ "dlopen", "egl", "cursor", "eventloop"] }
|
||||
calloop = "0.4.2"
|
||||
smithay-client-toolkit = "0.6.1"
|
||||
smithay-client-toolkit = "0.6"
|
||||
x11-dl = "2.18.3"
|
||||
percent-encoding = "1.0"
|
||||
|
||||
|
||||
30
FEATURES.md
30
FEATURES.md
@@ -194,18 +194,18 @@ Changes in the API that have been agreed upon but aren't implemented across all
|
||||
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |Emscripten|
|
||||
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||
|
||||
[#165]: https://github.com/tomaka/winit/issues/165
|
||||
[#219]: https://github.com/tomaka/winit/issues/219
|
||||
[#242]: https://github.com/tomaka/winit/issues/242
|
||||
[#306]: https://github.com/tomaka/winit/issues/306
|
||||
[#315]: https://github.com/tomaka/winit/issues/315
|
||||
[#319]: https://github.com/tomaka/winit/issues/319
|
||||
[#33]: https://github.com/tomaka/winit/issues/33
|
||||
[#459]: https://github.com/tomaka/winit/issues/459
|
||||
[#5]: https://github.com/tomaka/winit/issues/5
|
||||
[#63]: https://github.com/tomaka/winit/issues/63
|
||||
[#720]: https://github.com/tomaka/winit/issues/720
|
||||
[#721]: https://github.com/tomaka/winit/issues/721
|
||||
[#750]: https://github.com/tomaka/winit/issues/750
|
||||
[#804]: https://github.com/tomaka/winit/issues/804
|
||||
[#812]: https://github.com/tomaka/winit/issues/812
|
||||
[#165]: https://github.com/rust-windowing/winit/issues/165
|
||||
[#219]: https://github.com/rust-windowing/winit/issues/219
|
||||
[#242]: https://github.com/rust-windowing/winit/issues/242
|
||||
[#306]: https://github.com/rust-windowing/winit/issues/306
|
||||
[#315]: https://github.com/rust-windowing/winit/issues/315
|
||||
[#319]: https://github.com/rust-windowing/winit/issues/319
|
||||
[#33]: https://github.com/rust-windowing/winit/issues/33
|
||||
[#459]: https://github.com/rust-windowing/winit/issues/459
|
||||
[#5]: https://github.com/rust-windowing/winit/issues/5
|
||||
[#63]: https://github.com/rust-windowing/winit/issues/63
|
||||
[#720]: https://github.com/rust-windowing/winit/issues/720
|
||||
[#721]: https://github.com/rust-windowing/winit/issues/721
|
||||
[#750]: https://github.com/rust-windowing/winit/issues/750
|
||||
[#804]: https://github.com/rust-windowing/winit/issues/804
|
||||
[#812]: https://github.com/rust-windowing/winit/issues/812
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
# winit - Cross-platform window creation and management in Rust
|
||||
|
||||
[](https://crates.io/crates/winit)
|
||||
[](https://crates.io/crates/winit)
|
||||
[](https://docs.rs/winit)
|
||||
[](https://travis-ci.org/rust-windowing/winit)
|
||||
[](https://ci.appveyor.com/project/Osspial/winit/branch/master)
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
winit = "0.20.0-alpha1"
|
||||
winit = "0.20.0-alpha2"
|
||||
```
|
||||
|
||||
## [Documentation](https://docs.rs/winit)
|
||||
|
||||
For features _within_ the scope of winit, see [FEATURES.md](FEATURES.md).
|
||||
|
||||
For features _outside_ the scope of winit, see [Missing features provided by other crates](https://github.com/rust-windowing/winit/wiki/Missing-features-provided-by-other-crates) in the wiki.
|
||||
|
||||
## Contact Us
|
||||
|
||||
Join us in any of these:
|
||||
|
||||
@@ -12,37 +12,35 @@ fn main() {
|
||||
|
||||
let mut cursor_idx = 0;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
event:
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
state: ElementState::Pressed,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
|
||||
window.set_cursor_icon(CURSORS[cursor_idx]);
|
||||
if cursor_idx < CURSORS.len() - 1 {
|
||||
cursor_idx += 1;
|
||||
} else {
|
||||
cursor_idx = 0;
|
||||
}
|
||||
},
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
},
|
||||
_ => (),
|
||||
event_loop.run(move |event, _, control_flow| match event {
|
||||
Event::WindowEvent {
|
||||
event:
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
state: ElementState::Pressed,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
|
||||
window.set_cursor_icon(CURSORS[cursor_idx]);
|
||||
if cursor_idx < CURSORS.len() - 1 {
|
||||
cursor_idx += 1;
|
||||
} else {
|
||||
cursor_idx = 0;
|
||||
}
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
}
|
||||
_ => (),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use winit::{
|
||||
event::{ElementState, Event, KeyboardInput, WindowEvent},
|
||||
event::{DeviceEvent, ElementState, Event, KeyboardInput, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::WindowBuilder,
|
||||
};
|
||||
@@ -14,8 +14,8 @@ fn main() {
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
if let Event::WindowEvent { event, .. } = event {
|
||||
match event {
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
@@ -34,9 +34,18 @@ fn main() {
|
||||
H => window.set_cursor_visible(modifiers.shift),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
Event::DeviceEvent { event, .. } => match event {
|
||||
DeviceEvent::MouseMotion { delta } => println!("mouse moved: {:?}", delta),
|
||||
DeviceEvent::Button { button, state } => match state {
|
||||
ElementState::Pressed => println!("mouse button {} pressed", button),
|
||||
ElementState::Released => println!("mouse button {} released", button),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ fn main() {
|
||||
let num = num.trim().parse().ok().expect("Please enter a number");
|
||||
match num {
|
||||
2 => macos_use_simple_fullscreen = true,
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Prompt for monitor when using native fullscreen
|
||||
@@ -54,69 +54,62 @@ fn main() {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(virtual_code),
|
||||
state,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
match (virtual_code, state) {
|
||||
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
|
||||
(VirtualKeyCode::F, ElementState::Pressed) => {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if macos_use_simple_fullscreen {
|
||||
use winit::platform::macos::WindowExtMacOS;
|
||||
if WindowExtMacOS::set_simple_fullscreen(
|
||||
&window,
|
||||
!is_fullscreen,
|
||||
) {
|
||||
is_fullscreen = !is_fullscreen;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(virtual_code),
|
||||
state,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => match (virtual_code, state) {
|
||||
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
|
||||
(VirtualKeyCode::F, ElementState::Pressed) => {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if macos_use_simple_fullscreen {
|
||||
use winit::platform::macos::WindowExtMacOS;
|
||||
if WindowExtMacOS::set_simple_fullscreen(&window, !is_fullscreen) {
|
||||
is_fullscreen = !is_fullscreen;
|
||||
}
|
||||
|
||||
is_fullscreen = !is_fullscreen;
|
||||
if !is_fullscreen {
|
||||
window.set_fullscreen(None);
|
||||
} else {
|
||||
window.set_fullscreen(Some(window.current_monitor()));
|
||||
}
|
||||
},
|
||||
(VirtualKeyCode::S, ElementState::Pressed) => {
|
||||
println!("window.fullscreen {:?}", window.fullscreen());
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use winit::platform::macos::WindowExtMacOS;
|
||||
println!(
|
||||
"window.simple_fullscreen {:?}",
|
||||
WindowExtMacOS::simple_fullscreen(&window)
|
||||
);
|
||||
}
|
||||
},
|
||||
(VirtualKeyCode::M, ElementState::Pressed) => {
|
||||
is_maximized = !is_maximized;
|
||||
window.set_maximized(is_maximized);
|
||||
},
|
||||
(VirtualKeyCode::D, ElementState::Pressed) => {
|
||||
decorations = !decorations;
|
||||
window.set_decorations(decorations);
|
||||
},
|
||||
_ => (),
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
is_fullscreen = !is_fullscreen;
|
||||
if !is_fullscreen {
|
||||
window.set_fullscreen(None);
|
||||
} else {
|
||||
window.set_fullscreen(Some(window.current_monitor()));
|
||||
}
|
||||
}
|
||||
(VirtualKeyCode::S, ElementState::Pressed) => {
|
||||
println!("window.fullscreen {:?}", window.fullscreen());
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use winit::platform::macos::WindowExtMacOS;
|
||||
println!(
|
||||
"window.simple_fullscreen {:?}",
|
||||
WindowExtMacOS::simple_fullscreen(&window)
|
||||
);
|
||||
}
|
||||
}
|
||||
(VirtualKeyCode::M, ElementState::Pressed) => {
|
||||
is_maximized = !is_maximized;
|
||||
window.set_maximized(is_maximized);
|
||||
}
|
||||
(VirtualKeyCode::D, ElementState::Pressed) => {
|
||||
decorations = !decorations;
|
||||
window.set_decorations(decorations);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
},
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ fn main() {
|
||||
// action from the user, this is generally where you'd handle cleanup before
|
||||
// closing the window. How to close the window is detailed in the handler for
|
||||
// the Y key.
|
||||
},
|
||||
}
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
@@ -63,19 +63,19 @@ fn main() {
|
||||
// sent.
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
},
|
||||
}
|
||||
N => {
|
||||
if close_requested {
|
||||
println!("Your window will continue to stay by your side.");
|
||||
close_requested = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
|
||||
@@ -39,19 +39,15 @@ fn main() {
|
||||
use self::VirtualKeyCode::*;
|
||||
match key {
|
||||
A => window.set_always_on_top(state),
|
||||
C => {
|
||||
window.set_cursor_icon(match state {
|
||||
true => CursorIcon::Progress,
|
||||
false => CursorIcon::Default,
|
||||
})
|
||||
},
|
||||
C => window.set_cursor_icon(match state {
|
||||
true => CursorIcon::Progress,
|
||||
false => CursorIcon::Default,
|
||||
}),
|
||||
D => window.set_decorations(!state),
|
||||
F => {
|
||||
window.set_fullscreen(match state {
|
||||
true => Some(window.current_monitor()),
|
||||
false => None,
|
||||
})
|
||||
},
|
||||
F => window.set_fullscreen(match state {
|
||||
true => Some(window.current_monitor()),
|
||||
false => None,
|
||||
}),
|
||||
G => window.set_cursor_grab(state).unwrap(),
|
||||
H => window.set_cursor_visible(!state),
|
||||
I => {
|
||||
@@ -60,49 +56,41 @@ fn main() {
|
||||
println!("-> inner_position : {:?}", window.inner_position());
|
||||
println!("-> outer_size : {:?}", window.outer_size());
|
||||
println!("-> inner_size : {:?}", window.inner_size());
|
||||
},
|
||||
L => {
|
||||
window.set_min_inner_size(match state {
|
||||
true => Some(WINDOW_SIZE.into()),
|
||||
false => None,
|
||||
})
|
||||
},
|
||||
}
|
||||
L => window.set_min_inner_size(match state {
|
||||
true => Some(WINDOW_SIZE.into()),
|
||||
false => None,
|
||||
}),
|
||||
M => window.set_maximized(state),
|
||||
P => {
|
||||
window.set_outer_position({
|
||||
let mut position = window.outer_position().unwrap();
|
||||
let sign = if state { 1.0 } else { -1.0 };
|
||||
position.x += 10.0 * sign;
|
||||
position.y += 10.0 * sign;
|
||||
position
|
||||
})
|
||||
},
|
||||
P => window.set_outer_position({
|
||||
let mut position = window.outer_position().unwrap();
|
||||
let sign = if state { 1.0 } else { -1.0 };
|
||||
position.x += 10.0 * sign;
|
||||
position.y += 10.0 * sign;
|
||||
position
|
||||
}),
|
||||
Q => window.request_redraw(),
|
||||
R => window.set_resizable(state),
|
||||
S => {
|
||||
window.set_inner_size(
|
||||
match state {
|
||||
true => (WINDOW_SIZE.0 + 100, WINDOW_SIZE.1 + 100),
|
||||
false => WINDOW_SIZE,
|
||||
}
|
||||
.into(),
|
||||
S => window.set_inner_size(
|
||||
match state {
|
||||
true => (WINDOW_SIZE.0 + 100, WINDOW_SIZE.1 + 100),
|
||||
false => WINDOW_SIZE,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
W => window
|
||||
.set_cursor_position(
|
||||
(WINDOW_SIZE.0 as i32 / 2, WINDOW_SIZE.1 as i32 / 2).into(),
|
||||
)
|
||||
},
|
||||
W => {
|
||||
window
|
||||
.set_cursor_position(
|
||||
(WINDOW_SIZE.0 as i32 / 2, WINDOW_SIZE.1 as i32 / 2).into(),
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
.unwrap(),
|
||||
Z => {
|
||||
window.set_visible(false);
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
window.set_visible(true);
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -114,25 +102,23 @@ fn main() {
|
||||
false => ControlFlow::Exit,
|
||||
};
|
||||
match event {
|
||||
Event::WindowEvent { event, window_id } => {
|
||||
match event {
|
||||
WindowEvent::CloseRequested
|
||||
| WindowEvent::Destroyed
|
||||
| WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
window_senders.remove(&window_id);
|
||||
},
|
||||
_ => {
|
||||
if let Some(tx) = window_senders.get(&window_id) {
|
||||
tx.send(event).unwrap();
|
||||
}
|
||||
},
|
||||
Event::WindowEvent { event, window_id } => match event {
|
||||
WindowEvent::CloseRequested
|
||||
| WindowEvent::Destroyed
|
||||
| WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
window_senders.remove(&window_id);
|
||||
}
|
||||
_ => {
|
||||
if let Some(tx) = window_senders.get(&window_id) {
|
||||
tx.send(event).unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
|
||||
@@ -28,7 +28,7 @@ fn main() {
|
||||
if windows.is_empty() {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
},
|
||||
}
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
@@ -39,10 +39,10 @@ fn main() {
|
||||
} => {
|
||||
let window = Window::new(&event_loop).unwrap();
|
||||
windows.insert(window.id(), window);
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -14,19 +14,21 @@ fn main() {
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
println!("{:?}", event);
|
||||
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
Event::EventsCleared => {
|
||||
window.request_redraw();
|
||||
*control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0))
|
||||
},
|
||||
_ => (),
|
||||
event_loop.run(move |event, _, control_flow| match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
Event::EventsCleared => {
|
||||
window.request_redraw();
|
||||
*control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0))
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::RedrawRequested,
|
||||
..
|
||||
} => {
|
||||
println!("{:?}", event);
|
||||
}
|
||||
_ => (),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,24 +19,22 @@ fn main() {
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(VirtualKeyCode::Space),
|
||||
state: ElementState::Released,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
resizable = !resizable;
|
||||
println!("Resizable: {}", resizable);
|
||||
window.set_resizable(resizable);
|
||||
},
|
||||
_ => (),
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(VirtualKeyCode::Space),
|
||||
state: ElementState::Released,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
resizable = !resizable;
|
||||
println!("Resizable: {}", resizable);
|
||||
window.set_resizable(resizable);
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
};
|
||||
|
||||
@@ -21,11 +21,11 @@ fn main() {
|
||||
match event {
|
||||
Event::NewEvents(StartCause::Init) => {
|
||||
*control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length)
|
||||
},
|
||||
}
|
||||
Event::NewEvents(StartCause::ResumeTimeReached { .. }) => {
|
||||
*control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length);
|
||||
println!("\nTimer\n");
|
||||
},
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
|
||||
@@ -13,17 +13,7 @@ fn main() {
|
||||
// you'll be bitten by the low-quality downscaling built into the WM.
|
||||
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png");
|
||||
|
||||
let (icon_rgba, icon_width, icon_height) = {
|
||||
let image = image::open(path).expect("Failed to open icon path");
|
||||
use image::{GenericImageView, Pixel};
|
||||
let (width, height) = image.dimensions();
|
||||
let mut rgba = Vec::with_capacity((width * height) as usize * 4);
|
||||
for (_, _, pixel) in image.pixels() {
|
||||
rgba.extend_from_slice(&pixel.to_rgba().data);
|
||||
}
|
||||
(rgba, width, height)
|
||||
};
|
||||
let icon = Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon");
|
||||
let icon = load_icon(Path::new(path));
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
@@ -43,7 +33,7 @@ fn main() {
|
||||
CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
DroppedFile(path) => {
|
||||
window.set_window_icon(Some(load_icon(&path)));
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,12 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
println!("Close the window to continue.");
|
||||
event_loop.run_return(|event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
_ => *control_flow = ControlFlow::Wait,
|
||||
}
|
||||
event_loop.run_return(|event, _, control_flow| match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
_ => *control_flow = ControlFlow::Wait,
|
||||
});
|
||||
drop(window);
|
||||
|
||||
@@ -31,14 +29,12 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
println!("Wa ha ha! You thought that closing the window would finish this?!");
|
||||
event_loop.run_return(|event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
_ => *control_flow = ControlFlow::Wait,
|
||||
}
|
||||
event_loop.run_return(|event, _, control_flow| match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
_ => *control_flow = ControlFlow::Wait,
|
||||
});
|
||||
|
||||
println!("Okay we're done now for real.");
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
merge_imports=true
|
||||
match_block_trailing_comma=true
|
||||
force_explicit_abi=true
|
||||
format_macro_matchers=true
|
||||
use_field_init_shorthand=true
|
||||
format_code_in_doc_comments=true
|
||||
force_multiline_blocks=true
|
||||
# merge_imports=true
|
||||
|
||||
18
src/error.rs
18
src/error.rs
@@ -48,8 +48,8 @@ macro_rules! os_error {
|
||||
}
|
||||
|
||||
impl fmt::Display for OsError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
formatter.pad(&format!(
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.pad(&format!(
|
||||
"os error at {}:{}: {}",
|
||||
self.file, self.line, self.error
|
||||
))
|
||||
@@ -57,23 +57,23 @@ impl fmt::Display for OsError {
|
||||
}
|
||||
|
||||
impl fmt::Display for ExternalError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
ExternalError::NotSupported(e) => e.fmt(formatter),
|
||||
ExternalError::Os(e) => e.fmt(formatter),
|
||||
ExternalError::NotSupported(e) => e.fmt(f),
|
||||
ExternalError::Os(e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for NotSupportedError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
formatter.debug_struct("NotSupportedError").finish()
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.debug_struct("NotSupportedError").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for NotSupportedError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
formatter.pad("the requested operation is not supported by Winit")
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.pad("the requested operation is not supported by Winit")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
src/event.rs
14
src/event.rs
@@ -37,10 +37,11 @@ pub enum Event<T> {
|
||||
/// emitted, it is guaranteed to be the last event emitted.
|
||||
LoopDestroyed,
|
||||
|
||||
/// Emitted when the application has been suspended or resumed.
|
||||
///
|
||||
/// The parameter is true if app was suspended, and false if it has been resumed.
|
||||
Suspended(bool),
|
||||
/// Emitted when the application has been suspended.
|
||||
Suspended,
|
||||
|
||||
/// Emitted when the application has been resumed.
|
||||
Resumed,
|
||||
}
|
||||
|
||||
impl<T> Event<T> {
|
||||
@@ -53,7 +54,8 @@ impl<T> Event<T> {
|
||||
NewEvents(cause) => Ok(NewEvents(cause)),
|
||||
EventsCleared => Ok(EventsCleared),
|
||||
LoopDestroyed => Ok(LoopDestroyed),
|
||||
Suspended(suspended) => Ok(Suspended(suspended)),
|
||||
Suspended => Ok(Suspended),
|
||||
Resumed => Ok(Resumed),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,7 +198,7 @@ pub enum WindowEvent {
|
||||
/// * Changing the display's DPI factor (e.g. in Control Panel on Windows).
|
||||
/// * Moving the window to a display with a different DPI factor.
|
||||
///
|
||||
/// For more information about DPI in general, see the [`dpi`](dpi/index.html) module.
|
||||
/// For more information about DPI in general, see the [`dpi`](../dpi/index.html) module.
|
||||
HiDpiFactorChanged(f64),
|
||||
}
|
||||
|
||||
|
||||
@@ -22,14 +22,14 @@ use crate::{
|
||||
///
|
||||
/// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()`
|
||||
/// initializes everything that will be required to create windows. For example on Linux creating
|
||||
/// an events loop opens a connection to the X or Wayland server.
|
||||
/// an event loop opens a connection to the X or Wayland server.
|
||||
///
|
||||
/// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs.
|
||||
///
|
||||
/// Note that the `EventLoop` cannot be shared across threads (due to platform-dependant logic
|
||||
/// forbidding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the
|
||||
/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the
|
||||
/// `EventLoopProxy` allows you to wake up an `EventLoop` from an other thread.
|
||||
/// `EventLoopProxy` allows you to wake up an `EventLoop` from another thread.
|
||||
pub struct EventLoop<T: 'static> {
|
||||
pub(crate) event_loop: platform_impl::EventLoop<T>,
|
||||
pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
|
||||
@@ -46,14 +46,14 @@ pub struct EventLoopWindowTarget<T: 'static> {
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for EventLoop<T> {
|
||||
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmtr.pad("EventLoop { .. }")
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.pad("EventLoop { .. }")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for EventLoopWindowTarget<T> {
|
||||
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmtr.pad("EventLoopWindowTarget { .. }")
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.pad("EventLoopWindowTarget { .. }")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ impl<T> EventLoop<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Hijacks the calling thread and initializes the `winit` event loop with the provided
|
||||
/// Hijacks the calling thread and initializes the winit event loop with the provided
|
||||
/// closure. Since the closure is `'static`, it must be a `move` closure if it needs to
|
||||
/// access any data from the calling context.
|
||||
///
|
||||
@@ -189,8 +189,8 @@ impl<T: 'static> EventLoopProxy<T> {
|
||||
}
|
||||
|
||||
impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
|
||||
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmtr.pad("EventLoopProxy { .. }")
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.pad("EventLoopProxy { .. }")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ pub enum BadIcon {
|
||||
}
|
||||
|
||||
impl fmt::Display for BadIcon {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let msg = match self {
|
||||
&BadIcon::ByteCountNotDivisibleBy4 { byte_count } => format!(
|
||||
"The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.",
|
||||
@@ -44,7 +44,7 @@ impl fmt::Display for BadIcon {
|
||||
width, height, pixel_count, width_x_height,
|
||||
),
|
||||
};
|
||||
write!(formatter, "{}", msg)
|
||||
write!(f, "{}", msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
48
src/lib.rs
48
src/lib.rs
@@ -22,11 +22,15 @@
|
||||
//!
|
||||
//! # Event handling
|
||||
//!
|
||||
//! Once a [`Window`] has been created, it will *generate events*. For example whenever the user moves
|
||||
//! the [`Window`], resizes the [`Window`], moves the mouse, etc. an event is generated.
|
||||
//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can
|
||||
//! generate a [`WindowEvent`] when certain things happen, like whenever the user moves their mouse
|
||||
//! or presses a key inside the [`Window`]. Devices can generate a [`DeviceEvent`] directly as well,
|
||||
//! which contains unfiltered event data that isn't specific to a certain window. Some user
|
||||
//! activity, like mouse movement, can generate both a [`WindowEvent`] *and* a [`DeviceEvent`]. You
|
||||
//! can also create and handle your own custom [`UserEvent`]s, if desired.
|
||||
//!
|
||||
//! The events generated by a [`Window`] can be retreived from the [`EventLoop`] the [`Window`] was created
|
||||
//! with.
|
||||
//! Events can be retreived by using an [`EventLoop`]. A [`Window`] will send its events to the
|
||||
//! [`EventLoop`] object it was created with.
|
||||
//!
|
||||
//! You do this by calling [`event_loop.run(...)`][event_loop_run]. This function will run forever
|
||||
//! unless `control_flow` is set to [`ControlFlow`]`::`[`Exit`], at which point [`Event`]`::`[`LoopDestroyed`]
|
||||
@@ -35,13 +39,31 @@
|
||||
//! ```no_run
|
||||
//! use winit::{
|
||||
//! event::{Event, WindowEvent},
|
||||
//! event_loop::ControlFlow,
|
||||
//! event_loop::{ControlFlow, EventLoop},
|
||||
//! window::WindowBuilder,
|
||||
//! };
|
||||
//! # use winit::event_loop::EventLoop;
|
||||
//! # let event_loop = EventLoop::new();
|
||||
//!
|
||||
//! let event_loop = EventLoop::new();
|
||||
//! let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
//!
|
||||
//! event_loop.run(move |event, _, control_flow| {
|
||||
//! match event {
|
||||
//! Event::EventsCleared => {
|
||||
//! // Application update code.
|
||||
//!
|
||||
//! // Queue a RedrawRequested event.
|
||||
//! window.request_redraw();
|
||||
//! },
|
||||
//! Event::WindowEvent {
|
||||
//! event: WindowEvent::RedrawRequested,
|
||||
//! ..
|
||||
//! } => {
|
||||
//! // Redraw the application.
|
||||
//! //
|
||||
//! // It's preferrable to render in this event rather than in EventsCleared, since
|
||||
//! // rendering in here allows the program to gracefully handle redraws requested
|
||||
//! // by the OS.
|
||||
//! },
|
||||
//! Event::WindowEvent {
|
||||
//! event: WindowEvent::CloseRequested,
|
||||
//! ..
|
||||
@@ -49,7 +71,13 @@
|
||||
//! println!("The close button was pressed; stopping");
|
||||
//! *control_flow = ControlFlow::Exit
|
||||
//! },
|
||||
//! _ => *control_flow = ControlFlow::Wait,
|
||||
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
|
||||
//! // dispatched any events. This is ideal for games and similar applications.
|
||||
//! _ => *control_flow = ControlFlow::Poll,
|
||||
//! // ControlFlow::Wait pauses the event loop if no events are available to process.
|
||||
//! // This is ideal for non-game applications that only update in response to user
|
||||
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
|
||||
//! // _ => *control_flow = ControlFlow::Wait,
|
||||
//! }
|
||||
//! });
|
||||
//! ```
|
||||
@@ -76,7 +104,9 @@
|
||||
//! [window_builder_build]: ./window/struct.WindowBuilder.html#method.build
|
||||
//! [window_id_fn]: ./window/struct.Window.html#method.id
|
||||
//! [`Event`]: ./event/enum.Event.html
|
||||
//! [`WindowEvent`]: ./event/enum.Event.html#variant.WindowEvent
|
||||
//! [`WindowEvent`]: ./event/enum.WindowEvent.html
|
||||
//! [`DeviceEvent`]: ./event/enum.DeviceEvent.html
|
||||
//! [`UserEvent`]: ./event/enum.Event.html#variant.UserEvent
|
||||
//! [`LoopDestroyed`]: ./event/enum.Event.html#variant.LoopDestroyed
|
||||
//! [`platform`]: ./platform/index.html
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ impl MonitorHandle {
|
||||
|
||||
/// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa.
|
||||
///
|
||||
/// See the [`dpi`](dpi/index.html) module for more information.
|
||||
/// See the [`dpi`](../dpi/index.html) module for more information.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
|
||||
@@ -8,6 +8,26 @@ use crate::{
|
||||
window::{Window, WindowBuilder},
|
||||
};
|
||||
|
||||
/// Corresponds to `NSRequestUserAttentionType`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum RequestUserAttentionType {
|
||||
/// Corresponds to `NSCriticalRequest`.
|
||||
///
|
||||
/// Dock icon will bounce until the application is focused.
|
||||
Critical,
|
||||
|
||||
/// Corresponds to `NSInformationalRequest`.
|
||||
///
|
||||
/// Dock icon will bounce once.
|
||||
Informational,
|
||||
}
|
||||
|
||||
impl Default for RequestUserAttentionType {
|
||||
fn default() -> Self {
|
||||
RequestUserAttentionType::Critical
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional methods on `Window` that are specific to MacOS.
|
||||
pub trait WindowExtMacOS {
|
||||
/// Returns a pointer to the cocoa `NSWindow` that is used by this window.
|
||||
@@ -22,11 +42,7 @@ pub trait WindowExtMacOS {
|
||||
|
||||
/// Request user attention, causing the application's dock icon to bounce.
|
||||
/// Note that this has no effect if the application is already focused.
|
||||
///
|
||||
/// The `is_critical` flag has the following effects:
|
||||
/// - `false`: the dock icon will only bounce once.
|
||||
/// - `true`: the dock icon will bounce until the application is focused.
|
||||
fn request_user_attention(&self, is_critical: bool);
|
||||
fn request_user_attention(&self, request_type: RequestUserAttentionType);
|
||||
|
||||
/// Returns whether or not the window is in simple fullscreen mode.
|
||||
fn simple_fullscreen(&self) -> bool;
|
||||
@@ -53,8 +69,8 @@ impl WindowExtMacOS for Window {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn request_user_attention(&self, is_critical: bool) {
|
||||
self.window.request_user_attention(is_critical)
|
||||
fn request_user_attention(&self, request_type: RequestUserAttentionType) {
|
||||
self.window.request_user_attention(request_type)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -122,11 +122,9 @@ pub trait EventLoopExtUnix {
|
||||
impl<T> EventLoopExtUnix for EventLoop<T> {
|
||||
#[inline]
|
||||
fn new_x11() -> Result<Self, XNotSupported> {
|
||||
LinuxEventLoop::new_x11().map(|ev| {
|
||||
EventLoop {
|
||||
event_loop: ev,
|
||||
_marker: ::std::marker::PhantomData,
|
||||
}
|
||||
LinuxEventLoop::new_x11().map(|ev| EventLoop {
|
||||
event_loop: ev,
|
||||
_marker: ::std::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -294,7 +292,7 @@ impl WindowExtUnix for Window {
|
||||
fn set_wayland_theme(&self, theme: WaylandTheme) {
|
||||
match self.window {
|
||||
LinuxWindow::Wayland(ref w) => w.set_theme(WaylandThemeObject(theme)),
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,21 +79,21 @@ impl EventLoop {
|
||||
device_id: DEVICE_ID,
|
||||
}),
|
||||
})
|
||||
},
|
||||
}
|
||||
android_glue::Event::InitWindow => {
|
||||
// The activity went to foreground.
|
||||
if let Some(cb) = self.suspend_callback.borrow().as_ref() {
|
||||
(*cb)(false);
|
||||
}
|
||||
Some(Event::Suspended(false))
|
||||
},
|
||||
Some(Event::Resumed)
|
||||
}
|
||||
android_glue::Event::TermWindow => {
|
||||
// The activity went to background.
|
||||
if let Some(cb) = self.suspend_callback.borrow().as_ref() {
|
||||
(*cb)(true);
|
||||
}
|
||||
Some(Event::Suspended(true))
|
||||
},
|
||||
Some(Event::Suspended)
|
||||
}
|
||||
android_glue::Event::WindowResized | android_glue::Event::ConfigChanged => {
|
||||
// Activity Orientation changed or resized.
|
||||
let native_window = unsafe { android_glue::native_window() };
|
||||
@@ -108,14 +108,14 @@ impl EventLoop {
|
||||
event: WindowEvent::Resized(size),
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
android_glue::Event::WindowRedrawNeeded => {
|
||||
// The activity needs to be redrawn.
|
||||
Some(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId),
|
||||
event: WindowEvent::Redraw,
|
||||
})
|
||||
},
|
||||
}
|
||||
android_glue::Event::Wake => Some(Event::Awakened),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@@ -251,7 +251,7 @@ extern "C" fn mouse_callback(
|
||||
delta: ((*event).movementX as f64, (*event).movementY as f64),
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEDOWN
|
||||
| mouse_input @ ffi::EMSCRIPTEN_EVENT_MOUSEUP => {
|
||||
let button = match (*event).button {
|
||||
@@ -274,8 +274,8 @@ extern "C" fn mouse_callback(
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ffi::EM_FALSE
|
||||
@@ -310,7 +310,7 @@ extern "C" fn keyboard_callback(
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
ffi::EMSCRIPTEN_EVENT_KEYUP => {
|
||||
queue.lock().unwrap().push_back(::Event::WindowEvent {
|
||||
window_id: ::WindowId(WindowId(0)),
|
||||
@@ -324,8 +324,8 @@ extern "C" fn keyboard_callback(
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ffi::EM_FALSE
|
||||
@@ -757,7 +757,7 @@ fn error_to_str(code: ffi::EMSCRIPTEN_RESULT) -> &'static str {
|
||||
match code {
|
||||
ffi::EMSCRIPTEN_RESULT_SUCCESS | ffi::EMSCRIPTEN_RESULT_DEFERRED => {
|
||||
"Internal error in the library (success detected as failure)"
|
||||
},
|
||||
}
|
||||
|
||||
ffi::EMSCRIPTEN_RESULT_NOT_SUPPORTED => "Not supported",
|
||||
ffi::EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED => "Failed not deferred",
|
||||
@@ -778,7 +778,7 @@ fn key_translate(input: [ffi::EM_UTF8; ffi::EM_HTML5_SHORT_STRING_LEN_BYTES]) ->
|
||||
Ok(key) => key,
|
||||
Err(_) => {
|
||||
return 0;
|
||||
},
|
||||
}
|
||||
};
|
||||
if key.chars().count() == 1 {
|
||||
key.as_bytes()[0]
|
||||
@@ -797,25 +797,21 @@ fn key_translate_virt(
|
||||
Ok(key) => key,
|
||||
Err(_) => {
|
||||
return None;
|
||||
},
|
||||
}
|
||||
};
|
||||
use VirtualKeyCode::*;
|
||||
match key {
|
||||
"Alt" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LAlt),
|
||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RAlt),
|
||||
_ => None,
|
||||
}
|
||||
"Alt" => match location {
|
||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LAlt),
|
||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RAlt),
|
||||
_ => None,
|
||||
},
|
||||
"AltGraph" => None,
|
||||
"CapsLock" => None,
|
||||
"Control" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LControl),
|
||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RControl),
|
||||
_ => None,
|
||||
}
|
||||
"Control" => match location {
|
||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LControl),
|
||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RControl),
|
||||
_ => None,
|
||||
},
|
||||
"Fn" => None,
|
||||
"FnLock" => None,
|
||||
@@ -823,22 +819,18 @@ fn key_translate_virt(
|
||||
"Meta" => None,
|
||||
"NumLock" => Some(Numlock),
|
||||
"ScrollLock" => Some(Scroll),
|
||||
"Shift" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LShift),
|
||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RShift),
|
||||
_ => None,
|
||||
}
|
||||
"Shift" => match location {
|
||||
ffi::DOM_KEY_LOCATION_LEFT => Some(LShift),
|
||||
ffi::DOM_KEY_LOCATION_RIGHT => Some(RShift),
|
||||
_ => None,
|
||||
},
|
||||
"Super" => None,
|
||||
"Symbol" => None,
|
||||
"SymbolLock" => None,
|
||||
|
||||
"Enter" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadEnter),
|
||||
_ => Some(Return),
|
||||
}
|
||||
"Enter" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadEnter),
|
||||
_ => Some(Return),
|
||||
},
|
||||
"Tab" => Some(Tab),
|
||||
" " => Some(Space),
|
||||
@@ -1163,65 +1155,45 @@ fn key_translate_virt(
|
||||
"Divide" => Some(Divide),
|
||||
"Subtract" | "-" => Some(Subtract),
|
||||
"Separator" => None,
|
||||
"0" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad0),
|
||||
_ => Some(Key0),
|
||||
}
|
||||
"0" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad0),
|
||||
_ => Some(Key0),
|
||||
},
|
||||
"1" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad1),
|
||||
_ => Some(Key1),
|
||||
}
|
||||
"1" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad1),
|
||||
_ => Some(Key1),
|
||||
},
|
||||
"2" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad2),
|
||||
_ => Some(Key2),
|
||||
}
|
||||
"2" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad2),
|
||||
_ => Some(Key2),
|
||||
},
|
||||
"3" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad3),
|
||||
_ => Some(Key3),
|
||||
}
|
||||
"3" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad3),
|
||||
_ => Some(Key3),
|
||||
},
|
||||
"4" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad4),
|
||||
_ => Some(Key4),
|
||||
}
|
||||
"4" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad4),
|
||||
_ => Some(Key4),
|
||||
},
|
||||
"5" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad5),
|
||||
_ => Some(Key5),
|
||||
}
|
||||
"5" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad5),
|
||||
_ => Some(Key5),
|
||||
},
|
||||
"6" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad6),
|
||||
_ => Some(Key6),
|
||||
}
|
||||
"6" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad6),
|
||||
_ => Some(Key6),
|
||||
},
|
||||
"7" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad7),
|
||||
_ => Some(Key7),
|
||||
}
|
||||
"7" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad7),
|
||||
_ => Some(Key7),
|
||||
},
|
||||
"8" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad8),
|
||||
_ => Some(Key8),
|
||||
}
|
||||
"8" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad8),
|
||||
_ => Some(Key8),
|
||||
},
|
||||
"9" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad9),
|
||||
_ => Some(Key9),
|
||||
}
|
||||
"9" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(Numpad9),
|
||||
_ => Some(Key9),
|
||||
},
|
||||
|
||||
"A" | "a" => Some(A),
|
||||
@@ -1254,17 +1226,13 @@ fn key_translate_virt(
|
||||
"'" => Some(Apostrophe),
|
||||
"\\" => Some(Backslash),
|
||||
":" => Some(Colon),
|
||||
"," => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadComma),
|
||||
_ => Some(Comma),
|
||||
}
|
||||
"," => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadComma),
|
||||
_ => Some(Comma),
|
||||
},
|
||||
"=" => {
|
||||
match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadEquals),
|
||||
_ => Some(Equals),
|
||||
}
|
||||
"=" => match location {
|
||||
ffi::DOM_KEY_LOCATION_NUMPAD => Some(NumpadEquals),
|
||||
_ => Some(Equals),
|
||||
},
|
||||
"{" => Some(LBracket),
|
||||
"." => Some(Period),
|
||||
|
||||
@@ -71,7 +71,7 @@ impl Drop for AppStateImpl {
|
||||
let () = msg_send![window, release];
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,15 +128,13 @@ impl AppState {
|
||||
queued_windows.push(window);
|
||||
msg_send![window, retain];
|
||||
return;
|
||||
},
|
||||
&mut AppStateImpl::ProcessingEvents { .. } => {},
|
||||
&mut AppStateImpl::InUserCallback { .. } => {},
|
||||
&mut AppStateImpl::Terminated => {
|
||||
panic!(
|
||||
"Attempt to create a `Window` \
|
||||
after the app has terminated"
|
||||
)
|
||||
},
|
||||
}
|
||||
&mut AppStateImpl::ProcessingEvents { .. } => {}
|
||||
&mut AppStateImpl::InUserCallback { .. } => {}
|
||||
&mut AppStateImpl::Terminated => panic!(
|
||||
"Attempt to create a `Window` \
|
||||
after the app has terminated"
|
||||
),
|
||||
app_state => unreachable!("unexpected state: {:#?}", app_state), /* all other cases should be impossible */
|
||||
}
|
||||
drop(this);
|
||||
@@ -154,13 +152,11 @@ impl AppState {
|
||||
let windows = ptr::read(queued_windows);
|
||||
let events = ptr::read(queued_events);
|
||||
(windows, events)
|
||||
},
|
||||
_ => {
|
||||
panic!(
|
||||
"winit iOS expected the app to be in a `NotLaunched` \
|
||||
state, but was not - please file an issue"
|
||||
)
|
||||
},
|
||||
}
|
||||
_ => panic!(
|
||||
"winit iOS expected the app to be in a `NotLaunched` \
|
||||
state, but was not - please file an issue"
|
||||
),
|
||||
};
|
||||
ptr::write(
|
||||
&mut this.app_state,
|
||||
@@ -180,12 +176,10 @@ impl AppState {
|
||||
ref mut queued_windows,
|
||||
..
|
||||
} => mem::replace(queued_windows, Vec::new()),
|
||||
_ => {
|
||||
panic!(
|
||||
"winit iOS expected the app to be in a `Launching` \
|
||||
state, but was not - please file an issue"
|
||||
)
|
||||
},
|
||||
_ => panic!(
|
||||
"winit iOS expected the app to be in a `Launching` \
|
||||
state, but was not - please file an issue"
|
||||
),
|
||||
};
|
||||
// have to drop RefMut because the window setup code below can trigger new events
|
||||
drop(this);
|
||||
@@ -228,13 +222,11 @@ impl AppState {
|
||||
let events = ptr::read(queued_events);
|
||||
let event_handler = ptr::read(queued_event_handler);
|
||||
(windows, events, event_handler)
|
||||
},
|
||||
_ => {
|
||||
panic!(
|
||||
"winit iOS expected the app to be in a `Launching` \
|
||||
state, but was not - please file an issue"
|
||||
)
|
||||
},
|
||||
}
|
||||
_ => panic!(
|
||||
"winit iOS expected the app to be in a `Launching` \
|
||||
state, but was not - please file an issue"
|
||||
),
|
||||
};
|
||||
ptr::write(
|
||||
&mut this.app_state,
|
||||
@@ -283,7 +275,7 @@ impl AppState {
|
||||
},
|
||||
);
|
||||
Event::NewEvents(StartCause::Poll)
|
||||
},
|
||||
}
|
||||
ControlFlow::Wait => {
|
||||
let (event_handler, start) = match &mut this.app_state {
|
||||
&mut AppStateImpl::NotLaunched { .. }
|
||||
@@ -305,7 +297,7 @@ impl AppState {
|
||||
start,
|
||||
requested_resume: None,
|
||||
})
|
||||
},
|
||||
}
|
||||
ControlFlow::WaitUntil(requested_resume) => {
|
||||
let (event_handler, start) = match &mut this.app_state {
|
||||
&mut AppStateImpl::NotLaunched { .. }
|
||||
@@ -334,7 +326,7 @@ impl AppState {
|
||||
requested_resume: Some(requested_resume),
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
ControlFlow::Exit => bug!("unexpected controlflow `Exit`"),
|
||||
};
|
||||
drop(this);
|
||||
@@ -365,7 +357,7 @@ impl AppState {
|
||||
} => {
|
||||
queued_events.extend(events);
|
||||
return;
|
||||
},
|
||||
}
|
||||
&mut AppStateImpl::ProcessingEvents {
|
||||
ref mut event_handler,
|
||||
ref mut active_control_flow,
|
||||
@@ -461,7 +453,7 @@ impl AppState {
|
||||
let mut this = AppState::get_mut();
|
||||
match &mut this.app_state {
|
||||
&mut AppStateImpl::NotLaunched { .. } | &mut AppStateImpl::Launching { .. } => return,
|
||||
&mut AppStateImpl::ProcessingEvents { .. } => {},
|
||||
&mut AppStateImpl::ProcessingEvents { .. } => {}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
drop(this);
|
||||
@@ -474,25 +466,21 @@ impl AppState {
|
||||
&mut AppStateImpl::ProcessingEvents {
|
||||
ref mut event_handler,
|
||||
ref mut active_control_flow,
|
||||
} => {
|
||||
(
|
||||
ManuallyDrop::new(ptr::read(event_handler)),
|
||||
*active_control_flow,
|
||||
)
|
||||
},
|
||||
} => (
|
||||
ManuallyDrop::new(ptr::read(event_handler)),
|
||||
*active_control_flow,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let new = this.control_flow;
|
||||
match (old, new) {
|
||||
(ControlFlow::Poll, ControlFlow::Poll) => {
|
||||
ptr::write(
|
||||
&mut this.app_state,
|
||||
AppStateImpl::PollFinished {
|
||||
waiting_event_handler: ManuallyDrop::into_inner(event_handler),
|
||||
},
|
||||
)
|
||||
},
|
||||
(ControlFlow::Poll, ControlFlow::Poll) => ptr::write(
|
||||
&mut this.app_state,
|
||||
AppStateImpl::PollFinished {
|
||||
waiting_event_handler: ManuallyDrop::into_inner(event_handler),
|
||||
},
|
||||
),
|
||||
(ControlFlow::Wait, ControlFlow::Wait) => {
|
||||
let start = Instant::now();
|
||||
ptr::write(
|
||||
@@ -502,7 +490,7 @@ impl AppState {
|
||||
start,
|
||||
},
|
||||
)
|
||||
},
|
||||
}
|
||||
(ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant))
|
||||
if old_instant == new_instant =>
|
||||
{
|
||||
@@ -525,7 +513,7 @@ impl AppState {
|
||||
},
|
||||
);
|
||||
this.waker.stop()
|
||||
},
|
||||
}
|
||||
(_, ControlFlow::WaitUntil(new_instant)) => {
|
||||
let start = Instant::now();
|
||||
ptr::write(
|
||||
@@ -536,7 +524,7 @@ impl AppState {
|
||||
},
|
||||
);
|
||||
this.waker.start_at(new_instant)
|
||||
},
|
||||
}
|
||||
(_, ControlFlow::Poll) => {
|
||||
ptr::write(
|
||||
&mut this.app_state,
|
||||
@@ -545,13 +533,13 @@ impl AppState {
|
||||
},
|
||||
);
|
||||
this.waker.start()
|
||||
},
|
||||
}
|
||||
(_, ControlFlow::Exit) => {
|
||||
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
|
||||
// it is not possible to quit an iOS app gracefully and programatically
|
||||
warn!("`ControlFlow::Exit` ignored on iOS");
|
||||
this.control_flow = old
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
ffi::c_void,
|
||||
fmt::{self, Debug, Formatter},
|
||||
fmt::{self, Debug},
|
||||
marker::PhantomData,
|
||||
mem, ptr,
|
||||
sync::mpsc::{self, Receiver, Sender},
|
||||
@@ -264,9 +264,8 @@ struct EventLoopHandler<F, T: 'static> {
|
||||
}
|
||||
|
||||
impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("EventLoopHandler")
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("EventLoopHandler")
|
||||
.field("event_loop", &self.event_loop)
|
||||
.finish()
|
||||
}
|
||||
|
||||
@@ -161,14 +161,14 @@ impl UIInterfaceOrientationMask {
|
||||
match (valid_orientations, idiom) {
|
||||
(ValidOrientations::LandscapeAndPortrait, Idiom::Phone) => {
|
||||
UIInterfaceOrientationMask::AllButUpsideDown
|
||||
},
|
||||
}
|
||||
(ValidOrientations::LandscapeAndPortrait, _) => UIInterfaceOrientationMask::All,
|
||||
(ValidOrientations::Landscape, _) => UIInterfaceOrientationMask::Landscape,
|
||||
(ValidOrientations::Portrait, Idiom::Phone) => UIInterfaceOrientationMask::Portrait,
|
||||
(ValidOrientations::Portrait, _) => {
|
||||
UIInterfaceOrientationMask::Portrait
|
||||
| UIInterfaceOrientationMask::PortraitUpsideDown
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
//!
|
||||
//! This is how those event are represented in winit:
|
||||
//!
|
||||
//! - applicationDidBecomeActive is Suspended(false)
|
||||
//! - applicationWillResignActive is Suspended(true)
|
||||
//! - applicationDidBecomeActive is Resumed
|
||||
//! - applicationWillResignActive is Suspended
|
||||
//! - applicationWillTerminate is LoopDestroyed
|
||||
//!
|
||||
//! Keep in mind that after LoopDestroyed event is received every attempt to draw with
|
||||
|
||||
@@ -382,11 +382,11 @@ pub fn create_delegate_class() {
|
||||
}
|
||||
|
||||
extern "C" fn did_become_active(_: &Object, _: Sel, _: id) {
|
||||
unsafe { AppState::handle_nonuser_event(Event::Suspended(false)) }
|
||||
unsafe { AppState::handle_nonuser_event(Event::Resumed) }
|
||||
}
|
||||
|
||||
extern "C" fn will_resign_active(_: &Object, _: Sel, _: id) {
|
||||
unsafe { AppState::handle_nonuser_event(Event::Suspended(true)) }
|
||||
unsafe { AppState::handle_nonuser_event(Event::Suspended) }
|
||||
}
|
||||
|
||||
extern "C" fn will_enter_foreground(_: &Object, _: Sel, _: id) {}
|
||||
|
||||
@@ -170,7 +170,7 @@ impl Inner {
|
||||
let () = msg_send![self.window, setScreen: uiscreen];
|
||||
}
|
||||
let () = msg_send![self.window, setFrame: bounds];
|
||||
},
|
||||
}
|
||||
None => warn!("`Window::set_fullscreen(None)` ignored on iOS"),
|
||||
}
|
||||
}
|
||||
@@ -301,14 +301,12 @@ impl Window {
|
||||
let screen_bounds: CGRect = msg_send![screen, bounds];
|
||||
|
||||
let frame = match window_attributes.inner_size {
|
||||
Some(dim) => {
|
||||
CGRect {
|
||||
origin: screen_bounds.origin,
|
||||
size: CGSize {
|
||||
width: dim.width,
|
||||
height: dim.height,
|
||||
},
|
||||
}
|
||||
Some(dim) => CGRect {
|
||||
origin: screen_bounds.origin,
|
||||
size: CGSize {
|
||||
width: dim.width,
|
||||
height: dim.height,
|
||||
},
|
||||
},
|
||||
None => screen_bounds,
|
||||
};
|
||||
|
||||
@@ -55,10 +55,10 @@ pub enum OsError {
|
||||
}
|
||||
|
||||
impl fmt::Display for OsError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
OsError::XError(e) => formatter.pad(&e.description),
|
||||
OsError::XMisc(e) => formatter.pad(e),
|
||||
OsError::XError(e) => f.pad(&e.description),
|
||||
OsError::XMisc(e) => f.pad(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,10 +158,10 @@ impl Window {
|
||||
match *window_target {
|
||||
EventLoopWindowTarget::Wayland(ref window_target) => {
|
||||
wayland::Window::new(window_target, attribs, pl_attribs).map(Window::Wayland)
|
||||
},
|
||||
}
|
||||
EventLoopWindowTarget::X(ref window_target) => {
|
||||
x11::Window::new(window_target, attribs, pl_attribs).map(Window::X)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,13 +313,9 @@ impl Window {
|
||||
pub fn fullscreen(&self) -> Option<RootMonitorHandle> {
|
||||
match self {
|
||||
&Window::X(ref w) => w.fullscreen(),
|
||||
&Window::Wayland(ref w) => {
|
||||
w.fullscreen().map(|monitor_id| {
|
||||
RootMonitorHandle {
|
||||
inner: MonitorHandle::Wayland(monitor_id),
|
||||
}
|
||||
})
|
||||
},
|
||||
&Window::Wayland(ref w) => w.fullscreen().map(|monitor_id| RootMonitorHandle {
|
||||
inner: MonitorHandle::Wayland(monitor_id),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,15 +370,11 @@ impl Window {
|
||||
#[inline]
|
||||
pub fn current_monitor(&self) -> RootMonitorHandle {
|
||||
match self {
|
||||
&Window::X(ref window) => {
|
||||
RootMonitorHandle {
|
||||
inner: MonitorHandle::X(window.current_monitor()),
|
||||
}
|
||||
&Window::X(ref window) => RootMonitorHandle {
|
||||
inner: MonitorHandle::X(window.current_monitor()),
|
||||
},
|
||||
&Window::Wayland(ref window) => {
|
||||
RootMonitorHandle {
|
||||
inner: MonitorHandle::Wayland(window.current_monitor()),
|
||||
}
|
||||
&Window::Wayland(ref window) => RootMonitorHandle {
|
||||
inner: MonitorHandle::Wayland(window.current_monitor()),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -390,20 +382,16 @@ impl Window {
|
||||
#[inline]
|
||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
match self {
|
||||
&Window::X(ref window) => {
|
||||
window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect()
|
||||
},
|
||||
&Window::Wayland(ref window) => {
|
||||
window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect()
|
||||
},
|
||||
&Window::X(ref window) => window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect(),
|
||||
&Window::Wayland(ref window) => window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,16 +452,14 @@ impl<T: 'static> EventLoop<T> {
|
||||
"x11" => {
|
||||
// TODO: propagate
|
||||
return EventLoop::new_x11().expect("Failed to initialize X11 backend");
|
||||
},
|
||||
}
|
||||
"wayland" => {
|
||||
return EventLoop::new_wayland().expect("Failed to initialize Wayland backend");
|
||||
},
|
||||
_ => {
|
||||
panic!(
|
||||
"Unknown environment variable value for {}, try one of `x11`,`wayland`",
|
||||
BACKEND_PREFERENCE_ENV_VAR,
|
||||
)
|
||||
},
|
||||
}
|
||||
_ => panic!(
|
||||
"Unknown environment variable value for {}, try one of `x11`,`wayland`",
|
||||
BACKEND_PREFERENCE_ENV_VAR,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,19 +497,17 @@ impl<T: 'static> EventLoop<T> {
|
||||
#[inline]
|
||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
match *self {
|
||||
EventLoop::Wayland(ref evlp) => {
|
||||
evlp.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect()
|
||||
},
|
||||
EventLoop::X(ref evlp) => {
|
||||
evlp.x_connection()
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect()
|
||||
},
|
||||
EventLoop::Wayland(ref evlp) => evlp
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect(),
|
||||
EventLoop::X(ref evlp) => evlp
|
||||
.x_connection()
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@ use std::{
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{
|
||||
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
||||
zwp_relative_pointer_v1::ZwpRelativePointerV1,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
event::ModifiersState,
|
||||
@@ -15,7 +20,7 @@ use crate::{
|
||||
platform_impl::platform::sticky_exit_callback,
|
||||
};
|
||||
|
||||
use super::{window::WindowStore, WindowId};
|
||||
use super::{window::WindowStore, DeviceId, WindowId};
|
||||
|
||||
use smithay_client_toolkit::{
|
||||
output::OutputMgr,
|
||||
@@ -26,33 +31,37 @@ use smithay_client_toolkit::{
|
||||
Environment,
|
||||
};
|
||||
|
||||
pub struct WindowEventsSink {
|
||||
buffer: VecDeque<(crate::event::WindowEvent, crate::window::WindowId)>,
|
||||
pub struct WindowEventsSink<T> {
|
||||
buffer: VecDeque<crate::event::Event<T>>,
|
||||
}
|
||||
|
||||
impl WindowEventsSink {
|
||||
pub fn new() -> WindowEventsSink {
|
||||
impl<T> WindowEventsSink<T> {
|
||||
pub fn new() -> WindowEventsSink<T> {
|
||||
WindowEventsSink {
|
||||
buffer: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) {
|
||||
self.buffer.push_back((
|
||||
evt,
|
||||
crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)),
|
||||
));
|
||||
pub fn send_window_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) {
|
||||
self.buffer.push_back(crate::event::Event::WindowEvent {
|
||||
event: evt,
|
||||
window_id: crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)),
|
||||
});
|
||||
}
|
||||
|
||||
fn empty_with<F, T>(&mut self, mut callback: F)
|
||||
pub fn send_device_event(&mut self, evt: crate::event::DeviceEvent, dev_id: DeviceId) {
|
||||
self.buffer.push_back(crate::event::Event::DeviceEvent {
|
||||
event: evt,
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(dev_id)),
|
||||
});
|
||||
}
|
||||
|
||||
fn empty_with<F>(&mut self, mut callback: F)
|
||||
where
|
||||
F: FnMut(crate::event::Event<T>),
|
||||
{
|
||||
for (evt, wid) in self.buffer.drain(..) {
|
||||
callback(crate::event::Event::WindowEvent {
|
||||
event: evt,
|
||||
window_id: wid,
|
||||
})
|
||||
for evt in self.buffer.drain(..) {
|
||||
callback(evt)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +74,7 @@ pub struct EventLoop<T: 'static> {
|
||||
// the output manager
|
||||
pub outputs: OutputMgr,
|
||||
// our sink, shared with some handlers, buffering the events
|
||||
sink: Arc<Mutex<WindowEventsSink>>,
|
||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
||||
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
|
||||
user_sender: ::calloop::channel::Sender<T>,
|
||||
@@ -122,13 +131,14 @@ impl<T: 'static> EventLoop<T> {
|
||||
.handle()
|
||||
.insert_source(kbd_channel, move |evt, &mut ()| {
|
||||
if let ::calloop::channel::Event::Msg((evt, wid)) = evt {
|
||||
kbd_sink.lock().unwrap().send_event(evt, wid);
|
||||
kbd_sink.lock().unwrap().send_window_event(evt, wid);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut seat_manager = SeatManager {
|
||||
sink: sink.clone(),
|
||||
relative_pointer_manager_proxy: None,
|
||||
store: store.clone(),
|
||||
seats: seats.clone(),
|
||||
kbd_sender,
|
||||
@@ -137,22 +147,29 @@ impl<T: 'static> EventLoop<T> {
|
||||
let env = Environment::from_display_with_cb(
|
||||
&display,
|
||||
&mut event_queue,
|
||||
move |event, registry| {
|
||||
match event {
|
||||
GlobalEvent::New {
|
||||
id,
|
||||
ref interface,
|
||||
version,
|
||||
} => {
|
||||
if interface == "wl_seat" {
|
||||
seat_manager.add_seat(id, version, registry)
|
||||
}
|
||||
},
|
||||
GlobalEvent::Removed { id, ref interface } => {
|
||||
if interface == "wl_seat" {
|
||||
seat_manager.remove_seat(id)
|
||||
}
|
||||
},
|
||||
move |event, registry| match event {
|
||||
GlobalEvent::New {
|
||||
id,
|
||||
ref interface,
|
||||
version,
|
||||
} => {
|
||||
if interface == "zwp_relative_pointer_manager_v1" {
|
||||
seat_manager.relative_pointer_manager_proxy = Some(
|
||||
registry
|
||||
.bind(version, id, move |pointer_manager| {
|
||||
pointer_manager.implement_closure(|_, _| (), ())
|
||||
})
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
if interface == "wl_seat" {
|
||||
seat_manager.add_seat(id, version, registry)
|
||||
}
|
||||
}
|
||||
GlobalEvent::Removed { id, ref interface } => {
|
||||
if interface == "wl_seat" {
|
||||
seat_manager.remove_seat(id)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -299,7 +316,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
},
|
||||
}
|
||||
ControlFlow::Wait => {
|
||||
self.inner_loop.dispatch(None, &mut ()).unwrap();
|
||||
callback(
|
||||
@@ -310,7 +327,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
},
|
||||
}
|
||||
ControlFlow::WaitUntil(deadline) => {
|
||||
let start = Instant::now();
|
||||
// compute the blocking duration
|
||||
@@ -344,7 +361,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +407,7 @@ impl<T> EventLoop<T> {
|
||||
let pruned = window_target.store.lock().unwrap().cleanup();
|
||||
*cleanup_needed = false;
|
||||
for wid in pruned {
|
||||
sink.send_event(crate::event::WindowEvent::Destroyed, wid);
|
||||
sink.send_window_event(crate::event::WindowEvent::Destroyed, wid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,7 +419,10 @@ impl<T> EventLoop<T> {
|
||||
frame.resize(w, h);
|
||||
frame.refresh();
|
||||
let logical_size = crate::dpi::LogicalSize::new(w as f64, h as f64);
|
||||
sink.send_event(crate::event::WindowEvent::Resized(logical_size), wid);
|
||||
sink.send_window_event(
|
||||
crate::event::WindowEvent::Resized(logical_size),
|
||||
wid,
|
||||
);
|
||||
*size = (w, h);
|
||||
} else if frame_refresh {
|
||||
frame.refresh();
|
||||
@@ -412,16 +432,16 @@ impl<T> EventLoop<T> {
|
||||
}
|
||||
}
|
||||
if let Some(dpi) = new_dpi {
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64),
|
||||
wid,
|
||||
);
|
||||
}
|
||||
if refresh {
|
||||
sink.send_event(crate::event::WindowEvent::RedrawRequested, wid);
|
||||
sink.send_window_event(crate::event::WindowEvent::RedrawRequested, wid);
|
||||
}
|
||||
if closed {
|
||||
sink.send_event(crate::event::WindowEvent::CloseRequested, wid);
|
||||
sink.send_window_event(crate::event::WindowEvent::CloseRequested, wid);
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -432,14 +452,15 @@ impl<T> EventLoop<T> {
|
||||
* Wayland protocol implementations
|
||||
*/
|
||||
|
||||
struct SeatManager {
|
||||
sink: Arc<Mutex<WindowEventsSink>>,
|
||||
struct SeatManager<T: 'static> {
|
||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||
store: Arc<Mutex<WindowStore>>,
|
||||
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
||||
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
|
||||
relative_pointer_manager_proxy: Option<ZwpRelativePointerManagerV1>,
|
||||
}
|
||||
|
||||
impl SeatManager {
|
||||
impl<T: 'static> SeatManager<T> {
|
||||
fn add_seat(&mut self, id: u32, version: u32, registry: wl_registry::WlRegistry) {
|
||||
use std::cmp::min;
|
||||
|
||||
@@ -447,6 +468,8 @@ impl SeatManager {
|
||||
sink: self.sink.clone(),
|
||||
store: self.store.clone(),
|
||||
pointer: None,
|
||||
relative_pointer: None,
|
||||
relative_pointer_manager_proxy: self.relative_pointer_manager_proxy.as_ref().cloned(),
|
||||
keyboard: None,
|
||||
touch: None,
|
||||
kbd_sender: self.kbd_sender.clone(),
|
||||
@@ -472,17 +495,19 @@ impl SeatManager {
|
||||
}
|
||||
}
|
||||
|
||||
struct SeatData {
|
||||
sink: Arc<Mutex<WindowEventsSink>>,
|
||||
struct SeatData<T> {
|
||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||
store: Arc<Mutex<WindowStore>>,
|
||||
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
|
||||
pointer: Option<wl_pointer::WlPointer>,
|
||||
relative_pointer: Option<ZwpRelativePointerV1>,
|
||||
relative_pointer_manager_proxy: Option<ZwpRelativePointerManagerV1>,
|
||||
keyboard: Option<wl_keyboard::WlKeyboard>,
|
||||
touch: Option<wl_touch::WlTouch>,
|
||||
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
||||
}
|
||||
|
||||
impl SeatData {
|
||||
impl<T: 'static> SeatData<T> {
|
||||
fn receive(&mut self, evt: wl_seat::Event, seat: wl_seat::WlSeat) {
|
||||
match evt {
|
||||
wl_seat::Event::Name { .. } => (),
|
||||
@@ -494,7 +519,19 @@ impl SeatData {
|
||||
self.sink.clone(),
|
||||
self.store.clone(),
|
||||
self.modifiers_tracker.clone(),
|
||||
))
|
||||
));
|
||||
|
||||
self.relative_pointer =
|
||||
self.relative_pointer_manager_proxy
|
||||
.as_ref()
|
||||
.and_then(|manager| {
|
||||
super::pointer::implement_relative_pointer(
|
||||
self.sink.clone(),
|
||||
self.pointer.as_ref().unwrap(),
|
||||
manager,
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
}
|
||||
// destroy pointer if applicable
|
||||
if !capabilities.contains(wl_seat::Capability::Pointer) {
|
||||
@@ -536,13 +573,13 @@ impl SeatData {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SeatData {
|
||||
impl<T> Drop for SeatData<T> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(pointer) = self.pointer.take() {
|
||||
if pointer.as_ref().version() >= 3 {
|
||||
@@ -648,12 +685,10 @@ impl MonitorHandle {
|
||||
.with_info(&self.proxy, |_, info| info.modes.clone())
|
||||
.unwrap_or(vec![])
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
VideoMode {
|
||||
size: (x.dimensions.0 as u32, x.dimensions.1 as u32),
|
||||
refresh_rate: (x.refresh_rate as f32 / 1000.0).round() as u16,
|
||||
bit_depth: 32,
|
||||
}
|
||||
.map(|x| VideoMode {
|
||||
size: (x.dimensions.0 as u32, x.dimensions.1 as u32),
|
||||
refresh_rate: (x.refresh_rate as f32 / 1000.0).round() as u16,
|
||||
bit_depth: 32,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -674,11 +709,9 @@ pub fn primary_monitor(outputs: &OutputMgr) -> MonitorHandle {
|
||||
pub fn available_monitors(outputs: &OutputMgr) -> VecDeque<MonitorHandle> {
|
||||
outputs.with_all(|list| {
|
||||
list.iter()
|
||||
.map(|&(_, ref proxy, _)| {
|
||||
MonitorHandle {
|
||||
proxy: proxy.clone(),
|
||||
mgr: outputs.clone(),
|
||||
}
|
||||
.map(|&(_, ref proxy, _)| MonitorHandle {
|
||||
proxy: proxy.clone(),
|
||||
mgr: outputs.clone(),
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
|
||||
@@ -31,12 +31,12 @@ pub fn init_keyboard(
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||
*target.lock().unwrap() = Some(wid);
|
||||
},
|
||||
}
|
||||
KbEvent::Leave { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||
*target.lock().unwrap() = None;
|
||||
},
|
||||
}
|
||||
KbEvent::Key {
|
||||
rawkey,
|
||||
keysym,
|
||||
@@ -79,8 +79,8 @@ pub fn init_keyboard(
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
KbEvent::RepeatInfo { .. } => { /* Handled by smithay client toolkit */ },
|
||||
}
|
||||
KbEvent::RepeatInfo { .. } => { /* Handled by smithay client toolkit */ }
|
||||
KbEvent::Modifiers {
|
||||
modifiers: event_modifiers,
|
||||
} => *modifiers_tracker.lock().unwrap() = event_modifiers.into(),
|
||||
@@ -127,59 +127,56 @@ pub fn init_keyboard(
|
||||
// In this case, we don't have the keymap information (it is
|
||||
// supposed to be serialized by the compositor using libxkbcommon)
|
||||
|
||||
// { variables to be captured by the closure
|
||||
let mut target = None;
|
||||
let my_sink = sink;
|
||||
// }
|
||||
seat.get_keyboard(|keyboard| {
|
||||
// { variables to be captured by the closure
|
||||
let mut target = None;
|
||||
let my_sink = sink;
|
||||
// }
|
||||
|
||||
keyboard.implement_closure(
|
||||
move |evt, _| {
|
||||
match evt {
|
||||
wl_keyboard::Event::Enter { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||
target = Some(wid);
|
||||
},
|
||||
wl_keyboard::Event::Leave { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||
target = None;
|
||||
},
|
||||
wl_keyboard::Event::Key { key, state, .. } => {
|
||||
if let Some(wid) = target {
|
||||
let state = match state {
|
||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
my_sink
|
||||
.send((
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(
|
||||
DeviceId,
|
||||
),
|
||||
),
|
||||
input: KeyboardInput {
|
||||
state,
|
||||
scancode: key,
|
||||
virtual_keycode: None,
|
||||
modifiers: ModifiersState::default(),
|
||||
},
|
||||
},
|
||||
wid,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
move |evt, _| match evt {
|
||||
wl_keyboard::Event::Enter { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||
target = Some(wid);
|
||||
}
|
||||
wl_keyboard::Event::Leave { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||
target = None;
|
||||
}
|
||||
wl_keyboard::Event::Key { key, state, .. } => {
|
||||
if let Some(wid) = target {
|
||||
let state = match state {
|
||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
my_sink
|
||||
.send((
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
input: KeyboardInput {
|
||||
state,
|
||||
scancode: key,
|
||||
virtual_keycode: None,
|
||||
modifiers: ModifiersState::default(),
|
||||
},
|
||||
},
|
||||
wid,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::event::{
|
||||
ElementState, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent,
|
||||
DeviceEvent, ElementState, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase,
|
||||
WindowEvent,
|
||||
};
|
||||
|
||||
use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId};
|
||||
@@ -11,18 +12,23 @@ use smithay_client_toolkit::reexports::client::protocol::{
|
||||
wl_seat,
|
||||
};
|
||||
|
||||
pub fn implement_pointer(
|
||||
use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{
|
||||
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, zwp_relative_pointer_v1::Event,
|
||||
zwp_relative_pointer_v1::ZwpRelativePointerV1,
|
||||
};
|
||||
|
||||
pub fn implement_pointer<T: 'static>(
|
||||
seat: &wl_seat::WlSeat,
|
||||
sink: Arc<Mutex<WindowEventsSink>>,
|
||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||
store: Arc<Mutex<WindowStore>>,
|
||||
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
||||
) -> WlPointer {
|
||||
let mut mouse_focus = None;
|
||||
let mut axis_buffer = None;
|
||||
let mut axis_discrete_buffer = None;
|
||||
let mut axis_state = TouchPhase::Ended;
|
||||
|
||||
seat.get_pointer(|pointer| {
|
||||
let mut mouse_focus = None;
|
||||
let mut axis_buffer = None;
|
||||
let mut axis_discrete_buffer = None;
|
||||
let mut axis_state = TouchPhase::Ended;
|
||||
|
||||
pointer.implement_closure(
|
||||
move |evt, pointer| {
|
||||
let mut sink = sink.lock().unwrap();
|
||||
@@ -37,7 +43,7 @@ pub fn implement_pointer(
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
mouse_focus = Some(wid);
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::CursorEntered {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -45,7 +51,7 @@ pub fn implement_pointer(
|
||||
},
|
||||
wid,
|
||||
);
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::CursorMoved {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -56,12 +62,12 @@ pub fn implement_pointer(
|
||||
wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
PtrEvent::Leave { surface, .. } => {
|
||||
mouse_focus = None;
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::CursorLeft {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -70,14 +76,14 @@ pub fn implement_pointer(
|
||||
wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
PtrEvent::Motion {
|
||||
surface_x,
|
||||
surface_y,
|
||||
..
|
||||
} => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::CursorMoved {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -88,7 +94,7 @@ pub fn implement_pointer(
|
||||
wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
PtrEvent::Button { button, state, .. } => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
let state = match state {
|
||||
@@ -103,7 +109,7 @@ pub fn implement_pointer(
|
||||
// TODO figure out the translation ?
|
||||
_ => return,
|
||||
};
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::MouseInput {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -115,7 +121,7 @@ pub fn implement_pointer(
|
||||
wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
PtrEvent::Axis { axis, value, .. } => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
if pointer.as_ref().version() < 5 {
|
||||
@@ -127,7 +133,7 @@ pub fn implement_pointer(
|
||||
wl_pointer::Axis::HorizontalScroll => x += value as f32,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -155,13 +161,13 @@ pub fn implement_pointer(
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
PtrEvent::Frame => {
|
||||
let axis_buffer = axis_buffer.take();
|
||||
let axis_discrete_buffer = axis_discrete_buffer.take();
|
||||
if let Some(wid) = mouse_focus {
|
||||
if let Some((x, y)) = axis_discrete_buffer {
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -173,7 +179,7 @@ pub fn implement_pointer(
|
||||
wid,
|
||||
);
|
||||
} else if let Some((x, y)) = axis_buffer {
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -188,11 +194,11 @@ pub fn implement_pointer(
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
PtrEvent::AxisSource { .. } => (),
|
||||
PtrEvent::AxisStop { .. } => {
|
||||
axis_state = TouchPhase::Ended;
|
||||
},
|
||||
}
|
||||
PtrEvent::AxisDiscrete { axis, discrete } => {
|
||||
let (mut x, mut y) = axis_discrete_buffer.unwrap_or((0, 0));
|
||||
match axis {
|
||||
@@ -206,7 +212,7 @@ pub fn implement_pointer(
|
||||
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
||||
_ => TouchPhase::Started,
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
@@ -215,3 +221,23 @@ pub fn implement_pointer(
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn implement_relative_pointer<T: 'static>(
|
||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||
pointer: &WlPointer,
|
||||
manager: &ZwpRelativePointerManagerV1,
|
||||
) -> Result<ZwpRelativePointerV1, ()> {
|
||||
manager.get_relative_pointer(pointer, |rel_pointer| {
|
||||
rel_pointer.implement_closure(
|
||||
move |evt, _rel_pointer| {
|
||||
let mut sink = sink.lock().unwrap();
|
||||
match evt {
|
||||
Event::RelativeMotion { dx, dy, .. } => sink
|
||||
.send_device_event(DeviceEvent::MouseMotion { delta: (dx, dy) }, DeviceId),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ struct TouchPoint {
|
||||
id: i32,
|
||||
}
|
||||
|
||||
pub(crate) fn implement_touch(
|
||||
pub(crate) fn implement_touch<T: 'static>(
|
||||
seat: &wl_seat::WlSeat,
|
||||
sink: Arc<Mutex<WindowEventsSink>>,
|
||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||
store: Arc<Mutex<WindowStore>>,
|
||||
) -> WlTouch {
|
||||
let mut pending_ids = Vec::new();
|
||||
@@ -32,7 +32,7 @@ pub(crate) fn implement_touch(
|
||||
} => {
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -49,12 +49,12 @@ pub(crate) fn implement_touch(
|
||||
id,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
TouchEvent::Up { id, .. } => {
|
||||
let idx = pending_ids.iter().position(|p| p.id == id);
|
||||
if let Some(idx) = idx {
|
||||
let pt = pending_ids.remove(idx);
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -66,12 +66,12 @@ pub(crate) fn implement_touch(
|
||||
pt.wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
TouchEvent::Motion { id, x, y, .. } => {
|
||||
let pt = pending_ids.iter_mut().find(|p| p.id == id);
|
||||
if let Some(pt) = pt {
|
||||
pt.location = (x, y);
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -83,11 +83,11 @@ pub(crate) fn implement_touch(
|
||||
pt.wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
TouchEvent::Frame => (),
|
||||
TouchEvent::Cancel => {
|
||||
for pt in pending_ids.drain(..) {
|
||||
sink.send_event(
|
||||
sink.send_window_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
@@ -99,7 +99,7 @@ pub(crate) fn implement_touch(
|
||||
pt.wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
io::{Seek, SeekFrom, Write},
|
||||
sync::{Arc, Mutex, Weak},
|
||||
};
|
||||
|
||||
@@ -18,8 +17,8 @@ use crate::{
|
||||
use smithay_client_toolkit::{
|
||||
output::OutputMgr,
|
||||
reexports::client::{
|
||||
protocol::{wl_seat, wl_shm, wl_subsurface, wl_surface},
|
||||
Display, NewProxy,
|
||||
protocol::{wl_seat, wl_surface},
|
||||
Display,
|
||||
},
|
||||
surface::{get_dpi_factor, get_outputs},
|
||||
window::{ConceptFrame, Event as WEvent, State as WState, Theme, Window as SWindow},
|
||||
@@ -29,9 +28,7 @@ use super::{make_wid, EventLoopWindowTarget, MonitorHandle, WindowId};
|
||||
use crate::platform_impl::platform::wayland::event_loop::{available_monitors, primary_monitor};
|
||||
|
||||
pub struct Window {
|
||||
_bg_surface: wl_surface::WlSurface,
|
||||
user_surface: wl_surface::WlSurface,
|
||||
_user_subsurface: wl_subsurface::WlSubsurface,
|
||||
surface: wl_surface::WlSurface,
|
||||
frame: Arc<Mutex<SWindow<ConceptFrame>>>,
|
||||
outputs: OutputMgr, // Access to info for all monitors
|
||||
size: Arc<Mutex<(u32, u32)>>,
|
||||
@@ -54,78 +51,49 @@ impl Window {
|
||||
let fullscreen = Arc::new(Mutex::new(false));
|
||||
|
||||
let window_store = evlp.store.clone();
|
||||
let bg_surface = evlp
|
||||
.env
|
||||
.compositor
|
||||
.create_surface(NewProxy::implement_dummy)
|
||||
.unwrap();
|
||||
let user_surface = evlp.env.create_surface(move |dpi, surface| {
|
||||
let surface = evlp.env.create_surface(move |dpi, surface| {
|
||||
window_store.lock().unwrap().dpi_change(&surface, dpi);
|
||||
surface.set_buffer_scale(dpi);
|
||||
});
|
||||
let user_subsurface = evlp
|
||||
.env
|
||||
.subcompositor
|
||||
.get_subsurface(&user_surface, &bg_surface, NewProxy::implement_dummy)
|
||||
.unwrap();
|
||||
user_subsurface.set_desync();
|
||||
|
||||
let window_store = evlp.store.clone();
|
||||
let my_surface = user_surface.clone();
|
||||
let my_bg_surface = bg_surface.clone();
|
||||
|
||||
// prepare a 1px buffer to display on the root window
|
||||
let mut pool = smithay_client_toolkit::utils::MemPool::new(&evlp.env.shm, || {}).unwrap();
|
||||
pool.resize(4).unwrap();
|
||||
pool.seek(SeekFrom::Start(0)).unwrap();
|
||||
pool.write(&[0, 0, 0, 0]).unwrap();
|
||||
pool.flush().unwrap();
|
||||
let buffer = pool.buffer(0, 1, 1, 4, wl_shm::Format::Argb8888);
|
||||
|
||||
let my_surface = surface.clone();
|
||||
let mut frame = SWindow::<ConceptFrame>::init_from_env(
|
||||
&evlp.env,
|
||||
bg_surface.clone(),
|
||||
surface.clone(),
|
||||
(width, height),
|
||||
move |event| {
|
||||
match event {
|
||||
WEvent::Configure { new_size, states } => {
|
||||
let mut store = window_store.lock().unwrap();
|
||||
let is_fullscreen = states.contains(&WState::Fullscreen);
|
||||
move |event| match event {
|
||||
WEvent::Configure { new_size, states } => {
|
||||
let mut store = window_store.lock().unwrap();
|
||||
let is_fullscreen = states.contains(&WState::Fullscreen);
|
||||
|
||||
for window in &mut store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
window.newsize = new_size;
|
||||
*(window.need_refresh.lock().unwrap()) = true;
|
||||
*(window.fullscreen.lock().unwrap()) = is_fullscreen;
|
||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||
if !window.configured {
|
||||
// this is our first configure event, display ourselves !
|
||||
window.configured = true;
|
||||
my_bg_surface.attach(Some(&buffer), 0, 0);
|
||||
my_bg_surface.commit();
|
||||
}
|
||||
return;
|
||||
}
|
||||
for window in &mut store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
window.newsize = new_size;
|
||||
*(window.need_refresh.lock().unwrap()) = true;
|
||||
*(window.fullscreen.lock().unwrap()) = is_fullscreen;
|
||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||
return;
|
||||
}
|
||||
},
|
||||
WEvent::Refresh => {
|
||||
let store = window_store.lock().unwrap();
|
||||
for window in &store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
WEvent::Refresh => {
|
||||
let store = window_store.lock().unwrap();
|
||||
for window in &store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||
return;
|
||||
}
|
||||
},
|
||||
WEvent::Close => {
|
||||
let mut store = window_store.lock().unwrap();
|
||||
for window in &mut store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
window.closed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
WEvent::Close => {
|
||||
let mut store = window_store.lock().unwrap();
|
||||
for window in &mut store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
window.closed = true;
|
||||
return;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -173,19 +141,17 @@ impl Window {
|
||||
need_refresh: need_refresh.clone(),
|
||||
fullscreen: fullscreen.clone(),
|
||||
need_frame_refresh: need_frame_refresh.clone(),
|
||||
surface: user_surface.clone(),
|
||||
surface: surface.clone(),
|
||||
kill_switch: kill_switch.clone(),
|
||||
frame: Arc::downgrade(&frame),
|
||||
current_dpi: 1,
|
||||
new_dpi: None,
|
||||
configured: false,
|
||||
});
|
||||
evlp.evq.borrow_mut().sync_roundtrip().unwrap();
|
||||
|
||||
Ok(Window {
|
||||
display: evlp.display.clone(),
|
||||
_bg_surface: bg_surface,
|
||||
user_surface,
|
||||
_user_subsurface: user_subsurface,
|
||||
surface,
|
||||
frame,
|
||||
outputs: evlp.env.outputs.clone(),
|
||||
size,
|
||||
@@ -198,7 +164,7 @@ impl Window {
|
||||
|
||||
#[inline]
|
||||
pub fn id(&self) -> WindowId {
|
||||
make_wid(&self.user_surface)
|
||||
make_wid(&self.surface)
|
||||
}
|
||||
|
||||
pub fn set_title(&self, title: &str) {
|
||||
@@ -270,7 +236,7 @@ impl Window {
|
||||
|
||||
#[inline]
|
||||
pub fn hidpi_factor(&self) -> i32 {
|
||||
get_dpi_factor(&self.user_surface)
|
||||
get_dpi_factor(&self.surface)
|
||||
}
|
||||
|
||||
pub fn set_decorations(&self, decorate: bool) {
|
||||
@@ -337,11 +303,11 @@ impl Window {
|
||||
}
|
||||
|
||||
pub fn surface(&self) -> &wl_surface::WlSurface {
|
||||
&self.user_surface
|
||||
&self.surface
|
||||
}
|
||||
|
||||
pub fn current_monitor(&self) -> MonitorHandle {
|
||||
let output = get_outputs(&self.user_surface).last().unwrap().clone();
|
||||
let output = get_outputs(&self.surface).last().unwrap().clone();
|
||||
MonitorHandle {
|
||||
proxy: output,
|
||||
mgr: self.outputs.clone(),
|
||||
@@ -380,7 +346,6 @@ struct InternalWindow {
|
||||
frame: Weak<Mutex<SWindow<ConceptFrame>>>,
|
||||
current_dpi: i32,
|
||||
new_dpi: Option<i32>,
|
||||
configured: bool,
|
||||
}
|
||||
|
||||
pub struct WindowStore {
|
||||
|
||||
@@ -118,7 +118,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
wt.xconn
|
||||
.check_errors()
|
||||
.expect("Failed to call XRefreshKeyboardMapping");
|
||||
},
|
||||
}
|
||||
|
||||
ffi::ClientMessage => {
|
||||
let client_msg: &ffi::XClientMessageEvent = xev.as_ref();
|
||||
@@ -131,6 +131,16 @@ impl<T: 'static> EventProcessor<T> {
|
||||
window_id,
|
||||
event: WindowEvent::CloseRequested,
|
||||
});
|
||||
} else if client_msg.data.get_long(0) as ffi::Atom == wt.net_wm_ping {
|
||||
let response_msg: &mut ffi::XClientMessageEvent = xev.as_mut();
|
||||
response_msg.window = wt.root;
|
||||
wt.xconn
|
||||
.send_event(
|
||||
wt.root,
|
||||
Some(ffi::SubstructureNotifyMask | ffi::SubstructureRedirectMask),
|
||||
*response_msg,
|
||||
)
|
||||
.queue();
|
||||
} else if client_msg.message_type == self.dnd.atoms.enter {
|
||||
let source_window = client_msg.data.get_long(0) as c_ulong;
|
||||
let flags = client_msg.data.get_long(1);
|
||||
@@ -236,7 +246,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
event: WindowEvent::HoveredFileCancelled,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ffi::SelectionNotify => {
|
||||
let xsel: &ffi::XSelectionEvent = xev.as_ref();
|
||||
@@ -263,7 +273,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
|
||||
self.dnd.result = result;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ffi::ConfigureNotify => {
|
||||
#[derive(Debug, Default)]
|
||||
@@ -429,7 +439,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
callback(Event::WindowEvent { window_id, event });
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ffi::ReparentNotify => {
|
||||
let xev: &ffi::XReparentEvent = xev.as_ref();
|
||||
@@ -444,7 +454,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
self.with_window(xev.window, |window| {
|
||||
window.invalidate_cached_frame_extents();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
ffi::DestroyNotify => {
|
||||
let xev: &ffi::XDestroyWindowEvent = xev.as_ref();
|
||||
@@ -467,7 +477,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
window_id,
|
||||
event: WindowEvent::Destroyed,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
ffi::Expose => {
|
||||
let xev: &ffi::XExposeEvent = xev.as_ref();
|
||||
@@ -479,7 +489,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
window_id,
|
||||
event: WindowEvent::RedrawRequested,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
ffi::KeyPress | ffi::KeyRelease => {
|
||||
use crate::event::ElementState::{Pressed, Released};
|
||||
@@ -554,7 +564,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
callback(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ffi::GenericEvent => {
|
||||
let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) {
|
||||
@@ -596,39 +606,33 @@ impl<T: 'static> EventProcessor<T> {
|
||||
Released
|
||||
};
|
||||
match xev.detail as u32 {
|
||||
ffi::Button1 => {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Left,
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
ffi::Button2 => {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Middle,
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
ffi::Button3 => {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Right,
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
ffi::Button1 => callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Left,
|
||||
modifiers,
|
||||
},
|
||||
}),
|
||||
ffi::Button2 => callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Middle,
|
||||
modifiers,
|
||||
},
|
||||
}),
|
||||
ffi::Button3 => callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Right,
|
||||
modifiers,
|
||||
},
|
||||
}),
|
||||
|
||||
// Suppress emulated scroll wheel clicks, since we handle the real motion events for those.
|
||||
// In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in
|
||||
@@ -651,21 +655,19 @@ impl<T: 'static> EventProcessor<T> {
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
x => {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Other(x as u8),
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
x => callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Other(x as u8),
|
||||
modifiers,
|
||||
},
|
||||
}),
|
||||
}
|
||||
},
|
||||
}
|
||||
ffi::XI_Motion => {
|
||||
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
||||
let device_id = mkdid(xev.deviceid);
|
||||
@@ -734,11 +736,11 @@ impl<T: 'static> EventProcessor<T> {
|
||||
delta: match info.orientation {
|
||||
ScrollOrientation::Horizontal => {
|
||||
LineDelta(delta as f32, 0.0)
|
||||
},
|
||||
}
|
||||
// X11 vertical scroll coordinates are opposite to winit's
|
||||
ScrollOrientation::Vertical => {
|
||||
LineDelta(0.0, -delta as f32)
|
||||
},
|
||||
}
|
||||
},
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers,
|
||||
@@ -761,7 +763,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
for event in events {
|
||||
callback(event);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ffi::XI_Enter => {
|
||||
let xev: &ffi::XIEnterEvent = unsafe { &*(xev.data as *const _) };
|
||||
@@ -821,7 +823,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
ffi::XI_Leave => {
|
||||
let xev: &ffi::XILeaveEvent = unsafe { &*(xev.data as *const _) };
|
||||
|
||||
@@ -836,7 +838,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
ffi::XI_FocusIn => {
|
||||
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
||||
|
||||
@@ -878,7 +880,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
modifiers: ModifiersState::from(xev.mods),
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
ffi::XI_FocusOut => {
|
||||
let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
|
||||
if !self.window_exists(xev.event) {
|
||||
@@ -892,7 +894,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
window_id: mkwid(xev.event),
|
||||
event: Focused(false),
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
ffi::XI_TouchBegin | ffi::XI_TouchUpdate | ffi::XI_TouchEnd => {
|
||||
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
||||
@@ -920,7 +922,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
}),
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ffi::XI_RawButtonPress | ffi::XI_RawButtonRelease => {
|
||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||
@@ -937,7 +939,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ffi::XI_RawMotion => {
|
||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||
@@ -962,7 +964,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
1 => mouse_delta.1 = x,
|
||||
2 => scroll_delta.0 = x as f32,
|
||||
3 => scroll_delta.1 = x as f32,
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
callback(Event::DeviceEvent {
|
||||
device_id: did,
|
||||
@@ -988,7 +990,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
|
||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||
@@ -1033,7 +1035,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||
modifiers: ModifiersState::default(),
|
||||
}),
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
ffi::XI_HierarchyChanged => {
|
||||
let xev: &ffi::XIHierarchyEvent = unsafe { &*(xev.data as *const _) };
|
||||
@@ -1056,11 +1058,11 @@ impl<T: 'static> EventProcessor<T> {
|
||||
devices.remove(&DeviceId(info.deviceid));
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
if event_type == self.randr_event_offset {
|
||||
// In the future, it would be quite easy to emit monitor hotplug events.
|
||||
@@ -1101,13 +1103,13 @@ impl<T: 'static> EventProcessor<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
match self.ime_receiver.try_recv() {
|
||||
Ok((window_id, x, y)) => {
|
||||
wt.ime.borrow_mut().send_xim_spot(window_id, x, y);
|
||||
},
|
||||
}
|
||||
Err(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ use crate::{
|
||||
pub struct EventLoopWindowTarget<T> {
|
||||
xconn: Arc<XConnection>,
|
||||
wm_delete_window: ffi::Atom,
|
||||
net_wm_ping: ffi::Atom,
|
||||
ime_sender: ImeSender,
|
||||
root: ffi::Window,
|
||||
ime: RefCell<Ime>,
|
||||
@@ -75,6 +76,8 @@ impl<T: 'static> EventLoop<T> {
|
||||
|
||||
let wm_delete_window = unsafe { xconn.get_atom_unchecked(b"WM_DELETE_WINDOW\0") };
|
||||
|
||||
let net_wm_ping = unsafe { xconn.get_atom_unchecked(b"_NET_WM_PING\0") };
|
||||
|
||||
let dnd = Dnd::new(Arc::clone(&xconn))
|
||||
.expect("Failed to call XInternAtoms when initializing drag and drop");
|
||||
|
||||
@@ -142,6 +145,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
ime_sender,
|
||||
xconn,
|
||||
wm_delete_window,
|
||||
net_wm_ping,
|
||||
pending_redraws: Default::default(),
|
||||
}),
|
||||
_marker: ::std::marker::PhantomData,
|
||||
@@ -291,11 +295,6 @@ impl<T: 'static> EventLoop<T> {
|
||||
);
|
||||
}
|
||||
|
||||
// flush the X11 connection
|
||||
unsafe {
|
||||
(wt.xconn.xlib.XFlush)(wt.xconn.display);
|
||||
}
|
||||
|
||||
match control_flow {
|
||||
ControlFlow::Exit => break,
|
||||
ControlFlow::Poll => {
|
||||
@@ -308,7 +307,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
&self.target,
|
||||
&mut control_flow,
|
||||
);
|
||||
},
|
||||
}
|
||||
ControlFlow::Wait => {
|
||||
self.inner_loop.dispatch(None, &mut ()).unwrap();
|
||||
callback(
|
||||
@@ -319,7 +318,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
&self.target,
|
||||
&mut control_flow,
|
||||
);
|
||||
},
|
||||
}
|
||||
ControlFlow::WaitUntil(deadline) => {
|
||||
let start = ::std::time::Instant::now();
|
||||
// compute the blocking duration
|
||||
@@ -353,7 +352,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,8 +587,8 @@ impl Device {
|
||||
position: 0.0,
|
||||
},
|
||||
));
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,8 +618,8 @@ impl Device {
|
||||
{
|
||||
axis.position = info.value;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub const MWM_HINTS_DECORATIONS: c_ulong = 2;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StateOperation {
|
||||
Remove = 0, // _NET_WM_STATE_REMOVE
|
||||
@@ -93,6 +92,92 @@ impl WindowType {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MotifHints {
|
||||
hints: MwmHints,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct MwmHints {
|
||||
flags: c_ulong,
|
||||
functions: c_ulong,
|
||||
decorations: c_ulong,
|
||||
input_mode: c_long,
|
||||
status: c_ulong,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod mwm {
|
||||
use libc::c_ulong;
|
||||
|
||||
// Motif WM hints are obsolete, but still widely supported.
|
||||
// https://stackoverflow.com/a/1909708
|
||||
pub const MWM_HINTS_FUNCTIONS: c_ulong = 1 << 0;
|
||||
pub const MWM_HINTS_DECORATIONS: c_ulong = 1 << 1;
|
||||
|
||||
pub const MWM_FUNC_ALL: c_ulong = 1 << 0;
|
||||
pub const MWM_FUNC_RESIZE: c_ulong = 1 << 1;
|
||||
pub const MWM_FUNC_MOVE: c_ulong = 1 << 2;
|
||||
pub const MWM_FUNC_MINIMIZE: c_ulong = 1 << 3;
|
||||
pub const MWM_FUNC_MAXIMIZE: c_ulong = 1 << 4;
|
||||
pub const MWM_FUNC_CLOSE: c_ulong = 1 << 5;
|
||||
}
|
||||
|
||||
impl MotifHints {
|
||||
pub fn new() -> MotifHints {
|
||||
MotifHints {
|
||||
hints: MwmHints {
|
||||
flags: 0,
|
||||
functions: 0,
|
||||
decorations: 0,
|
||||
input_mode: 0,
|
||||
status: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_decorations(&mut self, decorations: bool) {
|
||||
self.hints.flags |= mwm::MWM_HINTS_DECORATIONS;
|
||||
self.hints.decorations = decorations as c_ulong;
|
||||
}
|
||||
|
||||
pub fn set_maximizable(&mut self, maximizable: bool) {
|
||||
if maximizable {
|
||||
self.add_func(mwm::MWM_FUNC_MAXIMIZE);
|
||||
} else {
|
||||
self.remove_func(mwm::MWM_FUNC_MAXIMIZE);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_func(&mut self, func: c_ulong) {
|
||||
if self.hints.flags & mwm::MWM_HINTS_FUNCTIONS != 0 {
|
||||
if self.hints.functions & mwm::MWM_FUNC_ALL != 0 {
|
||||
self.hints.functions &= !func;
|
||||
} else {
|
||||
self.hints.functions |= func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_func(&mut self, func: c_ulong) {
|
||||
if self.hints.flags & mwm::MWM_HINTS_FUNCTIONS == 0 {
|
||||
self.hints.flags |= mwm::MWM_HINTS_FUNCTIONS;
|
||||
self.hints.functions = mwm::MWM_FUNC_ALL;
|
||||
}
|
||||
|
||||
if self.hints.functions & mwm::MWM_FUNC_ALL != 0 {
|
||||
self.hints.functions |= func;
|
||||
} else {
|
||||
self.hints.functions &= !func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MwmHints {
|
||||
fn as_slice(&self) -> &[c_ulong] {
|
||||
unsafe { slice::from_raw_parts(self as *const _ as *const c_ulong, 5) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NormalHints<'a> {
|
||||
size_hints: XSmartPointer<'a, ffi::XSizeHints>,
|
||||
}
|
||||
@@ -254,4 +339,32 @@ impl XConnection {
|
||||
}
|
||||
Flusher::new(self)
|
||||
}
|
||||
|
||||
pub fn get_motif_hints(&self, window: ffi::Window) -> MotifHints {
|
||||
let motif_hints = unsafe { self.get_atom_unchecked(b"_MOTIF_WM_HINTS\0") };
|
||||
|
||||
let mut hints = MotifHints::new();
|
||||
|
||||
if let Ok(props) = self.get_property::<c_ulong>(window, motif_hints, motif_hints) {
|
||||
hints.hints.flags = props.get(0).cloned().unwrap_or(0);
|
||||
hints.hints.functions = props.get(1).cloned().unwrap_or(0);
|
||||
hints.hints.decorations = props.get(2).cloned().unwrap_or(0);
|
||||
hints.hints.input_mode = props.get(3).cloned().unwrap_or(0) as c_long;
|
||||
hints.hints.status = props.get(4).cloned().unwrap_or(0);
|
||||
}
|
||||
|
||||
hints
|
||||
}
|
||||
|
||||
pub fn set_motif_hints(&self, window: ffi::Window, hints: &MotifHints) -> Flusher<'_> {
|
||||
let motif_hints = unsafe { self.get_atom_unchecked(b"_MOTIF_WM_HINTS\0") };
|
||||
|
||||
self.change_property(
|
||||
window,
|
||||
motif_hints,
|
||||
motif_hints,
|
||||
PropMode::Replace,
|
||||
hints.hints.as_slice(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ pub fn calc_dpi_factor(
|
||||
}
|
||||
|
||||
// See http://xpra.org/trac/ticket/728 for more information.
|
||||
if width_mm == 0 || width_mm == 0 {
|
||||
if width_mm == 0 || height_mm == 0 {
|
||||
warn!("XRandR reported that the display's 0mm in size, which is certifiably insane");
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
@@ -330,8 +330,9 @@ impl UnownedWindow {
|
||||
(xconn.xlib.XSetWMProtocols)(
|
||||
xconn.display,
|
||||
window.xwindow,
|
||||
&event_loop.wm_delete_window as *const ffi::Atom as *mut ffi::Atom,
|
||||
1,
|
||||
&[event_loop.wm_delete_window, event_loop.net_wm_ping] as *const ffi::Atom
|
||||
as *mut ffi::Atom,
|
||||
2,
|
||||
);
|
||||
} //.queue();
|
||||
|
||||
@@ -384,7 +385,7 @@ impl UnownedWindow {
|
||||
ImeContextCreationError::XError(err) => OsError::XError(err),
|
||||
ImeContextCreationError::Null => {
|
||||
OsError::XMisc("IME Context creation failed")
|
||||
},
|
||||
}
|
||||
};
|
||||
return Err(os_error!(e));
|
||||
}
|
||||
@@ -558,7 +559,7 @@ impl UnownedWindow {
|
||||
self.set_position_inner(position.0, position.1).queue();
|
||||
}
|
||||
flusher
|
||||
},
|
||||
}
|
||||
Some(RootMonitorHandle {
|
||||
inner: PlatformMonitorHandle::X(monitor),
|
||||
}) => {
|
||||
@@ -568,7 +569,7 @@ impl UnownedWindow {
|
||||
self.set_position_inner(monitor_origin.0, monitor_origin.1)
|
||||
.queue();
|
||||
self.set_fullscreen_hint(true)
|
||||
},
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -666,20 +667,11 @@ impl UnownedWindow {
|
||||
}
|
||||
|
||||
fn set_decorations_inner(&self, decorations: bool) -> util::Flusher<'_> {
|
||||
let wm_hints = unsafe { self.xconn.get_atom_unchecked(b"_MOTIF_WM_HINTS\0") };
|
||||
self.xconn.change_property(
|
||||
self.xwindow,
|
||||
wm_hints,
|
||||
wm_hints,
|
||||
util::PropMode::Replace,
|
||||
&[
|
||||
util::MWM_HINTS_DECORATIONS, // flags
|
||||
0, // functions
|
||||
decorations as c_ulong, // decorations
|
||||
0, // input mode
|
||||
0, // status
|
||||
],
|
||||
)
|
||||
let mut hints = self.xconn.get_motif_hints(self.xwindow);
|
||||
|
||||
hints.set_decorations(decorations);
|
||||
|
||||
self.xconn.set_motif_hints(self.xwindow, &hints)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -690,6 +682,14 @@ impl UnownedWindow {
|
||||
self.invalidate_cached_frame_extents();
|
||||
}
|
||||
|
||||
fn set_maximizable_inner(&self, maximizable: bool) -> util::Flusher<'_> {
|
||||
let mut hints = self.xconn.get_motif_hints(self.xwindow);
|
||||
|
||||
hints.set_maximizable(maximizable);
|
||||
|
||||
self.xconn.set_motif_hints(self.xwindow, &hints)
|
||||
}
|
||||
|
||||
fn set_always_on_top_inner(&self, always_on_top: bool) -> util::Flusher<'_> {
|
||||
let above_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_ABOVE\0") };
|
||||
self.set_netwm(always_on_top.into(), (above_atom as c_long, 0, 0, 0))
|
||||
@@ -984,6 +984,8 @@ impl UnownedWindow {
|
||||
(window_size.clone(), window_size)
|
||||
};
|
||||
|
||||
self.set_maximizable_inner(resizable).queue();
|
||||
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
let min_inner_size = logical_min
|
||||
.map(|logical_size| logical_size.to_physical(dpi_factor))
|
||||
@@ -1190,11 +1192,11 @@ impl UnownedWindow {
|
||||
ffi::GrabSuccess => Ok(()),
|
||||
ffi::AlreadyGrabbed => {
|
||||
Err("Cursor could not be grabbed: already grabbed by another client")
|
||||
},
|
||||
}
|
||||
ffi::GrabInvalidTime => Err("Cursor could not be grabbed: invalid time"),
|
||||
ffi::GrabNotViewable => {
|
||||
Err("Cursor could not be grabbed: grab location not viewable")
|
||||
},
|
||||
}
|
||||
ffi::GrabFrozen => Err("Cursor could not be grabbed: frozen by another client"),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use objc::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
event::{DeviceEvent, Event},
|
||||
event::{DeviceEvent, ElementState, Event},
|
||||
platform_impl::platform::{app_state::AppState, util, DEVICE_ID},
|
||||
};
|
||||
|
||||
@@ -100,7 +100,33 @@ unsafe fn maybe_dispatch_device_event(event: id) {
|
||||
}
|
||||
|
||||
AppState::queue_events(events);
|
||||
},
|
||||
}
|
||||
appkit::NSLeftMouseDown | appkit::NSRightMouseDown | appkit::NSOtherMouseDown => {
|
||||
let mut events = VecDeque::with_capacity(1);
|
||||
|
||||
events.push_back(Event::DeviceEvent {
|
||||
device_id: DEVICE_ID,
|
||||
event: DeviceEvent::Button {
|
||||
button: event.buttonNumber() as u32,
|
||||
state: ElementState::Pressed,
|
||||
},
|
||||
});
|
||||
|
||||
AppState::queue_events(events);
|
||||
}
|
||||
appkit::NSLeftMouseUp | appkit::NSRightMouseUp | appkit::NSOtherMouseUp => {
|
||||
let mut events = VecDeque::with_capacity(1);
|
||||
|
||||
events.push_back(Event::DeviceEvent {
|
||||
device_id: DEVICE_ID,
|
||||
event: DeviceEvent::Button {
|
||||
button: event.buttonNumber() as u32,
|
||||
state: ElementState::Released,
|
||||
},
|
||||
});
|
||||
|
||||
AppState::queue_events(events);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ extern "C" fn did_finish_launching(_: &Object, _: Sel, _: id) -> BOOL {
|
||||
extern "C" fn did_become_active(_: &Object, _: Sel, _: id) {
|
||||
trace!("Triggered `didBecomeActive`");
|
||||
/*unsafe {
|
||||
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(false))
|
||||
HANDLER.lock().unwrap().handle_nonuser_event(Event::Resumed)
|
||||
}*/
|
||||
trace!("Completed `didBecomeActive`");
|
||||
}
|
||||
@@ -62,7 +62,7 @@ extern "C" fn did_become_active(_: &Object, _: Sel, _: id) {
|
||||
extern "C" fn will_resign_active(_: &Object, _: Sel, _: id) {
|
||||
trace!("Triggered `willResignActive`");
|
||||
/*unsafe {
|
||||
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(true))
|
||||
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended)
|
||||
}*/
|
||||
trace!("Completed `willResignActive`");
|
||||
}
|
||||
|
||||
@@ -213,11 +213,9 @@ impl AppState {
|
||||
let start = HANDLER.get_start_time().unwrap();
|
||||
let cause = match HANDLER.get_control_flow_and_update_prev() {
|
||||
ControlFlow::Poll => StartCause::Poll,
|
||||
ControlFlow::Wait => {
|
||||
StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: None,
|
||||
}
|
||||
ControlFlow::Wait => StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: None,
|
||||
},
|
||||
ControlFlow::WaitUntil(requested_resume) => {
|
||||
if Instant::now() >= requested_resume {
|
||||
@@ -231,7 +229,7 @@ impl AppState {
|
||||
requested_resume: Some(requested_resume),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
ControlFlow::Exit => StartCause::Poll, //panic!("unexpected `ControlFlow::Exit`"),
|
||||
};
|
||||
HANDLER.set_in_callback(true);
|
||||
|
||||
@@ -121,7 +121,7 @@ extern "C" fn control_flow_begin_handler(
|
||||
//trace!("Triggered `CFRunLoopAfterWaiting`");
|
||||
AppState::wakeup();
|
||||
//trace!("Completed `CFRunLoopAfterWaiting`");
|
||||
},
|
||||
}
|
||||
kCFRunLoopEntry => unimplemented!(), // not expected to ever happen
|
||||
_ => unreachable!(),
|
||||
}
|
||||
@@ -140,7 +140,7 @@ extern "C" fn control_flow_end_handler(
|
||||
//trace!("Triggered `CFRunLoopBeforeWaiting`");
|
||||
AppState::cleared();
|
||||
//trace!("Completed `CFRunLoopBeforeWaiting`");
|
||||
},
|
||||
}
|
||||
kCFRunLoopExit => (), //unimplemented!(), // not expected to ever happen
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ impl From<CursorIcon> for Cursor {
|
||||
CursorIcon::Alias => Cursor::Native("dragLinkCursor"),
|
||||
CursorIcon::NotAllowed | CursorIcon::NoDrop => {
|
||||
Cursor::Native("operationNotAllowedCursor")
|
||||
},
|
||||
}
|
||||
CursorIcon::ContextMenu => Cursor::Native("contextualMenuCursor"),
|
||||
CursorIcon::Crosshair => Cursor::Native("crosshairCursor"),
|
||||
CursorIcon::EResize => Cursor::Native("resizeRightCursor"),
|
||||
@@ -57,7 +57,7 @@ impl From<CursorIcon> for Cursor {
|
||||
// what's used in Safari and Chrome.
|
||||
CursorIcon::Wait | CursorIcon::Progress => {
|
||||
Cursor::Undocumented("busyButClickableCursor")
|
||||
},
|
||||
}
|
||||
|
||||
// For the rest, we can just snatch the cursors from WebKit...
|
||||
// They fit the style of the native cursors, and will seem
|
||||
@@ -81,7 +81,7 @@ impl Cursor {
|
||||
Cursor::Native(cursor_name) => {
|
||||
let sel = Sel::register(cursor_name);
|
||||
msg_send![class!(NSCursor), performSelector: sel]
|
||||
},
|
||||
}
|
||||
Cursor::Undocumented(cursor_name) => {
|
||||
let class = class!(NSCursor);
|
||||
let sel = Sel::register(cursor_name);
|
||||
@@ -92,7 +92,7 @@ impl Cursor {
|
||||
sel!(arrowCursor)
|
||||
};
|
||||
msg_send![class, performSelector: sel]
|
||||
},
|
||||
}
|
||||
Cursor::WebKit(cursor_name) => load_webkit_cursor(cursor_name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
use cocoa::base::{id, nil};
|
||||
|
||||
pub trait IntoOption: Sized {
|
||||
fn into_option(self) -> Option<Self>;
|
||||
}
|
||||
|
||||
impl IntoOption for id {
|
||||
fn into_option(self) -> Option<Self> {
|
||||
match self != nil {
|
||||
true => Some(self),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -900,7 +900,7 @@ extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) {
|
||||
let phase = match event.phase() {
|
||||
NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => {
|
||||
TouchPhase::Started
|
||||
},
|
||||
}
|
||||
NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended,
|
||||
_ => TouchPhase::Moved,
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::{
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
icon::Icon,
|
||||
monitor::MonitorHandle as RootMonitorHandle,
|
||||
platform::macos::{ActivationPolicy, WindowExtMacOS},
|
||||
platform::macos::{ActivationPolicy, RequestUserAttentionType, WindowExtMacOS},
|
||||
platform_impl::platform::{
|
||||
app_state::AppState,
|
||||
ffi,
|
||||
@@ -116,7 +116,7 @@ fn create_window(
|
||||
Some(ref monitor_id) => {
|
||||
let monitor_screen = monitor_id.inner.ns_screen();
|
||||
Some(monitor_screen.unwrap_or(appkit::NSScreen::mainScreen(nil)))
|
||||
},
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let frame = match screen {
|
||||
@@ -127,7 +127,7 @@ fn create_window(
|
||||
.map(|logical| (logical.width, logical.height))
|
||||
.unwrap_or_else(|| (800.0, 600.0));
|
||||
NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(width, height))
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let mut masks = if !attrs.decorations && !screen.is_some() {
|
||||
@@ -649,7 +649,7 @@ impl UnownedWindow {
|
||||
// Our best bet is probably to move to the origin of the
|
||||
// target monitor.
|
||||
unimplemented!()
|
||||
},
|
||||
}
|
||||
(&None, None) | (&Some(_), Some(_)) => return,
|
||||
_ => (),
|
||||
}
|
||||
@@ -778,11 +778,13 @@ impl WindowExtMacOS for UnownedWindow {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn request_user_attention(&self, is_critical: bool) {
|
||||
fn request_user_attention(&self, request_type: RequestUserAttentionType) {
|
||||
unsafe {
|
||||
NSApp().requestUserAttention_(match is_critical {
|
||||
true => NSRequestUserAttentionType::NSCriticalRequest,
|
||||
false => NSRequestUserAttentionType::NSInformationalRequest,
|
||||
NSApp().requestUserAttention_(match request_type {
|
||||
RequestUserAttentionType::Critical => NSRequestUserAttentionType::NSCriticalRequest,
|
||||
RequestUserAttentionType::Informational => {
|
||||
NSRequestUserAttentionType::NSInformationalRequest
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#![allow(non_snake_case, unused_unsafe)]
|
||||
|
||||
use std::{
|
||||
mem,
|
||||
os::raw::c_void,
|
||||
sync::{Once, ONCE_INIT},
|
||||
};
|
||||
use std::{mem, os::raw::c_void, sync::Once};
|
||||
|
||||
use winapi::{
|
||||
shared::{
|
||||
@@ -79,7 +75,7 @@ pub fn become_dpi_aware(enable: bool) {
|
||||
if !enable {
|
||||
return;
|
||||
}
|
||||
static ENABLE_DPI_AWARENESS: Once = ONCE_INIT;
|
||||
static ENABLE_DPI_AWARENESS: Once = Once::new();
|
||||
ENABLE_DPI_AWARENESS.call_once(|| {
|
||||
unsafe {
|
||||
if let Some(SetProcessDpiAwarenessContext) =
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
mem,
|
||||
os::windows::ffi::OsStringExt,
|
||||
path::PathBuf,
|
||||
ptr,
|
||||
@@ -11,7 +10,7 @@ use winapi::{
|
||||
ctypes::c_void,
|
||||
shared::{
|
||||
guiddef::REFIID,
|
||||
minwindef::{DWORD, MAX_PATH, UINT, ULONG},
|
||||
minwindef::{DWORD, UINT, ULONG},
|
||||
windef::{HWND, POINTL},
|
||||
winerror::S_OK,
|
||||
},
|
||||
@@ -171,7 +170,6 @@ impl FileDropHandler {
|
||||
F: Fn(PathBuf),
|
||||
{
|
||||
use winapi::{
|
||||
ctypes::wchar_t,
|
||||
shared::{
|
||||
winerror::{DV_E_FORMATETC, SUCCEEDED},
|
||||
wtypes::{CLIPFORMAT, DVASPECT_CONTENT},
|
||||
@@ -191,7 +189,7 @@ impl FileDropHandler {
|
||||
tymed: TYMED_HGLOBAL,
|
||||
};
|
||||
|
||||
let mut medium = mem::uninitialized();
|
||||
let mut medium = std::mem::zeroed();
|
||||
let get_data_result = (*data_obj).GetData(&mut drop_format, &mut medium);
|
||||
if SUCCEEDED(get_data_result) {
|
||||
let hglobal = (*medium.u).hGlobal();
|
||||
@@ -200,15 +198,19 @@ impl FileDropHandler {
|
||||
// The second parameter (0xFFFFFFFF) instructs the function to return the item count
|
||||
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);
|
||||
|
||||
let mut pathbuf: [wchar_t; MAX_PATH] = mem::uninitialized();
|
||||
|
||||
for i in 0..item_count {
|
||||
let character_count =
|
||||
DragQueryFileW(hdrop, i, pathbuf.as_mut_ptr(), MAX_PATH as UINT) as usize;
|
||||
// Get the length of the path string NOT including the terminating null character.
|
||||
// Previously, this was using a fixed size array of MAX_PATH length, but the
|
||||
// Windows API allows longer paths under certain circumstances.
|
||||
let character_count = DragQueryFileW(hdrop, i, ptr::null_mut(), 0) as usize;
|
||||
let str_len = character_count + 1;
|
||||
|
||||
if character_count > 0 {
|
||||
callback(OsString::from_wide(&pathbuf[0..character_count]).into());
|
||||
}
|
||||
// Fill path_buf with the null-terminated file name
|
||||
let mut path_buf = Vec::with_capacity(str_len);
|
||||
DragQueryFileW(hdrop, i, path_buf.as_mut_ptr(), str_len as UINT);
|
||||
path_buf.set_len(str_len);
|
||||
|
||||
callback(OsString::from_wide(&path_buf[0..character_count]).into());
|
||||
}
|
||||
|
||||
return Some(hdrop);
|
||||
|
||||
@@ -285,14 +285,14 @@ pub fn handle_extended_keys(
|
||||
} else {
|
||||
winuser::VK_LCONTROL
|
||||
}
|
||||
},
|
||||
}
|
||||
winuser::VK_MENU => {
|
||||
if extended {
|
||||
winuser::VK_RMENU
|
||||
} else {
|
||||
winuser::VK_LMENU
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
match scancode {
|
||||
// This is only triggered when using raw input. Without this check, we get two events whenever VK_PAUSE is
|
||||
@@ -308,10 +308,10 @@ pub fn handle_extended_keys(
|
||||
} else {
|
||||
winuser::VK_SCROLL
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => vkey,
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
Some((vkey, scancode))
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
match event {
|
||||
Some(e) => {
|
||||
runner.process_event(e);
|
||||
},
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
@@ -182,7 +182,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut msg = mem::uninitialized();
|
||||
let mut msg = mem::zeroed();
|
||||
let mut msg_unprocessed = false;
|
||||
|
||||
'main: loop {
|
||||
@@ -195,6 +195,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
}
|
||||
winuser::TranslateMessage(&mut msg);
|
||||
winuser::DispatchMessageW(&mut msg);
|
||||
|
||||
msg_unprocessed = false;
|
||||
}
|
||||
runner!().events_cleared();
|
||||
@@ -202,19 +203,21 @@ impl<T: 'static> EventLoop<T> {
|
||||
panic::resume_unwind(payload);
|
||||
}
|
||||
|
||||
let control_flow = runner!().control_flow;
|
||||
match control_flow {
|
||||
ControlFlow::Exit => break 'main,
|
||||
ControlFlow::Wait => {
|
||||
if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
|
||||
break 'main;
|
||||
if !msg_unprocessed {
|
||||
let control_flow = runner!().control_flow;
|
||||
match control_flow {
|
||||
ControlFlow::Exit => break 'main,
|
||||
ControlFlow::Wait => {
|
||||
if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
|
||||
break 'main;
|
||||
}
|
||||
msg_unprocessed = true;
|
||||
}
|
||||
msg_unprocessed = true;
|
||||
},
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
wait_until_time_or_msg(resume_time);
|
||||
},
|
||||
ControlFlow::Poll => (),
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
wait_until_time_or_msg(resume_time);
|
||||
}
|
||||
ControlFlow::Poll => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,6 +256,7 @@ pub(crate) struct EventLoopRunner<T> {
|
||||
runner_state: RunnerState,
|
||||
modal_redraw_window: HWND,
|
||||
in_modal_loop: bool,
|
||||
in_repaint: bool,
|
||||
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||
panic_error: Option<PanicError>,
|
||||
}
|
||||
@@ -316,6 +320,7 @@ impl<T> EventLoopRunner<T> {
|
||||
control_flow: ControlFlow::default(),
|
||||
runner_state: RunnerState::New,
|
||||
in_modal_loop: false,
|
||||
in_repaint: false,
|
||||
modal_redraw_window: event_loop.window_target.p.thread_msg_target,
|
||||
event_handler: mem::transmute::<
|
||||
Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||
@@ -335,7 +340,7 @@ impl<T> EventLoopRunner<T> {
|
||||
RunnerState::New => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::Init));
|
||||
RunnerState::HandlingEvents
|
||||
},
|
||||
}
|
||||
|
||||
// When `NewEvents` gets sent after an idle depends on the control flow...
|
||||
RunnerState::Idle(wait_start) => {
|
||||
@@ -371,7 +376,7 @@ impl<T> EventLoopRunner<T> {
|
||||
// `Exit` shouldn't really ever get sent here, but if it does do something somewhat sane.
|
||||
ControlFlow::Exit => RunnerState::DeferredNewEvents(wait_start),
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -405,27 +410,23 @@ impl<T> EventLoopRunner<T> {
|
||||
start: wait_start,
|
||||
requested_resume: None,
|
||||
}))
|
||||
},
|
||||
}
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
let start_cause = match Instant::now() >= resume_time {
|
||||
// If the current time is later than the requested resume time, the resume time
|
||||
// has been reached.
|
||||
true => {
|
||||
StartCause::ResumeTimeReached {
|
||||
start: wait_start,
|
||||
requested_resume: resume_time,
|
||||
}
|
||||
true => StartCause::ResumeTimeReached {
|
||||
start: wait_start,
|
||||
requested_resume: resume_time,
|
||||
},
|
||||
// Otherwise, the requested resume time HASN'T been reached and we send a WaitCancelled.
|
||||
false => {
|
||||
StartCause::WaitCancelled {
|
||||
start: wait_start,
|
||||
requested_resume: Some(resume_time),
|
||||
}
|
||||
false => StartCause::WaitCancelled {
|
||||
start: wait_start,
|
||||
requested_resume: Some(resume_time),
|
||||
},
|
||||
};
|
||||
self.call_event_handler(Event::NewEvents(start_cause));
|
||||
},
|
||||
}
|
||||
// This can be reached if the control flow is changed to poll during a `RedrawRequested`
|
||||
// that was sent after `EventsCleared`.
|
||||
ControlFlow::Poll => self.call_event_handler(Event::NewEvents(StartCause::Poll)),
|
||||
@@ -433,16 +434,32 @@ impl<T> EventLoopRunner<T> {
|
||||
}
|
||||
|
||||
self.runner_state = RunnerState::HandlingEvents;
|
||||
self.call_event_handler(event);
|
||||
match (self.in_repaint, &event) {
|
||||
(
|
||||
true,
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::RedrawRequested,
|
||||
..
|
||||
},
|
||||
)
|
||||
| (false, _) => self.call_event_handler(event),
|
||||
(true, _) => {
|
||||
self.events_cleared();
|
||||
self.new_events();
|
||||
self.process_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn events_cleared(&mut self) {
|
||||
self.in_repaint = false;
|
||||
|
||||
match self.runner_state {
|
||||
// If we were handling events, send the EventsCleared message.
|
||||
RunnerState::HandlingEvents => {
|
||||
self.call_event_handler(Event::EventsCleared);
|
||||
self.runner_state = RunnerState::Idle(Instant::now());
|
||||
},
|
||||
}
|
||||
|
||||
// If we *weren't* handling events, we don't have to do anything.
|
||||
RunnerState::New | RunnerState::Idle(..) => (),
|
||||
@@ -455,7 +472,7 @@ impl<T> EventLoopRunner<T> {
|
||||
ControlFlow::Poll => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::Poll));
|
||||
self.call_event_handler(Event::EventsCleared);
|
||||
},
|
||||
}
|
||||
// If we had deferred a WaitUntil and the resume time has since been reached,
|
||||
// send the resume notification and EventsCleared event.
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
@@ -468,27 +485,29 @@ impl<T> EventLoopRunner<T> {
|
||||
));
|
||||
self.call_event_handler(Event::EventsCleared);
|
||||
}
|
||||
},
|
||||
}
|
||||
// If we deferred a wait and no events were received, the user doesn't have to
|
||||
// get an event.
|
||||
ControlFlow::Wait | ControlFlow::Exit => (),
|
||||
}
|
||||
// Mark that we've entered an idle state.
|
||||
self.runner_state = RunnerState::Idle(wait_start)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn call_event_handler(&mut self, event: Event<T>) {
|
||||
match event {
|
||||
Event::NewEvents(_) => {
|
||||
self.trigger_newevents_on_redraw
|
||||
.store(true, Ordering::Relaxed)
|
||||
},
|
||||
Event::EventsCleared => {
|
||||
self.trigger_newevents_on_redraw
|
||||
.store(false, Ordering::Relaxed)
|
||||
},
|
||||
Event::NewEvents(_) => self
|
||||
.trigger_newevents_on_redraw
|
||||
.store(true, Ordering::Relaxed),
|
||||
Event::EventsCleared => self
|
||||
.trigger_newevents_on_redraw
|
||||
.store(false, Ordering::Relaxed),
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::RedrawRequested,
|
||||
..
|
||||
} => self.in_repaint = true,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@@ -513,7 +532,7 @@ impl<T> EventLoopRunner<T> {
|
||||
|
||||
// Returns true if the wait time was reached, and false if a message must be processed.
|
||||
unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool {
|
||||
let mut msg = mem::uninitialized();
|
||||
let mut msg = mem::zeroed();
|
||||
let now = Instant::now();
|
||||
if now <= wait_until {
|
||||
// MsgWaitForMultipleObjects tends to overshoot just a little bit. We subtract 1 millisecond
|
||||
@@ -825,18 +844,18 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
runner.in_modal_loop = true;
|
||||
}
|
||||
0
|
||||
},
|
||||
}
|
||||
winuser::WM_EXITSIZEMOVE => {
|
||||
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
||||
if let Some(ref mut runner) = *runner {
|
||||
runner.in_modal_loop = false;
|
||||
}
|
||||
0
|
||||
},
|
||||
}
|
||||
winuser::WM_NCCREATE => {
|
||||
enable_non_client_dpi_scaling(window);
|
||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_NCLBUTTONDOWN => {
|
||||
// jumpstart the modal loop
|
||||
@@ -850,7 +869,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
winuser::PostMessageW(window, winuser::WM_MOUSEMOVE, 0, 0);
|
||||
}
|
||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_CLOSE => {
|
||||
use crate::event::WindowEvent::CloseRequested;
|
||||
@@ -859,7 +878,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
event: CloseRequested,
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_DESTROY => {
|
||||
use crate::event::WindowEvent::Destroyed;
|
||||
@@ -872,17 +891,17 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
Box::from_raw(subclass_input);
|
||||
drop(subclass_input);
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
_ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => {
|
||||
use crate::event::WindowEvent::RedrawRequested;
|
||||
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
||||
subclass_input.window_state.lock().queued_out_of_band_redraw = false;
|
||||
if let Some(ref mut runner) = *runner {
|
||||
// This check makes sure that calls to `request_redraw()` during `EventsCleared`
|
||||
// handling dispatch `RedrawRequested` immediately after `EventsCleared`, without
|
||||
// spinning up a new event loop iteration. We do this because that's what the API
|
||||
// says to do.
|
||||
let control_flow = runner.control_flow;
|
||||
let runner_state = runner.runner_state;
|
||||
let mut request_redraw = || {
|
||||
runner.call_event_handler(Event::WindowEvent {
|
||||
@@ -893,21 +912,18 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
match runner_state {
|
||||
RunnerState::Idle(..) | RunnerState::DeferredNewEvents(..) => request_redraw(),
|
||||
RunnerState::HandlingEvents => {
|
||||
match control_flow {
|
||||
ControlFlow::Poll => request_redraw(),
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
if resume_time <= Instant::now() {
|
||||
request_redraw()
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
winuser::RedrawWindow(
|
||||
window,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
0
|
||||
},
|
||||
}
|
||||
winuser::WM_PAINT => {
|
||||
use crate::event::WindowEvent::RedrawRequested;
|
||||
subclass_input.send_event(Event::WindowEvent {
|
||||
@@ -915,7 +931,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
event: RedrawRequested,
|
||||
});
|
||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||
},
|
||||
}
|
||||
|
||||
// WM_MOVE supplies client area positions, so we send Moved here instead.
|
||||
winuser::WM_WINDOWPOSCHANGED => {
|
||||
@@ -934,7 +950,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
|
||||
// This is necessary for us to still get sent WM_SIZE.
|
||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_SIZE => {
|
||||
use crate::event::WindowEvent::Resized;
|
||||
@@ -962,7 +978,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
|
||||
subclass_input.send_event(event);
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_CHAR => {
|
||||
use crate::event::WindowEvent::ReceivedCharacter;
|
||||
@@ -972,7 +988,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
event: ReceivedCharacter(chr),
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
// Prevents default windows menu hotkeys playing unwanted
|
||||
// "ding" sounds. Alternatively could check for WM_SYSCOMMAND
|
||||
@@ -1024,7 +1040,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
});
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_MOUSELEAVE => {
|
||||
use crate::event::WindowEvent::CursorLeft;
|
||||
@@ -1043,7 +1059,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
});
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_MOUSEWHEEL => {
|
||||
use crate::event::MouseScrollDelta::LineDelta;
|
||||
@@ -1063,7 +1079,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
});
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_MOUSEHWHEEL => {
|
||||
use crate::event::MouseScrollDelta::LineDelta;
|
||||
@@ -1083,7 +1099,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
});
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => {
|
||||
use crate::event::{ElementState::Pressed, VirtualKeyCode};
|
||||
@@ -1114,7 +1130,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
}
|
||||
0
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_KEYUP | winuser::WM_SYSKEYUP => {
|
||||
use crate::event::ElementState::Released;
|
||||
@@ -1133,7 +1149,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
});
|
||||
}
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_LBUTTONDOWN => {
|
||||
use crate::event::{ElementState::Pressed, MouseButton::Left, WindowEvent::MouseInput};
|
||||
@@ -1150,7 +1166,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
},
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_LBUTTONUP => {
|
||||
use crate::event::{
|
||||
@@ -1169,7 +1185,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
},
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_RBUTTONDOWN => {
|
||||
use crate::event::{
|
||||
@@ -1188,7 +1204,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
},
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_RBUTTONUP => {
|
||||
use crate::event::{
|
||||
@@ -1207,7 +1223,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
},
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_MBUTTONDOWN => {
|
||||
use crate::event::{
|
||||
@@ -1226,7 +1242,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
},
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_MBUTTONUP => {
|
||||
use crate::event::{
|
||||
@@ -1245,7 +1261,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
},
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_XBUTTONDOWN => {
|
||||
use crate::event::{
|
||||
@@ -1265,7 +1281,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
},
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_XBUTTONUP => {
|
||||
use crate::event::{
|
||||
@@ -1285,7 +1301,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
},
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_INPUT_DEVICE_CHANGE => {
|
||||
let event = match wparam as _ {
|
||||
@@ -1300,7 +1316,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
});
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_INPUT => {
|
||||
use crate::event::{
|
||||
@@ -1399,7 +1415,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
}
|
||||
|
||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_TOUCH => {
|
||||
let pcount = LOWORD(wparam as DWORD) as usize;
|
||||
@@ -1439,7 +1455,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
}
|
||||
winuser::CloseTouchInputHandle(htouch);
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_SETFOCUS => {
|
||||
use crate::event::WindowEvent::Focused;
|
||||
@@ -1449,7 +1465,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
});
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_KILLFOCUS => {
|
||||
use crate::event::WindowEvent::Focused;
|
||||
@@ -1458,7 +1474,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
event: Focused(false),
|
||||
});
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_SETCURSOR => {
|
||||
let set_cursor_to = {
|
||||
@@ -1479,15 +1495,15 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
let cursor = winuser::LoadCursorW(ptr::null_mut(), cursor.to_windows_cursor());
|
||||
winuser::SetCursor(cursor);
|
||||
0
|
||||
},
|
||||
}
|
||||
None => winuser::DefWindowProcW(window, msg, wparam, lparam),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_DROPFILES => {
|
||||
// See `FileDropHandler` for implementation.
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
winuser::WM_GETMINMAXINFO => {
|
||||
let mmi = lparam as *mut winuser::MINMAXINFO;
|
||||
@@ -1516,7 +1532,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
}
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
// Only sent on Windows 8.1 or newer. On Windows 7 and older user has to log out to change
|
||||
// DPI, therefore all applications are closed while DPI is changing.
|
||||
@@ -1560,7 +1576,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
});
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
|
||||
_ => {
|
||||
if msg == *DESTROY_MSG_ID {
|
||||
@@ -1613,7 +1629,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||
} else {
|
||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1631,7 +1647,7 @@ unsafe extern "system" fn thread_event_target_callback<T>(
|
||||
Box::from_raw(subclass_input);
|
||||
drop(subclass_input);
|
||||
0
|
||||
},
|
||||
}
|
||||
// Because WM_PAINT comes after all other messages, we use it during modal loops to detect
|
||||
// when the event queue has been emptied. See `process_event` for more details.
|
||||
winuser::WM_PAINT => {
|
||||
@@ -1653,7 +1669,7 @@ unsafe extern "system" fn thread_event_target_callback<T>(
|
||||
}
|
||||
};
|
||||
if in_modal_loop {
|
||||
let mut msg = mem::uninitialized();
|
||||
let mut msg = mem::zeroed();
|
||||
loop {
|
||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) {
|
||||
break;
|
||||
@@ -1669,13 +1685,13 @@ unsafe extern "system" fn thread_event_target_callback<T>(
|
||||
winuser::TranslateMessage(&mut msg);
|
||||
winuser::DispatchMessageW(&mut msg);
|
||||
}
|
||||
},
|
||||
}
|
||||
// If the message isn't one of those three, it may be handled by the modal
|
||||
// loop so we should return control flow to it.
|
||||
_ => {
|
||||
queue_call_again();
|
||||
return 0;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1689,27 +1705,27 @@ unsafe extern "system" fn thread_event_target_callback<T>(
|
||||
wait_until_time_or_msg(resume_time);
|
||||
runner.new_events();
|
||||
queue_call_again();
|
||||
},
|
||||
}
|
||||
ControlFlow::Poll => {
|
||||
runner.new_events();
|
||||
queue_call_again();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
0
|
||||
},
|
||||
}
|
||||
_ if msg == *USER_EVENT_MSG_ID => {
|
||||
if let Ok(event) = subclass_input.user_event_receiver.recv() {
|
||||
subclass_input.send_event(Event::UserEvent(event));
|
||||
}
|
||||
0
|
||||
},
|
||||
}
|
||||
_ if msg == *EXEC_MSG_ID => {
|
||||
let mut function: ThreadExecFn = Box::from_raw(wparam as usize as *mut _);
|
||||
function();
|
||||
0
|
||||
},
|
||||
}
|
||||
_ => commctrl::DefSubclassProc(window, msg, wparam, lparam),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ impl Window {
|
||||
}
|
||||
|
||||
pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<winuser::MONITORINFOEXW, io::Error> {
|
||||
let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::uninitialized() };
|
||||
let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::zeroed() };
|
||||
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
|
||||
let status = unsafe {
|
||||
winuser::GetMonitorInfoW(
|
||||
|
||||
@@ -74,7 +74,7 @@ impl From<RID_DEVICE_INFO> for RawDeviceInfo {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
|
||||
let mut info: RID_DEVICE_INFO = unsafe { mem::uninitialized() };
|
||||
let mut info: RID_DEVICE_INFO = unsafe { mem::zeroed() };
|
||||
let info_size = size_of::<RID_DEVICE_INFO>() as UINT;
|
||||
|
||||
info.cbSize = info_size;
|
||||
@@ -164,7 +164,7 @@ pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> boo
|
||||
}
|
||||
|
||||
pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
|
||||
let mut data: RAWINPUT = unsafe { mem::uninitialized() };
|
||||
let mut data: RAWINPUT = unsafe { mem::zeroed() };
|
||||
let mut data_size = size_of::<RAWINPUT>() as UINT;
|
||||
let header_size = size_of::<RAWINPUTHEADER>() as UINT;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn wchar_ptr_to_string(wchar: *const wchar_t) -> String {
|
||||
}
|
||||
|
||||
pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
|
||||
let mut data: T = mem::uninitialized();
|
||||
let mut data: T = mem::zeroed();
|
||||
if fun(&mut data) != 0 {
|
||||
Some(data)
|
||||
} else {
|
||||
@@ -59,7 +59,7 @@ pub fn get_window_rect(hwnd: HWND) -> Option<RECT> {
|
||||
|
||||
pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
|
||||
unsafe {
|
||||
let mut rect = mem::uninitialized();
|
||||
let mut rect = mem::zeroed();
|
||||
let mut top_left = mem::zeroed();
|
||||
|
||||
win_to_err(|| winuser::ClientToScreen(hwnd, &mut top_left))?;
|
||||
@@ -129,7 +129,7 @@ impl CursorIcon {
|
||||
CursorIcon::NotAllowed | CursorIcon::NoDrop => winuser::IDC_NO,
|
||||
CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move | CursorIcon::AllScroll => {
|
||||
winuser::IDC_SIZEALL
|
||||
},
|
||||
}
|
||||
CursorIcon::EResize
|
||||
| CursorIcon::WResize
|
||||
| CursorIcon::EwResize
|
||||
@@ -140,10 +140,10 @@ impl CursorIcon {
|
||||
| CursorIcon::RowResize => winuser::IDC_SIZENS,
|
||||
CursorIcon::NeResize | CursorIcon::SwResize | CursorIcon::NeswResize => {
|
||||
winuser::IDC_SIZENESW
|
||||
},
|
||||
}
|
||||
CursorIcon::NwResize | CursorIcon::SeResize | CursorIcon::NwseResize => {
|
||||
winuser::IDC_SIZENWSE
|
||||
},
|
||||
}
|
||||
CursorIcon::Wait => winuser::IDC_WAIT,
|
||||
CursorIcon::Progress => winuser::IDC_APPSTARTING,
|
||||
CursorIcon::Help => winuser::IDC_HELP,
|
||||
|
||||
@@ -149,7 +149,11 @@ impl Window {
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
} else {
|
||||
winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0);
|
||||
let mut window_state = self.window_state.lock();
|
||||
if !window_state.queued_out_of_band_redraw {
|
||||
window_state.queued_out_of_band_redraw = true;
|
||||
winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,7 +215,7 @@ impl Window {
|
||||
}
|
||||
|
||||
pub(crate) fn inner_size_physical(&self) -> (u32, u32) {
|
||||
let mut rect: RECT = unsafe { mem::uninitialized() };
|
||||
let mut rect: RECT = unsafe { mem::zeroed() };
|
||||
if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 {
|
||||
panic!("Unexpected GetClientRect failure: please report this error to https://github.com/rust-windowing/winit")
|
||||
}
|
||||
@@ -271,7 +275,8 @@ impl Window {
|
||||
winuser::SWP_ASYNCWINDOWPOS
|
||||
| winuser::SWP_NOZORDER
|
||||
| winuser::SWP_NOREPOSITION
|
||||
| winuser::SWP_NOMOVE,
|
||||
| winuser::SWP_NOMOVE
|
||||
| winuser::SWP_NOACTIVATE,
|
||||
);
|
||||
winuser::UpdateWindow(self.window.0);
|
||||
}
|
||||
@@ -464,7 +469,7 @@ impl Window {
|
||||
|
||||
mark_fullscreen(window.0, true);
|
||||
});
|
||||
},
|
||||
}
|
||||
&None => {
|
||||
self.thread_executor.execute_in_thread(move || {
|
||||
let mut window_state_lock = window_state.lock();
|
||||
@@ -487,7 +492,7 @@ impl Window {
|
||||
|
||||
mark_fullscreen(window.0, false);
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ pub struct WindowState {
|
||||
pub dpi_factor: f64,
|
||||
|
||||
pub fullscreen: Option<MonitorHandle>,
|
||||
/// Used to supress duplicate redraw attempts when calling `request_redraw` multiple
|
||||
/// times in `EventsCleared`.
|
||||
pub queued_out_of_band_redraw: bool,
|
||||
window_flags: WindowFlags,
|
||||
}
|
||||
|
||||
@@ -110,6 +113,7 @@ impl WindowState {
|
||||
dpi_factor,
|
||||
|
||||
fullscreen: None,
|
||||
queued_out_of_band_redraw: false,
|
||||
window_flags: WindowFlags::empty(),
|
||||
}
|
||||
}
|
||||
@@ -170,7 +174,7 @@ impl MouseProperties {
|
||||
Err(e) => {
|
||||
self.cursor_flags = old_flags;
|
||||
return Err(e);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -215,8 +219,9 @@ impl WindowFlags {
|
||||
if self.contains(WindowFlags::NO_BACK_BUFFER) {
|
||||
style_ex |= WS_EX_NOREDIRECTIONBITMAP;
|
||||
}
|
||||
// if self.contains(WindowFlags::TRANSPARENT) {
|
||||
// }
|
||||
if self.contains(WindowFlags::TRANSPARENT) && self.contains(WindowFlags::DECORATIONS) {
|
||||
style_ex |= WS_EX_LAYERED;
|
||||
}
|
||||
if self.contains(WindowFlags::CHILD) {
|
||||
style |= WS_CHILD; // This is incompatible with WS_POPUP if that gets added eventually.
|
||||
}
|
||||
@@ -307,9 +312,11 @@ impl WindowFlags {
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
winuser::SWP_NOZORDER | winuser::SWP_FRAMECHANGED,
|
||||
winuser::SWP_NOZORDER
|
||||
| winuser::SWP_FRAMECHANGED
|
||||
| winuser::SWP_NOACTIVATE,
|
||||
);
|
||||
},
|
||||
}
|
||||
None => {
|
||||
// Refresh the window frame.
|
||||
winuser::SetWindowPos(
|
||||
@@ -322,9 +329,10 @@ impl WindowFlags {
|
||||
winuser::SWP_NOZORDER
|
||||
| winuser::SWP_NOMOVE
|
||||
| winuser::SWP_NOSIZE
|
||||
| winuser::SWP_FRAMECHANGED,
|
||||
| winuser::SWP_FRAMECHANGED
|
||||
| winuser::SWP_NOACTIVATE,
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 0, 0);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ pub struct WindowBuilder {
|
||||
/// The attributes to use to create the window.
|
||||
pub window: WindowAttributes,
|
||||
|
||||
// Platform-specific configuration. Private.
|
||||
// Platform-specific configuration.
|
||||
pub(crate) platform_specific: platform_impl::PlatformSpecificWindowBuilderAttributes,
|
||||
}
|
||||
|
||||
@@ -285,23 +285,12 @@ impl WindowBuilder {
|
||||
|
||||
/// Builds the window.
|
||||
///
|
||||
/// Error should be very rare and only occur in case of permission denied, incompatible system,
|
||||
/// out of memory, etc.
|
||||
/// Possible causes of error include denied permission, incompatible system, and lack of memory.
|
||||
#[inline]
|
||||
pub fn build<T: 'static>(
|
||||
mut self,
|
||||
self,
|
||||
window_target: &EventLoopWindowTarget<T>,
|
||||
) -> Result<Window, OsError> {
|
||||
self.window.inner_size = Some(self.window.inner_size.unwrap_or_else(|| {
|
||||
if let Some(ref monitor) = self.window.fullscreen {
|
||||
// resizing the window to the dimensions of the monitor when fullscreen
|
||||
LogicalSize::from_physical(monitor.size(), monitor.hidpi_factor()) // DPI factor applies here since this is a borderless window and not real fullscreen
|
||||
} else {
|
||||
// default dimensions
|
||||
(1024, 768).into()
|
||||
}
|
||||
}));
|
||||
|
||||
// building
|
||||
platform_impl::Window::new(&window_target.p, self.window, self.platform_specific)
|
||||
.map(|window| Window { window })
|
||||
@@ -330,7 +319,7 @@ impl Window {
|
||||
|
||||
/// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa.
|
||||
///
|
||||
/// See the [`dpi`](dpi/index.html) module for more information.
|
||||
/// See the [`dpi`](../dpi/index.html) module for more information.
|
||||
///
|
||||
/// Note that this value can change depending on user action (for example if the window is
|
||||
/// moved to another screen); as such, tracking `WindowEvent::HiDpiFactorChanged` events is
|
||||
|
||||
Reference in New Issue
Block a user