From ff09c3a256136b70cfc6e9bcf88c33a05cba4523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Mon, 23 Nov 2020 14:38:32 +0100 Subject: [PATCH] macOS: add timer triggering WindowHandler::on_frame (#58) * macOS: add simple NSTimer that triggers WindowHandler::on_frame * macOS: invalidate frame timer when releasing view * macOS: clean up --- src/macos/view.rs | 30 +++++++++++++++++++++++++++--- src/macos/window.rs | 29 ++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/macos/view.rs b/src/macos/view.rs index 8d958c3..f9f6f3b 100644 --- a/src/macos/view.rs +++ b/src/macos/view.rs @@ -20,7 +20,7 @@ use crate::{ }; use crate::MouseEvent::{ButtonPressed, ButtonReleased}; -use super::window::{WindowState, WINDOW_STATE_IVAR_NAME}; +use super::window::{WindowState, WINDOW_STATE_IVAR_NAME, FRAME_TIMER_IVAR_NAME}; pub(super) unsafe fn create_view( @@ -67,6 +67,11 @@ unsafe fn create_view_class() -> &'static Class { accepts_first_mouse:: as extern "C" fn(&Object, Sel, id) -> BOOL ); + class.add_method( + sel!(triggerOnFrame:), + trigger_on_frame:: as extern "C" fn(&Object, Sel, id) + ); + class.add_method( sel!(release), release:: as extern "C" fn(&Object, Sel) @@ -144,6 +149,7 @@ unsafe fn create_view_class() -> &'static Class { ); class.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR_NAME); + class.add_ivar::<*mut c_void>(FRAME_TIMER_IVAR_NAME); class.register() } @@ -174,6 +180,19 @@ extern "C" fn accepts_first_mouse( } +extern "C" fn trigger_on_frame( + this: &Object, + _sel: Sel, + _event: id +){ + let state: &mut WindowState = unsafe { + WindowState::from_field(this) + }; + + state.trigger_frame(); +} + + extern "C" fn release(this: &Object, _sel: Sel) { unsafe { let superclass = msg_send![this, superclass]; @@ -185,11 +204,16 @@ extern "C" fn release(this: &Object, _sel: Sel) { let retain_count: usize = msg_send![this, retainCount]; if retain_count == 1 { + // Invalidate frame timer + let frame_timer_ptr: *mut c_void = *this.get_ivar( + FRAME_TIMER_IVAR_NAME + ); + let _: () = msg_send![frame_timer_ptr as id, invalidate]; + + // Drop WindowState let state_ptr: *mut c_void = *this.get_ivar( WINDOW_STATE_IVAR_NAME ); - - // Drop WindowState Arc::from_raw(state_ptr as *mut WindowState); // Delete class diff --git a/src/macos/window.rs b/src/macos/window.rs index 5e228f5..7194eb8 100644 --- a/src/macos/window.rs +++ b/src/macos/window.rs @@ -9,7 +9,7 @@ use cocoa::appkit::{ NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSBackingStoreBuffered, NSWindow, NSWindowStyleMask, }; -use cocoa::base::{id, nil, NO}; +use cocoa::base::{id, nil, NO, YES}; use cocoa::foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize, NSString}; use keyboard_types::KeyboardEvent; @@ -30,6 +30,8 @@ use super::keyboard::KeyboardState; /// view class. pub(super) const WINDOW_STATE_IVAR_NAME: &str = "WINDOW_STATE_IVAR_NAME"; +pub(super) const FRAME_TIMER_IVAR_NAME: &str = "FRAME_TIMER"; + pub struct Window { /// Only set if we created the parent window, i.e. we are running in @@ -172,6 +174,27 @@ impl Window { ); } + // Activate timer after window handler is setup and save a pointer to + // it, so that it can be invalidated when view is released. + unsafe { + let timer_interval = 0.015; + let selector = sel!(triggerOnFrame:); + + let timer: id = msg_send![ + ::objc::class!(NSTimer), + scheduledTimerWithTimeInterval:timer_interval + target:window_state_arc.window.ns_view + selector:selector + userInfo:nil + repeats:YES + ]; + + (*window_state_arc.window.ns_view).set_ivar( + FRAME_TIMER_IVAR_NAME, + timer as *mut c_void, + ) + } + WindowHandle } } @@ -200,6 +223,10 @@ impl WindowState { self.window_handler.on_event(&mut self.window, event); } + pub(super) fn trigger_frame(&mut self){ + self.window_handler.on_frame() + } + pub(super) fn process_native_key_event( &mut self, event: *mut Object