Skip to content

Commit

Permalink
Add ability to send custom user events
Browse files Browse the repository at this point in the history
  • Loading branch information
Osspial committed Nov 9, 2018
1 parent a0b2bb3 commit 2c607ff
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 120 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ cocoa = "0.18.4"
core-foundation = "0.6"
core-graphics = "0.17.3"

[target.'cfg(target_os = "windows")'.dependencies.crossbeam-channel]
version = "0.3"

[target.'cfg(target_os = "windows")'.dependencies.winapi]
version = "0.3.6"
features = [
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ another library.
extern crate winit;

fn main() {
let mut events_loop = winit::EventsLoop::new();
let window = winit::Window::new(&events_loop).unwrap();
let mut event_loop = winit::EventLoop::new();
let window = winit::Window::new(&event_loop).unwrap();

events_loop.run_forever(|event| {
event_loop.run(|event| {
match event {
winit::Event::WindowEvent {
event: winit::WindowEvent::CloseRequested,
Expand Down
11 changes: 7 additions & 4 deletions examples/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
extern crate winit;
use winit::{EventLoop, WindowBuilder};

fn main() {
let events_loop = winit::EventLoop::new();
let events_loop: EventLoop<i32> = EventLoop::new_user_event();

let _window = winit::WindowBuilder::new()
let _window = WindowBuilder::new()
.with_title("A fantastic window!")
.build(&events_loop)
.unwrap();

let proxy = events_loop.create_proxy();

std::thread::spawn(move || {
let mut counter = 0;
// Wake up the `events_loop` once every second.
loop {
std::thread::sleep(std::time::Duration::from_secs(1));
proxy.wakeup().unwrap();
proxy.send_event(counter).unwrap();
counter += 1;
}
});

events_loop.run(move |event, _, control_flow| {
println!("{:?}", event);
match event {
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } =>
*control_flow = winit::ControlFlow::Wait,
*control_flow = winit::ControlFlow::Exit,
_ => *control_flow = winit::ControlFlow::Wait,
}
});
Expand Down
19 changes: 17 additions & 2 deletions src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use {DeviceId, LogicalPosition, LogicalSize, WindowId};

/// Describes a generic event.
#[derive(Clone, Debug, PartialEq)]
pub enum Event {
pub enum Event<T> {
WindowEvent {
window_id: WindowId,
event: WindowEvent,
Expand All @@ -14,7 +14,7 @@ pub enum Event {
device_id: DeviceId,
event: DeviceEvent,
},
Awakened,
UserEvent(T),
/// Emitted when new events arrive from the OS to be processed.
NewEvents(StartCause),
/// Emitted when all of the event loop's events have been processed and control flow is about
Expand All @@ -31,6 +31,21 @@ pub enum Event {
Suspended(bool),
}

impl<T> Event<T> {
pub fn map_nonuser_event<U>(self) -> Result<Event<U>, Event<T>> {
use self::Event::*;
match self {
UserEvent(_) => Err(self),
WindowEvent{window_id, event} => Ok(WindowEvent{window_id, event}),
DeviceEvent{device_id, event} => Ok(DeviceEvent{device_id, event}),
NewEvents(cause) => Ok(NewEvents(cause)),
EventsCleared => Ok(EventsCleared),
LoopDestroyed => Ok(LoopDestroyed),
Suspended(suspended) => Ok(Suspended(suspended)),
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StartCause {
/// Sent if the time specified by `ControlFlow::WaitTimeout` has been elapsed. Contains the
Expand Down
41 changes: 25 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ extern crate serde;

#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
#[macro_use]
extern crate crossbeam_channel;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use]
extern crate objc;
Expand Down Expand Up @@ -163,12 +166,12 @@ pub struct DeviceId(platform::DeviceId);
/// forbiding 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 wakeup an `EventLoop` from an other thread.
pub struct EventLoop {
events_loop: platform::EventLoop,
pub struct EventLoop<T> {
events_loop: platform::EventLoop<T>,
_marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync
}

impl std::fmt::Debug for EventLoop {
impl<T> std::fmt::Debug for EventLoop<T> {
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
fmtr.pad("EventLoop { .. }")
}
Expand Down Expand Up @@ -199,14 +202,20 @@ impl Default for ControlFlow {
}
}

impl EventLoop {
impl EventLoop<()> {
pub fn new() -> EventLoop<()> {
EventLoop::<()>::new_user_event()
}
}

impl<T> EventLoop<T> {
/// Builds a new events loop.
///
/// Usage will result in display backend initialisation, this can be controlled on linux
/// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
/// If it is not set, winit will try to connect to a wayland connection, and if it fails will
/// fallback on x11. If this variable is set with any other value, winit will panic.
pub fn new() -> EventLoop {
pub fn new_user_event() -> EventLoop<T> {
EventLoop {
events_loop: platform::EventLoop::new(),
_marker: ::std::marker::PhantomData,
Expand Down Expand Up @@ -234,14 +243,14 @@ impl EventLoop {
/// Any values not passed to this function will *not* be dropped.
#[inline]
pub fn run<F>(self, event_handler: F) -> !
where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow)
where F: 'static + FnMut(Event<T>, &EventLoop<T>, &mut ControlFlow)
{
self.events_loop.run(event_handler)
}

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

/// Used to wake up the `EventLoop` from another thread.
#[derive(Clone)]
pub struct EventLoopProxy {
events_loop_proxy: platform::EventLoopProxy,
pub struct EventLoopProxy<T> {
events_loop_proxy: platform::EventLoopProxy<T>,
}

impl std::fmt::Debug for EventLoopProxy {
impl<T> std::fmt::Debug for EventLoopProxy<T> {
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
fmtr.pad("EventLoopProxy { .. }")
}
}

impl EventLoopProxy {
/// Wake up the `EventLoop` from which this proxy was created.
///
/// This causes the `EventLoop` to emit an `Awakened` event.
impl<T> EventLoopProxy<T> {
/// Send an event to the `EventLoop` from which this proxy was created. This emits a
/// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
/// function.
///
/// Returns an `Err` if the associated `EventLoop` no longer exists.
pub fn wakeup(&self) -> Result<(), EventLoopClosed> {
self.events_loop_proxy.wakeup()
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
self.events_loop_proxy.send_event(event)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/os/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub trait EventLoopExt {
fn new_dpi_unaware() -> Self where Self: Sized;
}

impl EventLoopExt for EventLoop {
impl<T> EventLoopExt for EventLoop<T> {
#[inline]
fn new_dpi_unaware() -> Self {
EventLoop {
Expand Down
14 changes: 6 additions & 8 deletions src/platform/windows/drop_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{mem, ptr};
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::VecDeque;
use crossbeam_channel::Sender;

use winapi::ctypes::c_void;
use winapi::shared::guiddef::REFIID;
Expand All @@ -26,7 +24,7 @@ pub struct FileDropHandlerData {
pub interface: IDropTarget,
refcount: AtomicUsize,
window: HWND,
event_queue: Rc<RefCell<VecDeque<Event>>>,
event_sender: Sender<Event<()>>
}

pub struct FileDropHandler {
Expand All @@ -35,14 +33,14 @@ pub struct FileDropHandler {

#[allow(non_snake_case)]
impl FileDropHandler {
pub fn new(window: HWND, event_queue: Rc<RefCell<VecDeque<Event>>>) -> FileDropHandler {
pub fn new(window: HWND, event_sender: Sender<Event<()>>) -> FileDropHandler {
let data = Box::new(FileDropHandlerData {
interface: IDropTarget {
lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl,
},
refcount: AtomicUsize::new(1),
window,
event_queue,
event_sender,
});
FileDropHandler {
data: Box::into_raw(data),
Expand Down Expand Up @@ -187,8 +185,8 @@ impl FileDropHandler {
}

impl FileDropHandlerData {
fn send_event(&self, event: Event) {
self.event_queue.borrow_mut().push_back(event);
fn send_event(&self, event: Event<()>) {
self.event_sender.send(event).ok();
}
}

Expand Down
Loading

0 comments on commit 2c607ff

Please sign in to comment.