diff --git a/src/event_loop/driver.rs b/src/event_loop/driver.rs index 6c313ad1..3a0acb33 100644 --- a/src/event_loop/driver.rs +++ b/src/event_loop/driver.rs @@ -18,21 +18,25 @@ use crate::event_loop; use crate::logging; -use crate::main::Commands; -use crate::state::{ Application, Event }; +use crate::state::Application; use glib; use std::sync::mpsc; use std::thread; use std::time::Instant; +use super::{ActorState, Outcome}; // Traits use crate::logging::Warn; +use super::Event; -/// Type of the sender that waits for external events -type Sender = mpsc::Sender; -/// Type of the sender that waits for internal state changes -type UISender = glib::Sender; +type UISender = glib::Sender< + < + ::Outcome as Outcome + >::Commands +>; + +pub type Threaded = Threaded_; /// This loop driver spawns a new thread which updates the state in a loop, /// in response to incoming events. @@ -43,12 +47,27 @@ type UISender = glib::Sender; // This can/should be abstracted over Event and Commands, // so that the C call-ins can be thrown away from here and defined near events. #[derive(Clone)] -pub struct Threaded { - thread: Sender, +pub struct Threaded_ +where + S: ActorState + Send, + S::Event: Send, + ::Commands: Send, +{ + /// Waits for external events + thread: mpsc::Sender, } -impl Threaded { - pub fn new(ui: UISender, initial_state: Application) -> Self { +impl Threaded_ +where + // Not sure why this needs 'static. It's already owned. + S: ActorState + Send + 'static, + S::Event: Send, + ::Commands: Send, +{ + pub fn new( + ui: UISender, + initial_state: S, + ) -> Self { let (sender, receiver) = mpsc::channel(); let saved_sender = sender.clone(); thread::spawn(move || { @@ -71,13 +90,16 @@ impl Threaded { } } - pub fn send(&self, event: Event) -> Result<(), mpsc::SendError> { + pub fn send(&self, event: S::Event) -> Result<(), mpsc::SendError> { self.thread.send(event) } - fn handle_loop_event(loop_sender: &Sender, state: event_loop::State, event: Event, ui: &UISender) - -> event_loop::State - { + fn handle_loop_event( + loop_sender: &mpsc::Sender, + state: event_loop::State, + event: S::Event, + ui: &UISender, + ) -> event_loop::State { let now = Instant::now(); let (new_state, commands) = event_loop::handle_event(state.clone(), event, now); @@ -94,12 +116,15 @@ impl Threaded { new_state } - fn schedule_timeout_wake(loop_sender: &Sender, when: Instant) { + fn schedule_timeout_wake( + loop_sender: &mpsc::Sender, + when: Instant, + ) { let sender = loop_sender.clone(); thread::spawn(move || { let now = Instant::now(); thread::sleep(when - now); - sender.send(Event::TimeoutReached(when)) + sender.send(S::Event::new_timeout_reached(when)) .or_warn(&mut logging::Print, logging::Problem::Warning, "Can't wake visibility manager"); }); } @@ -109,7 +134,7 @@ impl Threaded { mod c { use super::*; - use crate::state::Presence; + use crate::state::{Event, Presence}; use crate::state::LayoutChoice; use crate::state::visibility; use crate::util; diff --git a/src/event_loop/mod.rs b/src/event_loop/mod.rs index 571b0a8d..05af69a7 100644 --- a/src/event_loop/mod.rs +++ b/src/event_loop/mod.rs @@ -45,6 +45,7 @@ use std::time::{ Duration, Instant }; /// Carries the incoming data to affect the actor state, /// plus an event to help schedule timed events. pub trait Event: Clone { + fn new_timeout_reached(when: Instant) -> Self; /// Returns the value of the reached timeout, if this event carries the timeout. fn get_timeout_reached(&self) -> Option; } diff --git a/src/state.rs b/src/state.rs index 6fc78c7e..5030a5d4 100644 --- a/src/state.rs +++ b/src/state.rs @@ -83,6 +83,10 @@ pub enum Event { } impl event_loop::Event for Event { + fn new_timeout_reached(when: Instant) -> Self { + Self::TimeoutReached(when) + } + fn get_timeout_reached(&self) -> Option { match self { Self::TimeoutReached(when) => Some(*when),