[Mac] Store a reference to callback delegates

This avoids a potential crashes by the GC reclaiming the delegates
prematurely.
This commit is contained in:
thefiddler 2014-07-23 10:10:08 +02:00
parent e81d8da068
commit 4093b39fac
2 changed files with 50 additions and 16 deletions

View file

@ -48,7 +48,7 @@ namespace OpenTK.Platform.MacOS
// Register a Quit method to be called on cmd-q // Register a Quit method to be called on cmd-q
IntPtr nsapp = Class.Get("NSApplication"); IntPtr nsapp = Class.Get("NSApplication");
Class.RegisterMethod(nsapp, new OnQuitDelegate(OnQuit), "quit", "v@:"); Class.RegisterMethod(nsapp, OnQuitHandler, "quit", "v@:");
// Fetch the application handle // Fetch the application handle
Handle = Cocoa.SendIntPtr(nsapp, Selector.Get("sharedApplication")); Handle = Cocoa.SendIntPtr(nsapp, Selector.Get("sharedApplication"));
@ -102,6 +102,7 @@ namespace OpenTK.Platform.MacOS
internal static event EventHandler<CancelEventArgs> Quit = delegate { }; internal static event EventHandler<CancelEventArgs> Quit = delegate { };
delegate void OnQuitDelegate(IntPtr self, IntPtr cmd); delegate void OnQuitDelegate(IntPtr self, IntPtr cmd);
static OnQuitDelegate OnQuitHandler = OnQuit;
static void OnQuit(IntPtr self, IntPtr cmd) static void OnQuit(IntPtr self, IntPtr cmd)
{ {
var e = new CancelEventArgs(); var e = new CancelEventArgs();

View file

@ -146,26 +146,44 @@ namespace OpenTK.Platform.MacOS
public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{ {
// Create callback methods. We need to store those,
// otherwise the GC may collect them while they are
// still active.
WindowKeyDownHandler = WindowKeyDown;
WindowDidResizeHandler = WindowDidResize;
WindowDidMoveHandler = WindowDidMove;
WindowDidBecomeKeyHandler = WindowDidBecomeKey;
WindowDidResignKeyHandler = WindowDidResignKey;
WindowWillMiniaturizeHandler = WindowWillMiniaturize;
WindowDidMiniaturizeHandler = WindowDidMiniaturize;
WindowDidDeminiaturizeHandler = WindowDidDeminiaturize;
WindowShouldZoomToFrameHandler = WindowShouldZoomToFrame;
WindowShouldCloseHandler = WindowShouldClose;
AcceptsFirstResponderHandler = AcceptsFirstResponder;
CanBecomeKeyWindowHandler = CanBecomeKeyWindow;
CanBecomeMainWindowHandler = CanBecomeMainWindow;
ResetCursorRectsHandler = ResetCursorRects;
// Create the window class // Create the window class
int unique_id = Interlocked.Increment(ref UniqueId); int unique_id = Interlocked.Increment(ref UniqueId);
windowClass = Class.AllocateClass("OpenTK_GameWindow" + unique_id, "NSWindow"); windowClass = Class.AllocateClass("OpenTK_GameWindow" + unique_id, "NSWindow");
Class.RegisterMethod(windowClass, new WindowKeyDownDelegate(WindowKeyDown), "keyDown:", "v@:@"); Class.RegisterMethod(windowClass, WindowKeyDownHandler, "keyDown:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidResizeDelegate(WindowDidResize), "windowDidResize:", "v@:@"); Class.RegisterMethod(windowClass, WindowDidResizeHandler, "windowDidResize:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidMoveDelegate(WindowDidMove), "windowDidMove:", "v@:@"); Class.RegisterMethod(windowClass, WindowDidMoveHandler, "windowDidMove:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidBecomeKeyDelegate(WindowDidBecomeKey), "windowDidBecomeKey:", "v@:@"); Class.RegisterMethod(windowClass, WindowDidBecomeKeyHandler, "windowDidBecomeKey:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidResignKeyDelegate(WindowDidResignKey), "windowDidResignKey:", "v@:@"); Class.RegisterMethod(windowClass, WindowDidResignKeyHandler, "windowDidResignKey:", "v@:@");
Class.RegisterMethod(windowClass, new WindowWillMiniaturizeDelegate(WindowWillMiniaturize), "windowWillMiniaturize:", "v@:@"); Class.RegisterMethod(windowClass, WindowWillMiniaturizeHandler, "windowWillMiniaturize:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidMiniaturizeDelegate(WindowDidMiniaturize), "windowDidMiniaturize:", "v@:@"); Class.RegisterMethod(windowClass, WindowDidMiniaturizeHandler, "windowDidMiniaturize:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidDeminiaturizeDelegate(WindowDidDeminiaturize), "windowDidDeminiaturize:", "v@:@"); Class.RegisterMethod(windowClass, WindowDidDeminiaturizeHandler, "windowDidDeminiaturize:", "v@:@");
Class.RegisterMethod(windowClass, new WindowShouldZoomToFrameDelegate(WindowShouldZoomToFrame), "windowShouldZoom:toFrame:", "b@:@{NSRect={NSPoint=ff}{NSSize=ff}}"); Class.RegisterMethod(windowClass, WindowShouldZoomToFrameHandler, "windowShouldZoom:toFrame:", "b@:@{NSRect={NSPoint=ff}{NSSize=ff}}");
Class.RegisterMethod(windowClass, new WindowShouldCloseDelegate(WindowShouldClose), "windowShouldClose:", "b@:@"); Class.RegisterMethod(windowClass, WindowShouldCloseHandler, "windowShouldClose:", "b@:@");
Class.RegisterMethod(windowClass, new AcceptsFirstResponderDelegate(AcceptsFirstResponder), "acceptsFirstResponder", "b@:"); Class.RegisterMethod(windowClass, AcceptsFirstResponderHandler, "acceptsFirstResponder", "b@:");
Class.RegisterMethod(windowClass, new CanBecomeKeyWindowDelegate(CanBecomeKeyWindow), "canBecomeKeyWindow", "b@:"); Class.RegisterMethod(windowClass, CanBecomeKeyWindowHandler, "canBecomeKeyWindow", "b@:");
Class.RegisterMethod(windowClass, new CanBecomeMainWindowDelegate(CanBecomeMainWindow), "canBecomeMainWindow", "b@:"); Class.RegisterMethod(windowClass, CanBecomeMainWindowHandler, "canBecomeMainWindow", "b@:");
Class.RegisterClass(windowClass); Class.RegisterClass(windowClass);
IntPtr viewClass = Class.AllocateClass("OpenTK_NSView" + unique_id, "NSView"); IntPtr viewClass = Class.AllocateClass("OpenTK_NSView" + unique_id, "NSView");
Class.RegisterMethod(viewClass, new ResetCursorRectsDelegate(ResetCursorRects), "resetCursorRects", "v@:"); Class.RegisterMethod(viewClass, ResetCursorRectsHandler, "resetCursorRects", "v@:");
Class.RegisterClass(viewClass); Class.RegisterClass(viewClass);
// Create window instance // Create window instance
@ -254,6 +272,21 @@ namespace OpenTK.Platform.MacOS
delegate bool CanBecomeMainWindowDelegate(IntPtr self, IntPtr cmd); delegate bool CanBecomeMainWindowDelegate(IntPtr self, IntPtr cmd);
delegate void ResetCursorRectsDelegate(IntPtr self, IntPtr cmd); delegate void ResetCursorRectsDelegate(IntPtr self, IntPtr cmd);
WindowKeyDownDelegate WindowKeyDownHandler;
WindowDidResizeDelegate WindowDidResizeHandler;
WindowDidMoveDelegate WindowDidMoveHandler;
WindowDidBecomeKeyDelegate WindowDidBecomeKeyHandler;
WindowDidResignKeyDelegate WindowDidResignKeyHandler;
WindowWillMiniaturizeDelegate WindowWillMiniaturizeHandler;
WindowDidMiniaturizeDelegate WindowDidMiniaturizeHandler;
WindowDidDeminiaturizeDelegate WindowDidDeminiaturizeHandler;
WindowShouldZoomToFrameDelegate WindowShouldZoomToFrameHandler;
WindowShouldCloseDelegate WindowShouldCloseHandler;
AcceptsFirstResponderDelegate AcceptsFirstResponderHandler;
CanBecomeKeyWindowDelegate CanBecomeKeyWindowHandler;
CanBecomeMainWindowDelegate CanBecomeMainWindowHandler;
ResetCursorRectsDelegate ResetCursorRectsHandler;
private void WindowKeyDown(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowKeyDown(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
// Steal the event to remove the "beep" sound that is normally played for unhandled key events. // Steal the event to remove the "beep" sound that is normally played for unhandled key events.
@ -1041,7 +1074,7 @@ namespace OpenTK.Platform.MacOS
if (disposed) if (disposed)
return; return;
Debug.Print("Disposing of CocoaNativeWindow."); Debug.Print("Disposing of CocoaNativeWindow (disposing={0}).", disposing);
NSApplication.Quit -= ApplicationQuit; NSApplication.Quit -= ApplicationQuit;
if (disposing) if (disposing)