portlight 0.0.2

Cross-platform window management for audio plugins
Documentation
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use std::time::Duration;

use windows::Win32::UI::WindowsAndMessaging::{KillTimer, SetTimer};

use crate::{EventLoop, Result};

pub struct TimerState {
    timer_id: Cell<Option<usize>>,
    event_loop: EventLoop,
    handler: RefCell<Box<dyn FnMut()>>,
}

impl TimerState {
    pub fn repeat<F>(
        event_loop: &EventLoop,
        duration: Duration,
        handler: F,
    ) -> Result<Rc<TimerState>>
    where
        F: FnMut() + 'static,
    {
        let timers = &event_loop.state.timers;

        let timer_id = timers.next_id.get();
        timers.next_id.set(timer_id + 1);

        let state = Rc::new(TimerState {
            timer_id: Cell::new(Some(timer_id)),
            event_loop: event_loop.clone(),
            handler: RefCell::new(Box::new(handler)),
        });

        timers.timers.borrow_mut().insert(timer_id, Rc::clone(&state));

        unsafe {
            let millis = duration.as_millis() as u32;
            SetTimer(event_loop.state.message_hwnd, timer_id, millis, None);
        }

        Ok(state)
    }

    pub fn cancel(&self) {
        if let Some(timer_id) = self.timer_id.take() {
            self.event_loop.state.timers.timers.borrow_mut().remove(&timer_id);
            let _ = unsafe { KillTimer(self.event_loop.state.message_hwnd, timer_id) };
        }
    }
}

pub struct Timers {
    next_id: Cell<usize>,
    timers: RefCell<HashMap<usize, Rc<TimerState>>>,
}

impl Timers {
    pub fn new() -> Timers {
        Timers {
            next_id: Cell::new(0),
            timers: RefCell::new(HashMap::new()),
        }
    }

    pub fn handle_timer(&self, timer_id: usize) -> Option<()> {
        let timer_state = self.timers.borrow().get(&timer_id).cloned();
        if let Some(timer_state) = timer_state {
            timer_state.handler.borrow_mut()();
        }

        Some(())
    }
}