1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-10 15:04:32 +03:00

plumb WindowOps for macos

This commit is contained in:
Wez Furlong 2019-08-12 08:38:44 -07:00
parent 0f25545014
commit d8b143776d
3 changed files with 173 additions and 15 deletions

View File

@ -42,4 +42,5 @@ libc = "0.2"
[target.'cfg(target_os="macos")'.dependencies]
cocoa = "0.19"
objc = "0.2"
core-foundation = "0.6"
core-graphics = "0.17"

View File

@ -1,17 +1,80 @@
use super::window::WindowInner;
use cocoa::appkit::{NSApp, NSApplication, NSApplicationActivationPolicyRegular};
use cocoa::base::{id, nil};
use core_foundation::runloop::*;
use failure::Fallible;
use objc::*;
use promise::{BasicExecutor, SpawnFunc};
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize;
use std::sync::{Arc, Mutex};
pub struct Connection {
ns_app: id,
pub(crate) windows: RefCell<HashMap<usize, Rc<RefCell<WindowInner>>>>,
pub(crate) next_window_id: AtomicUsize,
}
struct SpawnQueue {
spawned_funcs: Mutex<VecDeque<SpawnFunc>>,
}
thread_local! {
static CONN: RefCell<Option<Rc<Connection>>> = RefCell::new(None);
}
lazy_static::lazy_static! {
static ref SPAWN_QUEUE: Arc<SpawnQueue> = Arc::new(SpawnQueue::new().expect("failed to create SpawnQueue"));
}
impl Drop for SpawnQueue {
fn drop(&mut self) {}
}
impl SpawnQueue {
fn new() -> Fallible<Self> {
let spawned_funcs = Mutex::new(VecDeque::new());
let observer = unsafe {
CFRunLoopObserverCreate(
std::ptr::null(),
kCFRunLoopAllActivities,
1,
0,
SpawnQueue::trigger,
std::ptr::null_mut(),
)
};
unsafe {
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
}
Ok(Self { spawned_funcs })
}
extern "C" fn trigger(_observer: *mut __CFRunLoopObserver, _: u32, _: *mut std::ffi::c_void) {
SPAWN_QUEUE.run();
}
fn spawn(&self, f: SpawnFunc) {
self.spawned_funcs.lock().unwrap().push_back(f);
unsafe {
CFRunLoopWakeUp(CFRunLoopGetMain());
}
}
fn run(&self) {
loop {
if let Some(func) = self.spawned_funcs.lock().unwrap().pop_front() {
func();
} else {
return;
}
}
}
}
impl Connection {
pub fn get() -> Option<Rc<Self>> {
@ -25,10 +88,18 @@ impl Connection {
}
pub fn init() -> Fallible<Rc<Self>> {
// Ensure that the SPAWN_QUEUE is created; it will have nothing
// to run right now.
SPAWN_QUEUE.run();
unsafe {
let ns_app = NSApp();
ns_app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
let conn = Rc::new(Self { ns_app });
let conn = Rc::new(Self {
ns_app,
windows: RefCell::new(HashMap::new()),
next_window_id: AtomicUsize::new(1),
});
CONN.with(|m| *m.borrow_mut() = Some(Rc::clone(&conn)));
Ok(conn)
}
@ -46,4 +117,36 @@ impl Connection {
}
Ok(())
}
pub fn executor() -> impl BasicExecutor {
SpawnQueueExecutor {}
}
pub(crate) fn next_window_id(&self) -> usize {
self.next_window_id
.fetch_add(1, ::std::sync::atomic::Ordering::Relaxed)
}
fn window_by_id(&self, window_id: usize) -> Option<Rc<RefCell<WindowInner>>> {
self.windows.borrow().get(&window_id).map(Rc::clone)
}
pub(crate) fn with_window_inner<F: FnMut(&mut WindowInner) + Send + 'static>(
window_id: usize,
mut f: F,
) {
SpawnQueueExecutor {}.execute(Box::new(move || {
if let Some(handle) = Connection::get().unwrap().window_by_id(window_id) {
let mut inner = handle.borrow_mut();
f(&mut inner);
}
}));
}
}
struct SpawnQueueExecutor;
impl BasicExecutor for SpawnQueueExecutor {
fn execute(&self, f: SpawnFunc) {
SPAWN_QUEUE.spawn(f)
}
}

View File

@ -2,8 +2,9 @@ use super::{nsstring, nsstring_to_str};
use crate::bitmaps::Image;
use crate::os::macos::bitmap::BitmapRef;
use crate::{
BitmapImage, Color, Dimensions, KeyCode, KeyEvent, Modifiers, MouseButtons, MouseEvent,
MouseEventKind, MousePress, Operator, PaintContext, WindowCallbacks,
BitmapImage, Color, Connection, Dimensions, KeyCode, KeyEvent, Modifiers, MouseButtons,
MouseCursor, MouseEvent, MouseEventKind, MousePress, Operator, PaintContext, WindowCallbacks,
WindowOps, WindowOpsMut,
};
use cocoa::appkit::{
NSApplicationActivateIgnoringOtherApps, NSBackingStoreBuffered, NSEvent, NSEventModifierFlags,
@ -22,16 +23,14 @@ use std::cell::RefCell;
use std::ffi::c_void;
use std::rc::Rc;
pub struct Window {
pub(crate) struct WindowInner {
window_id: usize,
window: StrongPtr,
view: StrongPtr,
}
impl Drop for Window {
fn drop(&mut self) {
eprintln!("drop Window");
}
}
#[derive(Debug, Clone)]
pub struct Window(usize);
impl Window {
pub fn new_window(
@ -51,9 +50,14 @@ impl Window {
NSSize::new(width as f64, height as f64),
);
let conn = Connection::get().expect("Connection::init has not been called");
let window_id = conn.next_window_id();
let inner = Rc::new(RefCell::new(Inner {
callbacks,
view_id: None,
window_id,
}));
let window = StrongPtr::new(
@ -76,22 +80,70 @@ impl Window {
window.setContentView_(*view);
window.setDelegate_(*view);
Ok(Self { window, view })
let window_inner = Rc::new(RefCell::new(WindowInner {
window_id,
window,
view,
}));
conn.windows
.borrow_mut()
.insert(window_id, Rc::clone(&window_inner));
let window = Window(window_id);
inner.borrow_mut().callbacks.created(&window);
Ok(window)
}
}
}
pub fn show(&self) {
impl WindowOps for Window {
fn hide(&self) {
Connection::with_window_inner(self.0, |inner| inner.hide());
}
fn show(&self) {
eprintln!("schedule show");
Connection::with_window_inner(self.0, |inner| inner.show());
}
fn set_cursor(&self, cursor: Option<MouseCursor>) {
Connection::with_window_inner(self.0, move |inner| {
let _ = inner.set_cursor(cursor);
});
}
fn invalidate(&self) {
Connection::with_window_inner(self.0, |inner| inner.invalidate());
}
fn set_title(&self, title: &str) {
let title = title.to_owned();
Connection::with_window_inner(self.0, move |inner| inner.set_title(&title));
}
}
impl WindowOpsMut for WindowInner {
fn show(&mut self) {
eprintln!("do show");
unsafe {
let current_app = NSRunningApplication::currentApplication(nil);
current_app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps);
self.window.makeKeyAndOrderFront_(nil)
}
}
fn hide(&mut self) {}
fn set_cursor(&mut self, cursor: Option<MouseCursor>) {}
fn invalidate(&mut self) {
unsafe {
let () = msg_send![*self.view, setNeedsDisplay: YES];
}
}
fn set_title(&mut self, title: &str) {}
}
struct Inner {
callbacks: Box<WindowCallbacks>,
view_id: Option<WeakPtr>,
window_id: usize,
}
impl Drop for Inner {
@ -314,8 +366,9 @@ impl WindowView {
};
if let Some(myself) = Self::get_this(this) {
eprintln!("{:?}", event);
// myself.inner.borrow_mut().callbacks.mouse_event(&event, &window);
let mut inner = myself.inner.borrow_mut();
let window = Window(inner.window_id);
inner.callbacks.mouse_event(&event, &window);
}
}
@ -364,8 +417,9 @@ impl WindowView {
};
if let Some(myself) = Self::get_this(this) {
eprintln!("{:?}", event);
// myself.inner.borrow_mut().callbacks.key_event(&event, &window);
let mut inner = myself.inner.borrow_mut();
let window = Window(inner.window_id);
inner.callbacks.key_event(&event, &window);
}
}
}