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:
parent
726632624c
commit
ff09c3a256
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue