use crate::{
sk::{AppFocus, MainThreadToken, QuitReason, Sk, SkInfo, sk_quit, sk_step},
system::{Input, Log},
};
use std::{
any::{Any, TypeId},
cell::RefCell,
collections::VecDeque,
fmt,
rc::Rc,
thread::sleep,
time::Duration,
};
use winit::{
application::ApplicationHandler,
event::WindowEvent,
event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
window::WindowId,
};
type OnStepClosure<'a> = Box<dyn FnMut(&mut Sk, &MainThreadToken) + 'a>;
type OnDeviceEventClosure<'a> = Box<dyn FnMut(&mut Sk, WindowEvent) + 'a>;
#[derive(PartialEq)]
enum SleepPhase {
Sleeping,
WakingUp,
WokeUp,
Stopping,
}
pub struct SkClosures<'a> {
sk: Sk,
token: MainThreadToken,
on_step: OnStepClosure<'a>,
on_sleeping_step: OnStepClosure<'a>,
on_window_event: OnDeviceEventClosure<'a>,
shutdown: Box<dyn FnMut(&mut Sk) + 'a>,
window_id: Option<WindowId>,
sleeping: SleepPhase,
}
impl ApplicationHandler<StepperAction> for SkClosures<'_> {
fn user_event(&mut self, _event_loop: &ActiveEventLoop, user_event: StepperAction) {
Log::diag(format!("UserEvent {user_event:?}"));
self.sk.send_event(user_event);
}
fn resumed(&mut self, _event_loop: &ActiveEventLoop) {
Log::info("Resumed !!");
}
fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) {
if event == WindowEvent::Destroyed {
Log::info(format!("SkClosure Window {window_id:?} Destroyed !!!"));
return;
}
match event {
WindowEvent::RedrawRequested => {
Log::diag("RedrawRequested: Time to wake up");
self.sleeping = SleepPhase::WakingUp;
}
WindowEvent::Focused(value) => {
Log::diag(format!("!!!Window {window_id:?} focused: {value:?}"));
if self.window_id != Some(window_id) {
if self.window_id.is_none() {
self.window_id = Some(window_id);
} else {
Log::warn(format!("There are more than 1 windows: {:?} & {:?}", self.window_id, window_id));
}
}
if value {
Log::diag("GainedFocus: Time to wake up");
self.sleeping = SleepPhase::WakingUp;
}
}
WindowEvent::CloseRequested => {
Log::info("SkClosure LoopExiting !!");
self.sk.steppers.shutdown();
(self.shutdown)(&mut self.sk);
event_loop.exit();
}
WindowEvent::KeyboardInput { device_id: _, event, is_synthetic: _ } => match &event.state {
winit::event::ElementState::Pressed => {}
winit::event::ElementState::Released => {
Input::text_inject_chars(event.logical_key.to_text().unwrap_or("?"));
}
},
_ => (self.on_window_event)(&mut self.sk, event),
}
}
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
if self.sk.get_app_focus() == AppFocus::Hidden && self.sleeping == SleepPhase::WokeUp {
self.sleeping = SleepPhase::Sleeping;
Log::diag("Time to sleep")
}
match self.sleeping {
SleepPhase::WokeUp => {
self.step(event_loop);
}
SleepPhase::WakingUp => {
self.step(event_loop);
if self.sk.get_app_focus() != AppFocus::Hidden {
self.sleeping = SleepPhase::WokeUp;
Log::diag("WokeUp");
}
}
SleepPhase::Sleeping => {
sleep(Duration::from_millis(200));
if cfg!(not(target_os = "android")) {
self.step(event_loop);
}
(self.on_sleeping_step)(&mut self.sk, &self.token);
if self.sk.get_app_focus() == AppFocus::Active {
self.sleeping = SleepPhase::WakingUp;
}
}
SleepPhase::Stopping => {}
}
}
fn suspended(&mut self, _event_loop: &ActiveEventLoop) {
Log::info("SkClosure Suspended !!");
}
fn exiting(&mut self, _event_loop: &ActiveEventLoop) {
Log::info("SkClosure Exiting !!");
}
fn memory_warning(&mut self, _event_loop: &ActiveEventLoop) {
Log::warn("SkClosure Memory Warning !!");
}
}
impl<'a> SkClosures<'a> {
fn step(&mut self, event_loop: &ActiveEventLoop) {
if unsafe { sk_step(None) } == 0 {
self.window_event(event_loop, self.window_id.unwrap_or(WindowId::dummy()), WindowEvent::CloseRequested);
self.sleeping = SleepPhase::Stopping;
Log::diag("sk_step() says stop()!!");
}
if !self.sk.steppers.step(&mut self.token) {
self.sk.steppers.shutdown();
unsafe { sk_quit(QuitReason::User) }
Log::diag("The app demand to quit()!!");
};
while let Some(mut action) = self.sk.actions.pop_front() {
action();
}
(self.on_step)(&mut self.sk, &self.token);
self.token.event_report.clear();
}
pub fn run_app<U: FnMut(&mut Sk, &MainThreadToken) + 'a, S: FnMut(&mut Sk) + 'a>(
sk: Sk,
event_loop: EventLoop<StepperAction>,
on_step: U,
on_shutdown: S,
) {
let mut this = Self {
sk,
on_step: Box::new(on_step),
on_sleeping_step: Box::new(|_sk, _main_thread| {}),
on_window_event: Box::new(|_sk, _window_event| {}),
shutdown: Box::new(on_shutdown),
token: MainThreadToken {
#[cfg(feature = "event-loop")]
event_report: vec![],
},
window_id: None,
sleeping: SleepPhase::WakingUp,
};
event_loop.set_control_flow(ControlFlow::Poll);
if let Err(err) = event_loop.run_app(&mut this) {
Log::err(format!("event_loop.run_app returned with an error : {err:?}"));
}
}
pub fn new<U: FnMut(&mut Sk, &MainThreadToken) + 'a>(sk: Sk, on_step: U) -> Self {
Self {
sk,
on_step: Box::new(on_step),
on_sleeping_step: Box::new(|_sk, _main_thread| {}),
on_window_event: Box::new(|_sk, _windows_event| {}),
shutdown: Box::new(|_sk| {}),
token: MainThreadToken {
#[cfg(feature = "event-loop")]
event_report: vec![],
},
window_id: None,
sleeping: SleepPhase::WakingUp,
}
}
pub fn on_sleeping_step<U: FnMut(&mut Sk, &MainThreadToken) + 'a>(&mut self, on_sleeping_step: U) -> &mut Self {
self.on_sleeping_step = Box::new(on_sleeping_step);
self
}
pub fn on_window_event<U: FnMut(&mut Sk, WindowEvent) + 'a>(&mut self, on_window_event: U) -> &mut Self {
self.on_window_event = Box::new(on_window_event);
self
}
pub fn shutdown<S: FnMut(&mut Sk) + 'a>(&mut self, on_shutdown: S) -> &mut Self {
self.shutdown = Box::new(on_shutdown);
self
}
pub fn run(&mut self, event_loop: EventLoop<StepperAction>) {
event_loop.set_control_flow(ControlFlow::Poll);
if let Err(err) = event_loop.run_app(self) {
Log::err(format!("event_loop.run_app returned with an error : {err:?}"));
}
}
}
pub trait IStepper {
fn initialize(&mut self, id: StepperId, sk: Rc<RefCell<SkInfo>>) -> bool;
fn initialize_done(&mut self) -> bool {
true
}
fn enabled(&self) -> bool {
true
}
fn step(&mut self, token: &MainThreadToken);
fn shutdown(&mut self) {}
fn shutdown_done(&mut self) -> bool {
true
}
}
pub enum StepperAction {
Add(Box<dyn for<'a> IStepper + Send + 'static>, TypeId, StepperId),
RemoveAll(TypeId),
Remove(StepperId),
Quit(StepperId, String),
Event(StepperId, String, String),
}
impl fmt::Debug for StepperAction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StepperAction::Add(_stepper, _id, stepper_id) => {
write!(f, "StepperAction::Add(..., type_id: ... , stepper_id:{stepper_id:?} )")
}
StepperAction::RemoveAll(type_id) => write!(f, "StepperAction::RemoveAll( type_id:{type_id:?} )"),
StepperAction::Remove(stepper_id) => write!(f, "StepperAction::Remove( id:{stepper_id:?} )"),
StepperAction::Quit(stepper_id, reason) => {
write!(f, "StepperAction::Quit() sent by id:{stepper_id:?} for reason '{reason}'")
}
StepperAction::Event(stepper_id, key, value) => {
write!(f, "StepperAction::Event( id:{stepper_id:?} => {key}->{value} )")
}
}
}
}
impl StepperAction {
pub fn add_default<T: IStepper + Send + Default + 'static>(stepper_id: impl AsRef<str>) -> Self {
let stepper = <T>::default();
let stepper_type = stepper.type_id();
StepperAction::Add(Box::new(stepper), stepper_type, stepper_id.as_ref().to_owned())
}
pub fn add<T: IStepper + Send + 'static>(stepper_id: impl AsRef<str>, stepper: T) -> Self {
let stepper_type = stepper.type_id();
StepperAction::Add(Box::new(stepper), stepper_type, stepper_id.as_ref().to_string())
}
pub fn remove_all(type_id: TypeId) -> Self {
StepperAction::RemoveAll(type_id)
}
pub fn remove(stepper_id: impl AsRef<str>) -> Self {
StepperAction::Remove(stepper_id.as_ref().to_string())
}
pub fn quit(stepper_id: impl AsRef<str>, reason: impl AsRef<str>) -> Self {
StepperAction::Quit(stepper_id.as_ref().to_string(), reason.as_ref().to_string())
}
pub fn event<S: AsRef<str>>(stepper_id: S, key: S, value: S) -> Self {
StepperAction::Event(stepper_id.as_ref().to_string(), key.as_ref().to_owned(), value.as_ref().to_owned())
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StepperState {
Initializing,
Running,
Closing,
}
pub struct StepperHandler {
id: StepperId,
type_id: TypeId,
stepper: Box<dyn IStepper>,
state: StepperState,
}
impl StepperHandler {
pub fn get_id(&self) -> &StepperId {
&self.id
}
pub fn get_type_id(&self) -> TypeId {
self.type_id
}
pub fn get_state(&self) -> StepperState {
self.state
}
}
pub type StepperId = String;
pub const ISTEPPER_RUNNING: &str = "IStepper_Running";
pub const ISTEPPER_REMOVED: &str = "IStepper_Removed";
#[cfg(feature = "event-loop")]
pub struct Steppers {
sk_info: Rc<RefCell<SkInfo>>,
running_steppers: Vec<StepperHandler>,
stepper_actions: VecDeque<StepperAction>,
}
#[cfg(feature = "event-loop")]
impl Steppers {
pub fn new(sk_info: Rc<RefCell<SkInfo>>) -> Self {
Self { sk_info, running_steppers: vec![], stepper_actions: VecDeque::new() }
}
pub fn send_event(&mut self, action: StepperAction) {
self.stepper_actions.push_back(action);
}
pub(crate) fn step(&mut self, token: &mut MainThreadToken) -> bool {
while let Some(action) = self.stepper_actions.pop_front() {
match action {
StepperAction::Add(mut stepper, type_id, stepper_id) => {
if stepper.initialize(stepper_id.clone(), self.sk_info.clone()) {
let stepper_h =
StepperHandler { id: stepper_id, type_id, stepper, state: StepperState::Initializing };
self.running_steppers.push(stepper_h);
} else {
Log::warn(format!("Stepper {stepper_id} did not initialize"));
token.event_report.push(StepperAction::event(stepper_id.as_str(), ISTEPPER_REMOVED, "false"));
}
}
StepperAction::RemoveAll(stepper_type) => {
for stepper_h in
self.running_steppers.iter_mut().filter(|stepper_h| stepper_h.type_id == stepper_type)
{
stepper_h.stepper.shutdown();
stepper_h.state = StepperState::Closing;
}
}
StepperAction::Remove(stepper_id) => {
for stepper_h in self.running_steppers.iter_mut().filter(|stepper_h| stepper_h.id == stepper_id) {
stepper_h.stepper.shutdown();
stepper_h.state = StepperState::Closing;
}
}
StepperAction::Quit(from, reason) => {
Log::info(format!("Quit sent by {from} for reason: {reason}"));
return false;
}
_ => token.event_report.push(action),
}
}
let mut removed_steppers = vec![];
for stepper_h in &mut self.running_steppers {
match stepper_h.state {
StepperState::Initializing => {
if stepper_h.stepper.initialize_done() {
Log::info(format!("Stepper {} is initialized.", &stepper_h.id));
stepper_h.state = StepperState::Running;
token.event_report.push(StepperAction::event(stepper_h.id.as_str(), ISTEPPER_RUNNING, "true"));
}
}
StepperState::Running => (),
StepperState::Closing => {
if stepper_h.stepper.shutdown_done() {
removed_steppers.push(stepper_h.id.clone());
token.event_report.push(StepperAction::event(stepper_h.id.as_str(), ISTEPPER_REMOVED, "true"));
}
}
}
}
self.running_steppers.retain(|stepper_h| {
if removed_steppers.contains(&stepper_h.id) {
Log::info(format!("Stepper {} is removed.", &stepper_h.id));
false
} else {
true
}
});
for stepper_h in
&mut self.running_steppers.iter_mut().filter(|stepper_h| stepper_h.state == StepperState::Running)
{
stepper_h.stepper.step(token)
}
true
}
pub fn get_stepper_handlers(&self) -> &[StepperHandler] {
self.running_steppers.as_slice()
}
pub fn shutdown(&mut self) {
self.stepper_actions.clear();
for stepper_h in self.running_steppers.iter_mut() {
Log::diag(format!("Closing {}", stepper_h.id));
stepper_h.stepper.shutdown();
stepper_h.state = StepperState::Closing;
}
for _iter in 0..50 {
let mut removed_steppers = vec![];
for stepper_h in
&mut self.running_steppers.iter_mut().filter(|stepper_h| stepper_h.state == StepperState::Closing)
{
if stepper_h.stepper.shutdown_done() {
removed_steppers.push(stepper_h.id.clone());
}
}
self.running_steppers.retain(|stepper_h| {
if removed_steppers.contains(&stepper_h.id) {
Log::info(format!("Stepper {} is removed.", &stepper_h.id));
false
} else {
true
}
});
if self.running_steppers.is_empty() {
break;
}
sleep(Duration::from_millis(100));
}
self.running_steppers.clear();
}
pub fn get_count(&self) -> usize {
self.running_steppers.len()
}
}
pub struct StepperClosures<'a> {
on_step: Box<dyn FnMut(&MainThreadToken) + 'a>,
shutdown: Box<dyn FnMut() + 'a>,
}
impl Default for StepperClosures<'_> {
fn default() -> Self {
Self { on_step: Box::new(|_token| {}), shutdown: Box::new(|| {}) }
}
}
impl StepperClosures<'_> {
pub fn new() -> Self {
Self { ..Default::default() }
}
pub fn set<U: FnMut(&MainThreadToken) + 'static, S: FnMut() + 'static>(
&mut self,
on_step: U,
on_shutdown: S,
) -> &mut Self {
self.on_step = Box::new(on_step);
self.shutdown = Box::new(on_shutdown);
self
}
pub fn step(&mut self, token: &MainThreadToken) {
(self.on_step)(token)
}
pub fn shutdown(&mut self) {
(self.shutdown)()
}
}