1
0
Fork 0

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
This commit is contained in:
Joakim Frostegård 2020-11-23 14:38:32 +01:00 committed by GitHub
parent 726632624c
commit ff09c3a256
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 4 deletions

View file

@ -20,7 +20,7 @@ use crate::{
}; };
use crate::MouseEvent::{ButtonPressed, ButtonReleased}; 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<H: WindowHandler>( pub(super) unsafe fn create_view<H: WindowHandler>(
@ -67,6 +67,11 @@ unsafe fn create_view_class<H: WindowHandler>() -> &'static Class {
accepts_first_mouse::<H> as extern "C" fn(&Object, Sel, id) -> BOOL accepts_first_mouse::<H> as extern "C" fn(&Object, Sel, id) -> BOOL
); );
class.add_method(
sel!(triggerOnFrame:),
trigger_on_frame::<H> as extern "C" fn(&Object, Sel, id)
);
class.add_method( class.add_method(
sel!(release), sel!(release),
release::<H> as extern "C" fn(&Object, Sel) release::<H> as extern "C" fn(&Object, Sel)
@ -144,6 +149,7 @@ unsafe fn create_view_class<H: WindowHandler>() -> &'static Class {
); );
class.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR_NAME); class.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR_NAME);
class.add_ivar::<*mut c_void>(FRAME_TIMER_IVAR_NAME);
class.register() class.register()
} }
@ -174,6 +180,19 @@ extern "C" fn accepts_first_mouse<H: WindowHandler>(
} }
extern "C" fn trigger_on_frame<H: WindowHandler>(
this: &Object,
_sel: Sel,
_event: id
){
let state: &mut WindowState<H> = unsafe {
WindowState::from_field(this)
};
state.trigger_frame();
}
extern "C" fn release<H: WindowHandler>(this: &Object, _sel: Sel) { extern "C" fn release<H: WindowHandler>(this: &Object, _sel: Sel) {
unsafe { unsafe {
let superclass = msg_send![this, superclass]; let superclass = msg_send![this, superclass];
@ -185,11 +204,16 @@ extern "C" fn release<H: WindowHandler>(this: &Object, _sel: Sel) {
let retain_count: usize = msg_send![this, retainCount]; let retain_count: usize = msg_send![this, retainCount];
if retain_count == 1 { 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( let state_ptr: *mut c_void = *this.get_ivar(
WINDOW_STATE_IVAR_NAME WINDOW_STATE_IVAR_NAME
); );
// Drop WindowState
Arc::from_raw(state_ptr as *mut WindowState<H>); Arc::from_raw(state_ptr as *mut WindowState<H>);
// Delete class // Delete class

View file

@ -9,7 +9,7 @@ use cocoa::appkit::{
NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSApp, NSApplication, NSApplicationActivationPolicyRegular,
NSBackingStoreBuffered, NSWindow, NSWindowStyleMask, 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 cocoa::foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize, NSString};
use keyboard_types::KeyboardEvent; use keyboard_types::KeyboardEvent;
@ -30,6 +30,8 @@ use super::keyboard::KeyboardState;
/// view class. /// view class.
pub(super) const WINDOW_STATE_IVAR_NAME: &str = "WINDOW_STATE_IVAR_NAME"; 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 { pub struct Window {
/// Only set if we created the parent window, i.e. we are running in /// 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 WindowHandle
} }
} }
@ -200,6 +223,10 @@ impl <H: WindowHandler>WindowState<H> {
self.window_handler.on_event(&mut self.window, event); 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( pub(super) fn process_native_key_event(
&mut self, &mut self,
event: *mut Object event: *mut Object