Compare commits

...

33 Commits

Author SHA1 Message Date
Osspial
ce5cf97e17 Release Alpha 2 (#996) 2019-07-09 18:25:32 -04:00
Felix Rabe
3ee59696e5 Always use f as the argument name for &mut std::fmt::Formatter (#1023) 2019-07-09 17:49:07 -04:00
aloucks
f5c624bcd6 Handle RedrawRequested event in request_redraw example (#1030) 2019-07-08 22:22:10 -06:00
Felix Rabe
c1f314ccdc MacOS: request_user_attention(bool -> enum) (#1021) 2019-07-07 14:14:00 -06:00
Felix Rabe
53a89f28a0 Remove dead code (unused as of d5391686a) (#1022) 2019-07-07 14:13:17 -06:00
Felix Rabe
f874d76289 Fix warnings (#1020)
* Windows: Fix warning

* iOS: Fix warning
2019-07-07 14:12:39 -06:00
Bradley Smith
28775be115 Fix transparent window with decorations (#1011)
* Fix transparent window with decorations

* To changelog, added fix for transparent decorated windows.
2019-07-06 13:29:15 -04:00
Felix Rabe
7d3ff3d2d9 Fix warning (#1016) 2019-07-06 13:28:50 -04:00
Osspial
4a5d639d74 On Windows, fix with_maximized not properly setting window size to entire window. (#1013) 2019-07-05 17:28:11 -04:00
Osspial
74a7cf55ea Fix issues with redraw_requested when called during EventsCleared (#994)
* Fix issues with redraw_requested when called during EventsCleared

* Format

* Fix event dispatch after RedrawRequested but before EventsCleared

This could happen if the event queue was cleared, we processed WM_PAINT,
but the event queue got re-filled before we checked to see it was empty.

* Fix paint ordering issues when resizing window

* Format
2019-07-04 16:14:15 -04:00
Murarth
9393b14b01 X11: Disable maximize on non-resizable windows (#1000)
* X11: Disable maximize on non-resizable windows

* Add a note for the source for Motif WM constants
2019-07-04 04:43:44 -06:00
Aleksi Juvani
f8bd671073 Remove Metal dependency on macOS (#1003) 2019-07-03 14:19:07 -04:00
Murarth
2af753f307 Fix warnings on Linux (#1004) 2019-07-03 14:18:42 -04:00
Michael Streif
5bf303fd26 Improve handling of file paths in the windows DnD handler (#980)
* Make FileDropHandler::iterate_filenames more robust

by replacing the call to mem::uninitialized with mem::zeroed and change
file name retrieval to use buffers of exact length as reported
by DragQueryFileW instead of relying on MAX_PATH.

* Change remaining calls of uninitialized to zeroed

* Run rustfmt

* Add CHANGELOG entry and comment
2019-06-28 18:07:36 -04:00
Felix Rabe
e37e46b155 Remove comment that contradicts code (#992) 2019-06-28 15:32:27 -04:00
Victor Berger
b8192ef6f6 Revert "wayland: use an invisible surface as shell surface (#835)" (#981)
This reverts commit 65587ef43a.

It introduced sublte bugs in its interaction with OpenGL and glutin,
so we should better revert it for now.
2019-06-28 15:31:54 -04:00
Ho-Yon Mak
23354cf1a5 Implement _NET_WM_PING for X11 (#977) 2019-06-27 18:40:27 -06:00
Felix Rabe
dd38fab2f3 examples/window_icon.rs: De-duplicate code (#988) 2019-06-27 11:59:13 -04:00
Tristam MacDonald
ac08601b40 Implement DeviceEvent::Button on Mac (#967)
* Add deviceevent logging to cursor_grab example

* Implement DeviceEvent::Button on Mac
2019-06-27 02:58:21 -04:00
Austin Lasher
34db2d7d4c Fix broken links to mod DPI on various documentation pages (#984) 2019-06-26 15:35:54 +02:00
chichid
0e20973bdb Fix 968: Invisible windows steal focus from visible windows Win32 (#968) 2019-06-26 00:04:49 -04:00
Murarth
29e2481597 Remove XFlush call in event loop (#982)
Internally, `XFlush` calls `_XSend` to write data. It then calls
`XEventsQueued(display, QueuedAfterReading)`, which reads data from the
X server connection. This prevents the event loop source callback from
being run, as there is no longer data waiting on the socket.

Ideally, we would want to call `_XSend` directly to ensure that no
output is buffered by Xlib. However, this function is not exported as
part of Xlib's public API.

Testing with the `XFlush` call removed does not appear to adversely
affect the performance of an application. If any bugs should eventually
arise from this change, perhaps another function may be used in place of
`XFlush`, such as `XPending`, which writes buffered output but does not
so aggressively read from the X server connection.

Closes #865
2019-06-25 15:29:52 -06:00
Cherser-s
3555de114a Wayland: Add relative pointer movement (#973)
* Add relative pointer movement for Wayland

* Format changed code with rustfmt

* Wayland: merge window and device event queues into one

* Replace map_or_else call for simplification
2019-06-25 03:00:41 -06:00
Austin Lasher
dbe6a1bcdf Update docs to differentiate DeviceEvents and WindowEvents (#976) 2019-06-24 17:30:06 -04:00
Osspial
a195ce8146 Re-format on stable rustfmt (#974) 2019-06-24 12:14:55 -04:00
Felix Rabe
9dd15d00d8 Update PULL_REQUEST_TEMPLATE.md (#969) 2019-06-23 14:05:37 -04:00
Felix Rabe
2442305bb7 Forward porting (#966)
* README: Use shields.io instead of Herokuapp (#859)

* README: Link to FEATURES.md and missing features wiki page (#860)

Closes #854

* Update URLs (#863)

* CHANGELOG.md: Add line from #861 (legacy) that is missing from equivalent #964 (EL 2)
2019-06-23 02:39:26 -04:00
Felix Rabe
063648368d CHANGELOG.md: Move entries for #805 to 0.19.1 (#965) 2019-06-22 13:57:56 -04:00
Osspial
918b2efce7 Improve the example in lib.rs (#957) 2019-06-22 13:26:06 -04:00
Abendstolz
2467a997f4 [#963] Change XRandR display size check to also take height into account (#964) 2019-06-22 18:48:51 +02:00
Felix Rabe
f457c6a0b8 Change Suspended(true/false) => Suspended/Resumed (#959) 2019-06-21 20:59:31 -06:00
Felix Rabe
1193cada46 Minor spelling changes (#960) 2019-06-21 18:34:55 -06:00
Felix Rabe
b0e09b8ffe Rephrase (#958) 2019-06-21 17:35:08 -06:00
64 changed files with 1201 additions and 1059 deletions

View File

@@ -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
View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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"

View File

@@ -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

View File

@@ -1,17 +1,21 @@
# winit - Cross-platform window creation and management in Rust
[![](http://meritbadge.herokuapp.com/winit)](https://crates.io/crates/winit)
[![Crates.io](https://img.shields.io/crates/v/winit.svg)](https://crates.io/crates/winit)
[![Docs.rs](https://docs.rs/winit/badge.svg)](https://docs.rs/winit)
[![Build Status](https://travis-ci.org/rust-windowing/winit.svg?branch=master)](https://travis-ci.org/rust-windowing/winit)
[![Build status](https://ci.appveyor.com/api/projects/status/hr89but4x1n3dphq/branch/master?svg=true)](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:

View File

@@ -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;
}
_ => (),
});
}

View File

@@ -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),
},
_ => (),
}
},
_ => (),
}
});
}

View File

@@ -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);
}
_ => (),
}
},
_ => (),
},
_ => {},
_ => {}
}
});
}

View File

@@ -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;
}
},
}
_ => (),
}
},
}
_ => (),
}
},
}
_ => (),
}
});

View File

@@ -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();
}
}
},
_ => (),

View File

@@ -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);
},
}
_ => (),
}
},
}
_ => (),
}
})

View File

@@ -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);
}
_ => (),
});
}

View File

@@ -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);
}
_ => (),
},
_ => (),
};

View File

@@ -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,
..

View File

@@ -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)));
},
}
_ => (),
}
}

View File

@@ -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.");

View File

@@ -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

View File

@@ -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")
}
}

View File

@@ -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),
}

View File

@@ -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 { .. }")
}
}

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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
///

View File

@@ -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]

View File

@@ -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)),
_ => {},
_ => {}
}
}

View File

@@ -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,
};

View File

@@ -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),

View File

@@ -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
},
}
}
}

View File

@@ -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()
}

View File

@@ -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
},
}
}
}
}

View File

@@ -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

View File

@@ -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) {}

View File

@@ -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,
};

View File

@@ -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(),
}
}

View File

@@ -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()
})

View File

@@ -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()
},
}
}
}

View File

@@ -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!(),
}
},
(),
)
})
}

View File

@@ -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!(),
}
},

View File

@@ -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 {

View File

@@ -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(_) => (),
}
}

View File

@@ -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;
}
},
_ => {},
}
_ => {}
}
}
}

View File

@@ -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(),
)
}
}

View File

@@ -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;
}

View File

@@ -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!(),
}

View File

@@ -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);
}
_ => (),
}
}

View File

@@ -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`");
}

View File

@@ -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);

View File

@@ -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!(),
}

View File

@@ -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),
}
}

View File

@@ -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,
}
}
}

View File

@@ -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,
};

View File

@@ -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
}
});
}
}

View File

@@ -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) =

View File

@@ -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);

View File

@@ -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))
}

View File

@@ -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),
}
}

View File

@@ -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(

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);
});
},
}
}
}
}

View File

@@ -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);
}

View File

@@ -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