178 lines
5.4 KiB
Plaintext
178 lines
5.4 KiB
Plaintext
#[allow(unused_imports)]
|
|
use log::{debug, error, info, trace, warn};
|
|
|
|
use std::{
|
|
thread,
|
|
sync::mpsc,
|
|
time::Duration,
|
|
};
|
|
|
|
use winit::{
|
|
dpi::PhysicalSize,
|
|
event_loop::{EventLoop, EventLoopProxy},
|
|
window::{WindowBuilder, Window},
|
|
};
|
|
|
|
//TODO fix that
|
|
use crate::{
|
|
io::{Output, Input, Key, Signal, ReadError},
|
|
utils::Rect,
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
pub struct WinitWindow {
|
|
pub name: String,
|
|
size: Rect<i32>,
|
|
id: usize,
|
|
|
|
receiver: mpsc::Receiver<Key>,
|
|
window: Window,
|
|
event_loop_proxy: EventLoopProxy<Signal>,
|
|
}
|
|
|
|
impl Drop for WinitWindow {
|
|
fn drop(&mut self) {
|
|
use winit::event::Event;
|
|
|
|
// kill event_loop
|
|
if self.event_loop_proxy.send_event(Signal::Exit).is_err() {
|
|
warn!("EventLoop thread is dead before Exit signal");
|
|
}
|
|
//while match self.read(Duration::from_millis(1)) {
|
|
// Ok(Key::Closed) => false,
|
|
// _ => true,
|
|
//} {}
|
|
}
|
|
}
|
|
|
|
impl WinitWindow {
|
|
pub fn new(title: &str, size: Rect<i32>) -> Result<WinitWindow, &'static str> {
|
|
use winit::platform::unix::EventLoopExtUnix;
|
|
|
|
debug!("Creating window");
|
|
let name = title.to_string();
|
|
let id = 0;
|
|
|
|
//Since we can't move the EventLoop from one thread to another, we need to create it in the
|
|
//right thread and then move the Window back to the main thread instead
|
|
let cloned_name = name.clone();
|
|
let (tx, rx) = mpsc::channel();
|
|
let (tmp_tx, tmp_rx) = mpsc::sync_channel(1);
|
|
let builder = thread::Builder::new().name(title);
|
|
//the EventLoop hijacks the thread so there is no need to join it later...
|
|
thread::spawn(move || {
|
|
|
|
trace!("Creating Window in EventLoop thread");
|
|
//winit doesn't like us creating the EventLoop in another thread either so we have to
|
|
//drop crossplatform compatibility :/
|
|
let event_loop = EventLoop::new_any_thread();
|
|
let window = WindowBuilder::new()
|
|
.with_inner_size(PhysicalSize {width: size.w, height: size.h})
|
|
.with_title(cloned_name)
|
|
.build(&event_loop).unwrap();
|
|
let event_loop_proxy = event_loop.create_proxy();
|
|
|
|
trace!("Sending Window back to main thread");
|
|
tmp_tx.send((window, event_loop_proxy)).unwrap();
|
|
|
|
event_loop.run(move |event: winit::event::Event<'_, Signal>, _, control_flow| {
|
|
use winit::{
|
|
event_loop::ControlFlow,
|
|
event::Event,
|
|
event,
|
|
};
|
|
|
|
*control_flow = ControlFlow::Wait;
|
|
|
|
match event {
|
|
Event::LoopDestroyed => {
|
|
tx.send(Key::Closed).unwrap();
|
|
debug!("Closed EventLoop");
|
|
},
|
|
Event::WindowEvent{window_id: _, event} => match event {
|
|
event::WindowEvent::CloseRequested => {
|
|
debug!("Close requested");
|
|
tx.send(Key::Close).unwrap();
|
|
},
|
|
event::WindowEvent::CursorMoved{position, ..} => {
|
|
tx.send(Key::MouseMove{
|
|
x: position.x,
|
|
y: position.y,
|
|
}).unwrap();
|
|
},
|
|
_ => (),
|
|
},
|
|
Event::UserEvent(signal) => match signal {
|
|
Signal::Exit => {
|
|
debug!("Stopping input thread...");
|
|
*control_flow = ControlFlow::Exit;
|
|
},
|
|
Signal::Test => {
|
|
tx.send(Key::Test).unwrap();
|
|
},
|
|
},
|
|
_ => (),
|
|
}})
|
|
});
|
|
|
|
let (window, event_loop_proxy) = tmp_rx.recv().unwrap();
|
|
trace!("Received Window in main thread");
|
|
|
|
Ok(Self {
|
|
name,
|
|
size,
|
|
id,
|
|
receiver: rx,
|
|
window,
|
|
event_loop_proxy,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Output<Window> for WinitWindow {
|
|
fn get_id(&self) -> usize { self.id }
|
|
fn set_id(&mut self, id: usize) { self.id = id; }
|
|
|
|
fn size(&mut self) -> &mut Rect<i32> { &mut self.size }
|
|
|
|
fn window(&self) -> &Window { &self.window }
|
|
}
|
|
|
|
impl Input for WinitWindow {
|
|
fn read(&self, timeout: Duration) -> Result<Key, ReadError> {
|
|
|
|
match self.receiver.recv_timeout(timeout) {
|
|
Ok(key) => Ok(key),
|
|
Err(_) => Err(ReadError::Timeout),
|
|
}
|
|
}
|
|
|
|
fn write(&self, signal: Signal) {
|
|
|
|
self.event_loop_proxy.send_event(signal)
|
|
.map_err(|_| "Could not send Signal to EventLoop").unwrap();
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
use crate::utils::Rect;
|
|
|
|
#[test]
|
|
fn test_new_drop() {
|
|
let _window1 = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap();
|
|
let _window2 = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap();
|
|
panic!("test");
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_write() {
|
|
let window = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap();
|
|
window.write(Signal::Test);
|
|
let input = window.read(Duration::from_millis(1)).unwrap();
|
|
assert!(matches!(input, Key::Test));
|
|
}
|
|
}
|