[Mac] Mark callback calling convention

Callbacks are now explicitly marked as unmanaged pointers with the
correct (platform-defined) calling convention. Exceptions raised inside
these callbacks are no longer allowed to escape into unmanaged code,
where they will crash the runtime.

Additionally, the window is now only closed on the UI thread, and only
if it is actually open.
This commit is contained in:
thefiddler 2014-07-23 21:18:34 +02:00
parent a6c4a7c9b5
commit d12643cf44

View file

@ -257,19 +257,33 @@ namespace OpenTK.Platform.MacOS
NSApplication.Quit += ApplicationQuit; NSApplication.Quit += ApplicationQuit;
} }
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void WindowKeyDownDelegate(IntPtr self, IntPtr cmd, IntPtr notification); delegate void WindowKeyDownDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void WindowDidResizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification); delegate void WindowDidResizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void WindowDidMoveDelegate(IntPtr self, IntPtr cmd, IntPtr notification); delegate void WindowDidMoveDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void WindowDidBecomeKeyDelegate(IntPtr self, IntPtr cmd, IntPtr notification); delegate void WindowDidBecomeKeyDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void WindowDidResignKeyDelegate(IntPtr self, IntPtr cmd, IntPtr notification); delegate void WindowDidResignKeyDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void WindowWillMiniaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification); delegate void WindowWillMiniaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void WindowDidMiniaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification); delegate void WindowDidMiniaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void WindowDidDeminiaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification); delegate void WindowDidDeminiaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate bool WindowShouldZoomToFrameDelegate(IntPtr self, IntPtr cmd, IntPtr nsWindow, RectangleF toFrame); delegate bool WindowShouldZoomToFrameDelegate(IntPtr self, IntPtr cmd, IntPtr nsWindow, RectangleF toFrame);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate bool WindowShouldCloseDelegate(IntPtr self, IntPtr cmd, IntPtr sender); delegate bool WindowShouldCloseDelegate(IntPtr self, IntPtr cmd, IntPtr sender);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate bool AcceptsFirstResponderDelegate(IntPtr self, IntPtr cmd); delegate bool AcceptsFirstResponderDelegate(IntPtr self, IntPtr cmd);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate bool CanBecomeKeyWindowDelegate(IntPtr self, IntPtr cmd); delegate bool CanBecomeKeyWindowDelegate(IntPtr self, IntPtr cmd);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate bool CanBecomeMainWindowDelegate(IntPtr self, IntPtr cmd); delegate bool CanBecomeMainWindowDelegate(IntPtr self, IntPtr cmd);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
delegate void ResetCursorRectsDelegate(IntPtr self, IntPtr cmd); delegate void ResetCursorRectsDelegate(IntPtr self, IntPtr cmd);
WindowKeyDownDelegate WindowKeyDownHandler; WindowKeyDownDelegate WindowKeyDownHandler;
@ -294,7 +308,14 @@ namespace OpenTK.Platform.MacOS
private void WindowDidResize(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidResize(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
OnResize(true); try
{
OnResize(true);
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
} }
private void OnResize(bool resetTracking) private void OnResize(bool resetTracking)
@ -316,77 +337,141 @@ namespace OpenTK.Platform.MacOS
private void ApplicationQuit(object sender, CancelEventArgs e) private void ApplicationQuit(object sender, CancelEventArgs e)
{ {
bool close = WindowShouldClose(windowInfo.Handle, IntPtr.Zero, IntPtr.Zero); try
e.Cancel |= !close; {
bool close = WindowShouldClose(windowInfo.Handle, IntPtr.Zero, IntPtr.Zero);
e.Cancel |= !close;
}
catch (Exception ex)
{
Debug.Print(ex.ToString());
}
} }
private void WindowDidMove(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidMove(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
// Problem: Called only when you stop moving for a brief moment, try
// not each frame as it is on PC. {
OnMove(EventArgs.Empty); // Problem: Called only when you stop moving for a brief moment,
// not each frame as it is on PC.
OnMove(EventArgs.Empty);
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
} }
private void WindowDidBecomeKey(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidBecomeKey(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
OnFocusedChanged(EventArgs.Empty); try
{
OnFocusedChanged(EventArgs.Empty);
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
} }
private void WindowDidResignKey(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidResignKey(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
OnFocusedChanged(EventArgs.Empty); try
{
OnFocusedChanged(EventArgs.Empty);
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
} }
private void WindowWillMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowWillMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
// Can get stuck in weird states if we maximize, then minimize; try
// restoring to the old state would override the normalBounds. {
// To avoid this without adding complexity, just restore state here. // Can get stuck in weird states if we maximize, then minimize;
RestoreWindowState(); // Avoid getting in weird states // restoring to the old state would override the normalBounds.
// To avoid this without adding complexity, just restore state here.
RestoreWindowState(); // Avoid getting in weird states
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
} }
private void WindowDidMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
windowState = WindowState.Minimized; try
OnWindowStateChanged(EventArgs.Empty); {
OnResize(false); // Don't set tracking area when we minimize windowState = WindowState.Minimized;
OnWindowStateChanged(EventArgs.Empty);
OnResize(false); // Don't set tracking area when we minimize
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
} }
private void WindowDidDeminiaturize(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidDeminiaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
windowState = WindowState.Normal; try
OnWindowStateChanged(EventArgs.Empty); {
OnResize(true); windowState = WindowState.Normal;
OnWindowStateChanged(EventArgs.Empty);
OnResize(true);
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
} }
private bool WindowShouldZoomToFrame(IntPtr self, IntPtr cmd, IntPtr nsWindow, RectangleF toFrame) private bool WindowShouldZoomToFrame(IntPtr self, IntPtr cmd, IntPtr nsWindow, RectangleF toFrame)
{ {
if (windowState == WindowState.Maximized) try
{ {
WindowState = WindowState.Normal; if (windowState == WindowState.Maximized)
{
WindowState = WindowState.Normal;
}
else
{
previousBounds = InternalBounds;
previousWindowBorder = WindowBorder;
InternalBounds = toFrame;
windowState = WindowState.Maximized;
OnWindowStateChanged(EventArgs.Empty);
}
} }
else catch (Exception e)
{ {
previousBounds = InternalBounds; Debug.Print(e.ToString());
previousWindowBorder = WindowBorder;
InternalBounds = toFrame;
windowState = WindowState.Maximized;
OnWindowStateChanged(EventArgs.Empty);
} }
return false; return false;
} }
private bool WindowShouldClose(IntPtr self, IntPtr cmd, IntPtr sender) private bool WindowShouldClose(IntPtr self, IntPtr cmd, IntPtr sender)
{ {
var cancelArgs = new CancelEventArgs(); try
OnClosing(cancelArgs);
if (!cancelArgs.Cancel)
{ {
OnClosed(EventArgs.Empty); var cancelArgs = new CancelEventArgs();
return true; OnClosing(cancelArgs);
if (!cancelArgs.Cancel)
{
OnClosed(EventArgs.Empty);
return true;
}
}
catch (Exception e)
{
Debug.Print(e.ToString());
} }
return false; return false;
@ -409,24 +494,31 @@ namespace OpenTK.Platform.MacOS
private void ResetTrackingArea() private void ResetTrackingArea()
{ {
var owner = windowInfo.ViewHandle; try
if (trackingArea != IntPtr.Zero)
{ {
Cocoa.SendVoid(owner, selRemoveTrackingArea, trackingArea); var owner = windowInfo.ViewHandle;
Cocoa.SendVoid(trackingArea, Selector.Release); if (trackingArea != IntPtr.Zero)
{
Cocoa.SendVoid(owner, selRemoveTrackingArea, trackingArea);
Cocoa.SendVoid(trackingArea, Selector.Release);
}
var ownerBounds = Cocoa.SendRect(owner, selBounds);
var options = (int)(
NSTrackingAreaOptions.MouseEnteredAndExited |
NSTrackingAreaOptions.ActiveInKeyWindow |
NSTrackingAreaOptions.MouseMoved |
NSTrackingAreaOptions.CursorUpdate);
trackingArea = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSTrackingArea"), Selector.Alloc),
selInitWithRect, ownerBounds, options, owner, IntPtr.Zero);
Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea);
}
catch (Exception e)
{
Debug.Print(e.ToString());
} }
var ownerBounds = Cocoa.SendRect(owner, selBounds);
var options = (int)(
NSTrackingAreaOptions.MouseEnteredAndExited |
NSTrackingAreaOptions.ActiveInKeyWindow |
NSTrackingAreaOptions.MouseMoved |
NSTrackingAreaOptions.CursorUpdate);
trackingArea = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSTrackingArea"), Selector.Alloc),
selInitWithRect, ownerBounds, options, owner, IntPtr.Zero);
Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea);
} }
public override void Close() public override void Close()
@ -1075,6 +1167,10 @@ namespace OpenTK.Platform.MacOS
return; return;
Debug.Print("Disposing of CocoaNativeWindow (disposing={0}).", disposing); Debug.Print("Disposing of CocoaNativeWindow (disposing={0}).", disposing);
if (!NSApplication.IsUIThread)
return;
NSApplication.Quit -= ApplicationQuit; NSApplication.Quit -= ApplicationQuit;
if (disposing) if (disposing)
@ -1193,6 +1289,9 @@ namespace OpenTK.Platform.MacOS
void CloseWindow(bool shutdown) void CloseWindow(bool shutdown)
{ {
if (!Exists)
return;
exists = false; exists = false;
// PerformClose is equivalent to pressing the close-button, which // PerformClose is equivalent to pressing the close-button, which