use std::cell::{self, RefCell}; use std::rc::Rc; use glk; use glk::gidispatch; use glk::helpers::pool; use glk::helpers::stream_manager::StreamManager; use glk::types::{stream_result_t, strid_t, style, stylehint, winid_t, winmethod, wintype}; use crate::util::unhandled; use crate::window::Window; /** Handles window-related Glk calls. */ pub struct WindowManager { /** Object registry callbacks. */ obj_registry: gidispatch::ObjRegistry, /** Retained registry callbacks. */ retained_registry: gidispatch::RetainedRegistry, /** Pool of Windows. These are wrapped in a Rc> because * the WindowStream needs to have a reference to the associated window. */ windows: pool::ObjPool>, winid_t>, /** Root window. */ root: winid_t, } impl WindowManager { pub fn new() -> Self { Self { obj_registry: gidispatch::ObjRegistry::new(), retained_registry: gidispatch::RetainedRegistry::new(), windows: pool::ObjPool::new(), root: 0 as winid_t, } } pub fn get_window(&self, win: winid_t) -> cell::RefMut { self.windows.get(win).unwrap().borrow_mut() } pub fn set_object_registry(&mut self, obj_registry: gidispatch::ObjRegistry) { self.obj_registry = obj_registry; for (id, obj) in self.windows.iter_mut() { obj.borrow_mut().girock = obj_registry.register(id); } } pub fn set_retained_registry(&mut self, retained_registry: gidispatch::RetainedRegistry) { self.retained_registry = retained_registry; } pub fn get_root(&mut self) -> winid_t { self.root } pub fn open( &mut self, streams: &mut StreamManager, split: winid_t, method: winmethod, size: u32, wtype: wintype, rock: u32, ) -> winid_t { println!( "glk_window_open {:?} {:?} {:?} {:?} {:?}", split, method, size, wtype, rock ); if self.root != 0 as winid_t { // Block window creation after the first one, the current dumb // implementation definitely cannot handle different windows. return 0 as winid_t; } let (winid, winrc) = self .windows .insert(Rc::new(RefCell::new(Window::new(wtype, rock)))); let mut window = winrc.borrow_mut(); window.girock = self.obj_registry.register(winid); window.stream = streams.open_window(winrc.clone()); self.root = winid; winid } pub fn close(&mut self, streams: &mut StreamManager, win: winid_t) -> stream_result_t { println!("glk_window_close"); { let window = self.get_window(win); // Close associated stream (this is the only way a window stream can be closed) // this will also unregister the steram from object registry. streams.remove(window.stream); // Unregister window from object registry. self.obj_registry.unregister(win, window.girock); } // Finally, really remove it self.windows.remove(win); stream_result_t { readcount: 0, writecount: 0, } } pub fn get_size(&mut self, win: winid_t) -> (u32, u32) { self.get_window(win).get_size() } pub fn set_arrangement(&mut self, win: winid_t, method: winmethod, size: u32, keywin: winid_t) { self.get_window(win).set_arrangement(method, size, keywin) } pub fn get_arrangement(&mut self, win: winid_t) -> (u32, u32, winid_t) { self.get_window(win).get_arrangement() } pub fn iterate(&mut self, win: winid_t) -> (winid_t, u32) { let win = self.windows.next(win); if let Some(window) = self.windows.get(win) { (win, window.borrow().rock) } else { (win, 0) } } pub fn get_rock(&mut self, win: winid_t) -> u32 { self.get_window(win).get_rock() } pub fn get_type(&mut self, win: winid_t) -> wintype { self.get_window(win).get_type() } pub fn get_parent(&mut self, win: winid_t) -> winid_t { self.get_window(win).get_parent() } pub fn get_sibling(&mut self, win: winid_t) -> winid_t { self.get_window(win).get_sibling() } pub fn clear(&mut self, win: winid_t) { self.get_window(win).clear() } pub fn move_cursor(&mut self, win: winid_t, xpos: u32, ypos: u32) { self.get_window(win).move_cursor(xpos, ypos) } pub fn get_stream(&self, win: winid_t) -> strid_t { self.get_window(win).get_stream() } pub fn set_echo_stream(&mut self, win: winid_t, str: strid_t) { self.get_window(win).set_echo_stream(str) } pub fn get_echo_stream(&mut self, win: winid_t) -> strid_t { self.get_window(win).get_echo_stream() } pub fn get_di_rock(&self, win: winid_t) -> gidispatch::rock { self.get_window(win).get_di_rock() } /* Text style handling */ pub fn stylehint_set(&mut self, _wtype: wintype, _styl: style, _hint: stylehint, _val: i32) { /* TODO */ unhandled("glk_stylehint_set"); } pub fn stylehint_clear(&mut self, _wtype: wintype, _styl: style, _hint: stylehint) { /* TODO */ unhandled("glk_stylehint_clear"); } pub fn style_distinguish(&mut self, _win: winid_t, _styl1: style, _styl2: style) -> u32 { /* TODO */ unhandled("glk_style_distinguish"); // Assume all styles can be distinguished. 1 } pub fn style_measure(&mut self, _win: winid_t, _styl: style, _hint: stylehint) -> Option { /* TODO */ unhandled("glk_style_measure"); None } }