diff --git a/src/graphics/metal.rs b/src/graphics/metal.rs index 4d75ad7e..a2ab5b03 100644 --- a/src/graphics/metal.rs +++ b/src/graphics/metal.rs @@ -210,13 +210,6 @@ pub struct Buffer { next_value: usize, } -#[derive(Clone, Copy, Debug, PartialEq)] -struct ShaderUniform { - size: u64, - offset: u64, - format: MTLVertexFormat, -} - #[derive(Debug)] struct ShaderInternal { vertex_function: ObjcId, diff --git a/src/native/apple/frameworks.rs b/src/native/apple/frameworks.rs index 5f0de3c4..ec4b7dd3 100644 --- a/src/native/apple/frameworks.rs +++ b/src/native/apple/frameworks.rs @@ -14,10 +14,10 @@ pub use { class, declare::ClassDecl, msg_send, - runtime::{Class, Object, Protocol, Sel, BOOL, NO, YES}, + runtime::{Class, Object, Sel, BOOL, NO, YES}, sel, sel_impl, Encode, Encoding, }, - std::{ffi::c_void, os::raw::c_ulong, ptr::NonNull}, + std::{ffi::c_void, ptr::NonNull}, }; //use bitflags::bitflags; diff --git a/src/native/ios.rs b/src/native/ios.rs index 84d721a1..ad1fcfbf 100644 --- a/src/native/ios.rs +++ b/src/native/ios.rs @@ -340,7 +340,10 @@ pub fn define_glk_or_mtk_view_dlg(superclass: &Class) -> *const Class { d.screen_width = screen_width; d.screen_height = screen_height; } - send_message(Message::Resize { width: screen_width, height: screen_height }); + send_message(Message::Resize { + width: screen_width, + height: screen_height, + }); } if let Some(ref mut event_handler) = payload.event_handler { @@ -648,8 +651,7 @@ pub fn define_app_delegate() -> *const Class { // I hope it will work the same on the real device. if conf.platform.blocking_event_loop { msg_send_![&*view, performSelectorOnMainThread:sel!(setNeedsDisplay) withObject:nil waitUntilDone:NO]; - } - else { + } else { msg_send_![&*view, performSelectorOnMainThread:sel!(display) withObject:nil waitUntilDone:YES]; } } diff --git a/src/native/linux_x11/keycodes.rs b/src/native/linux_x11/keycodes.rs index c0133dd2..f8ee3e17 100644 --- a/src/native/linux_x11/keycodes.rs +++ b/src/native/linux_x11/keycodes.rs @@ -165,6 +165,9 @@ pub unsafe fn translate_mouse_button(button: i32) -> MouseButton { }; } -pub unsafe extern "C" fn keysym_to_unicode(libxkbcommon: &mut LibXkbCommon, keysym: super::libx11::KeySym) -> i32 { - return (libxkbcommon.xkb_keysym_to_utf32)(keysym as u32) as i32 +pub unsafe extern "C" fn keysym_to_unicode( + libxkbcommon: &mut LibXkbCommon, + keysym: super::libx11::KeySym, +) -> i32 { + return (libxkbcommon.xkb_keysym_to_utf32)(keysym as u32) as i32; } diff --git a/src/native/macos.rs b/src/native/macos.rs index e5f5604d..32398a35 100644 --- a/src/native/macos.rs +++ b/src/native/macos.rs @@ -5,16 +5,28 @@ use { crate::{ conf::{AppleGfxApi, Icon}, - event::{EventHandler, MouseButton}, + event::{EventHandler, KeyCode, KeyMods, MouseButton}, native::{ apple::{apple_util::*, frameworks::*}, gl, NativeDisplayData, Request, }, native_display, CursorIcon, }, - std::{collections::HashMap, os::raw::c_void, sync::mpsc::Receiver}, + std::{ + cell::RefCell, + collections::HashMap, + os::raw::c_void, + sync::{mpsc, Arc, Mutex}, + thread, + }, }; +struct MainThreadState { + quit: bool, + view: *mut Object, + cur_msg: Message, +} + pub struct MacosDisplay { window: ObjcId, view: ObjcId, @@ -32,7 +44,7 @@ pub struct MacosDisplay { event_handler: Option>, f: Option Box>>, modifiers: Modifiers, - native_requests: Receiver, + state: Arc>, update_requested: bool, } @@ -196,6 +208,63 @@ impl MacosDisplay { } } +#[derive(Debug, Clone, Copy)] +enum Message { + Resize { + width: i32, + height: i32, + }, + RawMouseMove { + dx: f32, + dy: f32, + }, + MouseMove { + x: f32, + y: f32, + }, + MouseButtonDown { + button: MouseButton, + x: f32, + y: f32, + }, + MouseButtonUp { + button: MouseButton, + x: f32, + y: f32, + }, + MouseWheel { + dx: f32, + dy: f32, + }, + Character { + character: char, + keymods: KeyMods, + repeat: bool, + }, + KeyDown { + keycode: KeyCode, + keymods: KeyMods, + repeat: bool, + }, + KeyUp { + keycode: KeyCode, + keymods: KeyMods, + }, + Destroy, +} +unsafe impl Send for Message {} + +thread_local! { + static MESSAGES_TX: RefCell>> = RefCell::new(None); +} + +fn send_message(message: Message) { + MESSAGES_TX.with(|tx| { + let mut tx = tx.borrow_mut(); + tx.as_mut().unwrap().send(message).unwrap(); + }) +} + #[derive(Default)] struct Modifiers { left_shift: bool, @@ -280,18 +349,14 @@ pub fn define_cocoa_window_delegate() -> *const Class { extern "C" fn window_did_resize(this: &Object, _: Sel, _: ObjcId) { let payload = get_window_payload(this); if let Some((w, h)) = unsafe { payload.update_dimensions() } { - if let Some(event_handler) = payload.context() { - event_handler.resize_event(w as _, h as _); - } + send_message(Message::Resize { width: w, height: h }); } } extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: ObjcId) { let payload = get_window_payload(this); if let Some((w, h)) = unsafe { payload.update_dimensions() } { - if let Some(event_handler) = payload.context() { - event_handler.resize_event(w as _, h as _); - } + send_message(Message::Resize { width: w, height: h }); } } extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: ObjcId) { @@ -372,15 +437,17 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { if payload.cursor_grabbed { let dx: f64 = msg_send!(event, deltaX); let dy: f64 = msg_send!(event, deltaY); - if let Some(event_handler) = payload.context() { - event_handler.raw_mouse_motion(dx as f32, dy as f32); - } + send_message(Message::RawMouseMove { + dx: dx as f32, + dy: dy as f32, + }); } else { let point: NSPoint = msg_send!(event, locationInWindow); let point = payload.transform_mouse_point(&point); - if let Some(event_handler) = payload.context() { - event_handler.mouse_motion_event(point.0, point.1); - } + send_message(Message::MouseMove { + x: point.0, + y: point.1, + }); } } } @@ -391,12 +458,18 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { unsafe { let point: NSPoint = msg_send!(event, locationInWindow); let point = payload.transform_mouse_point(&point); - if let Some(event_handler) = payload.context() { - if down { - event_handler.mouse_button_down_event(btn, point.0, point.1); - } else { - event_handler.mouse_button_up_event(btn, point.0, point.1); - } + if down { + send_message(Message::MouseButtonDown { + button: btn, + x: point.0, + y: point.1, + }); + } else { + send_message(Message::MouseButtonUp { + button: btn, + x: point.0, + y: point.1, + }); } } } @@ -418,8 +491,7 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { extern "C" fn other_mouse_up(this: &Object, _sel: Sel, event: ObjcId) { fire_mouse_event(this, event, false, MouseButton::Middle); } - extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: ObjcId) { - let payload = get_window_payload(this); + extern "C" fn scroll_wheel(_: &Object, _sel: Sel, event: ObjcId) { unsafe { let mut dx: f64 = msg_send![event, scrollingDeltaX]; let mut dy: f64 = msg_send![event, scrollingDeltaY]; @@ -428,9 +500,10 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { dx *= 10.0; dy *= 10.0; } - if let Some(event_handler) = payload.context() { - event_handler.mouse_wheel_event(dx as f32, dy as f32); - } + send_message(Message::MouseWheel { + dx: dx as f32, + dy: dy as f32, + }); } } extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) { @@ -456,36 +529,38 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { } } - extern "C" fn key_down(this: &Object, _sel: Sel, event: ObjcId) { - let payload = get_window_payload(this); + extern "C" fn key_down(_: &Object, _sel: Sel, event: ObjcId) { let mods = get_event_key_modifier(event); let repeat: bool = unsafe { msg_send!(event, isARepeat) }; if let Some(key) = get_event_keycode(event) { - if let Some(event_handler) = payload.context() { - event_handler.key_down_event(key, mods, repeat); - } + send_message(Message::KeyDown { + keycode: key, + keymods: mods, + repeat, + }); } if let Some(character) = get_event_char(event) { - if let Some(event_handler) = payload.context() { - event_handler.char_event(character, mods, repeat); - } + send_message(Message::Character { + character, + keymods: mods, + repeat, + }); } } - extern "C" fn key_up(this: &Object, _sel: Sel, event: ObjcId) { - let payload = get_window_payload(this); + extern "C" fn key_up(_: &Object, _sel: Sel, event: ObjcId) { let mods = get_event_key_modifier(event); if let Some(key) = get_event_keycode(event) { - if let Some(event_handler) = payload.context() { - event_handler.key_up_event(key, mods); - } + send_message(Message::KeyUp { + keycode: key, + keymods: mods, + }); } } extern "C" fn flags_changed(this: &Object, _sel: Sel, event: ObjcId) { fn produce_event( - payload: &mut MacosDisplay, keycode: crate::KeyCode, mods: crate::KeyMods, old_pressed: bool, @@ -493,13 +568,16 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { ) { if new_pressed ^ old_pressed { if new_pressed { - if let Some(event_handler) = payload.context() { - event_handler.key_down_event(keycode, mods, false); - } + send_message(Message::KeyDown { + keycode, + keymods: mods, + repeat: false, + }); } else { - if let Some(event_handler) = payload.context() { - event_handler.key_up_event(keycode, mods); - } + send_message(Message::KeyUp { + keycode, + keymods: mods, + }); } } } @@ -510,56 +588,48 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { let new_modifiers = Modifiers::new(flags); produce_event( - payload, crate::KeyCode::LeftShift, mods, payload.modifiers.left_shift, new_modifiers.left_shift, ); produce_event( - payload, crate::KeyCode::RightShift, mods, payload.modifiers.right_shift, new_modifiers.right_shift, ); produce_event( - payload, crate::KeyCode::LeftControl, mods, payload.modifiers.left_control, new_modifiers.left_control, ); produce_event( - payload, crate::KeyCode::RightControl, mods, payload.modifiers.right_control, new_modifiers.right_control, ); produce_event( - payload, crate::KeyCode::LeftSuper, mods, payload.modifiers.left_command, new_modifiers.left_command, ); produce_event( - payload, crate::KeyCode::RightSuper, mods, payload.modifiers.right_command, new_modifiers.right_command, ); produce_event( - payload, crate::KeyCode::LeftAlt, mods, payload.modifiers.left_alt, new_modifiers.left_alt, ); produce_event( - payload, crate::KeyCode::RightAlt, mods, payload.modifiers.right_alt, @@ -568,6 +638,75 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { payload.modifiers = new_modifiers; } + + extern "C" fn process_message(this: &Object, _: Sel, _: ObjcId) { + use Message::*; + let payload = get_window_payload(this); + let msg = { + let state = payload.state.lock().unwrap(); + state.cur_msg + }; + match msg { + Destroy => { + let mut state = payload.state.lock().unwrap(); + state.quit = true; + } + MouseMove { x, y } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.mouse_motion_event(x, y); + } + } + RawMouseMove { dx, dy } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.raw_mouse_motion(dx, dy); + } + } + MouseButtonDown { button, x, y } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.mouse_button_down_event(button, x, y); + } + } + MouseButtonUp { button, x, y } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.mouse_button_up_event(button, x, y); + } + } + MouseWheel { dx, dy } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.mouse_wheel_event(dx as f32, dy as f32); + } + } + Character { + character, + keymods, + repeat, + } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.char_event(character, keymods, repeat); + } + } + KeyDown { + keycode, + keymods, + repeat, + } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.key_down_event(keycode, keymods, repeat); + } + } + KeyUp { keycode, keymods } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.key_up_event(keycode, keymods); + } + } + Resize { width, height } => { + if let Some(ref mut event_handler) = payload.event_handler { + event_handler.resize_event(width as _, height as _); + } + } + } + } + decl.add_method( sel!(canBecomeKey), yes as extern "C" fn(&Object, Sel) -> BOOL, @@ -634,6 +773,10 @@ unsafe fn view_base_decl(decl: &mut ClassDecl) { flags_changed as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method(sel!(keyUp:), key_up as extern "C" fn(&Object, Sel, ObjcId)); + decl.add_method( + sel!(processMessage:), + process_message as extern "C" fn(&Object, Sel, ObjcId), + ); } pub fn define_opengl_view_class() -> *const Class { @@ -647,7 +790,12 @@ pub fn define_opengl_view_class() -> *const Class { let () = msg_send![super(this, superclass), reshape]; if let Some((w, h)) = payload.update_dimensions() { - if let Some(event_handler) = payload.context() { + // left this because post_processing.rs turns black after the first resize + // and somehow this makes it draw until manual window resize + // (bug existed even on original macos implementation) + + // send_message(Message::Resize { width: w, height: h }); + if let Some(ref mut event_handler) = payload.event_handler { event_handler.resize_event(w as _, h as _); } } @@ -905,7 +1053,7 @@ pub unsafe fn run(conf: crate::conf::Conf, f: F) where F: 'static + FnOnce() -> Box, { - let (tx, rx) = std::sync::mpsc::channel(); + let (tx, requests_rx) = std::sync::mpsc::channel(); let clipboard = Box::new(MacosClipboard); crate::set_display(NativeDisplayData { high_dpi: conf.high_dpi, @@ -914,6 +1062,12 @@ where ..NativeDisplayData::new(conf.window_width, conf.window_height, tx, clipboard) }); + let state_original = Arc::new(Mutex::new(MainThreadState { + quit: false, + view: std::ptr::null_mut(), + cur_msg: Message::MouseMove { x: 0., y: 0. }, + })); + let mut display = MacosDisplay { view: std::ptr::null_mut(), window: std::ptr::null_mut(), @@ -925,9 +1079,9 @@ where gfx_api: conf.platform.apple_gfx_api, f: Some(Box::new(f)), event_handler: None, - native_requests: rx, modifiers: Modifiers::default(), update_requested: true, + state: state_original.clone(), }; let app_delegate_class = define_app_delegate(); @@ -990,6 +1144,10 @@ where let mut d = native_display().lock().unwrap(); d.view = view; } + { + let mut s = state_original.lock().unwrap(); + s.view = view; + } (*view).set_ivar("display_ptr", &mut display as *mut _ as *mut c_void); display.window = window; @@ -1009,45 +1167,80 @@ where let () = msg_send![window, makeKeyAndOrderFront: nil]; - let ns_app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; + let (tx, rx) = std::sync::mpsc::channel(); - // Basically reimplementing msg_send![ns_app, run] here - let () = msg_send![ns_app, finishLaunching]; + MESSAGES_TX.with(move |messages_tx| *messages_tx.borrow_mut() = Some(tx)); - let distant_future: ObjcId = msg_send![class!(NSDate), distantFuture]; - let distant_past: ObjcId = msg_send![class!(NSDate), distantPast]; - let mut done = false; - while !(done || crate::native_display().lock().unwrap().quit_ordered) { - while let Ok(request) = display.native_requests.try_recv() { - display.process_request(request); - } + struct SendHack(F); + unsafe impl Send for SendHack {} - { - let d = native_display().lock().unwrap(); - if d.quit_requested || d.quit_ordered { - done = true; + let state = SendHack(state_original.clone()); + thread::spawn(move || { + let s = state.0; + + loop { + while let Ok(request) = requests_rx.try_recv() { + let s = s.lock().unwrap(); + let view = s.view; + let payload = get_window_payload(view.as_ref().unwrap()); + payload.process_request(request); } - } - let block_on_wait = conf.platform.blocking_event_loop && !display.update_requested; - if block_on_wait { - let event: ObjcId = msg_send![ns_app, nextEventMatchingMask: NSEventMask::NSAnyEventMask untilDate: distant_future inMode:NSDefaultRunLoopMode dequeue:YES]; + let block_on_wait = { + let s = s.lock().unwrap(); + let view = s.view; - let () = msg_send![ns_app, sendEvent:event]; - } else { - loop { - let event: ObjcId = msg_send![ns_app, nextEventMatchingMask: NSEventMask::NSAnyEventMask untilDate: distant_past inMode:NSDefaultRunLoopMode dequeue:YES]; - if event == nil { - break; + let payload = get_window_payload(view.as_ref().unwrap()); + conf.platform.blocking_event_loop && !payload.update_requested + }; + + if block_on_wait { + let res = rx.recv(); + + if let Ok(msg) = res { + let view; + { + let mut s = s.lock().unwrap(); + view = s.view; + s.cur_msg = msg; + } + msg_send_![&*view, performSelectorOnMainThread:sel!(processMessage:) withObject:nil waitUntilDone:YES]; + } + } else { + // process all the messages from the main thread + while let Ok(msg) = rx.try_recv() { + let view; + { + let mut s = s.lock().unwrap(); + view = s.view; + s.cur_msg = msg; + } + msg_send_![&*view, performSelectorOnMainThread:sel!(processMessage:) withObject:nil waitUntilDone:YES]; } - let () = msg_send![ns_app, sendEvent:event]; } - } - if !conf.platform.blocking_event_loop || display.update_requested { - unsafe { - let () = msg_send!(view, setNeedsDisplay: YES); + let update_requested; + let view; + { + let s = s.lock().unwrap(); + view = s.view; + + let payload = get_window_payload(view.as_ref().unwrap()); + update_requested = payload.update_requested; + } + + if !conf.platform.blocking_event_loop || update_requested { + unsafe { + msg_send_![view, performSelectorOnMainThread:sel!(setNeedsDisplay:) withObject:YES waitUntilDone:NO]; + } } + thread::yield_now(); } - } + }); + + let () = msg_send![ns_app, run]; + + // run should never return + // but just in case + unreachable!(); }