use std::mem;
use std::ptr::null_mut;
use std::sync::{Arc, Mutex};
use winapi::shared::windef::*;
use winapi::ctypes::c_int;
use winapi::um::winbase::*;
use winapi::um::winnt::*;
use winapi::um::winuser::*;
#[derive(Clone, Default)]
pub struct RunLoopHandle(Arc<Mutex<RunLoopState>>);
#[derive(Default)]
struct RunLoopState {
listeners: Vec<Listener>,
}
unsafe impl Send for Listener {}
struct Listener {
h: HANDLE,
callback: Box<FnMut()>,
}
pub struct RunLoop {
handle: RunLoopHandle,
accel: HACCEL,
}
impl RunLoop {
pub fn new() -> RunLoop {
RunLoop {
handle: Default::default(),
accel: null_mut(),
}
}
pub fn get_handle(&self) -> RunLoopHandle {
self.handle.clone()
}
pub fn set_accel(&mut self, accel: &[ACCEL]) {
unsafe {
self.accel = CreateAcceleratorTableW(accel as *const _ as *mut _,
accel.len() as c_int);
}
}
pub fn run(&mut self) {
unsafe {
loop {
let mut handles = Vec::new();
for listener in &self.handle.0.lock().unwrap().listeners {
handles.push(listener.h);
}
let len = handles.len() as u32;
let res = MsgWaitForMultipleObjectsEx(
len,
handles.as_ptr(),
INFINITE,
QS_ALLEVENTS,
0
);
if res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_0 + len {
let ix = (res - WAIT_OBJECT_0) as usize;
(&mut self.handle.0.lock().unwrap().listeners[ix].callback)();
}
loop {
let mut msg = mem::uninitialized();
let res = PeekMessageW(&mut msg, null_mut(), 0, 0, PM_NOREMOVE);
if res == 0 {
break;
}
let res = GetMessageW(&mut msg, null_mut(), 0, 0);
if res <= 0 {
return;
}
if self.accel.is_null() ||
TranslateAcceleratorW(msg.hwnd, self.accel, &mut msg) == 0
{
TranslateMessage(&mut msg);
DispatchMessageW(&mut msg);
}
}
}
}
}
}
pub fn request_quit() {
unsafe {
PostQuitMessage(0);
}
}
impl RunLoopHandle {
pub unsafe fn add_handler<F>(&self, h: HANDLE, callback: F)
where F: FnMut() + 'static
{
let listener = Listener {
h,
callback: Box::new(callback),
};
self.0.lock().unwrap().listeners.push(listener);
}
}