From 4130035f18990248d32f92734257f6bc0d94a24f Mon Sep 17 00:00:00 2001 From: Edward Barnard Date: Thu, 25 Jan 2018 10:36:19 +0000 Subject: [PATCH 1/2] Add a sendable EventSender type for pushing events to the event queue from non-main threads. --- src/sdl2/event.rs | 128 +++++++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 35 deletions(-) diff --git a/src/sdl2/event.rs b/src/sdl2/event.rs index 7ad754e1..71ff1957 100644 --- a/src/sdl2/event.rs +++ b/src/sdl2/event.rs @@ -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(&self, event:T) -> Result<(), String> { - use ::std::any::TypeId; - let cet = CUSTOM_EVENT_TYPES.lock().unwrap(); - let type_id = TypeId::of::>(); + 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::().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::().unwrap(); + /// assert_eq!(e2.a, 42); + /// } + /// ``` + pub fn push_custom_event(&self, event:T) + -> Result<(), String> { + + use ::std::any::TypeId; + let cet = CUSTOM_EVENT_TYPES.lock().unwrap(); + let type_id = TypeId::of::>(); + + 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() + }; + + try!(self.push_event(event)); + + Ok(()) + } +} + From b1823e0ca1467a30eb91f0343f33e33b3b3f987a Mon Sep 17 00:00:00 2001 From: Edward Barnard Date: Thu, 25 Jan 2018 10:58:28 +0000 Subject: [PATCH 2/2] Add tests for EventSender behaviour when the event subsystem has been shut down. --- src/sdl2/event.rs | 2 +- tests/events.rs | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sdl2/event.rs b/src/sdl2/event.rs index 71ff1957..8ff46871 100644 --- a/src/sdl2/event.rs +++ b/src/sdl2/event.rs @@ -2098,7 +2098,7 @@ impl EventSender { data2: ::std::ptr::null_mut() }; - try!(self.push_event(event)); + r#try!(self.push_event(event)); Ok(()) } diff --git a/tests/events.rs b/tests/events.rs index 3955e1bd..d3b1d93b 100644 --- a/tests/events.rs +++ b/tests/events.rs @@ -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()); +} \ No newline at end of file