mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-09 23:25:42 +00:00
Merge pull request #158 from thefiddler/fuzzfix
[Mac] Improve stability under Cocoa
This commit is contained in:
commit
ed7b83178f
|
@ -150,6 +150,7 @@ namespace OpenTK.Graphics
|
||||||
|
|
||||||
implementation = factory.CreateGLContext(mode, window, shareContext, direct_rendering, major, minor, flags);
|
implementation = factory.CreateGLContext(mode, window, shareContext, direct_rendering, major, minor, flags);
|
||||||
handle_cached = ((IGraphicsContextInternal)implementation).Context;
|
handle_cached = ((IGraphicsContextInternal)implementation).Context;
|
||||||
|
factory.RegisterResource(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddContext(this);
|
AddContext(this);
|
||||||
|
|
|
@ -1,39 +1,42 @@
|
||||||
#region License
|
#region License
|
||||||
//
|
//
|
||||||
// The Open Toolkit Library License
|
// GraphicsContextBase.cs
|
||||||
//
|
//
|
||||||
// Copyright (c) 2006 - 2009 the Open Toolkit library.
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
// in the Software without restriction, including without limitation the rights to
|
// in the Software without restriction, including without limitation the rights
|
||||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
// the Software, and to permit persons to whom the Software is furnished to do
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
// so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
// copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
// THE SOFTWARE.
|
||||||
// OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
//
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using OpenTK.Platform;
|
using OpenTK.Platform;
|
||||||
|
|
||||||
namespace OpenTK.Graphics
|
namespace OpenTK.Graphics
|
||||||
{
|
{
|
||||||
// Provides the foundation for all IGraphicsContext implementations.
|
// Provides the foundation for all IGraphicsContext implementations.
|
||||||
abstract class GraphicsContextBase : IGraphicsContext, IGraphicsContextInternal
|
abstract class GraphicsContextBase : IGraphicsContext, IGraphicsContextInternal, IEquatable<IGraphicsContextInternal>
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
|
@ -106,7 +109,53 @@ namespace OpenTK.Graphics
|
||||||
|
|
||||||
#region IDisposable Members
|
#region IDisposable Members
|
||||||
|
|
||||||
public abstract void Dispose();
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void Dispose(bool disposing);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
~GraphicsContextBase()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
Debug.Print("[Warning] {0}:{1} leaked. Did you forget to call Dispose()?",
|
||||||
|
GetType().FullName, Handle);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEquatable<IGraphicsContextInternal> Members
|
||||||
|
|
||||||
|
public bool Equals(IGraphicsContextInternal other)
|
||||||
|
{
|
||||||
|
return Context.Equals(other.Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Members
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("[{0}: IsCurrent={1}, IsDisposed={2}, VSync={3}, SwapInterval={4}, GraphicsMode={5}, ErrorChecking={6}, Implementation={7}, Context={8}]",
|
||||||
|
GetType().Name, IsCurrent, IsDisposed, VSync, SwapInterval, GraphicsMode, ErrorChecking, Implementation, Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Handle.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
obj is IGraphicsContextInternal &&
|
||||||
|
Equals((IGraphicsContextInternal)obj);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,9 @@ namespace OpenTK
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.device = device;
|
this.device = device;
|
||||||
|
|
||||||
implementation = Factory.Default.CreateNativeWindow(x, y, width, height, title, mode, options, this.device);
|
IPlatformFactory factory = Factory.Default;
|
||||||
|
implementation = factory.CreateNativeWindow(x, y, width, height, title, mode, options, this.device);
|
||||||
|
factory.RegisterResource(this);
|
||||||
|
|
||||||
if ((options & GameWindowFlags.Fullscreen) != 0)
|
if ((options & GameWindowFlags.Fullscreen) != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace OpenTK.Platform.Dummy
|
||||||
|
|
||||||
#region --- IDisposable Members ---
|
#region --- IDisposable Members ---
|
||||||
|
|
||||||
public override void Dispose() { IsDisposed = true; }
|
protected override void Dispose(bool disposing) { IsDisposed = true; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,15 +180,9 @@ namespace OpenTK.Platform.Egl
|
||||||
|
|
||||||
#region IDisposable Members
|
#region IDisposable Members
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Todo: cross-reference the specs. What should happen if the context is destroyed from a different
|
// Todo: cross-reference the specs. What should happen if the context is destroyed from a different
|
||||||
// thread?
|
// thread?
|
||||||
protected virtual void Dispose(bool manual)
|
protected override void Dispose(bool manual)
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
|
@ -197,19 +191,10 @@ namespace OpenTK.Platform.Egl
|
||||||
Egl.MakeCurrent(WindowInfo.Display, WindowInfo.Surface, WindowInfo.Surface, IntPtr.Zero);
|
Egl.MakeCurrent(WindowInfo.Display, WindowInfo.Surface, WindowInfo.Surface, IntPtr.Zero);
|
||||||
Egl.DestroyContext(WindowInfo.Display, HandleAsEGLContext);
|
Egl.DestroyContext(WindowInfo.Display, HandleAsEGLContext);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Print("[Warning] {0}:{1} was not disposed.", this.GetType().Name, HandleAsEGLContext);
|
|
||||||
}
|
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~EglContext()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,11 @@ namespace OpenTK.Platform
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
static Factory()
|
static Factory()
|
||||||
|
{
|
||||||
|
Toolkit.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Factory()
|
||||||
{
|
{
|
||||||
// Ensure we are correctly initialized.
|
// Ensure we are correctly initialized.
|
||||||
Toolkit.Init();
|
Toolkit.Init();
|
||||||
|
@ -160,6 +165,11 @@ namespace OpenTK.Platform
|
||||||
#pragma warning restore 612,618
|
#pragma warning restore 612,618
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RegisterResource(IDisposable resource)
|
||||||
|
{
|
||||||
|
default_implementation.RegisterResource(resource);
|
||||||
|
}
|
||||||
|
|
||||||
class UnsupportedPlatform : PlatformFactoryBase
|
class UnsupportedPlatform : PlatformFactoryBase
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
|
@ -55,5 +55,7 @@ namespace OpenTK.Platform
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
Input.IJoystickDriver CreateLegacyJoystickDriver();
|
Input.IJoystickDriver CreateLegacyJoystickDriver();
|
||||||
|
|
||||||
|
void RegisterResource(IDisposable resource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,9 @@ namespace OpenTK.Platform.MacOS
|
||||||
[DllImport (Cocoa.LibObjC)]
|
[DllImport (Cocoa.LibObjC)]
|
||||||
extern static void objc_registerClassPair(IntPtr classToRegister);
|
extern static void objc_registerClassPair(IntPtr classToRegister);
|
||||||
|
|
||||||
|
[DllImport (Cocoa.LibObjC)]
|
||||||
|
extern static void objc_disposeClassPair(IntPtr cls);
|
||||||
|
|
||||||
public static IntPtr Get(string name)
|
public static IntPtr Get(string name)
|
||||||
{
|
{
|
||||||
var id = objc_getClass(name);
|
var id = objc_getClass(name);
|
||||||
|
@ -75,7 +78,10 @@ namespace OpenTK.Platform.MacOS
|
||||||
objc_registerClassPair(handle);
|
objc_registerClassPair(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<Delegate> storedDelegates = new List<Delegate>();
|
public static void DisposeClass(IntPtr handle)
|
||||||
|
{
|
||||||
|
objc_disposeClassPair(handle);
|
||||||
|
}
|
||||||
|
|
||||||
public static void RegisterMethod(IntPtr handle, Delegate d, string selector, string typeString)
|
public static void RegisterMethod(IntPtr handle, Delegate d, string selector, string typeString)
|
||||||
{
|
{
|
||||||
|
@ -89,8 +95,6 @@ namespace OpenTK.Platform.MacOS
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Could not register method " + d + " in class + " + class_getName(handle));
|
throw new ArgumentException("Could not register method " + d + " in class + " + class_getName(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
storedDelegates.Add(d); // Don't let the garbage collector eat our delegates.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,14 +209,13 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
fixed (byte* pBytes = b)
|
fixed (byte* pBytes = b)
|
||||||
{
|
{
|
||||||
IntPtr nsData = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSData"), Selector.Alloc),
|
IntPtr nsData = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSData"), Selector.Alloc),
|
||||||
Selector.Get("initWithBytes:length:"), (IntPtr)pBytes, b.Length),
|
Selector.Get("initWithBytes:length:"), (IntPtr)pBytes, b.Length);
|
||||||
Selector.Autorelease);
|
|
||||||
|
|
||||||
IntPtr nsImage = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSImage"), Selector.Alloc),
|
IntPtr nsImage = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSImage"), Selector.Alloc),
|
||||||
Selector.Get("initWithData:"), nsData),
|
Selector.Get("initWithData:"), nsData);
|
||||||
Selector.Autorelease);
|
|
||||||
|
|
||||||
|
Cocoa.SendVoid(nsData, Selector.Release);
|
||||||
return nsImage;
|
return nsImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
using OpenTK.Platform.MacOS;
|
using OpenTK.Platform.MacOS;
|
||||||
|
|
||||||
namespace OpenTK.Platform.MacOS
|
namespace OpenTK.Platform.MacOS
|
||||||
|
@ -41,14 +43,21 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
static readonly IntPtr selQuit = Selector.Get("quit");
|
static readonly IntPtr selQuit = Selector.Get("quit");
|
||||||
|
|
||||||
internal static void Initialize()
|
static readonly int ThreadId =
|
||||||
|
System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||||
|
|
||||||
|
internal static void Initialize() { }
|
||||||
|
|
||||||
|
static NSApplication()
|
||||||
{
|
{
|
||||||
|
Cocoa.Initialize();
|
||||||
|
|
||||||
// Create the NSAutoreleasePool
|
// Create the NSAutoreleasePool
|
||||||
AutoreleasePool = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Alloc), Selector.Init);
|
AutoreleasePool = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Alloc), Selector.Init);
|
||||||
|
|
||||||
// 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"));
|
||||||
|
@ -58,22 +67,17 @@ namespace OpenTK.Platform.MacOS
|
||||||
Cocoa.SendVoid(Handle, Selector.Get("activateIgnoringOtherApps:"), true);
|
Cocoa.SendVoid(Handle, Selector.Get("activateIgnoringOtherApps:"), true);
|
||||||
|
|
||||||
// Create the menu bar
|
// Create the menu bar
|
||||||
var menubar = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc),
|
var menubar = Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc);
|
||||||
Selector.Autorelease);
|
var menuItem = Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc);
|
||||||
|
|
||||||
var menuItem = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc),
|
|
||||||
Selector.Autorelease);
|
|
||||||
|
|
||||||
// Add menu item to bar, and bar to application
|
// Add menu item to bar, and bar to application
|
||||||
Cocoa.SendIntPtr(menubar, Selector.Get("addItem:"), menuItem);
|
Cocoa.SendIntPtr(menubar, Selector.Get("addItem:"), menuItem);
|
||||||
Cocoa.SendIntPtr(Handle, Selector.Get("setMainMenu:"), menubar);
|
Cocoa.SendIntPtr(Handle, Selector.Get("setMainMenu:"), menubar);
|
||||||
|
|
||||||
// Add a "Quit" menu item and bind the button.
|
// Add a "Quit" menu item and bind the button.
|
||||||
var appMenu = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc),
|
var appMenu = Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc);
|
||||||
Selector.Autorelease);
|
var quitMenuItem = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc),
|
||||||
var quitMenuItem = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc),
|
Selector.Get("initWithTitle:action:keyEquivalent:"), Cocoa.ToNSString("Quit"), selQuit, Cocoa.ToNSString("q"));
|
||||||
Selector.Get("initWithTitle:action:keyEquivalent:"), Cocoa.ToNSString("Quit"), selQuit, Cocoa.ToNSString("q")),
|
|
||||||
Selector.Autorelease);
|
|
||||||
|
|
||||||
Cocoa.SendIntPtr(appMenu, Selector.Get("addItem:"), quitMenuItem);
|
Cocoa.SendIntPtr(appMenu, Selector.Get("addItem:"), quitMenuItem);
|
||||||
Cocoa.SendIntPtr(menuItem, Selector.Get("setSubmenu:"), appMenu);
|
Cocoa.SendIntPtr(menuItem, Selector.Get("setSubmenu:"), appMenu);
|
||||||
|
@ -99,9 +103,27 @@ namespace OpenTK.Platform.MacOS
|
||||||
Cocoa.SendVoid(settings, Selector.Release);
|
Cocoa.SendVoid(settings, Selector.Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool IsUIThread
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int thread_id = Thread.CurrentThread.ManagedThreadId;
|
||||||
|
bool is_ui_thread = thread_id == NSApplication.ThreadId;
|
||||||
|
if (!is_ui_thread)
|
||||||
|
{
|
||||||
|
Debug.Print("[Warning] UI resources must be disposed in the UI thread #{0}, not #{1}.",
|
||||||
|
NSApplication.ThreadId, thread_id);
|
||||||
|
}
|
||||||
|
return is_ui_thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static event EventHandler<CancelEventArgs> Quit = delegate { };
|
internal static event EventHandler<CancelEventArgs> Quit = delegate { };
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||||
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();
|
||||||
|
|
|
@ -326,23 +326,16 @@ namespace OpenTK
|
||||||
|
|
||||||
#region IDisposable Members
|
#region IDisposable Members
|
||||||
|
|
||||||
~CocoaContext()
|
protected override void Dispose(bool disposing)
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dispose(bool disposing)
|
|
||||||
{
|
{
|
||||||
if (IsDisposed || Handle.Handle == IntPtr.Zero)
|
if (IsDisposed || Handle.Handle == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug.Print("Disposing of Cocoa context.");
|
Debug.Print("Disposing of Cocoa context.");
|
||||||
|
|
||||||
|
if (!NSApplication.IsUIThread)
|
||||||
|
return;
|
||||||
|
|
||||||
Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext"));
|
Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext"));
|
||||||
Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable"));
|
Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable"));
|
||||||
Cocoa.SendVoid(Handle.Handle, Selector.Get("release"));
|
Cocoa.SendVoid(Handle.Handle, Selector.Get("release"));
|
||||||
|
|
|
@ -128,6 +128,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
private CocoaWindowInfo windowInfo;
|
private CocoaWindowInfo windowInfo;
|
||||||
private IntPtr windowClass;
|
private IntPtr windowClass;
|
||||||
private IntPtr trackingArea;
|
private IntPtr trackingArea;
|
||||||
|
private IntPtr current_icon_handle;
|
||||||
private bool disposed = false;
|
private bool disposed = false;
|
||||||
private bool exists;
|
private bool exists;
|
||||||
private bool cursorVisible = true;
|
private bool cursorVisible = true;
|
||||||
|
@ -145,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
|
||||||
Interlocked.Increment(ref UniqueId);
|
int unique_id = Interlocked.Increment(ref UniqueId);
|
||||||
windowClass = Class.AllocateClass("OpenTK_GameWindow" + UniqueId, "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" + UniqueId, "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
|
||||||
|
@ -182,15 +201,34 @@ namespace OpenTK.Platform.MacOS
|
||||||
var style = GetStyleMask(windowBorder);
|
var style = GetStyleMask(windowBorder);
|
||||||
var bufferingType = NSBackingStore.Buffered;
|
var bufferingType = NSBackingStore.Buffered;
|
||||||
|
|
||||||
IntPtr windowPtr;
|
IntPtr classPtr;
|
||||||
windowPtr = Cocoa.SendIntPtr(windowClass, Selector.Alloc);
|
classPtr = Cocoa.SendIntPtr(windowClass, Selector.Alloc);
|
||||||
windowPtr = Cocoa.SendIntPtr(windowPtr, Selector.Get("initWithContentRect:styleMask:backing:defer:"), contentRect, (int)style, (int)bufferingType, false);
|
if (classPtr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Error] Failed to allocate window class.");
|
||||||
|
throw new PlatformException();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool defer = false;
|
||||||
|
IntPtr windowPtr = Cocoa.SendIntPtr(classPtr, Selector.Get("initWithContentRect:styleMask:backing:defer:"), contentRect, (int)style, (int)bufferingType, defer);
|
||||||
|
if (windowPtr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Error] Failed to initialize window with ({0}, {1}, {2}, {3}).",
|
||||||
|
contentRect, style, bufferingType, defer);
|
||||||
|
throw new PlatformException();
|
||||||
|
}
|
||||||
|
|
||||||
// Replace view with our custom implementation
|
// Replace view with our custom implementation
|
||||||
// that overrides resetCursorRects (maybe there is
|
// that overrides resetCursorRects (maybe there is
|
||||||
// a better way to implement this override?)
|
// a better way to implement this override?)
|
||||||
// Existing view:
|
// Existing view:
|
||||||
IntPtr viewPtr = Cocoa.SendIntPtr(windowPtr, Selector.Get("contentView"));
|
IntPtr viewPtr = Cocoa.SendIntPtr(windowPtr, Selector.Get("contentView"));
|
||||||
|
if (viewPtr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Error] Failed to retrieve content view for window {0}.", windowPtr);
|
||||||
|
throw new PlatformException();
|
||||||
|
}
|
||||||
|
|
||||||
// Our custom view with the same bounds:
|
// Our custom view with the same bounds:
|
||||||
viewPtr = Cocoa.SendIntPtr(
|
viewPtr = Cocoa.SendIntPtr(
|
||||||
Cocoa.SendIntPtr(viewClass, Selector.Alloc),
|
Cocoa.SendIntPtr(viewClass, Selector.Alloc),
|
||||||
|
@ -200,6 +238,11 @@ namespace OpenTK.Platform.MacOS
|
||||||
{
|
{
|
||||||
Cocoa.SendVoid(windowPtr, Selector.Get("setContentView:"), viewPtr);
|
Cocoa.SendVoid(windowPtr, Selector.Get("setContentView:"), viewPtr);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[Error] Failed to initialize content view with frame {0}.", selBounds);
|
||||||
|
throw new PlatformException();
|
||||||
|
}
|
||||||
|
|
||||||
windowInfo = new CocoaWindowInfo(windowPtr);
|
windowInfo = new CocoaWindowInfo(windowPtr);
|
||||||
|
|
||||||
|
@ -214,30 +257,66 @@ 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;
|
||||||
|
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.
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WindowDidResize(IntPtr self, IntPtr cmd, IntPtr notification)
|
private void WindowDidResize(IntPtr self, IntPtr cmd, IntPtr notification)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
OnResize(true);
|
OnResize(true);
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Print(e.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnResize(bool resetTracking)
|
private void OnResize(bool resetTracking)
|
||||||
{
|
{
|
||||||
|
@ -257,51 +336,102 @@ namespace OpenTK.Platform.MacOS
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplicationQuit(object sender, CancelEventArgs e)
|
private void ApplicationQuit(object sender, CancelEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
bool close = WindowShouldClose(windowInfo.Handle, IntPtr.Zero, IntPtr.Zero);
|
bool close = WindowShouldClose(windowInfo.Handle, IntPtr.Zero, IntPtr.Zero);
|
||||||
e.Cancel |= !close;
|
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)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// Problem: Called only when you stop moving for a brief moment,
|
// Problem: Called only when you stop moving for a brief moment,
|
||||||
// not each frame as it is on PC.
|
// not each frame as it is on PC.
|
||||||
OnMove(EventArgs.Empty);
|
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)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
OnFocusedChanged(EventArgs.Empty);
|
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)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
OnFocusedChanged(EventArgs.Empty);
|
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)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// Can get stuck in weird states if we maximize, then minimize;
|
// Can get stuck in weird states if we maximize, then minimize;
|
||||||
// restoring to the old state would override the normalBounds.
|
// restoring to the old state would override the normalBounds.
|
||||||
// To avoid this without adding complexity, just restore state here.
|
// To avoid this without adding complexity, just restore state here.
|
||||||
RestoreWindowState(); // Avoid getting in weird states
|
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)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
windowState = WindowState.Minimized;
|
windowState = WindowState.Minimized;
|
||||||
OnWindowStateChanged(EventArgs.Empty);
|
OnWindowStateChanged(EventArgs.Empty);
|
||||||
OnResize(false); // Don't set tracking area when we minimize
|
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)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
windowState = WindowState.Normal;
|
windowState = WindowState.Normal;
|
||||||
OnWindowStateChanged(EventArgs.Empty);
|
OnWindowStateChanged(EventArgs.Empty);
|
||||||
OnResize(true);
|
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)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (windowState == WindowState.Maximized)
|
if (windowState == WindowState.Maximized)
|
||||||
{
|
{
|
||||||
|
@ -317,10 +447,18 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
OnWindowStateChanged(EventArgs.Empty);
|
OnWindowStateChanged(EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Print(e.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool WindowShouldClose(IntPtr self, IntPtr cmd, IntPtr sender)
|
private bool WindowShouldClose(IntPtr self, IntPtr cmd, IntPtr sender)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var cancelArgs = new CancelEventArgs();
|
var cancelArgs = new CancelEventArgs();
|
||||||
OnClosing(cancelArgs);
|
OnClosing(cancelArgs);
|
||||||
|
@ -330,6 +468,11 @@ namespace OpenTK.Platform.MacOS
|
||||||
OnClosed(EventArgs.Empty);
|
OnClosed(EventArgs.Empty);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Print(e.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -350,6 +493,8 @@ namespace OpenTK.Platform.MacOS
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetTrackingArea()
|
private void ResetTrackingArea()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var owner = windowInfo.ViewHandle;
|
var owner = windowInfo.ViewHandle;
|
||||||
if (trackingArea != IntPtr.Zero)
|
if (trackingArea != IntPtr.Zero)
|
||||||
|
@ -370,6 +515,11 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea);
|
Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea);
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Print(e.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void Close()
|
public override void Close()
|
||||||
{
|
{
|
||||||
|
@ -573,20 +723,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
if (shouldClose)
|
if (shouldClose)
|
||||||
{
|
{
|
||||||
shouldClose = false;
|
shouldClose = false;
|
||||||
|
CloseWindow(false);
|
||||||
// PerformClose is equivalent to pressing the close-button, which
|
|
||||||
// does not work in a borderless window. Handle this special case.
|
|
||||||
if (GetStyleMask() == NSWindowStyle.Borderless)
|
|
||||||
{
|
|
||||||
if (WindowShouldClose(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
|
|
||||||
{
|
|
||||||
Cocoa.SendVoid(windowInfo.Handle, selClose);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Cocoa.SendVoid(windowInfo.Handle, selPerformClose, windowInfo.Handle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,15 +750,37 @@ namespace OpenTK.Platform.MacOS
|
||||||
get { return icon; }
|
get { return icon; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
icon = value;
|
if (value != null && value != icon)
|
||||||
using (Image img = icon.ToBitmap())
|
{
|
||||||
|
// Create and set new icon
|
||||||
|
IntPtr nsimg = IntPtr.Zero;
|
||||||
|
using (Image img = value.ToBitmap())
|
||||||
|
{
|
||||||
|
nsimg = Cocoa.ToNSImage(img);
|
||||||
|
if (nsimg != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
IntPtr nsimg = Cocoa.ToNSImage(img);
|
|
||||||
Cocoa.SendVoid(NSApplication.Handle, selSetApplicationIconImage, nsimg);
|
Cocoa.SendVoid(NSApplication.Handle, selSetApplicationIconImage, nsimg);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[Mac] Failed to create NSImage for {0}", value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release previous icon
|
||||||
|
if (current_icon_handle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Cocoa.SendVoid(current_icon_handle, Selector.Release);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raise IconChanged event
|
||||||
|
current_icon_handle = nsimg;
|
||||||
|
icon = value;
|
||||||
OnIconChanged(EventArgs.Empty);
|
OnIconChanged(EventArgs.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override string Title
|
public override string Title
|
||||||
{
|
{
|
||||||
|
@ -888,7 +1047,6 @@ namespace OpenTK.Platform.MacOS
|
||||||
// premultiply alpha, even though that "generally has negligible
|
// premultiply alpha, even though that "generally has negligible
|
||||||
// effect on output quality."
|
// effect on output quality."
|
||||||
IntPtr imgdata =
|
IntPtr imgdata =
|
||||||
Cocoa.SendIntPtr(
|
|
||||||
Cocoa.SendIntPtr(
|
Cocoa.SendIntPtr(
|
||||||
Cocoa.SendIntPtr(NSBitmapImageRep, Selector.Alloc),
|
Cocoa.SendIntPtr(NSBitmapImageRep, Selector.Alloc),
|
||||||
selInitWithBitmapDataPlanes,
|
selInitWithBitmapDataPlanes,
|
||||||
|
@ -902,8 +1060,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
NSDeviceRGBColorSpace,
|
NSDeviceRGBColorSpace,
|
||||||
NSBitmapFormat.AlphaFirst,
|
NSBitmapFormat.AlphaFirst,
|
||||||
4 * cursor.Width,
|
4 * cursor.Width,
|
||||||
32),
|
32);
|
||||||
Selector.Autorelease);
|
|
||||||
if (imgdata == IntPtr.Zero)
|
if (imgdata == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Debug.Print("Failed to create NSBitmapImageRep with size ({0},{1]})",
|
Debug.Print("Failed to create NSBitmapImageRep with size ({0},{1]})",
|
||||||
|
@ -934,30 +1091,28 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
// Construct the actual NSImage
|
// Construct the actual NSImage
|
||||||
IntPtr img =
|
IntPtr img =
|
||||||
Cocoa.SendIntPtr(
|
|
||||||
Cocoa.SendIntPtr(
|
Cocoa.SendIntPtr(
|
||||||
Cocoa.SendIntPtr(NSImage, Selector.Alloc),
|
Cocoa.SendIntPtr(NSImage, Selector.Alloc),
|
||||||
selInitWithSize,
|
selInitWithSize,
|
||||||
new SizeF(cursor.Width, cursor.Height)),
|
new SizeF(cursor.Width, cursor.Height));
|
||||||
Selector.Autorelease);
|
|
||||||
if (img == IntPtr.Zero)
|
if (img == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Debug.Print("Failed to construct NSImage from NSBitmapImageRep");
|
Debug.Print("Failed to construct NSImage from NSBitmapImageRep");
|
||||||
|
Cocoa.SendVoid(imgdata, Selector.Release);
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
}
|
}
|
||||||
Cocoa.SendVoid(img, selAddRepresentation, imgdata);
|
Cocoa.SendVoid(img, selAddRepresentation, imgdata);
|
||||||
|
|
||||||
// Convert the NSImage to a NSCursor
|
// Convert the NSImage to a NSCursor
|
||||||
IntPtr nscursor =
|
IntPtr nscursor =
|
||||||
Cocoa.SendIntPtr(
|
|
||||||
Cocoa.SendIntPtr(
|
Cocoa.SendIntPtr(
|
||||||
Cocoa.SendIntPtr(NSCursor, Selector.Alloc),
|
Cocoa.SendIntPtr(NSCursor, Selector.Alloc),
|
||||||
selInitWithImageHotSpot,
|
selInitWithImageHotSpot,
|
||||||
img,
|
img,
|
||||||
new PointF(cursor.X, cursor.Y)
|
new PointF(cursor.X, cursor.Y));
|
||||||
),
|
|
||||||
Selector.Autorelease);
|
|
||||||
|
|
||||||
|
Cocoa.SendVoid(imgdata, Selector.Release);
|
||||||
|
Cocoa.SendVoid(img, Selector.Release);
|
||||||
return nscursor;
|
return nscursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,15 +1149,15 @@ namespace OpenTK.Platform.MacOS
|
||||||
get { return cursorVisible; }
|
get { return cursorVisible; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
cursorVisible = value;
|
if (value && !cursorVisible)
|
||||||
if (value)
|
|
||||||
{
|
{
|
||||||
SetCursorVisible(true);
|
SetCursorVisible(true);
|
||||||
}
|
}
|
||||||
else
|
else if (!value && cursorVisible)
|
||||||
{
|
{
|
||||||
SetCursorVisible(false);
|
SetCursorVisible(false);
|
||||||
}
|
}
|
||||||
|
cursorVisible = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1011,15 +1166,21 @@ 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;
|
|
||||||
|
|
||||||
CursorVisible = true;
|
if (!NSApplication.IsUIThread)
|
||||||
disposed = true;
|
return;
|
||||||
exists = false;
|
|
||||||
|
NSApplication.Quit -= ApplicationQuit;
|
||||||
|
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
|
CursorVisible = true;
|
||||||
|
if (exists)
|
||||||
|
{
|
||||||
|
CloseWindow(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (trackingArea != IntPtr.Zero)
|
if (trackingArea != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Cocoa.SendVoid(windowInfo.ViewHandle, selRemoveTrackingArea, trackingArea);
|
Cocoa.SendVoid(windowInfo.ViewHandle, selRemoveTrackingArea, trackingArea);
|
||||||
|
@ -1027,9 +1188,15 @@ namespace OpenTK.Platform.MacOS
|
||||||
trackingArea = IntPtr.Zero;
|
trackingArea = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug.Print("[Mac] Disposing {0}", windowInfo);
|
||||||
windowInfo.Dispose();
|
windowInfo.Dispose();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType().FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
OnDisposed(EventArgs.Empty);
|
OnDisposed(EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1119,5 +1286,28 @@ namespace OpenTK.Platform.MacOS
|
||||||
{
|
{
|
||||||
return (NSWindowStyle)Cocoa.SendUint(windowInfo.Handle, selStyleMask);
|
return (NSWindowStyle)Cocoa.SendUint(windowInfo.Handle, selStyleMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CloseWindow(bool shutdown)
|
||||||
|
{
|
||||||
|
if (!Exists)
|
||||||
|
return;
|
||||||
|
|
||||||
|
exists = false;
|
||||||
|
|
||||||
|
// PerformClose is equivalent to pressing the close-button, which
|
||||||
|
// does not work in a borderless window. Handle this special case.
|
||||||
|
if (GetStyleMask() == NSWindowStyle.Borderless || shutdown)
|
||||||
|
{
|
||||||
|
if (WindowShouldClose(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
|
||||||
|
{
|
||||||
|
Cocoa.SendVoid(windowInfo.Handle, selClose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Cocoa.SendVoid(windowInfo.Handle, selPerformClose, windowInfo.Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
new Dictionary<IOHIDElementRef, JoystickHat>(new IntPtrEqualityComparer());
|
new Dictionary<IOHIDElementRef, JoystickHat>(new IntPtrEqualityComparer());
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly IOHIDManagerRef hidmanager;
|
IOHIDManagerRef hidmanager;
|
||||||
|
|
||||||
readonly Dictionary<IntPtr, MouseData> MouseDevices =
|
readonly Dictionary<IntPtr, MouseData> MouseDevices =
|
||||||
new Dictionary<IntPtr, MouseData>(new IntPtrEqualityComparer());
|
new Dictionary<IntPtr, MouseData>(new IntPtrEqualityComparer());
|
||||||
|
@ -94,7 +94,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
readonly Dictionary<int, IntPtr> JoystickIndexToDevice =
|
readonly Dictionary<int, IntPtr> JoystickIndexToDevice =
|
||||||
new Dictionary<int, IntPtr>();
|
new Dictionary<int, IntPtr>();
|
||||||
|
|
||||||
readonly CFRunLoop RunLoop = CF.CFRunLoopGetMain();
|
readonly CFRunLoop RunLoop;
|
||||||
readonly CFString InputLoopMode = CF.RunLoopModeDefault;
|
readonly CFString InputLoopMode = CF.RunLoopModeDefault;
|
||||||
readonly CFDictionary DeviceTypes = new CFDictionary();
|
readonly CFDictionary DeviceTypes = new CFDictionary();
|
||||||
|
|
||||||
|
@ -118,12 +118,28 @@ namespace OpenTK.Platform.MacOS
|
||||||
{
|
{
|
||||||
Debug.Print("Using HIDInput.");
|
Debug.Print("Using HIDInput.");
|
||||||
|
|
||||||
|
RunLoop = CF.CFRunLoopGetMain();
|
||||||
|
if (RunLoop == IntPtr.Zero)
|
||||||
|
RunLoop = CF.CFRunLoopGetCurrent();
|
||||||
|
if (RunLoop == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Error] No CFRunLoop found for {0}", GetType().FullName);
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
CF.CFRetain(RunLoop);
|
||||||
|
|
||||||
HandleDeviceAdded = DeviceAdded;
|
HandleDeviceAdded = DeviceAdded;
|
||||||
HandleDeviceRemoved = DeviceRemoved;
|
HandleDeviceRemoved = DeviceRemoved;
|
||||||
HandleDeviceValueReceived = DeviceValueReceived;
|
HandleDeviceValueReceived = DeviceValueReceived;
|
||||||
|
|
||||||
// For retrieving input directly from the hardware
|
// For retrieving input directly from the hardware
|
||||||
hidmanager = CreateHIDManager();
|
hidmanager = CreateHIDManager();
|
||||||
|
if (hidmanager == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Mac] Failed to create IO HID manager, HIDInput driver not supported.");
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
RegisterHIDCallbacks(hidmanager);
|
RegisterHIDCallbacks(hidmanager);
|
||||||
|
|
||||||
// For retrieving the global cursor position
|
// For retrieving the global cursor position
|
||||||
|
@ -163,6 +179,8 @@ namespace OpenTK.Platform.MacOS
|
||||||
CGEventType type,
|
CGEventType type,
|
||||||
IntPtr @event,
|
IntPtr @event,
|
||||||
IntPtr refcon)
|
IntPtr refcon)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
CursorState.SetIsConnected(true);
|
CursorState.SetIsConnected(true);
|
||||||
|
|
||||||
|
@ -212,6 +230,12 @@ namespace OpenTK.Platform.MacOS
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Do not let any exceptions escape into unmanaged code!
|
||||||
|
Debug.Print(e.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
return @event;
|
return @event;
|
||||||
}
|
}
|
||||||
|
@ -234,8 +258,6 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
NativeMethods.IOHIDManagerSetDeviceMatching(hidmanager, DeviceTypes.Ref);
|
NativeMethods.IOHIDManagerSetDeviceMatching(hidmanager, DeviceTypes.Ref);
|
||||||
NativeMethods.IOHIDManagerOpen(hidmanager, IOOptionBits.Zero);
|
NativeMethods.IOHIDManagerOpen(hidmanager, IOOptionBits.Zero);
|
||||||
|
|
||||||
OpenTK.Platform.MacOS.Carbon.CF.CFRunLoopRunInMode(InputLoopMode, 0.0, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceAdded(IntPtr context, IOReturn res, IntPtr sender, IOHIDDeviceRef device)
|
void DeviceAdded(IntPtr context, IOReturn res, IntPtr sender, IOHIDDeviceRef device)
|
||||||
|
@ -322,6 +344,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
{
|
{
|
||||||
NativeMethods.IOHIDDeviceRegisterInputValueCallback(device, IntPtr.Zero, IntPtr.Zero);
|
NativeMethods.IOHIDDeviceRegisterInputValueCallback(device, IntPtr.Zero, IntPtr.Zero);
|
||||||
NativeMethods.IOHIDDeviceUnscheduleFromRunLoop(device, RunLoop, InputLoopMode);
|
NativeMethods.IOHIDDeviceUnscheduleFromRunLoop(device, RunLoop, InputLoopMode);
|
||||||
|
NativeMethods.IOHIDDeviceClose(device, IOOptionBits.Zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -1032,7 +1055,11 @@ namespace OpenTK.Platform.MacOS
|
||||||
|
|
||||||
[DllImport(hid)]
|
[DllImport(hid)]
|
||||||
public static extern IOHIDManagerRef IOHIDManagerCreate(
|
public static extern IOHIDManagerRef IOHIDManagerCreate(
|
||||||
CFAllocatorRef allocator, IOOptionBits options) ;
|
CFAllocatorRef allocator, IOOptionBits options);
|
||||||
|
|
||||||
|
[DllImport(hid)]
|
||||||
|
public static extern IOReturn IOHIDManagerClose(
|
||||||
|
IOHIDManagerRef allocator, IOOptionBits options);
|
||||||
|
|
||||||
// This routine will be called when a new (matching) device is connected.
|
// This routine will be called when a new (matching) device is connected.
|
||||||
[DllImport(hid)]
|
[DllImport(hid)]
|
||||||
|
@ -1075,7 +1102,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
[DllImport(hid)]
|
[DllImport(hid)]
|
||||||
public static extern void IOHIDManagerSetDeviceMatching(
|
public static extern void IOHIDManagerSetDeviceMatching(
|
||||||
IOHIDManagerRef manager,
|
IOHIDManagerRef manager,
|
||||||
CFDictionaryRef matching) ;
|
CFDictionaryRef matching);
|
||||||
|
|
||||||
[DllImport(hid)]
|
[DllImport(hid)]
|
||||||
public static extern IOReturn IOHIDManagerOpen(
|
public static extern IOReturn IOHIDManagerOpen(
|
||||||
|
@ -1087,6 +1114,11 @@ namespace OpenTK.Platform.MacOS
|
||||||
IOHIDDeviceRef manager,
|
IOHIDDeviceRef manager,
|
||||||
IOOptionBits opts);
|
IOOptionBits opts);
|
||||||
|
|
||||||
|
[DllImport(hid)]
|
||||||
|
public static extern IOReturn IOHIDDeviceClose(
|
||||||
|
IOHIDDeviceRef device,
|
||||||
|
IOOptionBits options);
|
||||||
|
|
||||||
[DllImport(hid)]
|
[DllImport(hid)]
|
||||||
public static extern CFTypeRef IOHIDDeviceGetProperty(
|
public static extern CFTypeRef IOHIDDeviceGetProperty(
|
||||||
IOHIDDeviceRef device,
|
IOHIDDeviceRef device,
|
||||||
|
@ -1724,6 +1756,15 @@ namespace OpenTK.Platform.MacOS
|
||||||
{
|
{
|
||||||
if (manual)
|
if (manual)
|
||||||
{
|
{
|
||||||
|
if (MouseEventTapSource != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
// Note: releasing the mach port (tap source)
|
||||||
|
// automatically releases the event tap.
|
||||||
|
CF.RunLoopRemoveSource(RunLoop, MouseEventTapSource, CF.RunLoopModeDefault);
|
||||||
|
CF.CFRelease(MouseEventTapSource);
|
||||||
|
MouseEventTapSource = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
NativeMethods.IOHIDManagerRegisterDeviceMatchingCallback(
|
NativeMethods.IOHIDManagerRegisterDeviceMatchingCallback(
|
||||||
hidmanager, IntPtr.Zero, IntPtr.Zero);
|
hidmanager, IntPtr.Zero, IntPtr.Zero);
|
||||||
NativeMethods.IOHIDManagerRegisterDeviceRemovalCallback(
|
NativeMethods.IOHIDManagerRegisterDeviceRemovalCallback(
|
||||||
|
@ -1746,19 +1787,15 @@ namespace OpenTK.Platform.MacOS
|
||||||
DeviceRemoved(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, device);
|
DeviceRemoved(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleDeviceAdded = null;
|
if (hidmanager != IntPtr.Zero)
|
||||||
HandleDeviceRemoved = null;
|
|
||||||
HandleDeviceValueReceived = null;
|
|
||||||
|
|
||||||
if (MouseEventTap != IntPtr.Zero)
|
|
||||||
{
|
{
|
||||||
CF.CFRelease(MouseEventTap);
|
NativeMethods.IOHIDManagerClose(hidmanager, IOOptionBits.Zero);
|
||||||
MouseEventTap = IntPtr.Zero;
|
hidmanager = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
if (MouseEventTapSource != IntPtr.Zero)
|
|
||||||
|
if (RunLoop != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
CF.CFRelease(MouseEventTapSource);
|
CF.CFRelease(RunLoop);
|
||||||
MouseEventTapSource = IntPtr.Zero;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -43,7 +43,13 @@ namespace OpenTK.Platform.MacOS
|
||||||
internal const float ScrollFactor = 0.1f;
|
internal const float ScrollFactor = 0.1f;
|
||||||
internal static bool ExclusiveFullscreen = false;
|
internal static bool ExclusiveFullscreen = false;
|
||||||
|
|
||||||
readonly IInputDriver2 InputDriver = new HIDInput();
|
readonly IInputDriver2 InputDriver;
|
||||||
|
|
||||||
|
public MacOSFactory()
|
||||||
|
{
|
||||||
|
NSApplication.Initialize();
|
||||||
|
InputDriver = new HIDInput();
|
||||||
|
}
|
||||||
|
|
||||||
#region IPlatformFactory Members
|
#region IPlatformFactory Members
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,9 @@ namespace OpenTK.Platform.MacOS.Carbon
|
||||||
[DllImport(appServices)]
|
[DllImport(appServices)]
|
||||||
internal static extern IntPtr CFDictionaryGetValue(IntPtr theDictionary, IntPtr theKey);
|
internal static extern IntPtr CFDictionaryGetValue(IntPtr theDictionary, IntPtr theKey);
|
||||||
|
|
||||||
|
[DllImport(appServices)]
|
||||||
|
internal static extern IntPtr CFRetain(CFTypeRef cf);
|
||||||
|
|
||||||
[DllImport(appServices)]
|
[DllImport(appServices)]
|
||||||
internal static extern void CFRelease(CFTypeRef cf);
|
internal static extern void CFRelease(CFTypeRef cf);
|
||||||
|
|
||||||
|
@ -230,5 +233,11 @@ namespace OpenTK.Platform.MacOS.Carbon
|
||||||
CFRunLoopRef rl,
|
CFRunLoopRef rl,
|
||||||
CFRunLoopSourceRef source,
|
CFRunLoopSourceRef source,
|
||||||
CFStringRef mode);
|
CFStringRef mode);
|
||||||
|
|
||||||
|
[DllImport(appServices, EntryPoint = "CFRunLoopRemoveSource")]
|
||||||
|
internal static extern void RunLoopRemoveSource(
|
||||||
|
CFRunLoopRef rl,
|
||||||
|
CFRunLoopSourceRef source,
|
||||||
|
CFStringRef mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,22 @@ using System;
|
||||||
|
|
||||||
namespace OpenTK
|
namespace OpenTK
|
||||||
{
|
{
|
||||||
/// <summary>Defines a plaftorm specific exception.</summary>
|
/// <summary>
|
||||||
|
/// Defines a plaftorm-specific exception.
|
||||||
|
/// </summary>
|
||||||
public class PlatformException : Exception
|
public class PlatformException : Exception
|
||||||
{
|
{
|
||||||
/// <summary>Constructs a new PlatformException.</summary>
|
/// <summary>
|
||||||
public PlatformException(string s) : base(s) { }
|
/// Initializes a new instance of the <see cref="OpenTK.PlatformException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public PlatformException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="OpenTK.PlatformException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">A message explaining the cause for this exception.</param>
|
||||||
|
public PlatformException(string message) : base(message) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -28,6 +28,7 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
@ -42,6 +43,9 @@ namespace OpenTK.Platform
|
||||||
/// </summary>
|
/// </summary>
|
||||||
abstract class PlatformFactoryBase : IPlatformFactory
|
abstract class PlatformFactoryBase : IPlatformFactory
|
||||||
{
|
{
|
||||||
|
static readonly object sync = new object();
|
||||||
|
readonly List<IDisposable> Resources = new List<IDisposable>();
|
||||||
|
|
||||||
protected bool IsDisposed;
|
protected bool IsDisposed;
|
||||||
|
|
||||||
public PlatformFactoryBase()
|
public PlatformFactoryBase()
|
||||||
|
@ -80,6 +84,14 @@ namespace OpenTK.Platform
|
||||||
return new LegacyJoystickDriver();
|
return new LegacyJoystickDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RegisterResource(IDisposable resource)
|
||||||
|
{
|
||||||
|
lock (sync)
|
||||||
|
{
|
||||||
|
Resources.Add(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IDisposable implementation
|
#region IDisposable implementation
|
||||||
|
@ -96,10 +108,19 @@ namespace OpenTK.Platform
|
||||||
{
|
{
|
||||||
if (manual)
|
if (manual)
|
||||||
{
|
{
|
||||||
|
lock (sync)
|
||||||
|
{
|
||||||
|
foreach (var resource in Resources)
|
||||||
|
{
|
||||||
|
resource.Dispose();
|
||||||
|
}
|
||||||
|
Resources.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Print("[OpenTK] {0} leaked, did you forget to call Dispose()?", GetType());
|
Debug.Print("[OpenTK] {0} leaked with {1} live resources, did you forget to call Dispose()?",
|
||||||
|
GetType().FullName, Resources.Count);
|
||||||
}
|
}
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,7 +376,7 @@ namespace OpenTK.Platform.SDL2
|
||||||
|
|
||||||
#region IDisposable Members
|
#region IDisposable Members
|
||||||
|
|
||||||
void Dispose(bool manual)
|
protected override void Dispose(bool manual)
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
|
@ -397,17 +397,6 @@ namespace OpenTK.Platform.SDL2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Sdl2GraphicsContext()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -465,13 +465,7 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
#region IDisposable Members
|
#region IDisposable Members
|
||||||
|
|
||||||
public override void Dispose()
|
protected override void Dispose(bool calledManually)
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Dispose(bool calledManually)
|
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
|
@ -479,20 +473,10 @@ namespace OpenTK.Platform.Windows
|
||||||
{
|
{
|
||||||
DestroyContext();
|
DestroyContext();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Print("[Warning] OpenGL context {0} leaked. Did you forget to call IGraphicsContext.Dispose()?",
|
|
||||||
Handle.Handle);
|
|
||||||
}
|
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~WinGLContext()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region private void DestroyContext()
|
#region private void DestroyContext()
|
||||||
|
|
||||||
private void DestroyContext()
|
private void DestroyContext()
|
||||||
|
|
|
@ -483,13 +483,7 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
#region --- IDisposable Members ---
|
#region --- IDisposable Members ---
|
||||||
|
|
||||||
public override void Dispose()
|
protected override void Dispose(bool manuallyCalled)
|
||||||
{
|
|
||||||
this.Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Dispose(bool manuallyCalled)
|
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
|
@ -517,12 +511,6 @@ namespace OpenTK.Platform.X11
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
~X11GLContext()
|
|
||||||
{
|
|
||||||
this.Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,22 +178,19 @@ namespace OpenTK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Print("OpenTK.Toolkit leaked, did you forget to call Dispose()?");
|
|
||||||
platform_factory = null;
|
|
||||||
toolkit = null;
|
|
||||||
initialized = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finalizes this instance.
|
/// Finalizes this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
~Toolkit()
|
~Toolkit()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Debug.Print("[Warning] {0} leaked, did you forget to call Dispose()?");
|
||||||
|
// We may not Dispose() the toolkit from the finalizer thread,
|
||||||
|
// as that will crash on many operating systems.
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue