[Mac] Close CocoaNativeWindow in Dispose()

Also fix various memory management issues regarding the `MouseCursor`
and `Icon` properties.
This commit is contained in:
thefiddler 2014-07-22 16:29:21 +02:00
parent 7956126c8d
commit 0e40f63cf2

View file

@ -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;
@ -573,20 +574,7 @@ namespace OpenTK.Platform.MacOS
if (shouldClose) if (shouldClose)
{ {
shouldClose = false; shouldClose = false;
CloseWindow();
// 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,13 +601,35 @@ namespace OpenTK.Platform.MacOS
get { return icon; } get { return icon; }
set set
{ {
icon = value; if (value != null && value != icon)
using (Image img = icon.ToBitmap())
{ {
IntPtr nsimg = Cocoa.ToNSImage(img); // Create and set new icon
Cocoa.SendVoid(NSApplication.Handle, selSetApplicationIconImage, nsimg); IntPtr nsimg = IntPtr.Zero;
using (Image img = value.ToBitmap())
{
nsimg = Cocoa.ToNSImage(img);
if (nsimg != IntPtr.Zero)
{
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);
} }
} }
@ -889,21 +899,19 @@ namespace OpenTK.Platform.MacOS
// 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, IntPtr.Zero,
IntPtr.Zero, cursor.Width,
cursor.Width, cursor.Height,
cursor.Height, 8,
8, 4,
4, 1,
1, 0,
0, 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]})",
@ -935,14 +943,13 @@ 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);
@ -950,14 +957,13 @@ namespace OpenTK.Platform.MacOS
// 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;
} }
@ -1015,8 +1021,10 @@ namespace OpenTK.Platform.MacOS
NSApplication.Quit -= ApplicationQuit; NSApplication.Quit -= ApplicationQuit;
CursorVisible = true; CursorVisible = true;
disposed = true; if (exists)
exists = false; {
CloseWindow();
}
if (disposing) if (disposing)
{ {
@ -1027,9 +1035,11 @@ namespace OpenTK.Platform.MacOS
trackingArea = IntPtr.Zero; trackingArea = IntPtr.Zero;
} }
Debug.Print("[Mac] Disposing {0}", windowInfo);
windowInfo.Dispose(); windowInfo.Dispose();
} }
disposed = true;
OnDisposed(EventArgs.Empty); OnDisposed(EventArgs.Empty);
} }
@ -1119,5 +1129,25 @@ namespace OpenTK.Platform.MacOS
{ {
return (NSWindowStyle)Cocoa.SendUint(windowInfo.Handle, selStyleMask); return (NSWindowStyle)Cocoa.SendUint(windowInfo.Handle, selStyleMask);
} }
void CloseWindow()
{
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)
{
if (WindowShouldClose(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
{
Cocoa.SendVoid(windowInfo.Handle, selClose);
}
}
else
{
Cocoa.SendVoid(windowInfo.Handle, selPerformClose, windowInfo.Handle);
}
}
} }
} }