Merge pull request #915 from kosyak/event-sender

EventSubsystem::push_event should be callable from non-main threads.
This commit is contained in:
Cobrand
2019-09-10 21:24:34 +00:00
committed by GitHub
2 changed files with 116 additions and 35 deletions
+93 -35
View File
@@ -112,16 +112,7 @@ impl crate::EventSubsystem {
/// Pushes an event to the event queue.
pub fn push_event(&self, event: Event) -> Result<(), String> {
match event.to_ll() {
Some(mut raw_event) => {
let ok = unsafe { sys::SDL_PushEvent(&mut raw_event) == 1 };
if ok { Ok(()) }
else { Err(get_error()) }
},
None => {
Err("Cannot push unsupported event type to the queue".to_owned())
}
}
self.event_sender().push_event(event)
}
@@ -232,32 +223,17 @@ impl crate::EventSubsystem {
/// ```
pub fn push_custom_event<T: ::std::any::Any>(&self, event:T)
-> Result<(), String> {
use ::std::any::TypeId;
let cet = CUSTOM_EVENT_TYPES.lock().unwrap();
let type_id = TypeId::of::<Box<T>>();
self.event_sender().push_custom_event(event)
}
let user_event_id = *match cet.type_id_to_sdl_id.get(&type_id) {
Some(id) => id,
None => {
return Err(
"Type is not registered as a custom event type!".to_owned()
);
}
};
let event_box = Box::new(event);
let event = Event::User {
timestamp: 0,
window_id: 0,
type_: user_event_id,
code: 0,
data1: Box::into_raw(event_box) as *mut c_void,
data2: ::std::ptr::null_mut()
};
r#try!(self.push_event(event));
Ok(())
/// Create an event sender that can be sent to other threads.
///
/// An `EventSender` will not keep the event subsystem alive. If the event subsystem is
/// shut down calls to `push_event` and `push_custom_event` will return errors.
pub fn event_sender(&self) -> EventSender {
EventSender {
_priv: (),
}
}
}
@@ -2046,3 +2022,85 @@ mod test {
}
}
/// A sendible type that can push events to the event queue.
pub struct EventSender {
_priv: (),
}
impl EventSender {
/// Pushes an event to the event queue.
pub fn push_event(&self, event: Event) -> Result<(), String> {
match event.to_ll() {
Some(mut raw_event) => {
let ok = unsafe { sys::SDL_PushEvent(&mut raw_event) == 1 };
if ok { Ok(()) }
else { Err(get_error()) }
},
None => {
Err("Cannot push unsupported event type to the queue".to_owned())
}
}
}
/// Push a custom event
///
/// If the event type ``T`` was not registered using
/// [EventSubsystem::register_custom_event]
/// (../struct.EventSubsystem.html#method.register_custom_event),
/// this method will panic.
///
/// # Example: pushing and receiving a custom event
/// ```
/// struct SomeCustomEvent {
/// a: i32
/// }
///
/// let sdl = sdl2::init().unwrap();
/// let ev = sdl.event().unwrap();
/// let mut ep = sdl.event_pump().unwrap();
///
/// ev.register_custom_event::<SomeCustomEvent>().unwrap();
///
/// let event = SomeCustomEvent { a: 42 };
///
/// ev.push_custom_event(event);
///
/// let received = ep.poll_event().unwrap(); // or within a for event in ep.poll_iter()
/// if received.is_user_event() {
/// let e2 = received.as_user_event_type::<SomeCustomEvent>().unwrap();
/// assert_eq!(e2.a, 42);
/// }
/// ```
pub fn push_custom_event<T: ::std::any::Any>(&self, event:T)
-> Result<(), String> {
use ::std::any::TypeId;
let cet = CUSTOM_EVENT_TYPES.lock().unwrap();
let type_id = TypeId::of::<Box<T>>();
let user_event_id = *match cet.type_id_to_sdl_id.get(&type_id) {
Some(id) => id,
None => {
return Err(
"Type is not registered as a custom event type!".to_owned()
);
}
};
let event_box = Box::new(event);
let event = Event::User {
timestamp: 0,
window_id: 0,
type_: user_event_id,
code: 0,
data1: Box::into_raw(event_box) as *mut c_void,
data2: ::std::ptr::null_mut()
};
r#try!(self.push_event(event));
Ok(())
}
}
+23
View File
@@ -1,4 +1,5 @@
extern crate sdl2;
use sdl2::event;
#[test]
@@ -98,3 +99,25 @@ fn test4(ev: &sdl2::EventSubsystem, ep: &mut sdl2::EventPump) {
assert_eq!(e2.a, 42);
}
}
#[test]
fn test_event_sender_no_subsystem() {
let sdl = sdl2::init().unwrap();
let ev = sdl.event().unwrap();
let tx = ev.event_sender();
assert!(tx.push_event(sdl2::event::Event::Window {
timestamp: 0,
window_id: 0,
win_event: sdl2::event::WindowEvent::Shown,
}).is_ok());
drop(ev);
// Should return an error now the evet subsystem has been shut down
assert!(tx.push_event(sdl2::event::Event::Window {
timestamp: 0,
window_id: 0,
win_event: sdl2::event::WindowEvent::Hidden,
}).is_err());
}