mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
On Windows, fix bug where RedrawRequested would only get emitted every other iteration of the event loop (#1366)
* Fix bug causing RedrawRequested events to only get emitted every other iteration of the event loop. * Initialize simple_logger in examples. This PR's primary bug was discovered because a friend of mine reported that winit was emitting concerning log messages, which I'd never seen since none of the examples print out the log messages. This addresses that, to hopefully reduce the chance of bugs going unnoticed in the future. * Add changelog entry * Format
This commit is contained in:
parent
627a127f1b
commit
6a330a2894
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- On Windows, fix bug where `RedrawRequested` would only get emitted every other iteration of the event loop.
|
||||||
|
|
||||||
# 0.20.0 (2020-01-05)
|
# 0.20.0 (2020-01-05)
|
||||||
|
|
||||||
- On X11, fix `ModifiersChanged` emitting incorrect modifier change events
|
- On X11, fix `ModifiersChanged` emitting incorrect modifier change events
|
||||||
|
|
|
@ -29,7 +29,7 @@ bitflags = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
image = "0.21"
|
image = "0.21"
|
||||||
env_logger = "0.5"
|
simple_logger = "1"
|
||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies.android_glue]
|
[target.'cfg(target_os = "android")'.dependencies.android_glue]
|
||||||
version = "0.2"
|
version = "0.2"
|
||||||
|
|
|
@ -5,6 +5,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
|
|
@ -5,6 +5,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new()
|
||||||
|
|
|
@ -11,6 +11,7 @@ fn main() {
|
||||||
Timer,
|
Timer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::<CustomEvent>::with_user_event();
|
let event_loop = EventLoop::<CustomEvent>::with_user_event();
|
||||||
|
|
||||||
let _window = WindowBuilder::new()
|
let _window = WindowBuilder::new()
|
||||||
|
|
|
@ -5,6 +5,7 @@ use winit::monitor::{MonitorHandle, VideoMode};
|
||||||
use winit::window::{Fullscreen, WindowBuilder};
|
use winit::window::{Fullscreen, WindowBuilder};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
print!("Please choose the fullscreen mode: (1) exclusive, (2) borderless: ");
|
print!("Please choose the fullscreen mode: (1) exclusive, (2) borderless: ");
|
||||||
|
|
|
@ -5,6 +5,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let _window = WindowBuilder::new()
|
let _window = WindowBuilder::new()
|
||||||
|
|
|
@ -6,6 +6,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
|
|
@ -5,6 +5,7 @@ use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
use winit::window::WindowBuilder;
|
use winit::window::WindowBuilder;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use winit::{event_loop::EventLoop, window::WindowBuilder};
|
use winit::{event_loop::EventLoop, window::WindowBuilder};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
fn main() {
|
fn main() {
|
||||||
extern crate env_logger;
|
|
||||||
|
|
||||||
use std::{collections::HashMap, sync::mpsc, thread, time::Duration};
|
use std::{collections::HashMap, sync::mpsc, thread, time::Duration};
|
||||||
|
|
||||||
use winit::{
|
use winit::{
|
||||||
|
@ -14,7 +12,7 @@ fn main() {
|
||||||
const WINDOW_COUNT: usize = 3;
|
const WINDOW_COUNT: usize = 3;
|
||||||
const WINDOW_SIZE: PhysicalSize<u32> = PhysicalSize::new(600, 400);
|
const WINDOW_SIZE: PhysicalSize<u32> = PhysicalSize::new(600, 400);
|
||||||
|
|
||||||
env_logger::init();
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let mut window_senders = HashMap::with_capacity(WINDOW_COUNT);
|
let mut window_senders = HashMap::with_capacity(WINDOW_COUNT);
|
||||||
for _ in 0..WINDOW_COUNT {
|
for _ in 0..WINDOW_COUNT {
|
||||||
|
|
|
@ -6,6 +6,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let mut windows = HashMap::new();
|
let mut windows = HashMap::new();
|
||||||
|
|
|
@ -5,6 +5,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new()
|
||||||
|
|
|
@ -6,6 +6,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let mut resizable = false;
|
let mut resizable = false;
|
||||||
|
|
|
@ -7,6 +7,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let _window = WindowBuilder::new()
|
let _window = WindowBuilder::new()
|
||||||
|
|
|
@ -5,6 +5,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use winit::event_loop::EventLoop;
|
use winit::event_loop::EventLoop;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let monitor = event_loop.primary_monitor();
|
let monitor = event_loop.primary_monitor();
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new()
|
||||||
|
|
|
@ -8,6 +8,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new()
|
||||||
|
|
|
@ -7,6 +7,8 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
|
|
||||||
// You'll have to choose an icon size at your own discretion. On X11, the desired size varies
|
// You'll have to choose an icon size at your own discretion. On X11, the desired size varies
|
||||||
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px,
|
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px,
|
||||||
// since it seems to work well enough in most cases. Be careful about going too high, or
|
// since it seems to work well enough in most cases. Be careful about going too high, or
|
||||||
|
|
|
@ -18,6 +18,7 @@ fn main() {
|
||||||
};
|
};
|
||||||
let mut event_loop = EventLoop::new();
|
let mut event_loop = EventLoop::new();
|
||||||
|
|
||||||
|
simple_logger::init().unwrap();
|
||||||
let _window = WindowBuilder::new()
|
let _window = WindowBuilder::new()
|
||||||
.with_title("A fantastic window!")
|
.with_title("A fantastic window!")
|
||||||
.build(&event_loop)
|
.build(&event_loop)
|
||||||
|
|
|
@ -100,13 +100,9 @@ pub(crate) struct SubclassInput<T: 'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SubclassInput<T> {
|
impl<T> SubclassInput<T> {
|
||||||
unsafe fn send_event(&self, event: Event<'static, T>) {
|
unsafe fn send_event(&self, event: Event<'_, T>) {
|
||||||
self.event_loop_runner.send_event(event);
|
self.event_loop_runner.send_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn send_event_unbuffered<'e>(&self, event: Event<'e, T>) -> Result<(), Event<'e, T>> {
|
|
||||||
self.event_loop_runner.send_event_unbuffered(event)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ThreadMsgTargetSubclassInput<T: 'static> {
|
struct ThreadMsgTargetSubclassInput<T: 'static> {
|
||||||
|
@ -116,7 +112,7 @@ struct ThreadMsgTargetSubclassInput<T: 'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ThreadMsgTargetSubclassInput<T> {
|
impl<T> ThreadMsgTargetSubclassInput<T> {
|
||||||
unsafe fn send_event(&self, event: Event<'static, T>) {
|
unsafe fn send_event(&self, event: Event<'_, T>) {
|
||||||
self.event_loop_runner.send_event(event);
|
self.event_loop_runner.send_event(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,28 +212,57 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut msg = mem::zeroed();
|
let mut msg = mem::zeroed();
|
||||||
let mut msg_unprocessed = false;
|
let mut unread_message_exists = false;
|
||||||
|
|
||||||
'main: loop {
|
'main: loop {
|
||||||
runner.new_events();
|
|
||||||
loop {
|
|
||||||
if !msg_unprocessed {
|
|
||||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
winuser::TranslateMessage(&mut msg);
|
|
||||||
winuser::DispatchMessageW(&mut msg);
|
|
||||||
|
|
||||||
msg_unprocessed = false;
|
|
||||||
}
|
|
||||||
runner.events_cleared();
|
|
||||||
if let Err(payload) = runner.take_panic_error() {
|
if let Err(payload) = runner.take_panic_error() {
|
||||||
runner.destroy_runner();
|
runner.destroy_runner();
|
||||||
panic::resume_unwind(payload);
|
panic::resume_unwind(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !msg_unprocessed {
|
runner.new_events();
|
||||||
|
loop {
|
||||||
|
if !unread_message_exists {
|
||||||
|
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if msg.message == winuser::WM_PAINT {
|
||||||
|
unread_message_exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
winuser::TranslateMessage(&mut msg);
|
||||||
|
winuser::DispatchMessageW(&mut msg);
|
||||||
|
|
||||||
|
unread_message_exists = false;
|
||||||
|
}
|
||||||
|
runner.main_events_cleared();
|
||||||
|
loop {
|
||||||
|
if !unread_message_exists {
|
||||||
|
if 0 == winuser::PeekMessageW(
|
||||||
|
&mut msg,
|
||||||
|
ptr::null_mut(),
|
||||||
|
winuser::WM_PAINT,
|
||||||
|
winuser::WM_PAINT,
|
||||||
|
1,
|
||||||
|
) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
winuser::TranslateMessage(&mut msg);
|
||||||
|
winuser::DispatchMessageW(&mut msg);
|
||||||
|
|
||||||
|
unread_message_exists = false;
|
||||||
|
}
|
||||||
|
if runner.redraw_events_cleared().events_buffered() {
|
||||||
|
if runner.control_flow() == ControlFlow::Exit {
|
||||||
|
break 'main;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !unread_message_exists {
|
||||||
let control_flow = runner.control_flow();
|
let control_flow = runner.control_flow();
|
||||||
match control_flow {
|
match control_flow {
|
||||||
ControlFlow::Exit => break 'main,
|
ControlFlow::Exit => break 'main,
|
||||||
|
@ -245,7 +270,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
|
if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
|
||||||
break 'main;
|
break 'main;
|
||||||
}
|
}
|
||||||
msg_unprocessed = true;
|
unread_message_exists = true;
|
||||||
}
|
}
|
||||||
ControlFlow::WaitUntil(resume_time) => {
|
ControlFlow::WaitUntil(resume_time) => {
|
||||||
wait_until_time_or_msg(resume_time);
|
wait_until_time_or_msg(resume_time);
|
||||||
|
@ -651,6 +676,7 @@ unsafe extern "system" fn public_window_callback<T: 'static>(
|
||||||
}
|
}
|
||||||
|
|
||||||
winuser::WM_PAINT => {
|
winuser::WM_PAINT => {
|
||||||
|
subclass_input.event_loop_runner.main_events_cleared();
|
||||||
subclass_input.send_event(Event::RedrawRequested(RootWindowId(WindowId(window))));
|
subclass_input.send_event(Event::RedrawRequested(RootWindowId(WindowId(window))));
|
||||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
}
|
}
|
||||||
|
@ -1497,7 +1523,7 @@ unsafe extern "system" fn public_window_callback<T: 'static>(
|
||||||
false => old_physical_inner_size,
|
false => old_physical_inner_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = subclass_input.send_event_unbuffered(Event::WindowEvent {
|
let _ = subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: RootWindowId(WindowId(window)),
|
window_id: RootWindowId(WindowId(window)),
|
||||||
event: ScaleFactorChanged {
|
event: ScaleFactorChanged {
|
||||||
scale_factor: new_dpi_factor,
|
scale_factor: new_dpi_factor,
|
||||||
|
@ -1697,44 +1723,49 @@ unsafe extern "system" fn thread_event_target_callback<T: 'static>(
|
||||||
let in_modal_loop = subclass_input.event_loop_runner.in_modal_loop();
|
let in_modal_loop = subclass_input.event_loop_runner.in_modal_loop();
|
||||||
if in_modal_loop {
|
if in_modal_loop {
|
||||||
let mut msg = mem::zeroed();
|
let mut msg = mem::zeroed();
|
||||||
loop {
|
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) {
|
||||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) {
|
if msg.message != 0 && msg.message != winuser::WM_PAINT {
|
||||||
break;
|
queue_call_again();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
// Clear all paint/timer messages from the queue before sending the events cleared message.
|
|
||||||
match msg.message {
|
|
||||||
// Flush the event queue of WM_PAINT messages.
|
|
||||||
winuser::WM_PAINT | winuser::WM_TIMER => {
|
|
||||||
// Remove the message from the message queue.
|
|
||||||
winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1);
|
|
||||||
|
|
||||||
if msg.hwnd != window {
|
subclass_input.event_loop_runner.main_events_cleared();
|
||||||
winuser::TranslateMessage(&mut msg);
|
loop {
|
||||||
winuser::DispatchMessageW(&mut msg);
|
if 0 == winuser::PeekMessageW(
|
||||||
}
|
&mut msg,
|
||||||
|
ptr::null_mut(),
|
||||||
|
winuser::WM_PAINT,
|
||||||
|
winuser::WM_PAINT,
|
||||||
|
1,
|
||||||
|
) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// 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.
|
if msg.hwnd != window {
|
||||||
_ => {
|
winuser::TranslateMessage(&mut msg);
|
||||||
queue_call_again();
|
winuser::DispatchMessageW(&mut msg);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we don't borrow until here because TODO SAFETY
|
||||||
let runner = &subclass_input.event_loop_runner;
|
let runner = &subclass_input.event_loop_runner;
|
||||||
runner.events_cleared();
|
if runner.redraw_events_cleared().events_buffered() {
|
||||||
match runner.control_flow() {
|
queue_call_again();
|
||||||
// Waiting is handled by the modal loop.
|
runner.new_events();
|
||||||
ControlFlow::Exit | ControlFlow::Wait => runner.new_events(),
|
} else {
|
||||||
ControlFlow::WaitUntil(resume_time) => {
|
match runner.control_flow() {
|
||||||
wait_until_time_or_msg(resume_time);
|
// Waiting is handled by the modal loop.
|
||||||
runner.new_events();
|
ControlFlow::Exit | ControlFlow::Wait => runner.new_events(),
|
||||||
queue_call_again();
|
ControlFlow::WaitUntil(resume_time) => {
|
||||||
}
|
wait_until_time_or_msg(resume_time);
|
||||||
ControlFlow::Poll => {
|
runner.new_events();
|
||||||
runner.new_events();
|
queue_call_again();
|
||||||
queue_call_again();
|
}
|
||||||
|
ControlFlow::Poll => {
|
||||||
|
runner.new_events();
|
||||||
|
queue_call_again();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,17 @@ use std::{any::Any, cell::RefCell, collections::VecDeque, mem, panic, ptr, rc::R
|
||||||
use winapi::{shared::windef::HWND, um::winuser};
|
use winapi::{shared::windef::HWND, um::winuser};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
event::{Event, StartCause},
|
dpi::PhysicalSize,
|
||||||
|
event::{Event, StartCause, WindowEvent},
|
||||||
event_loop::ControlFlow,
|
event_loop::ControlFlow,
|
||||||
platform_impl::platform::event_loop::EventLoop,
|
platform_impl::platform::{event_loop::EventLoop, util},
|
||||||
window::WindowId,
|
window::WindowId,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
|
pub(crate) type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
|
||||||
pub(crate) struct ELRShared<T: 'static> {
|
pub(crate) struct ELRShared<T: 'static> {
|
||||||
runner: RefCell<Option<EventLoopRunner<T>>>,
|
runner: RefCell<Option<EventLoopRunner<T>>>,
|
||||||
buffer: RefCell<VecDeque<Event<'static, T>>>,
|
buffer: RefCell<VecDeque<BufferedEvent<T>>>,
|
||||||
redraw_buffer: Rc<RefCell<VecDeque<WindowId>>>,
|
redraw_buffer: Rc<RefCell<VecDeque<WindowId>>>,
|
||||||
}
|
}
|
||||||
struct EventLoopRunner<T: 'static> {
|
struct EventLoopRunner<T: 'static> {
|
||||||
|
@ -26,6 +27,63 @@ struct EventLoopRunner<T: 'static> {
|
||||||
}
|
}
|
||||||
pub type PanicError = Box<dyn Any + Send + 'static>;
|
pub type PanicError = Box<dyn Any + Send + 'static>;
|
||||||
|
|
||||||
|
pub enum BufferedEvent<T: 'static> {
|
||||||
|
Event(Event<'static, T>),
|
||||||
|
ScaleFactorChanged(WindowId, f64, PhysicalSize<u32>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum AreEventsBuffered {
|
||||||
|
EventsBuffered,
|
||||||
|
ReadyToSleep,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AreEventsBuffered {
|
||||||
|
pub fn events_buffered(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::EventsBuffered => true,
|
||||||
|
Self::ReadyToSleep => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> BufferedEvent<T> {
|
||||||
|
pub fn from_event(event: Event<'_, T>) -> BufferedEvent<T> {
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent {
|
||||||
|
event:
|
||||||
|
WindowEvent::ScaleFactorChanged {
|
||||||
|
scale_factor,
|
||||||
|
new_inner_size,
|
||||||
|
},
|
||||||
|
window_id,
|
||||||
|
} => BufferedEvent::ScaleFactorChanged(window_id, scale_factor, *new_inner_size),
|
||||||
|
event => BufferedEvent::Event(event.to_static().unwrap()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dispatch_event(self, dispatch: impl FnOnce(Event<'_, T>)) {
|
||||||
|
match self {
|
||||||
|
Self::Event(event) => dispatch(event),
|
||||||
|
Self::ScaleFactorChanged(window_id, scale_factor, mut new_inner_size) => {
|
||||||
|
dispatch(Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::ScaleFactorChanged {
|
||||||
|
scale_factor,
|
||||||
|
new_inner_size: &mut new_inner_size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
util::set_inner_size_physical(
|
||||||
|
(window_id.0).0,
|
||||||
|
new_inner_size.width as _,
|
||||||
|
new_inner_size.height as _,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> ELRShared<T> {
|
impl<T> ELRShared<T> {
|
||||||
pub(crate) fn new() -> ELRShared<T> {
|
pub(crate) fn new() -> ELRShared<T> {
|
||||||
ELRShared {
|
ELRShared {
|
||||||
|
@ -45,9 +103,7 @@ impl<T> ELRShared<T> {
|
||||||
loop {
|
loop {
|
||||||
let event = self.buffer.borrow_mut().pop_front();
|
let event = self.buffer.borrow_mut().pop_front();
|
||||||
match event {
|
match event {
|
||||||
Some(e) => {
|
Some(e) => e.dispatch_event(|e| runner.process_event(e)),
|
||||||
runner.process_event(e);
|
|
||||||
}
|
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,35 +119,65 @@ impl<T> ELRShared<T> {
|
||||||
let mut runner_ref = self.runner.borrow_mut();
|
let mut runner_ref = self.runner.borrow_mut();
|
||||||
if let Some(ref mut runner) = *runner_ref {
|
if let Some(ref mut runner) = *runner_ref {
|
||||||
runner.new_events();
|
runner.new_events();
|
||||||
|
loop {
|
||||||
|
let buffered_event_opt = self.buffer.borrow_mut().pop_front();
|
||||||
|
match buffered_event_opt {
|
||||||
|
Some(e) => e.dispatch_event(|e| runner.process_event(e)),
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn send_event(&self, event: Event<'static, T>) {
|
pub(crate) unsafe fn send_event(&self, event: Event<'_, T>) {
|
||||||
if let Err(event) = self.send_event_unbuffered(event) {
|
let handling_redraw = self
|
||||||
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
|
.runner
|
||||||
// the event to a buffer to be processed later.
|
.borrow()
|
||||||
self.buffer_event(event);
|
.as_ref()
|
||||||
|
.map(|r| RunnerState::HandlingRedraw == r.runner_state)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let mut send = None;
|
||||||
|
if handling_redraw {
|
||||||
|
if let Event::RedrawRequested(_) = event {
|
||||||
|
send = Some(event);
|
||||||
|
} else {
|
||||||
|
self.buffer_event(event);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
send = Some(event);
|
||||||
|
}
|
||||||
|
if let Some(event) = send {
|
||||||
|
if let Err(event) = self.send_event_unbuffered(event) {
|
||||||
|
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
|
||||||
|
// the event to a buffer to be processed later.
|
||||||
|
self.buffer_event(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn send_event_unbuffered<'e>(
|
unsafe fn send_event_unbuffered<'e>(&self, event: Event<'e, T>) -> Result<(), Event<'e, T>> {
|
||||||
&self,
|
|
||||||
event: Event<'e, T>,
|
|
||||||
) -> Result<(), Event<'e, T>> {
|
|
||||||
if let Ok(mut runner_ref) = self.runner.try_borrow_mut() {
|
if let Ok(mut runner_ref) = self.runner.try_borrow_mut() {
|
||||||
if let Some(ref mut runner) = *runner_ref {
|
if let Some(ref mut runner) = *runner_ref {
|
||||||
runner.process_event(event);
|
runner.process_event(event);
|
||||||
|
|
||||||
// Dispatch any events that were buffered during the call to `process_event`.
|
let handling_redraw = if let RunnerState::HandlingRedraw = runner.runner_state {
|
||||||
loop {
|
true
|
||||||
// We do this instead of using a `while let` loop because if we use a `while let`
|
} else {
|
||||||
// loop the reference returned `borrow_mut()` doesn't get dropped until the end
|
false
|
||||||
// of the loop's body and attempts to add events to the event buffer while in
|
};
|
||||||
// `process_event` will fail.
|
|
||||||
let buffered_event_opt = self.buffer.borrow_mut().pop_front();
|
if !handling_redraw {
|
||||||
match buffered_event_opt {
|
// Dispatch any events that were buffered during the call to `process_event`.
|
||||||
Some(event) => runner.process_event(event),
|
loop {
|
||||||
None => break,
|
// We do this instead of using a `while let` loop because if we use a `while let`
|
||||||
|
// loop the reference returned `borrow_mut()` doesn't get dropped until the end
|
||||||
|
// of the loop's body and attempts to add events to the event buffer while in
|
||||||
|
// `process_event` will fail.
|
||||||
|
let buffered_event_opt = self.buffer.borrow_mut().pop_front();
|
||||||
|
match buffered_event_opt {
|
||||||
|
Some(e) => e.dispatch_event(|e| runner.process_event(e)),
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,10 +197,21 @@ impl<T> ELRShared<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn events_cleared(&self) {
|
pub(crate) fn main_events_cleared(&self) {
|
||||||
let mut runner_ref = self.runner.borrow_mut();
|
let mut runner_ref = self.runner.borrow_mut();
|
||||||
if let Some(ref mut runner) = *runner_ref {
|
if let Some(ref mut runner) = *runner_ref {
|
||||||
runner.events_cleared();
|
runner.main_events_cleared();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn redraw_events_cleared(&self) -> AreEventsBuffered {
|
||||||
|
let mut runner_ref = self.runner.borrow_mut();
|
||||||
|
if let Some(ref mut runner) = *runner_ref {
|
||||||
|
runner.redraw_events_cleared();
|
||||||
|
}
|
||||||
|
match self.buffer.borrow().len() {
|
||||||
|
0 => AreEventsBuffered::ReadyToSleep,
|
||||||
|
_ => AreEventsBuffered::EventsBuffered,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,12 +249,15 @@ impl<T> ELRShared<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_event(&self, event: Event<'static, T>) {
|
fn buffer_event(&self, event: Event<'_, T>) {
|
||||||
match event {
|
match event {
|
||||||
Event::RedrawRequested(window_id) => {
|
Event::RedrawRequested(window_id) => {
|
||||||
self.redraw_buffer.borrow_mut().push_back(window_id)
|
self.redraw_buffer.borrow_mut().push_back(window_id)
|
||||||
}
|
}
|
||||||
_ => self.buffer.borrow_mut().push_back(event),
|
_ => self
|
||||||
|
.buffer
|
||||||
|
.borrow_mut()
|
||||||
|
.push_back(BufferedEvent::from_event(event)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,16 +417,20 @@ impl<T> EventLoopRunner<T> {
|
||||||
(RunnerState::HandlingRedraw, Event::RedrawRequested(_)) => {
|
(RunnerState::HandlingRedraw, Event::RedrawRequested(_)) => {
|
||||||
self.call_event_handler(event)
|
self.call_event_handler(event)
|
||||||
}
|
}
|
||||||
(_, Event::RedrawRequested(_)) => {
|
(RunnerState::New, Event::RedrawRequested(_))
|
||||||
self.call_event_handler(Event::MainEventsCleared);
|
| (RunnerState::Idle(..), Event::RedrawRequested(_)) => {
|
||||||
self.runner_state = RunnerState::HandlingRedraw;
|
self.new_events();
|
||||||
|
self.main_events_cleared();
|
||||||
self.call_event_handler(event);
|
self.call_event_handler(event);
|
||||||
}
|
}
|
||||||
|
(_, Event::RedrawRequested(_)) => {
|
||||||
|
panic!("redraw event in non-redraw phase");
|
||||||
|
}
|
||||||
(RunnerState::HandlingRedraw, _) => {
|
(RunnerState::HandlingRedraw, _) => {
|
||||||
warn!("Non-redraw event dispatched durning redraw phase");
|
panic!(
|
||||||
self.events_cleared();
|
"Non-redraw event dispatched durning redraw phase: {:?}",
|
||||||
self.new_events();
|
event.map_nonuser_event::<()>().ok()
|
||||||
self.call_event_handler(event);
|
);
|
||||||
}
|
}
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
self.runner_state = RunnerState::HandlingEvents;
|
self.runner_state = RunnerState::HandlingEvents;
|
||||||
|
@ -345,17 +449,64 @@ impl<T> EventLoopRunner<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn events_cleared(&mut self) {
|
fn main_events_cleared(&mut self) {
|
||||||
match self.runner_state {
|
match self.runner_state {
|
||||||
// If we were handling events, send the EventsCleared message.
|
// If we were handling events, send the EventsCleared message.
|
||||||
RunnerState::HandlingEvents => {
|
RunnerState::HandlingEvents => {
|
||||||
self.call_event_handler(Event::MainEventsCleared);
|
self.call_event_handler(Event::MainEventsCleared);
|
||||||
|
self.runner_state = RunnerState::HandlingRedraw;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunnerState::HandlingRedraw => (),
|
||||||
|
|
||||||
|
// If we *weren't* handling events, we don't have to do anything.
|
||||||
|
RunnerState::New | RunnerState::Idle(..) => (),
|
||||||
|
|
||||||
|
// Some control flows require a NewEvents call even if no events were received. This
|
||||||
|
// branch handles those.
|
||||||
|
RunnerState::DeferredNewEvents(wait_start) => {
|
||||||
|
match self.control_flow {
|
||||||
|
// If we had deferred a Poll, send the Poll NewEvents and EventsCleared.
|
||||||
|
ControlFlow::Poll => {
|
||||||
|
self.call_event_handler(Event::NewEvents(StartCause::Poll));
|
||||||
|
self.call_event_handler(Event::MainEventsCleared);
|
||||||
|
self.runner_state = RunnerState::HandlingRedraw;
|
||||||
|
}
|
||||||
|
// 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) => {
|
||||||
|
if Instant::now() >= resume_time {
|
||||||
|
self.call_event_handler(Event::NewEvents(
|
||||||
|
StartCause::ResumeTimeReached {
|
||||||
|
start: wait_start,
|
||||||
|
requested_resume: resume_time,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
self.call_event_handler(Event::MainEventsCleared);
|
||||||
|
self.runner_state = RunnerState::HandlingRedraw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we deferred a wait and no events were received, the user doesn't have to
|
||||||
|
// get an event.
|
||||||
|
ControlFlow::Wait | ControlFlow::Exit => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn redraw_events_cleared(&mut self) {
|
||||||
|
match self.runner_state {
|
||||||
|
// If we were handling events, send the EventsCleared message.
|
||||||
|
RunnerState::HandlingEvents => {
|
||||||
|
self.call_event_handler(Event::MainEventsCleared);
|
||||||
|
self.runner_state = RunnerState::HandlingRedraw;
|
||||||
self.flush_redraws();
|
self.flush_redraws();
|
||||||
self.call_event_handler(Event::RedrawEventsCleared);
|
self.call_event_handler(Event::RedrawEventsCleared);
|
||||||
self.runner_state = RunnerState::Idle(Instant::now());
|
self.runner_state = RunnerState::Idle(Instant::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
RunnerState::HandlingRedraw => {
|
RunnerState::HandlingRedraw => {
|
||||||
|
self.flush_redraws();
|
||||||
self.call_event_handler(Event::RedrawEventsCleared);
|
self.call_event_handler(Event::RedrawEventsCleared);
|
||||||
self.runner_state = RunnerState::Idle(Instant::now());
|
self.runner_state = RunnerState::Idle(Instant::now());
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,38 @@ pub fn adjust_size(hwnd: HWND, size: PhysicalSize<u32>) -> PhysicalSize<u32> {
|
||||||
PhysicalSize::new((rect.right - rect.left) as _, (rect.bottom - rect.top) as _)
|
PhysicalSize::new((rect.right - rect.left) as _, (rect.bottom - rect.top) as _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32) {
|
||||||
|
unsafe {
|
||||||
|
let rect = adjust_window_rect(
|
||||||
|
window,
|
||||||
|
RECT {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
bottom: y as LONG,
|
||||||
|
right: x as LONG,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("adjust_window_rect failed");
|
||||||
|
|
||||||
|
let outer_x = (rect.right - rect.left).abs() as _;
|
||||||
|
let outer_y = (rect.top - rect.bottom).abs() as _;
|
||||||
|
winuser::SetWindowPos(
|
||||||
|
window,
|
||||||
|
ptr::null_mut(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
outer_x,
|
||||||
|
outer_y,
|
||||||
|
winuser::SWP_ASYNCWINDOWPOS
|
||||||
|
| winuser::SWP_NOZORDER
|
||||||
|
| winuser::SWP_NOREPOSITION
|
||||||
|
| winuser::SWP_NOMOVE
|
||||||
|
| winuser::SWP_NOACTIVATE,
|
||||||
|
);
|
||||||
|
winuser::UpdateWindow(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn adjust_window_rect(hwnd: HWND, rect: RECT) -> Option<RECT> {
|
pub fn adjust_window_rect(hwnd: HWND, rect: RECT) -> Option<RECT> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let style = winuser::GetWindowLongW(hwnd, winuser::GWL_STYLE);
|
let style = winuser::GetWindowLongW(hwnd, winuser::GWL_STYLE);
|
||||||
|
|
|
@ -24,7 +24,7 @@ use winapi::{
|
||||||
oleidl::LPDROPTARGET,
|
oleidl::LPDROPTARGET,
|
||||||
shobjidl_core::{CLSID_TaskbarList, ITaskbarList2},
|
shobjidl_core::{CLSID_TaskbarList, ITaskbarList2},
|
||||||
wingdi::{CreateRectRgn, DeleteObject},
|
wingdi::{CreateRectRgn, DeleteObject},
|
||||||
winnt::{LONG, LPCWSTR},
|
winnt::LPCWSTR,
|
||||||
winuser,
|
winuser,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -215,38 +215,6 @@ impl Window {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_inner_size_physical(&self, x: u32, y: u32) {
|
|
||||||
unsafe {
|
|
||||||
let rect = util::adjust_window_rect(
|
|
||||||
self.window.0,
|
|
||||||
RECT {
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
bottom: y as LONG,
|
|
||||||
right: x as LONG,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.expect("adjust_window_rect failed");
|
|
||||||
|
|
||||||
let outer_x = (rect.right - rect.left).abs() as c_int;
|
|
||||||
let outer_y = (rect.top - rect.bottom).abs() as c_int;
|
|
||||||
winuser::SetWindowPos(
|
|
||||||
self.window.0,
|
|
||||||
ptr::null_mut(),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
outer_x,
|
|
||||||
outer_y,
|
|
||||||
winuser::SWP_ASYNCWINDOWPOS
|
|
||||||
| winuser::SWP_NOZORDER
|
|
||||||
| winuser::SWP_NOREPOSITION
|
|
||||||
| winuser::SWP_NOMOVE
|
|
||||||
| winuser::SWP_NOACTIVATE,
|
|
||||||
);
|
|
||||||
winuser::UpdateWindow(self.window.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_inner_size(&self, size: Size) {
|
pub fn set_inner_size(&self, size: Size) {
|
||||||
let dpi_factor = self.scale_factor();
|
let dpi_factor = self.scale_factor();
|
||||||
|
@ -260,7 +228,7 @@ impl Window {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
self.set_inner_size_physical(width, height);
|
util::set_inner_size_physical(self.window.0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Reference in a new issue