diff --git a/src/frontend/software/termwindow.rs b/src/frontend/software/termwindow.rs index 2297e6487..51d3bdeeb 100644 --- a/src/frontend/software/termwindow.rs +++ b/src/frontend/software/termwindow.rs @@ -1,19 +1,20 @@ use crate::config::Config; use crate::font::FontConfiguration; use crate::frontend::guicommon::host::{HostHelper, HostImpl, TabHost}; -use crate::frontend::guicommon::window::TerminalWindow; use crate::mux::tab::Tab; use crate::mux::window::WindowId as MuxWindowId; use crate::mux::Mux; use ::window::*; use failure::Fallible; use promise::Future; +use std::any::Any; use std::rc::Rc; use std::sync::Arc; pub struct TermWindow { - config: Arc, + window: Option, fonts: Rc, + config: Arc, width: usize, height: usize, cell_height: usize, @@ -22,6 +23,10 @@ pub struct TermWindow { } impl WindowCallbacks for TermWindow { + fn created(&mut self, window: &Window) { + self.window.replace(window.clone()); + } + fn can_close(&mut self) -> bool { // self.host.close_current_tab(); true @@ -38,6 +43,13 @@ impl WindowCallbacks for TermWindow { */ Connection::get().unwrap().terminate_message_loop(); } + + fn as_any(&mut self) -> &mut dyn Any { + self + } + + fn paint(&mut self, ctx: &mut dyn PaintContext) { + } } impl Drop for TermWindow { @@ -72,6 +84,7 @@ impl TermWindow { width, height, Box::new(Self { + window: None, width, height, cell_height, diff --git a/window/examples/basic.rs b/window/examples/basic.rs index ef24a6169..c10232140 100644 --- a/window/examples/basic.rs +++ b/window/examples/basic.rs @@ -1,5 +1,6 @@ use ::window::*; use failure::Fallible; +use std::any::Any; struct MyWindow { allow_close: bool, @@ -75,6 +76,10 @@ impl WindowCallbacks for MyWindow { spawn_window().unwrap(); } } + + fn as_any(&mut self) -> &mut dyn Any { + self + } } fn spawn_window() -> Fallible<()> { @@ -90,6 +95,14 @@ fn spawn_window() -> Fallible<()> { )?; win.show(); + win.apply(|myself, win| { + if let Some(myself) = myself.downcast_ref::() { + eprintln!( + "got myself; allow_close={}, cursor_pos:{:?}", + myself.allow_close, myself.cursor_pos + ); + } + }); Ok(()) } diff --git a/window/src/lib.rs b/window/src/lib.rs index d3c18e007..b54a9a6a1 100644 --- a/window/src/lib.rs +++ b/window/src/lib.rs @@ -1,3 +1,4 @@ +use std::any::Any; pub mod bitmaps; pub mod color; pub mod input; @@ -100,7 +101,7 @@ pub enum MouseCursor { } #[allow(unused_variables)] -pub trait WindowCallbacks { +pub trait WindowCallbacks: Any { /// Called when the window close button is clicked. /// Return true to allow the close to continue, false to /// prevent it from closing. @@ -134,6 +135,13 @@ pub trait WindowCallbacks { /// Called when the window is created and allows the embedding /// app to reference the window and operate upon it. fn created(&mut self, window: &Window) {} + + /// An unfortunate bit of boilerplate; you need to provie an impl + /// of this method that returns `self` in order for the downcast_ref + /// method of the Any trait to be usable on WindowCallbacks. + /// https://stackoverflow.com/q/46045298/149111 and others have + /// some rationale on why Rust works this way. + fn as_any(&mut self) -> &mut dyn Any; } pub trait WindowOps { @@ -152,6 +160,14 @@ pub trait WindowOps { /// Change the titlebar text for the window fn set_title(&self, title: &str); + + /// Schedule a callback on the data associated with the window. + /// The `Any` that is passed in corresponds to the WindowCallbacks + /// impl you passed to `new_window`, pre-converted to Any so that + /// you can `downcast_ref` or `downcast_mut` it and operate on it. + fn apply(&self, func: F) + where + Self: Sized; } pub trait WindowOpsMut { diff --git a/window/src/os/macos/window.rs b/window/src/os/macos/window.rs index 6cd599bbd..9cb4c1cfe 100644 --- a/window/src/os/macos/window.rs +++ b/window/src/os/macos/window.rs @@ -19,6 +19,7 @@ use objc::declare::ClassDecl; use objc::rc::{StrongPtr, WeakPtr}; use objc::runtime::{Class, Object, Sel}; use objc::*; +use std::any::Any; use std::cell::RefCell; use std::ffi::c_void; use std::rc::Rc; @@ -119,6 +120,19 @@ impl WindowOps for Window { let title = title.to_owned(); Connection::with_window_inner(self.0, move |inner| inner.set_title(&title)); } + + fn apply(&self, func: F) + where + Self: Sized, + { + Connection::with_window_inner(self.0, move |inner| { + let window = Window(inner.window_id); + + if let Some(window_view) = WindowView::get_this(unsafe { &**inner.view }) { + func(window_view.inner.borrow_mut().callbacks.as_any(), &window); + } + }); + } } impl WindowOpsMut for WindowInner {