loop driver: Decouple from concrete state

This commit is contained in:
Dorota Czaplejewicz
2022-11-28 15:29:37 +00:00
parent 2f011a57dd
commit e5be92efae
3 changed files with 47 additions and 17 deletions

View File

@ -18,21 +18,25 @@
use crate::event_loop; use crate::event_loop;
use crate::logging; use crate::logging;
use crate::main::Commands; use crate::state::Application;
use crate::state::{ Application, Event };
use glib; use glib;
use std::sync::mpsc; use std::sync::mpsc;
use std::thread; use std::thread;
use std::time::Instant; use std::time::Instant;
use super::{ActorState, Outcome};
// Traits // Traits
use crate::logging::Warn; use crate::logging::Warn;
use super::Event;
/// Type of the sender that waits for external events type UISender<S> = glib::Sender<
type Sender = mpsc::Sender<Event>; <
/// Type of the sender that waits for internal state changes <S as ActorState>::Outcome as Outcome
type UISender = glib::Sender<Commands>; >::Commands
>;
pub type Threaded = Threaded_<Application>;
/// This loop driver spawns a new thread which updates the state in a loop, /// This loop driver spawns a new thread which updates the state in a loop,
/// in response to incoming events. /// in response to incoming events.
@ -43,12 +47,27 @@ type UISender = glib::Sender<Commands>;
// This can/should be abstracted over Event and Commands, // 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. // so that the C call-ins can be thrown away from here and defined near events.
#[derive(Clone)] #[derive(Clone)]
pub struct Threaded { pub struct Threaded_<S>
thread: Sender, where
S: ActorState + Send,
S::Event: Send,
<S::Outcome as Outcome>::Commands: Send,
{
/// Waits for external events
thread: mpsc::Sender<S::Event>,
} }
impl Threaded { impl<S> Threaded_<S>
pub fn new(ui: UISender, initial_state: Application) -> Self { where
// Not sure why this needs 'static. It's already owned.
S: ActorState + Send + 'static,
S::Event: Send,
<S::Outcome as Outcome>::Commands: Send,
{
pub fn new(
ui: UISender<S>,
initial_state: S,
) -> Self {
let (sender, receiver) = mpsc::channel(); let (sender, receiver) = mpsc::channel();
let saved_sender = sender.clone(); let saved_sender = sender.clone();
thread::spawn(move || { thread::spawn(move || {
@ -71,13 +90,16 @@ impl Threaded {
} }
} }
pub fn send(&self, event: Event) -> Result<(), mpsc::SendError<Event>> { pub fn send(&self, event: S::Event) -> Result<(), mpsc::SendError<S::Event>> {
self.thread.send(event) self.thread.send(event)
} }
fn handle_loop_event(loop_sender: &Sender, state: event_loop::State<Application>, event: Event, ui: &UISender) fn handle_loop_event(
-> event_loop::State<Application> loop_sender: &mpsc::Sender<S::Event>,
{ state: event_loop::State<S>,
event: S::Event,
ui: &UISender<S>,
) -> event_loop::State<S> {
let now = Instant::now(); let now = Instant::now();
let (new_state, commands) = event_loop::handle_event(state.clone(), event, now); let (new_state, commands) = event_loop::handle_event(state.clone(), event, now);
@ -94,12 +116,15 @@ impl Threaded {
new_state new_state
} }
fn schedule_timeout_wake(loop_sender: &Sender, when: Instant) { fn schedule_timeout_wake(
loop_sender: &mpsc::Sender<S::Event>,
when: Instant,
) {
let sender = loop_sender.clone(); let sender = loop_sender.clone();
thread::spawn(move || { thread::spawn(move || {
let now = Instant::now(); let now = Instant::now();
thread::sleep(when - 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"); .or_warn(&mut logging::Print, logging::Problem::Warning, "Can't wake visibility manager");
}); });
} }
@ -109,7 +134,7 @@ impl Threaded {
mod c { mod c {
use super::*; use super::*;
use crate::state::Presence; use crate::state::{Event, Presence};
use crate::state::LayoutChoice; use crate::state::LayoutChoice;
use crate::state::visibility; use crate::state::visibility;
use crate::util; use crate::util;

View File

@ -45,6 +45,7 @@ use std::time::{ Duration, Instant };
/// Carries the incoming data to affect the actor state, /// Carries the incoming data to affect the actor state,
/// plus an event to help schedule timed events. /// plus an event to help schedule timed events.
pub trait Event: Clone { pub trait Event: Clone {
fn new_timeout_reached(when: Instant) -> Self;
/// Returns the value of the reached timeout, if this event carries the timeout. /// Returns the value of the reached timeout, if this event carries the timeout.
fn get_timeout_reached(&self) -> Option<Instant>; fn get_timeout_reached(&self) -> Option<Instant>;
} }

View File

@ -83,6 +83,10 @@ pub enum Event {
} }
impl event_loop::Event for Event { impl event_loop::Event for Event {
fn new_timeout_reached(when: Instant) -> Self {
Self::TimeoutReached(when)
}
fn get_timeout_reached(&self) -> Option<Instant> { fn get_timeout_reached(&self) -> Option<Instant> {
match self { match self {
Self::TimeoutReached(when) => Some(*when), Self::TimeoutReached(when) => Some(*when),