Skip to content

Commit 2c607ff

Browse files
committed
Add ability to send custom user events
1 parent a0b2bb3 commit 2c607ff

File tree

12 files changed

+176
-120
lines changed

12 files changed

+176
-120
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ cocoa = "0.18.4"
3535
core-foundation = "0.6"
3636
core-graphics = "0.17.3"
3737

38+
[target.'cfg(target_os = "windows")'.dependencies.crossbeam-channel]
39+
version = "0.3"
40+
3841
[target.'cfg(target_os = "windows")'.dependencies.winapi]
3942
version = "0.3.6"
4043
features = [

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ another library.
2626
extern crate winit;
2727

2828
fn main() {
29-
let mut events_loop = winit::EventsLoop::new();
30-
let window = winit::Window::new(&events_loop).unwrap();
29+
let mut event_loop = winit::EventLoop::new();
30+
let window = winit::Window::new(&event_loop).unwrap();
3131

32-
events_loop.run_forever(|event| {
32+
event_loop.run(|event| {
3333
match event {
3434
winit::Event::WindowEvent {
3535
event: winit::WindowEvent::CloseRequested,

examples/proxy.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
extern crate winit;
2+
use winit::{EventLoop, WindowBuilder};
23

34
fn main() {
4-
let events_loop = winit::EventLoop::new();
5+
let events_loop: EventLoop<i32> = EventLoop::new_user_event();
56

6-
let _window = winit::WindowBuilder::new()
7+
let _window = WindowBuilder::new()
78
.with_title("A fantastic window!")
89
.build(&events_loop)
910
.unwrap();
1011

1112
let proxy = events_loop.create_proxy();
1213

1314
std::thread::spawn(move || {
15+
let mut counter = 0;
1416
// Wake up the `events_loop` once every second.
1517
loop {
1618
std::thread::sleep(std::time::Duration::from_secs(1));
17-
proxy.wakeup().unwrap();
19+
proxy.send_event(counter).unwrap();
20+
counter += 1;
1821
}
1922
});
2023

2124
events_loop.run(move |event, _, control_flow| {
2225
println!("{:?}", event);
2326
match event {
2427
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } =>
25-
*control_flow = winit::ControlFlow::Wait,
28+
*control_flow = winit::ControlFlow::Exit,
2629
_ => *control_flow = winit::ControlFlow::Wait,
2730
}
2831
});

src/events.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use {DeviceId, LogicalPosition, LogicalSize, WindowId};
55

66
/// Describes a generic event.
77
#[derive(Clone, Debug, PartialEq)]
8-
pub enum Event {
8+
pub enum Event<T> {
99
WindowEvent {
1010
window_id: WindowId,
1111
event: WindowEvent,
@@ -14,7 +14,7 @@ pub enum Event {
1414
device_id: DeviceId,
1515
event: DeviceEvent,
1616
},
17-
Awakened,
17+
UserEvent(T),
1818
/// Emitted when new events arrive from the OS to be processed.
1919
NewEvents(StartCause),
2020
/// Emitted when all of the event loop's events have been processed and control flow is about
@@ -31,6 +31,21 @@ pub enum Event {
3131
Suspended(bool),
3232
}
3333

34+
impl<T> Event<T> {
35+
pub fn map_nonuser_event<U>(self) -> Result<Event<U>, Event<T>> {
36+
use self::Event::*;
37+
match self {
38+
UserEvent(_) => Err(self),
39+
WindowEvent{window_id, event} => Ok(WindowEvent{window_id, event}),
40+
DeviceEvent{device_id, event} => Ok(DeviceEvent{device_id, event}),
41+
NewEvents(cause) => Ok(NewEvents(cause)),
42+
EventsCleared => Ok(EventsCleared),
43+
LoopDestroyed => Ok(LoopDestroyed),
44+
Suspended(suspended) => Ok(Suspended(suspended)),
45+
}
46+
}
47+
}
48+
3449
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3550
pub enum StartCause {
3651
/// Sent if the time specified by `ControlFlow::WaitTimeout` has been elapsed. Contains the

src/lib.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ extern crate serde;
7272

7373
#[cfg(target_os = "windows")]
7474
extern crate winapi;
75+
#[cfg(target_os = "windows")]
76+
#[macro_use]
77+
extern crate crossbeam_channel;
7578
#[cfg(any(target_os = "macos", target_os = "ios"))]
7679
#[macro_use]
7780
extern crate objc;
@@ -163,12 +166,12 @@ pub struct DeviceId(platform::DeviceId);
163166
/// forbiding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the
164167
/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the
165168
/// `EventLoopProxy` allows you to wakeup an `EventLoop` from an other thread.
166-
pub struct EventLoop {
167-
events_loop: platform::EventLoop,
169+
pub struct EventLoop<T> {
170+
events_loop: platform::EventLoop<T>,
168171
_marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync
169172
}
170173

171-
impl std::fmt::Debug for EventLoop {
174+
impl<T> std::fmt::Debug for EventLoop<T> {
172175
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
173176
fmtr.pad("EventLoop { .. }")
174177
}
@@ -199,14 +202,20 @@ impl Default for ControlFlow {
199202
}
200203
}
201204

202-
impl EventLoop {
205+
impl EventLoop<()> {
206+
pub fn new() -> EventLoop<()> {
207+
EventLoop::<()>::new_user_event()
208+
}
209+
}
210+
211+
impl<T> EventLoop<T> {
203212
/// Builds a new events loop.
204213
///
205214
/// Usage will result in display backend initialisation, this can be controlled on linux
206215
/// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
207216
/// If it is not set, winit will try to connect to a wayland connection, and if it fails will
208217
/// fallback on x11. If this variable is set with any other value, winit will panic.
209-
pub fn new() -> EventLoop {
218+
pub fn new_user_event() -> EventLoop<T> {
210219
EventLoop {
211220
events_loop: platform::EventLoop::new(),
212221
_marker: ::std::marker::PhantomData,
@@ -234,14 +243,14 @@ impl EventLoop {
234243
/// Any values not passed to this function will *not* be dropped.
235244
#[inline]
236245
pub fn run<F>(self, event_handler: F) -> !
237-
where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow)
246+
where F: 'static + FnMut(Event<T>, &EventLoop<T>, &mut ControlFlow)
238247
{
239248
self.events_loop.run(event_handler)
240249
}
241250

242251
/// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another
243252
/// thread.
244-
pub fn create_proxy(&self) -> EventLoopProxy {
253+
pub fn create_proxy(&self) -> EventLoopProxy<T> {
245254
EventLoopProxy {
246255
events_loop_proxy: self.events_loop.create_proxy(),
247256
}
@@ -250,24 +259,24 @@ impl EventLoop {
250259

251260
/// Used to wake up the `EventLoop` from another thread.
252261
#[derive(Clone)]
253-
pub struct EventLoopProxy {
254-
events_loop_proxy: platform::EventLoopProxy,
262+
pub struct EventLoopProxy<T> {
263+
events_loop_proxy: platform::EventLoopProxy<T>,
255264
}
256265

257-
impl std::fmt::Debug for EventLoopProxy {
266+
impl<T> std::fmt::Debug for EventLoopProxy<T> {
258267
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
259268
fmtr.pad("EventLoopProxy { .. }")
260269
}
261270
}
262271

263-
impl EventLoopProxy {
264-
/// Wake up the `EventLoop` from which this proxy was created.
265-
///
266-
/// This causes the `EventLoop` to emit an `Awakened` event.
272+
impl<T> EventLoopProxy<T> {
273+
/// Send an event to the `EventLoop` from which this proxy was created. This emits a
274+
/// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
275+
/// function.
267276
///
268277
/// Returns an `Err` if the associated `EventLoop` no longer exists.
269-
pub fn wakeup(&self) -> Result<(), EventLoopClosed> {
270-
self.events_loop_proxy.wakeup()
278+
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
279+
self.events_loop_proxy.send_event(event)
271280
}
272281
}
273282

src/os/windows.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub trait EventLoopExt {
1515
fn new_dpi_unaware() -> Self where Self: Sized;
1616
}
1717

18-
impl EventLoopExt for EventLoop {
18+
impl<T> EventLoopExt for EventLoop<T> {
1919
#[inline]
2020
fn new_dpi_unaware() -> Self {
2121
EventLoop {

src/platform/windows/drop_handler.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ use std::os::windows::ffi::OsStringExt;
33
use std::path::PathBuf;
44
use std::sync::atomic::{AtomicUsize, Ordering};
55
use std::{mem, ptr};
6-
use std::rc::Rc;
7-
use std::cell::RefCell;
8-
use std::collections::VecDeque;
6+
use crossbeam_channel::Sender;
97

108
use winapi::ctypes::c_void;
119
use winapi::shared::guiddef::REFIID;
@@ -26,7 +24,7 @@ pub struct FileDropHandlerData {
2624
pub interface: IDropTarget,
2725
refcount: AtomicUsize,
2826
window: HWND,
29-
event_queue: Rc<RefCell<VecDeque<Event>>>,
27+
event_sender: Sender<Event<()>>
3028
}
3129

3230
pub struct FileDropHandler {
@@ -35,14 +33,14 @@ pub struct FileDropHandler {
3533

3634
#[allow(non_snake_case)]
3735
impl FileDropHandler {
38-
pub fn new(window: HWND, event_queue: Rc<RefCell<VecDeque<Event>>>) -> FileDropHandler {
36+
pub fn new(window: HWND, event_sender: Sender<Event<()>>) -> FileDropHandler {
3937
let data = Box::new(FileDropHandlerData {
4038
interface: IDropTarget {
4139
lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl,
4240
},
4341
refcount: AtomicUsize::new(1),
4442
window,
45-
event_queue,
43+
event_sender,
4644
});
4745
FileDropHandler {
4846
data: Box::into_raw(data),
@@ -187,8 +185,8 @@ impl FileDropHandler {
187185
}
188186

189187
impl FileDropHandlerData {
190-
fn send_event(&self, event: Event) {
191-
self.event_queue.borrow_mut().push_back(event);
188+
fn send_event(&self, event: Event<()>) {
189+
self.event_sender.send(event).ok();
192190
}
193191
}
194192

0 commit comments

Comments
 (0)