Skip to content

Commit 99c0f84

Browse files
committed
Add request_redraw
1 parent a0fef1a commit 99c0f84

File tree

5 files changed

+157
-38
lines changed

5 files changed

+157
-38
lines changed

examples/request_redraw.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
extern crate winit;
2+
use winit::{Event, WindowEvent};
3+
use std::time::{Instant, Duration};
4+
5+
fn main() {
6+
let events_loop = winit::EventLoop::new();
7+
8+
let window = winit::WindowBuilder::new()
9+
.with_title("A fantastic window!")
10+
.build(&events_loop)
11+
.unwrap();
12+
13+
events_loop.run(move |event, _, control_flow| {
14+
println!("{:?}", event);
15+
16+
match event {
17+
Event::WindowEvent {
18+
event: WindowEvent::CloseRequested,
19+
..
20+
} => *control_flow = winit::ControlFlow::Exit,
21+
Event::EventsCleared => {
22+
window.request_redraw();
23+
*control_flow = winit::ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0))
24+
},
25+
_ => ()
26+
}
27+
});
28+
}

src/events.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ pub enum WindowEvent {
140140
/// Motion on some analog axis. May report data redundant to other, more specific events.
141141
AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 },
142142

143-
/// The window needs to be redrawn.
144-
Redraw,
143+
/// The OS or application has requested that the window be redrawn.
144+
RedrawRequested,
145145

146146
/// Touch event has been received
147147
Touch(Touch),

src/platform/windows/events_loop.rs

+94-35
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use winapi::shared::basetsd::DWORD_PTR;
1616
use winapi::shared::basetsd::UINT_PTR;
1717
use std::{mem, ptr};
1818
use std::sync::Arc;
19+
use std::sync::atomic::{AtomicBool, Ordering};
1920
use std::time::{Duration, Instant};
2021
use std::rc::Rc;
2122
use std::cell::RefCell;
@@ -129,11 +130,10 @@ pub(crate) struct SubclassInput<T> {
129130

130131
impl<T> SubclassInput<T> {
131132
unsafe fn send_event(&self, event: Event<T>) {
132-
let runner = self.event_loop_runner.borrow_mut();
133-
if let Some(runner) = *runner {
134-
(*runner).process_event(event);
135-
} else {
136-
panic!("Attempted to send event without active runner");
133+
let mut runner = self.event_loop_runner.borrow_mut();
134+
match *runner {
135+
ELRSharedOption::Runner(runner) => (*runner).process_event(event),
136+
ELRSharedOption::Buffer(ref mut buffer) => buffer.push(event)
137137
}
138138
}
139139
}
@@ -145,11 +145,10 @@ struct ThreadMsgTargetSubclassInput<T> {
145145

146146
impl<T> ThreadMsgTargetSubclassInput<T> {
147147
unsafe fn send_event(&self, event: Event<T>) {
148-
let runner = self.event_loop_runner.borrow_mut();
149-
if let Some(runner) = *runner {
150-
(*runner).process_event(event);
151-
} else {
152-
panic!("Attempted to send event without active runner");
148+
let mut runner = self.event_loop_runner.borrow_mut();
149+
match *runner {
150+
ELRSharedOption::Runner(runner) => (*runner).process_event(event),
151+
ELRSharedOption::Buffer(ref mut buffer) => buffer.push(event)
153152
}
154153
}
155154
}
@@ -159,6 +158,7 @@ pub struct EventLoop<T> {
159158
thread_id: DWORD,
160159
thread_msg_target: HWND,
161160
thread_msg_sender: Sender<T>,
161+
trigger_newevents_on_redraw: Arc<AtomicBool>,
162162
pub(crate) runner_shared: EventLoopRunnerShared<T>,
163163
}
164164

@@ -171,12 +171,13 @@ impl<T> EventLoop<T> {
171171
become_dpi_aware(dpi_aware);
172172

173173
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
174-
let runner_shared = Rc::new(RefCell::new(None));
174+
let runner_shared = Rc::new(RefCell::new(ELRSharedOption::Buffer(vec![])));
175175
let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone());
176176

177177
EventLoop {
178178
thread_id,
179179
thread_msg_target, thread_msg_sender,
180+
trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)),
180181
runner_shared
181182
}
182183
}
@@ -197,7 +198,19 @@ impl<T> EventLoop<T> {
197198
modal_loop_data: None,
198199
event_handler: &mut event_handler
199200
};
200-
*runner.event_loop.events_loop.runner_shared.borrow_mut() = Some(&mut runner);
201+
{
202+
let runner_shared = runner.event_loop.events_loop.runner_shared.clone();
203+
let mut runner_shared = runner_shared.borrow_mut();
204+
let mut event_buffer = vec![];
205+
if let ELRSharedOption::Buffer(ref mut buffer) = *runner_shared {
206+
mem::swap(buffer, &mut event_buffer);
207+
}
208+
for event in event_buffer.drain(..) {
209+
runner.process_event(event);
210+
}
211+
*runner_shared = ELRSharedOption::Runner(&mut runner);
212+
}
213+
201214
let timer_handle = winuser::SetTimer(ptr::null_mut(), 0, 0x7FFFFFFF, None);
202215

203216
let mut msg = mem::uninitialized();
@@ -242,7 +255,7 @@ impl<T> EventLoop<T> {
242255
}
243256

244257
runner.call_event_handler(Event::LoopDestroyed);
245-
*runner.event_loop.events_loop.runner_shared.borrow_mut() = None;
258+
*runner.event_loop.events_loop.runner_shared.borrow_mut() = ELRSharedOption::Buffer(vec![]);
246259
}
247260

248261
drop(event_handler);
@@ -259,12 +272,17 @@ impl<T> EventLoop<T> {
259272
#[inline(always)]
260273
pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
261274
EventLoopThreadExecutor {
262-
thread_id: self.thread_id
275+
thread_id: self.thread_id,
276+
trigger_newevents_on_redraw: self.trigger_newevents_on_redraw.clone()
263277
}
264278
}
265279
}
266280

267-
pub(crate) type EventLoopRunnerShared<T> = Rc<RefCell<Option<*mut EventLoopRunner<T>>>>;
281+
pub(crate) type EventLoopRunnerShared<T> = Rc<RefCell<ELRSharedOption<T>>>;
282+
pub(crate) enum ELRSharedOption<T> {
283+
Runner(*mut EventLoopRunner<T>),
284+
Buffer(Vec<Event<T>>)
285+
}
268286
pub(crate) struct EventLoopRunner<T> {
269287
event_loop: ::EventLoop<T>,
270288
control_flow: ControlFlow,
@@ -346,8 +364,10 @@ impl<T> EventLoopRunner<T> {
346364
}
347365

348366
unsafe fn process_event(&mut self, event: Event<T>) {
367+
// If we're in the middle of a modal loop, only set the timer for zero if it hasn't been
368+
// reset in a prior call to `process_event`.
349369
if let Some(ModalLoopData{hwnd, timer_handle}) = self.modal_loop_data {
350-
if !self.event_processing_active() {
370+
if self.runner_state != RunnerState::HandlingEvents {
351371
winuser::SetTimer(hwnd, timer_handle, 0, None);
352372
}
353373
}
@@ -385,10 +405,9 @@ impl<T> EventLoopRunner<T> {
385405
ControlFlow::Poll |
386406
ControlFlow::Exit => unreachable!()
387407
}
388-
389-
self.runner_state = RunnerState::HandlingEvents;
390408
}
391409

410+
self.runner_state = RunnerState::HandlingEvents;
392411
self.call_event_handler(event);
393412
}
394413

@@ -437,6 +456,12 @@ impl<T> EventLoopRunner<T> {
437456

438457
unsafe fn call_event_handler(&mut self, event: Event<T>) {
439458
if self.event_handler != mem::zeroed() {
459+
match event {
460+
Event::NewEvents(_) => self.event_loop.events_loop.trigger_newevents_on_redraw.store(true, Ordering::Relaxed),
461+
Event::EventsCleared => self.event_loop.events_loop.trigger_newevents_on_redraw.store(false, Ordering::Relaxed),
462+
_ => ()
463+
}
464+
440465
if self.control_flow != ControlFlow::Exit {
441466
(*self.event_handler)(event, &self.event_loop, &mut self.control_flow);
442467
} else {
@@ -446,15 +471,6 @@ impl<T> EventLoopRunner<T> {
446471
panic!("Tried to call event handler with null handler");
447472
}
448473
}
449-
450-
fn event_processing_active(&self) -> bool {
451-
match self.runner_state {
452-
RunnerState::HandlingEvents => true,
453-
RunnerState::DeferredNewEvents(..) |
454-
RunnerState::New |
455-
RunnerState::Idle(..) => false
456-
}
457-
}
458474
}
459475

460476
// Implementation taken from https://github.com/rust-lang/rust/blob/db5476571d9b27c862b95c1e64764b0ac8980e23/src/libstd/sys/windows/mod.rs
@@ -490,7 +506,8 @@ impl<T> Drop for EventLoop<T> {
490506
}
491507

492508
pub(crate) struct EventLoopThreadExecutor {
493-
thread_id: DWORD
509+
thread_id: DWORD,
510+
trigger_newevents_on_redraw: Arc<AtomicBool>
494511
}
495512

496513
impl EventLoopThreadExecutor {
@@ -500,6 +517,10 @@ impl EventLoopThreadExecutor {
500517
self.thread_id == cur_thread_id
501518
}
502519

520+
pub(super) fn trigger_newevents_on_redraw(&self) -> bool {
521+
!self.in_event_loop_thread() || self.trigger_newevents_on_redraw.load(Ordering::Relaxed)
522+
}
523+
503524
/// Executes a function in the event loop thread. If we're already in the event loop thread,
504525
/// we just call the function directly.
505526
///
@@ -586,6 +607,12 @@ lazy_static! {
586607
winuser::RegisterWindowMessageA("Winit::InitialDpiMsg\0".as_ptr() as LPCSTR)
587608
}
588609
};
610+
// Message sent by a `Window` if it's requesting a redraw without sending a NewEvents.
611+
pub static ref REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID: u32 = {
612+
unsafe {
613+
winuser::RegisterWindowMessageA("Winit::RequestRedrawNoNewevents\0".as_ptr() as LPCSTR)
614+
}
615+
};
589616
static ref THREAD_EVENT_TARGET_WINDOW_CLASS: Vec<u16> = unsafe {
590617
use std::ffi::OsStr;
591618
use std::os::windows::ffi::OsStrExt;
@@ -708,7 +735,7 @@ unsafe extern "system" fn public_window_callback<T>(
708735
}
709736
winuser::WM_ENTERSIZEMOVE => {
710737
let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle;
711-
if let Some(runner) = *subclass_input.event_loop_runner.borrow_mut() {
738+
if let ELRSharedOption::Runner(runner) = *subclass_input.event_loop_runner.borrow_mut() {
712739
(*runner).modal_loop_data = Some(ModalLoopData {
713740
hwnd: window,
714741
timer_handle: modal_timer_handle
@@ -719,7 +746,7 @@ unsafe extern "system" fn public_window_callback<T>(
719746
},
720747
winuser::WM_EXITSIZEMOVE => {
721748
let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle;
722-
if let Some(runner) = *subclass_input.event_loop_runner.borrow_mut() {
749+
if let ELRSharedOption::Runner(runner) = *subclass_input.event_loop_runner.borrow_mut() {
723750
(*runner).modal_loop_data = None;
724751
}
725752
winuser::SetTimer(window, modal_timer_handle, 0x7FFFFFFF, None);
@@ -729,7 +756,7 @@ unsafe extern "system" fn public_window_callback<T>(
729756
let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle;
730757
if wparam == modal_timer_handle {
731758
let runner = subclass_input.event_loop_runner.borrow_mut();
732-
if let Some(runner) = *runner {
759+
if let ELRSharedOption::Runner(runner) = *runner {
733760
let runner = &mut *runner;
734761
if runner.modal_loop_data.is_some() {
735762
runner.events_cleared();
@@ -791,12 +818,44 @@ unsafe extern "system" fn public_window_callback<T>(
791818
0
792819
},
793820

821+
_ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => {
822+
use events::WindowEvent::RedrawRequested;
823+
let runner = subclass_input.event_loop_runner.borrow_mut();
824+
if let ELRSharedOption::Runner(runner) = *runner {
825+
let runner = &mut *runner;
826+
match runner.runner_state {
827+
RunnerState::Idle(..) |
828+
RunnerState::DeferredNewEvents(..) => runner.call_event_handler(Event::WindowEvent {
829+
window_id: SuperWindowId(WindowId(window)),
830+
event: RedrawRequested,
831+
}),
832+
_ => ()
833+
}
834+
}
835+
0
836+
},
794837
winuser::WM_PAINT => {
795-
use events::WindowEvent::Redraw;
796-
subclass_input.send_event(Event::WindowEvent {
838+
use events::WindowEvent::RedrawRequested;
839+
let event = || Event::WindowEvent {
797840
window_id: SuperWindowId(WindowId(window)),
798-
event: Redraw,
799-
});
841+
event: RedrawRequested,
842+
};
843+
844+
let mut send_event = false;
845+
{
846+
let runner = subclass_input.event_loop_runner.borrow_mut();
847+
if let ELRSharedOption::Runner(runner) = *runner {
848+
let runner = &mut *runner;
849+
match runner.runner_state {
850+
RunnerState::Idle(..) |
851+
RunnerState::DeferredNewEvents(..) => runner.call_event_handler(event()),
852+
_ => send_event = true
853+
}
854+
}
855+
}
856+
if send_event {
857+
subclass_input.send_event(event());
858+
}
800859
commctrl::DefSubclassProc(window, msg, wparam, lparam)
801860
},
802861

src/platform/windows/window.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ use {
3030
};
3131
use platform::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId};
3232
use platform::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi};
33-
use platform::platform::events_loop::{self, DESTROY_MSG_ID, EventLoop, INITIAL_DPI_MSG_ID, WindowState};
33+
use platform::platform::events_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID};
34+
use platform::platform::events_loop::WindowState;
3435
use platform::platform::icon::{self, IconType, WinIcon};
3536
use platform::platform::monitor;
3637
use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input;
@@ -140,6 +141,22 @@ impl Window {
140141
}
141142
}
142143

144+
#[inline]
145+
pub fn request_redraw(&self) {
146+
unsafe {
147+
if self.thread_executor.trigger_newevents_on_redraw() {
148+
winuser::RedrawWindow(
149+
self.window.0,
150+
ptr::null(),
151+
ptr::null_mut(),
152+
winuser::RDW_INTERNALPAINT
153+
);
154+
} else {
155+
winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0);
156+
}
157+
}
158+
}
159+
143160
pub(crate) fn get_position_physical(&self) -> Option<(i32, i32)> {
144161
util::get_window_rect(self.window.0)
145162
.map(|rect| (rect.left as i32, rect.top as i32))

src/window.rs

+15
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,21 @@ impl Window {
205205
self.window.hide()
206206
}
207207

208+
/// Emits a `WindowEvent::RedrawRequested` event in the associated event loop after all OS
209+
/// events have been processed by the event loop.
210+
///
211+
/// This is the **strongly encouraged** method of redrawing windows, as it can integrates with
212+
/// OS-requested redraws (e.g. when a window gets resized).
213+
///
214+
/// This function can cause `RedrawRequested` events to be emitted after `Event::EventsCleared`
215+
/// but before `Event::NewEvents` if called in the following circumstances:
216+
/// * While processing `EventsCleared`.
217+
/// * While processing a `RedrawRequested` event that was sent during `EventsCleared` or any
218+
/// directly subsequent `RedrawRequested` event.
219+
pub fn request_redraw(&self) {
220+
self.window.request_redraw()
221+
}
222+
208223
/// Returns the position of the top-left hand corner of the window relative to the
209224
/// top-left hand corner of the desktop.
210225
///

0 commit comments

Comments
 (0)