From 44a52d50ab67b3b54029363b0b712d621cb98e47 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 4 Nov 2015 12:11:23 +1100 Subject: [PATCH] Hopefully fix OSX issues this time. --- Launcher2/Gui/PlatformDrawer.cs | 32 +- OpenTK/OpenTK.csproj | 1 - OpenTK/Platform/MacOS/AglContext.cs | 69 ++- OpenTK/Platform/MacOS/Application.cs | 50 ++- .../MacOS/CarbonBindings/CarbonAPI.cs | 274 ++++++++---- OpenTK/Platform/MacOS/CarbonGLNative.cs | 396 ++++++++++++------ OpenTK/Platform/MacOS/CarbonWindowInfo.cs | 81 +++- OpenTK/Platform/MacOS/EventInfo.cs | 31 -- 8 files changed, 644 insertions(+), 290 deletions(-) delete mode 100644 OpenTK/Platform/MacOS/EventInfo.cs diff --git a/Launcher2/Gui/PlatformDrawer.cs b/Launcher2/Gui/PlatformDrawer.cs index ca2b38ffc..ae64ad76c 100644 --- a/Launcher2/Gui/PlatformDrawer.cs +++ b/Launcher2/Gui/PlatformDrawer.cs @@ -4,6 +4,7 @@ using ClassicalSharp; using OpenTK.Platform; using OpenTK.Platform.X11; using OSX = OpenTK.Platform.MacOS.Carbon; +using OSStatus = OpenTK.Platform.MacOS.OSStatus; namespace Launcher2 { @@ -19,7 +20,7 @@ namespace Launcher2 { public sealed class WinPlatformDrawer : PlatformDrawer { - Graphics g; + Graphics g; public override void Init( IWindowInfo info ) { g = Graphics.FromHwnd( info.WinHandle ); } @@ -49,13 +50,38 @@ namespace Launcher2 { } public override void Draw( IWindowInfo info, Bitmap framebuffer ) { - //g.DrawImage( framebuffer, 0, 0, framebuffer.Width, framebuffer.Height ); + + using( FastBitmap bmp = new FastBitmap( framebuffer, true ) ) { + IntPtr scan0 = bmp.Scan0; + int size = bmp.Width * bmp.Height * 4; + + IntPtr colorSpace = OSX.API.CGColorSpaceCreateDeviceRGB(); + IntPtr provider = OSX.API.CGDataProviderCreateWithData( IntPtr.Zero, scan0, size, IntPtr.Zero ); + IntPtr image = OSX.API.CGImageCreate( bmp.Width, bmp.Height, 8, 8 * 4, bmp.Stride, + colorSpace, 4, provider, IntPtr.Zero, 0, 0 ); + IntPtr context = IntPtr.Zero; + OSStatus err = OSX.API.QDBeginCGContext( windowPort, ref context ); + OSX.API.CheckReturn( err ); + + OSX.HIRect rect = new OSX.HIRect(); + rect.Origin.X = 0; rect.Origin.Y = 0; + rect.Size.X = bmp.Width; rect.Size.Y = bmp.Height; + + OSX.API.CGContextDrawImage( context, rect, image ); + OSX.API.CGContextSynchronize( context ); + err = OSX.API.QDEndCGContext( windowPort, ref context ); + OSX.API.CheckReturn( err ); + + OSX.API.CGImageRelease( image ); + OSX.API.CGDataProviderRelease( provider ); + OSX.API.CGColorSpaceRelease( colorSpace ); + } } } public sealed class X11PlatformDrawer : PlatformDrawer { - IntPtr gc; + IntPtr gc; public override void Init( IWindowInfo info ) { gc = API.XCreateGC( API.DefaultDisplay, info.WinHandle, IntPtr.Zero, null ); } diff --git a/OpenTK/OpenTK.csproj b/OpenTK/OpenTK.csproj index a3a1fa415..7d7307066 100644 --- a/OpenTK/OpenTK.csproj +++ b/OpenTK/OpenTK.csproj @@ -92,7 +92,6 @@ - diff --git a/OpenTK/Platform/MacOS/AglContext.cs b/OpenTK/Platform/MacOS/AglContext.cs index c63592431..e86ca7d9f 100644 --- a/OpenTK/Platform/MacOS/AglContext.cs +++ b/OpenTK/Platform/MacOS/AglContext.cs @@ -106,15 +106,32 @@ namespace OpenTK.Platform.MacOS { Update(carbonWindow); MakeCurrent(carbonWindow); + Debug.Print("context: {0}", ContextHandle); } - private IntPtr GetQuartzDevice( CarbonWindowInfo carbonWindow ) { - CarbonGLNative nativeWindow = carbonWindow.nativeWindow; - return QuartzDisplayDeviceDriver.HandleTo( nativeWindow.TargetDisplayDevice ); + private IntPtr GetQuartzDevice(CarbonWindowInfo carbonWindow) + { + IntPtr windowRef = carbonWindow.WindowRef; + + if (!CarbonGLNative.WindowRefMap.ContainsKey(windowRef)) + return IntPtr.Zero; + + WeakReference nativeRef = CarbonGLNative.WindowRefMap[windowRef]; + if (!nativeRef.IsAlive) + return IntPtr.Zero; + + CarbonGLNative window = nativeRef.Target as CarbonGLNative; + + if (window == null) + return IntPtr.Zero; + + return QuartzDisplayDeviceDriver.HandleTo(window.TargetDisplayDevice); + } - void SetDrawable(CarbonWindowInfo carbonWindow) { + void SetDrawable(CarbonWindowInfo carbonWindow) + { IntPtr windowPort = API.GetWindowPort(carbonWindow.WindowRef); //Debug.Print("Setting drawable for context {0} to window port: {1}", Handle.Handle, windowPort); @@ -122,12 +139,14 @@ namespace OpenTK.Platform.MacOS { Agl.CheckReturnValue( code, "aglSetDrawable" ); } - public override void Update(IWindowInfo window) { - CarbonWindowInfo winInfo = (CarbonWindowInfo)window; + public override void Update(IWindowInfo window) + { + CarbonWindowInfo carbonWindow = (CarbonWindowInfo)window; - if (winInfo.goFullScreenHack) { - winInfo.goFullScreenHack = false; - CarbonGLNative wind = winInfo.nativeWindow; + if (carbonWindow.goFullScreenHack) + { + carbonWindow.goFullScreenHack = false; + CarbonGLNative wind = GetCarbonWindow(carbonWindow); if (wind != null) wind.SetFullscreen(this); @@ -135,9 +154,11 @@ namespace OpenTK.Platform.MacOS { Debug.Print("Could not find window!"); return; - } else if (winInfo.goWindowedHack) { - winInfo.goWindowedHack = false; - CarbonGLNative wind = winInfo.nativeWindow; + } + else if (carbonWindow.goWindowedHack) + { + carbonWindow.goWindowedHack = false; + CarbonGLNative wind = GetCarbonWindow(carbonWindow); if (wind != null) wind.UnsetFullscreen(this); @@ -149,13 +170,22 @@ namespace OpenTK.Platform.MacOS { if (mIsFullscreen) return; - SetDrawable(winInfo); + SetDrawable(carbonWindow); + Agl.aglUpdateContext(ContextHandle); } + private CarbonGLNative GetCarbonWindow(CarbonWindowInfo carbonWindow) + { + WeakReference r = CarbonGLNative.WindowRefMap[carbonWindow.WindowRef]; + return r.IsAlive ? (CarbonGLNative)r.Target : null; + } + bool firstFullScreen = false; - internal void SetFullScreen(CarbonWindowInfo info, out int width, out int height) { - CarbonGLNative wind = info.nativeWindow; + internal void SetFullScreen(CarbonWindowInfo info, out int width, out int height) + { + CarbonGLNative wind = GetCarbonWindow(info); + Debug.Print("Switching to full screen {0}x{1} on context {2}", wind.TargetDisplayDevice.Width, wind.TargetDisplayDevice.Height, ContextHandle); @@ -175,10 +205,12 @@ namespace OpenTK.Platform.MacOS { UnsetFullScreen(info); SetFullScreen(info, out width, out height); } + mIsFullscreen = true; } - internal void UnsetFullScreen(CarbonWindowInfo windowInfo) { + internal void UnsetFullScreen(CarbonWindowInfo windowInfo) + { Debug.Print("Unsetting AGL fullscreen."); byte code = Agl.aglSetDrawable(ContextHandle, IntPtr.Zero); Agl.CheckReturnValue( code, "aglSetDrawable" ); @@ -192,6 +224,7 @@ namespace OpenTK.Platform.MacOS { mIsFullscreen = false; } + #region IGraphicsContext Members public override void SwapBuffers() { @@ -205,7 +238,7 @@ namespace OpenTK.Platform.MacOS { } public override bool IsCurrent { - get { return ContextHandle == Agl.aglGetCurrentContext(); } + get { return ContextHandle == Agl.aglGetCurrentContext(); } } public override bool VSync { @@ -281,4 +314,4 @@ namespace OpenTK.Platform.MacOS { #endregion } -} +} \ No newline at end of file diff --git a/OpenTK/Platform/MacOS/Application.cs b/OpenTK/Platform/MacOS/Application.cs index e8c85c294..0943e7fa4 100644 --- a/OpenTK/Platform/MacOS/Application.cs +++ b/OpenTK/Platform/MacOS/Application.cs @@ -12,35 +12,41 @@ using System.Collections.Generic; using System.IO; using System.Text; -namespace OpenTK.Platform.MacOS.Carbon { - - static class Application { - +namespace OpenTK.Platform.MacOS.Carbon +{ + static class Application + { static bool mInitialized = false; static IntPtr uppHandler; - public static CarbonGLNative WindowEventHandler; + static CarbonGLNative eventHandler; static int osMajor, osMinor, osBugfix; - static Application() { + static Application() + { Initialize(); } - internal static void Initialize() { + internal static void Initialize() + { if (mInitialized) return; API.AcquireRootMenu(); + ConnectEvents(); API.Gestalt(GestaltSelector.SystemVersionMajor, out osMajor); API.Gestalt(GestaltSelector.SystemVersionMinor, out osMinor); API.Gestalt(GestaltSelector.SystemVersionBugFix, out osBugfix); + Debug.Print("Running on Mac OS X {0}.{1}.{2}.", osMajor, osMinor, osBugfix); TransformProcessToForeground(); } - private static void TransformProcessToForeground() { + private static void TransformProcessToForeground() + { Carbon.ProcessSerialNumber psn = new ProcessSerialNumber(); + Debug.Print("Setting process to be foreground application."); API.GetCurrentProcess(ref psn); @@ -48,8 +54,16 @@ namespace OpenTK.Platform.MacOS.Carbon { API.SetFrontProcess(ref psn); } - static void ConnectEvents() { - EventTypeSpec[] eventTypes = new EventTypeSpec[] { + internal static CarbonGLNative WindowEventHandler + { + get { return eventHandler; } + set { eventHandler = value; } + } + + static void ConnectEvents() + { + EventTypeSpec[] eventTypes = new EventTypeSpec[] + { new EventTypeSpec(EventClass.Application, AppEventKind.AppActivated), new EventTypeSpec(EventClass.Application, AppEventKind.AppDeactivated), new EventTypeSpec(EventClass.Application, AppEventKind.AppQuit), @@ -74,13 +88,17 @@ namespace OpenTK.Platform.MacOS.Carbon { uppHandler = API.NewEventHandlerUPP(handler); API.InstallApplicationEventHandler( - uppHandler, eventTypes, IntPtr.Zero, IntPtr.Zero); + uppHandler, eventTypes, IntPtr.Zero, IntPtr.Zero); + mInitialized = true; } - static OSStatus EventHandler(IntPtr inCaller, IntPtr inEvent, IntPtr userData) { - EventInfo evt = new EventInfo(inEvent); - switch (evt.EventClass) { + static OSStatus EventHandler(IntPtr inCaller, IntPtr inEvent, IntPtr userData) + { + EventInfo evt = new EventInfo(inEvent); + + switch (evt.EventClass) + { case EventClass.AppleEvent: // only event here is the apple event. Debug.Print("Processing apple event."); @@ -90,10 +108,12 @@ namespace OpenTK.Platform.MacOS.Carbon { case EventClass.Keyboard: case EventClass.Mouse: if (WindowEventHandler != null) + { return WindowEventHandler.DispatchEvent(inCaller, inEvent, evt, userData); + } break; } return OSStatus.EventNotHandled; } } -} +} \ No newline at end of file diff --git a/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs b/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs index 7b769e1f9..fe8258cd0 100644 --- a/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs +++ b/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs @@ -15,8 +15,8 @@ namespace OpenTK.Platform.MacOS.Carbon [StructLayout(LayoutKind.Sequential)] public struct CarbonPoint { - internal short V; - internal short H; + public short V; + public short H; public CarbonPoint(int x, int y) { @@ -33,26 +33,26 @@ namespace OpenTK.Platform.MacOS.Carbon short bottom; short right; - internal Rect(short _left, short _top, short _width, short _height) { + public Rect(short _left, short _top, short _width, short _height) { top = _top; left = _left; bottom = (short)(_top + _height); right = (short)(_left + _width); } - internal short X { + public short X { get { return left; } } - internal short Y { + public short Y { get { return top; } } - internal short Width { + public short Width { get { return (short)(right - left); } } - internal short Height { + public short Height { get { return (short)(bottom - top); } } @@ -108,7 +108,7 @@ namespace OpenTK.Platform.MacOS.Carbon } [StructLayout(LayoutKind.Sequential)] - internal struct HIRect { + public struct HIRect { public HIPoint Origin; public HIPoint Size; @@ -120,6 +120,21 @@ namespace OpenTK.Platform.MacOS.Carbon #endregion + public struct EventInfo { + + public EventInfo(IntPtr eventRef) { + EventClass = API.GetEventClass(eventRef); + EventKind = API.GetEventKind(eventRef); + } + + public uint EventKind; + public EventClass EventClass; + + public override string ToString() { + return "Event: " + EventClass + ",kind: " + EventKind; + } + } + #region --- Types defined in CarbonEvents.h --- enum EventAttributes : uint @@ -132,34 +147,34 @@ namespace OpenTK.Platform.MacOS.Carbon [StructLayout(LayoutKind.Sequential)] public struct EventTypeSpec { - internal EventTypeSpec(EventClass evtClass, AppEventKind evtKind) + public EventTypeSpec(EventClass evtClass, AppEventKind evtKind) { this.EventClass = evtClass; this.EventKind = (uint)evtKind; } - internal EventTypeSpec(EventClass evtClass, AppleEventKind appleKind) + public EventTypeSpec(EventClass evtClass, AppleEventKind appleKind) { this.EventClass = evtClass; this.EventKind = (uint)appleKind; } - internal EventTypeSpec(EventClass evtClass, MouseEventKind evtKind) + public EventTypeSpec(EventClass evtClass, MouseEventKind evtKind) { this.EventClass = evtClass; this.EventKind = (uint)evtKind; } - internal EventTypeSpec(EventClass evtClass, KeyboardEventKind evtKind) + public EventTypeSpec(EventClass evtClass, KeyboardEventKind evtKind) { this.EventClass = evtClass; this.EventKind = (uint)evtKind; } - internal EventTypeSpec(EventClass evtClass, WindowEventKind evtKind) + public EventTypeSpec(EventClass evtClass, WindowEventKind evtKind) { this.EventClass = evtClass; this.EventKind = (uint)evtKind; } - internal EventClass EventClass; - internal uint EventKind; + public EventClass EventClass; + public uint EventKind; } public enum EventClass : int @@ -182,7 +197,7 @@ namespace OpenTK.Platform.MacOS.Carbon Menu = 0x6d656e75, Window = 0x77696e64, } - internal enum WindowEventKind : int + public enum WindowEventKind : int { // window events WindowUpdate = 1, @@ -204,7 +219,7 @@ namespace OpenTK.Platform.MacOS.Carbon WindowClose = 72, WindowClosed = 73, } - internal enum MouseEventKind : int + public enum MouseEventKind : int { MouseDown = 1, MouseUp = 2, @@ -221,7 +236,7 @@ namespace OpenTK.Platform.MacOS.Carbon Tertiary = 3, } - internal enum KeyboardEventKind : int + public enum KeyboardEventKind : int { // raw keyboard events RawKeyDown = 1, @@ -230,7 +245,7 @@ namespace OpenTK.Platform.MacOS.Carbon RawKeyModifiersChanged = 4, } - internal enum AppEventKind : int + public enum AppEventKind : int { // application events AppActivated = 1, @@ -239,12 +254,12 @@ namespace OpenTK.Platform.MacOS.Carbon AppLaunchNotification = 4, } - enum AppleEventKind : int + public enum AppleEventKind : int { AppleEvent = 1, } - internal enum EventParamName : int + public enum EventParamName : int { WindowRef = 0x77696e64, // typeWindowRef, @@ -263,7 +278,7 @@ namespace OpenTK.Platform.MacOS.Carbon KeyModifiers = 0x6b6d6f64, // typeUInt32 } - internal enum EventParamType : int + public enum EventParamType : int { typeWindowRef = 0x77696e64, @@ -283,7 +298,7 @@ namespace OpenTK.Platform.MacOS.Carbon typeIEEE64BitFloatingPoint = 0x646f7562, } - internal enum EventMouseButton : int + public enum EventMouseButton : int { Primary = 0, Secondary = 1, @@ -354,7 +369,8 @@ namespace OpenTK.Platform.MacOS.Carbon StandardFloating = (CloseBox | CollapseBox) } - public enum WindowPositionMethod : uint { + public enum WindowPositionMethod : uint + { CenterOnMainScreen = 1, CenterOnParentWindow = 2, CenterOnParentWindowScreen = 3, @@ -369,7 +385,8 @@ namespace OpenTK.Platform.MacOS.Carbon public delegate OSStatus MacOSEventHandler(IntPtr inCaller, IntPtr inEvent, IntPtr userData); - internal enum WindowPartCode : short { + public enum WindowPartCode : short + { inDesk = 0, inNoWindow = 0, inMenuBar = 1, @@ -400,11 +417,13 @@ namespace OpenTK.Platform.MacOS.Carbon #endregion #region --- Process Manager --- - public enum ProcessApplicationTransformState : int { + public enum ProcessApplicationTransformState : int + { kProcessTransformToForegroundApplication = 1, } - public struct ProcessSerialNumber { + public struct ProcessSerialNumber + { public ulong high; public ulong low; } @@ -422,8 +441,8 @@ namespace OpenTK.Platform.MacOS.Carbon #region --- Carbon API Methods --- - public static class API { - + public class API + { const string carbon = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon"; [DllImport(carbon)] @@ -463,11 +482,12 @@ namespace OpenTK.Platform.MacOS.Carbon [DllImport(carbon)] static extern OSStatus GetWindowBounds(IntPtr window, WindowRegionCode regionCode, out Rect globalBounds); - public static Rect GetWindowBounds(IntPtr window, WindowRegionCode regionCode) { - Rect rect; - OSStatus result = GetWindowBounds(window, regionCode, out rect); - CheckReturn(result); - return rect; + public static Rect GetWindowBounds(IntPtr window, WindowRegionCode regionCode) + { + Rect retval; + OSStatus error = GetWindowBounds(window, regionCode, out retval); + CheckReturn( error ); + return retval; } //[DllImport(carbon)] @@ -479,9 +499,11 @@ namespace OpenTK.Platform.MacOS.Carbon [DllImport(carbon)] static extern IntPtr GetEventDispatcherTarget(); - [DllImport(carbon)] - static extern OSStatus ReceiveNextEvent(uint inNumTypes, IntPtr inList, - double inTimeout, bool inPullEvent, + [DllImport(carbon,EntryPoint="ReceiveNextEvent")] + static extern OSStatus ReceiveNextEvent(uint inNumTypes, + IntPtr inList, + double inTimeout, + bool inPullEvent, out IntPtr outEvent); [DllImport(carbon)] @@ -490,32 +512,56 @@ namespace OpenTK.Platform.MacOS.Carbon [DllImport(carbon)] static extern void ReleaseEvent(IntPtr theEvent); + public static void SendEvent(IntPtr theEvent) + { + IntPtr theTarget = GetEventDispatcherTarget(); + SendEventToEventTarget(theEvent, theTarget); + } + // Processes events in the queue and then returns. - public static void ProcessEvents() { + public static void ProcessEvents() + { IntPtr theEvent; IntPtr theTarget = GetEventDispatcherTarget(); - for (;;) { + for (;;) + { OSStatus status = ReceiveNextEvent(0, IntPtr.Zero, 0.0, true, out theEvent); if (status == OSStatus.EventLoopTimedOut) break; - if (status != OSStatus.NoError) { + if (status != OSStatus.NoError) + { Debug.Print("Message Loop status: {0}", status); break; } if (theEvent == IntPtr.Zero) break; - SendEventToEventTarget(theEvent, theTarget); + try + { + SendEventToEventTarget(theEvent, theTarget); + } + catch (System.ExecutionEngineException e) + { + Console.Error.WriteLine("ExecutionEngineException caught."); + Console.Error.WriteLine("theEvent: " + new EventInfo(theEvent).ToString()); + Console.Error.WriteLine(e.Message); + Console.Error.WriteLine(e.StackTrace); + } + ReleaseEvent(theEvent); } } - + + #region --- Processing apple event --- + [StructLayout(LayoutKind.Sequential)] - struct EventRecord { + + struct EventRecord + { public ushort what; public uint message; public uint when; @@ -529,15 +575,33 @@ namespace OpenTK.Platform.MacOS.Carbon [DllImport(carbon)] static extern OSStatus AEProcessAppleEvent(ref EventRecord theEventRecord); - public static void ProcessAppleEvent(IntPtr inEvent) { + static public void ProcessAppleEvent(IntPtr inEvent) + { EventRecord record; + ConvertEventRefToEventRecord(inEvent, out record); AEProcessAppleEvent(ref record); } - + #endregion - #region --- Event handlers --- + #endregion + #region --- Getting Event Parameters --- + + [DllImport(carbon)] + static extern OSStatus CreateEvent( IntPtr inAllocator, + EventClass inClassID, UInt32 kind, EventTime when, + EventAttributes flags, out IntPtr outEvent); + + public static IntPtr CreateWindowEvent(WindowEventKind kind) { + IntPtr retval; + OSStatus stat = CreateEvent(IntPtr.Zero, EventClass.Window, (uint)kind, + 0, EventAttributes.kEventAttributeNone, out retval); + + if (stat != OSStatus.NoError) + throw new MacOSException(stat); + return retval; + } [DllImport(carbon)] static extern OSStatus GetEventParameter( @@ -549,7 +613,9 @@ namespace OpenTK.Platform.MacOS.Carbon OSStatus result = API.GetEventParameter(inEvent, EventParamName.KeyCode, EventParamType.typeUInt32, IntPtr.Zero, sizeof(uint), IntPtr.Zero, (IntPtr)(void*)&code); - CheckReturn(result); + + if (result != OSStatus.NoError) + throw new MacOSException(result); return (MacOSKeyCode)code; } @@ -558,7 +624,9 @@ namespace OpenTK.Platform.MacOS.Carbon OSStatus result = API.GetEventParameter(inEvent, EventParamName.KeyMacCharCode, EventParamType.typeChar, IntPtr.Zero, Marshal.SizeOf(typeof(char)), IntPtr.Zero, (IntPtr)(void*)&code); - CheckReturn(result); + + if (result != OSStatus.NoError) + throw new MacOSException(result); return code; } @@ -567,7 +635,9 @@ namespace OpenTK.Platform.MacOS.Carbon OSStatus result = API.GetEventParameter(inEvent, EventParamName.MouseButton, EventParamType.typeMouseButton, IntPtr.Zero, sizeof(short), IntPtr.Zero, (IntPtr)(void*)&button); - CheckReturn(result); + + if (result != OSStatus.NoError) + throw new MacOSException(result); return (MacOSMouseButton)button; } @@ -576,7 +646,9 @@ namespace OpenTK.Platform.MacOS.Carbon OSStatus result = API.GetEventParameter(inEvent, EventParamName.MouseWheelDelta, EventParamType.typeSInt32, IntPtr.Zero, sizeof(int), IntPtr.Zero, (IntPtr)(void*)&delta); - CheckReturn(result); + + if (result != OSStatus.NoError) + throw new MacOSException(result); return delta; } @@ -585,7 +657,7 @@ namespace OpenTK.Platform.MacOS.Carbon OSStatus result = API.GetEventParameter(inEvent, EventParamName.WindowMouseLocation, EventParamType.typeHIPoint, IntPtr.Zero, Marshal.SizeOf(typeof(HIPoint)), IntPtr.Zero, (IntPtr)(void*)&point); - //CheckReturn(result); + pt = point; return result; } @@ -595,7 +667,7 @@ namespace OpenTK.Platform.MacOS.Carbon OSStatus result = API.GetEventParameter(inEvent, EventParamName.WindowRef, EventParamType.typeWindowRef, IntPtr.Zero, sizeof(IntPtr), IntPtr.Zero, (IntPtr)(void*)&retval); - //CheckReturn(result); + windowRef = retval; return result; } @@ -605,7 +677,7 @@ namespace OpenTK.Platform.MacOS.Carbon OSStatus result = API.GetEventParameter(inEvent, EventParamName.MouseLocation, EventParamType.typeHIPoint, IntPtr.Zero, Marshal.SizeOf(typeof(HIPoint)), IntPtr.Zero, (IntPtr)(void*)&point); - //CheckReturn(result); + pt = point; return result; } @@ -615,26 +687,33 @@ namespace OpenTK.Platform.MacOS.Carbon OSStatus result = API.GetEventParameter(inEvent, EventParamName.KeyModifiers, EventParamType.typeUInt32, IntPtr.Zero, sizeof(uint), IntPtr.Zero, (IntPtr)(void*)&code); - CheckReturn(result); + + if (result != OSStatus.NoError) + throw new MacOSException(result); return (MacOSKeyModifiers)code; } - [DllImport(carbon)] - static extern OSStatus InstallEventHandler( - IntPtr eventTargetRef, IntPtr handlerProc, - int numtypes, EventTypeSpec[] typeList, - IntPtr userData, IntPtr handlerRef); + #endregion + #region --- Event Handlers --- - public static void InstallWindowEventHandler(IntPtr windowRef, IntPtr uppHandlerProc, EventTypeSpec[] eventTypes, - IntPtr userData, IntPtr handlerRef) { + [DllImport(carbon)] + static extern OSStatus InstallEventHandler( IntPtr eventTargetRef, IntPtr handlerProc, + int numtypes, EventTypeSpec[] typeList, + IntPtr userData, IntPtr handlerRef); + + public static void InstallWindowEventHandler(IntPtr windowRef, IntPtr uppHandlerProc, + EventTypeSpec[] eventTypes, IntPtr userData, IntPtr handlerRef) + { IntPtr windowTarget = GetWindowEventTarget(windowRef); - OSStatus error = InstallEventHandler(windowTarget, uppHandlerProc, eventTypes.Length, - eventTypes, userData, handlerRef); + OSStatus error = InstallEventHandler(windowTarget, uppHandlerProc, + eventTypes.Length, eventTypes, + userData, handlerRef); CheckReturn( error ); } - public static void InstallApplicationEventHandler(IntPtr uppHandlerProc, EventTypeSpec[] eventTypes, - IntPtr userData, IntPtr handlerRef) { + public static void InstallApplicationEventHandler(IntPtr uppHandlerProc, + EventTypeSpec[] eventTypes, IntPtr userData, IntPtr handlerRef) + { OSStatus error = InstallEventHandler(GetApplicationEventTarget(), uppHandlerProc, eventTypes.Length, eventTypes, userData, handlerRef); @@ -644,11 +723,17 @@ namespace OpenTK.Platform.MacOS.Carbon [DllImport(carbon)] public static extern OSStatus RemoveEventHandler(IntPtr inHandlerRef); + #endregion + #region --- GetWindowEventTarget --- + [DllImport(carbon)] public static extern IntPtr GetWindowEventTarget(IntPtr window); [DllImport(carbon)] public static extern IntPtr GetApplicationEventTarget(); + + #endregion + #region --- UPP Event Handlers --- [DllImport(carbon)] public static extern IntPtr NewEventHandlerUPP(MacOSEventHandler handler); @@ -672,24 +757,50 @@ namespace OpenTK.Platform.MacOS.Carbon [DllImport(carbon)] public extern static IntPtr CGColorSpaceCreateDeviceRGB(); [DllImport(carbon)] - public extern static IntPtr CGDataProviderCreateWithData(IntPtr info, IntPtr[] data, int size, IntPtr releasefunc); + public extern static IntPtr CGDataProviderCreateWithData(IntPtr info, IntPtr data, int size, IntPtr releasefunc); [DllImport(carbon)] - public extern static IntPtr CGImageCreate(int width, int height, int bitsPerComponent, int bitsPerPixel, int bytesPerRow, IntPtr colorspace, uint bitmapInfo, IntPtr provider, IntPtr decode, int shouldInterpolate, int intent); + public extern static IntPtr CGImageCreate(int width, int height, int bitsPerComponent, int bitsPerPixel, int bytesPerRow, IntPtr colorspace, + uint bitmapInfo, IntPtr provider, IntPtr decode, int shouldInterpolate, int intent); [DllImport(carbon)] public extern static void SetApplicationDockTileImage(IntPtr imageRef); [DllImport(carbon)] public extern static void RestoreApplicationDockTileImage(); - + [DllImport(carbon)] + public extern static void CGImageRelease(IntPtr image); + [DllImport(carbon)] + public extern static void CGDataProviderRelease(IntPtr provider); + [DllImport(carbon)] + public extern static void CGColorSpaceRelease(IntPtr space); + [DllImport(carbon)] + public extern static void CGContextDrawImage( IntPtr context, HIRect rect, IntPtr image ); + [DllImport(carbon)] + public extern static void CGContextSynchronize( IntPtr context ); + [DllImport(carbon)] + public extern static OSStatus QDBeginCGContext( IntPtr port, ref IntPtr context ); + [DllImport(carbon)] + public extern static OSStatus QDEndCGContext( IntPtr port, ref IntPtr context ); #endregion + [DllImport(carbon)] + public static extern OSStatus ActivateWindow (IntPtr inWindow, bool inActivate); + + [DllImport(carbon)] + public static extern void RunApplicationEventLoop(); + + [DllImport(carbon)] + public static extern void QuitApplicationEventLoop(); + #region --- SetWindowTitle --- [DllImport(carbon)] static extern void SetWindowTitleWithCFString(IntPtr windowRef, IntPtr title); - public static void SetWindowTitle(IntPtr windowRef, string title) { + public static void SetWindowTitle(IntPtr windowRef, string title) + { IntPtr str = __CFStringMakeConstantString(title); + Debug.Print("Setting window title: {0}, CFstring : {1}, Text : {2}", windowRef, str, title); + SetWindowTitleWithCFString(windowRef, str); // Apparently releasing this reference to the CFConstantString here @@ -712,30 +823,36 @@ namespace OpenTK.Platform.MacOS.Carbon [DllImport(carbon)] public static extern IntPtr GetWindowPort(IntPtr windowRef); + + #region --- Menus --- [DllImport(carbon)] public static extern IntPtr AcquireRootMenu(); + + #endregion + [DllImport(carbon)] public static extern bool IsWindowCollapsed(IntPtr windowRef); [DllImport(carbon)] public static extern OSStatus CollapseWindow(IntPtr windowRef, bool collapse); + + public static void CheckReturn(OSStatus error ) { + if( error != OSStatus.NoError ) + throw new MacOSException( error ); + } [DllImport(carbon, EntryPoint="IsWindowInStandardState")] static extern bool _IsWindowInStandardState(IntPtr windowRef, IntPtr inIdealSize, IntPtr outIdealStandardState); - public static bool IsWindowInStandardState(IntPtr windowRef) { + public static bool IsWindowInStandardState(IntPtr windowRef) + { return _IsWindowInStandardState(windowRef, IntPtr.Zero, IntPtr.Zero); } [DllImport(carbon)] public unsafe static extern OSStatus ZoomWindowIdeal(IntPtr windowRef, short inPartCode, ref CarbonPoint toIdealSize); - - public static void CheckReturn( OSStatus status ) { - if( status != OSStatus.NoError ) - throw new MacOSException( status ); - } [DllImport(carbon)] public unsafe static extern OSStatus DMGetGDeviceByDisplayID( @@ -792,8 +909,13 @@ namespace OpenTK.Platform.MacOS.Carbon #endregion const string gestaltlib = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon"; + + [DllImport(gestaltlib)] public static extern OSStatus Gestalt(GestaltSelector selector, out int response); } + #endregion -} \ No newline at end of file + +} + diff --git a/OpenTK/Platform/MacOS/CarbonGLNative.cs b/OpenTK/Platform/MacOS/CarbonGLNative.cs index ddaff39bf..bb3a825a6 100644 --- a/OpenTK/Platform/MacOS/CarbonGLNative.cs +++ b/OpenTK/Platform/MacOS/CarbonGLNative.cs @@ -26,15 +26,17 @@ #endregion using System; +using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using OpenTK.Input; +using OpenTK.Graphics; using OpenTK.Platform.MacOS.Carbon; +using OpenTK.Input; -namespace OpenTK.Platform.MacOS { - - class CarbonGLNative : INativeWindow { - +namespace OpenTK.Platform.MacOS +{ + class CarbonGLNative : INativeWindow + { CarbonWindowInfo window; static MacOSKeyMap Keymap = new MacOSKeyMap(); IntPtr uppHandler; @@ -42,88 +44,111 @@ namespace OpenTK.Platform.MacOS { string title = "OpenTK Window"; Rectangle bounds, clientRectangle; Rectangle windowedBounds; - bool isDisposed = false; - bool exists = true; - DisplayDevice displayDevice; + bool mIsDisposed = false; + bool mExists = true; + DisplayDevice mDisplayDevice; - WindowPositionMethod positionMethod = WindowPositionMethod.CenterOnMainScreen; - int titlebarHeight; + WindowPositionMethod mPositionMethod = WindowPositionMethod.CenterOnMainScreen; + int mTitlebarHeight; private WindowState windowState = WindowState.Normal; + static Dictionary mWindows = new Dictionary(); + KeyPressEventArgs mKeyPressArgs = new KeyPressEventArgs(); + bool mMouseIn = false; + bool mIsActive = false; + Icon mIcon; - KeyPressEventArgs keyPressArgs = new KeyPressEventArgs(); - bool mouseIn = false, isActive = false; - Icon icon; - internal DisplayDevice TargetDisplayDevice { get { return displayDevice; } } + static internal Dictionary WindowRefMap { get { return mWindows; } } + internal DisplayDevice TargetDisplayDevice { get { return mDisplayDevice; } } static CarbonGLNative() { Application.Initialize(); } - - public CarbonGLNative(int x, int y, int width, int height, string title, - GameWindowFlags options, DisplayDevice device) { + + public CarbonGLNative(int x, int y, int width, int height, string title, GameWindowFlags options, DisplayDevice device) + { this.title = title; CreateNativeWindow(WindowClass.Document, WindowAttributes.StandardDocument | WindowAttributes.StandardHandler | WindowAttributes.InWindowMenu | WindowAttributes.LiveResize, new Rect((short)x, (short)y, (short)width, (short)height)); - displayDevice = device; + + mDisplayDevice = device; } - public void Dispose() { + #region IDisposable + + public void Dispose() + { Dispose(true); GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) { - if (isDisposed) + protected virtual void Dispose(bool disposing) + { + if (mIsDisposed) return; Debug.Print("Disposing of CarbonGLNative window."); - API.DisposeWindow(window.WindowRef); - isDisposed = true; - exists = false; - if (disposing) { + API.DisposeWindow(window.WindowRef); + + mIsDisposed = true; + mExists = false; + + if (disposing) + { + mWindows.Remove(window.WindowRef); + window.Dispose(); window = null; } DisposeUPP(); } - ~CarbonGLNative() { + ~CarbonGLNative() + { Dispose(false); } - void DisposeUPP() { - if (uppHandler != IntPtr.Zero) { - API.RemoveEventHandler(uppHandler); - API.DisposeEventHandlerUPP(uppHandler); + #endregion + + #region Private Members + + void DisposeUPP() + { + if (uppHandler != IntPtr.Zero) + { + //API.RemoveEventHandler(uppHandler); + //API.DisposeEventHandlerUPP(uppHandler); } + uppHandler = IntPtr.Zero; } void CreateNativeWindow(WindowClass @class, WindowAttributes attrib, Rect r) { Debug.Print("Creating window..."); + IntPtr windowRef; OSStatus err = API.CreateNewWindow(@class, attrib, ref r, out windowRef); - Debug.Print("Created Window: {0}", windowRef); - API.CheckReturn(err); - + API.CheckReturn( err ); + Debug.Print( "Created window " + windowRef ); API.SetWindowTitle(windowRef, title); - window = new CarbonWindowInfo(windowRef, this); + + window = new CarbonWindowInfo(windowRef, true); SetLocation(r.X, r.Y); SetSize(r.Width, r.Height); - + mWindows.Add(windowRef, new WeakReference(this)); LoadSize(); - Rect titleSize = API.GetWindowBounds(window.WindowRef, WindowRegionCode.TitleBarRegion); - titlebarHeight = titleSize.Height; + Rect titleSize = API.GetWindowBounds(window.WindowRef, WindowRegionCode.TitleBarRegion); + mTitlebarHeight = titleSize.Height; Debug.Print("Titlebar size: {0}", titleSize); ConnectEvents(); Debug.Print("Attached window events."); } - void ConnectEvents() { + void ConnectEvents() + { EventTypeSpec[] eventTypes = new EventTypeSpec[] { new EventTypeSpec(EventClass.Window, WindowEventKind.WindowClose), @@ -146,9 +171,8 @@ namespace OpenTK.Platform.MacOS { //new EventTypeSpec(EventClass.Keyboard, KeyboardEventKind.RawKeyModifiersChanged), }; - uppHandler = API.NewEventHandlerUPP(EventHandler); - // TODO: not sure if we need this. - GC.KeepAlive( this ); // don't want to dispose the window as we need to keep the event handler open. + MacOSEventHandler handler = EventHandler; + uppHandler = API.NewEventHandlerUPP(handler); API.InstallWindowEventHandler(window.WindowRef, uppHandler, eventTypes, window.WindowRef, IntPtr.Zero); Application.WindowEventHandler = this; } @@ -159,7 +183,7 @@ namespace OpenTK.Platform.MacOS { void Show() { API.ShowWindow(window.WindowRef); - API.RepositionWindow(window.WindowRef, IntPtr.Zero, positionMethod); + API.RepositionWindow(window.WindowRef, IntPtr.Zero, mPositionMethod); API.SelectWindow(window.WindowRef); } @@ -177,7 +201,7 @@ namespace OpenTK.Platform.MacOS { Debug.Print("New Size: {0}, {1}", Width, Height); // TODO: if we go full screen we need to make this use the device specified. - bounds = displayDevice.Bounds; + bounds = mDisplayDevice.Bounds; windowState = WindowState.Fullscreen; } @@ -186,57 +210,82 @@ namespace OpenTK.Platform.MacOS { Debug.Print("Telling Carbon to reset window state to " + windowState.ToString()); SetCarbonWindowState(); + SetSize((short)windowedBounds.Width, (short)windowedBounds.Height); } - internal OSStatus DispatchEvent( IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData ) { - switch (evt.EventClass) { + internal OSStatus DispatchEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData) + { + switch (evt.EventClass) + { case EventClass.Window: return ProcessWindowEvent(inCaller, inEvent, evt, userData); + case EventClass.Mouse: return ProcessMouseEvent(inCaller, inEvent, evt, userData); + case EventClass.Keyboard: return ProcessKeyboardEvent(inCaller, inEvent, evt, userData); + default: return OSStatus.EventNotHandled; } } - protected OSStatus EventHandler( IntPtr inCaller, IntPtr inEvent, IntPtr userData ) { + protected static OSStatus EventHandler(IntPtr inCaller, IntPtr inEvent, IntPtr userData) + { // bail out if the window passed in is not actually our window. - if( window == null || userData != window.WindowRef ) + // I think this happens if using winforms with a GameWindow sometimes. + if (!mWindows.ContainsKey(userData)) return OSStatus.EventNotHandled; - + + WeakReference reference = mWindows[userData]; + + // bail out if the CarbonGLNative window has been garbage collected. + if (!reference.IsAlive) { + mWindows.Remove(userData); + return OSStatus.EventNotHandled; + } + + CarbonGLNative window = (CarbonGLNative)reference.Target; + //Debug.Print("Processing {0} event for {1}.", evt, window.window); + if (window == null) { + Debug.Print("Window for event not found."); + return OSStatus.EventNotHandled; + } EventInfo evt = new EventInfo(inEvent); - return DispatchEvent( inCaller, inEvent, evt, userData ); + return window.DispatchEvent(inCaller, inEvent, evt, userData); } - private OSStatus ProcessKeyboardEvent( IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData ) { + private OSStatus ProcessKeyboardEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData) { MacOSKeyCode code = (MacOSKeyCode)0; char charCode = '\0'; //Debug.Print("Processing keyboard event {0}", evt.KeyboardEventKind); - switch ((KeyboardEventKind)evt.EventKind) { + switch ((KeyboardEventKind)evt.EventKind) + { case KeyboardEventKind.RawKeyDown: case KeyboardEventKind.RawKeyRepeat: case KeyboardEventKind.RawKeyUp: GetCharCodes(inEvent, out code, out charCode); - keyPressArgs.KeyChar = charCode; + mKeyPressArgs.KeyChar = charCode; break; - } + } + if( !Keymap.ContainsKey( code ) ) { - Debug.Print( "{0} is not mapped, ignoring" ); + Debug.Print( "{0} not mapped, ignoring press.", code ); return OSStatus.NoError; } - switch ((KeyboardEventKind)evt.EventKind) { + switch ((KeyboardEventKind)evt.EventKind) + { case KeyboardEventKind.RawKeyRepeat: keyboard.KeyRepeat = true; goto case KeyboardEventKind.RawKeyDown; case KeyboardEventKind.RawKeyDown: - OnKeyPress(keyPressArgs); + OnKeyPress(mKeyPressArgs); keyboard[Keymap[code]] = true; return OSStatus.NoError; @@ -254,7 +303,8 @@ namespace OpenTK.Platform.MacOS { } private OSStatus ProcessWindowEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData) { - switch ((WindowEventKind)evt.EventKind) { + switch ((WindowEventKind)evt.EventKind) + { case WindowEventKind.WindowClose: CancelEventArgs cancel = new CancelEventArgs(); OnClosing(cancel); @@ -265,7 +315,7 @@ namespace OpenTK.Platform.MacOS { return OSStatus.EventNotHandled; case WindowEventKind.WindowClosed: - exists = false; + mExists = false; OnClosed(); return OSStatus.NoError; @@ -290,34 +340,40 @@ namespace OpenTK.Platform.MacOS { return OSStatus.EventNotHandled; default: - Debug.Print("unhandled {0}", evt); + Debug.Print("{0}", evt); + return OSStatus.EventNotHandled; } } - - protected OSStatus ProcessMouseEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData) { + OSStatus ProcessMouseEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData) { MacOSMouseButton button; HIPoint pt = new HIPoint(); HIPoint screenLoc = new HIPoint(); OSStatus err = API.GetEventMouseLocation(inEvent, out screenLoc); - if (this.windowState == WindowState.Fullscreen) { + if (this.windowState == WindowState.Fullscreen) + { pt = screenLoc; - } else { + } + else + { err = API.GetEventWindowMouseLocation(inEvent, out pt); } - if (err != OSStatus.NoError) { + if (err != OSStatus.NoError) + { // this error comes up from the application event handler. - if (err != OSStatus.EventParameterNotFound) { + if (err != OSStatus.EventParameterNotFound) + { throw new MacOSException(err); } } Point mousePosInClient = new Point((int)pt.X, (int)pt.Y); - if (this.windowState != WindowState.Fullscreen) { - mousePosInClient.Y -= titlebarHeight; + if (this.windowState != WindowState.Fullscreen) + { + mousePosInClient.Y -= mTitlebarHeight; } // check for enter/leave events @@ -325,7 +381,8 @@ namespace OpenTK.Platform.MacOS { API.GetEventWindowRef(inEvent, out thisEventWindow); CheckEnterLeaveEvents(thisEventWindow, mousePosInClient); - switch ((MouseEventKind)evt.EventKind) { + switch ((MouseEventKind)evt.EventKind) + { case MouseEventKind.MouseDown: button = API.GetEventMouseButton(inEvent); @@ -392,12 +449,13 @@ namespace OpenTK.Platform.MacOS { return OSStatus.EventNotHandled; default: - Debug.Print("unhandled {0}", evt); + Debug.Print("{0}", evt); return OSStatus.EventNotHandled; } } - private void CheckEnterLeaveEvents(IntPtr eventWindowRef, Point pt) { + private void CheckEnterLeaveEvents(IntPtr eventWindowRef, Point pt) + { if (window == null) return; @@ -406,21 +464,25 @@ namespace OpenTK.Platform.MacOS { if (pt.Y < 0) thisIn = false; - if (thisIn == mouseIn) return; - mouseIn = thisIn; + if (thisIn != mMouseIn) + { + mMouseIn = thisIn; - if (mouseIn) - OnMouseEnter(); - else - OnMouseLeave(); + if (mMouseIn) + OnMouseEnter(); + else + OnMouseLeave(); + } } - private static void GetCharCodes(IntPtr inEvent, out MacOSKeyCode code, out char charCode) { + private static void GetCharCodes(IntPtr inEvent, out MacOSKeyCode code, out char charCode) + { code = API.GetEventKeyboardKeyCode(inEvent); charCode = API.GetEventKeyboardChar(inEvent); } - private void ProcessModifierKey(IntPtr inEvent) { + private void ProcessModifierKey(IntPtr inEvent) + { MacOSKeyModifiers modifiers = API.GetEventKeyModifiers(inEvent); bool caps = (modifiers & MacOSKeyModifiers.CapsLock) != 0; @@ -445,6 +507,11 @@ namespace OpenTK.Platform.MacOS { if (keyboard[Key.CapsLock] ^ caps) keyboard[Key.CapsLock] = caps; + + } + + Rect GetRegion() { + return API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion); } void SetLocation(short x, short y) { @@ -492,43 +559,53 @@ namespace OpenTK.Platform.MacOS { clientRectangle = new Rectangle(0, 0, r.Width, r.Height); } + #endregion + #region INativeWindow Members - public void ProcessEvents() { + public void ProcessEvents() + { API.ProcessEvents(); } - public Point PointToClient(Point point) { + public Point PointToClient(Point point) + { IntPtr handle = window.WindowRef; + Rect r = Carbon.API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion); Debug.Print("Rect: {0}", r); + return new Point(point.X - r.X, point.Y - r.Y); } - - public Point PointToScreen(Point point) { + public Point PointToScreen(Point point) + { IntPtr handle = window.WindowRef; + Rect r = Carbon.API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion); Debug.Print("Rect: {0}", r); + return new Point(point.X + r.X, point.Y + r.Y); } - public bool Exists { - get { return exists; } + public bool Exists + { + get { return mExists; } } - public IWindowInfo WindowInfo { + public IWindowInfo WindowInfo + { get { return window; } } public Icon Icon { - get { return icon; } + get { return mIcon; } set { - icon = value; SetIcon(value); } } - private void SetIcon(Icon icon) { + private unsafe void SetIcon(Icon icon) + { // The code for this function was adapted from Mono's // XplatUICarbon implementation, written by Geoff Norton // http://anonsvn.mono-project.com/viewvc/trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUICarbon.cs?view=markup&pathrev=136932 @@ -572,37 +649,53 @@ namespace OpenTK.Platform.MacOS { } } - IntPtr provider = API.CGDataProviderCreateWithData(IntPtr.Zero, data, size * 4, IntPtr.Zero); - IntPtr image = API.CGImageCreate(128, 128, 8, 32, 4 * 128, API.CGColorSpaceCreateDeviceRGB(), 4, provider, IntPtr.Zero, 0, 0); - API.SetApplicationDockTileImage(image); + fixed( IntPtr* ptr = data ) { + IntPtr provider = API.CGDataProviderCreateWithData(IntPtr.Zero, (IntPtr)(void*)ptr, size * 4, IntPtr.Zero); + IntPtr image = API.CGImageCreate(128, 128, 8, 32, 4 * 128, API.CGColorSpaceCreateDeviceRGB(), 4, provider, IntPtr.Zero, 0, 0); + API.SetApplicationDockTileImage(image); + } } } - public string Title { - get { return title; } - set { + public string Title + { + get + { + return title; + } + set + { API.SetWindowTitle(window.WindowRef, value); title = value; } } - public bool Visible { + public bool Visible + { get { return API.IsWindowVisible(window.WindowRef); } - set { - if (value && !Visible) + set + { + if (value && Visible == false) Show(); else Hide(); } } - public bool Focused { - get { return isActive; } + public bool Focused + { + get { return this.mIsActive; } } - public Rectangle Bounds { - get { return bounds; } - set { + public Rectangle Bounds + { + get + { + + return bounds; + } + set + { Location = value.Location; Size = value.Size; } @@ -618,12 +711,14 @@ namespace OpenTK.Platform.MacOS { set { SetSize((short)value.Width, (short)value.Height); } } - public int Width { + public int Width + { get { return ClientRectangle.Width; } set { SetClientSize((short)value, (short)Height); } } - public int Height { + public int Height + { get { return ClientRectangle.Height; } set { SetClientSize((short)Width, (short)value); } } @@ -638,24 +733,35 @@ namespace OpenTK.Platform.MacOS { set { Location = new Point(X, value); } } - public Rectangle ClientRectangle { - get { return clientRectangle; } - set { + public Rectangle ClientRectangle + { + get + { + return clientRectangle; + } + set + { // just set the size, and ignore the location value. // this is the behavior of the Windows WinGLNative. ClientSize = value.Size; } } - public Size ClientSize { - get { return clientRectangle.Size; } - set { + public Size ClientSize + { + get + { + return clientRectangle.Size; + } + set + { API.SizeWindow(window.WindowRef, (short)value.Width, (short)value.Height, true); OnResize(); } } - public void Close() { + public void Close() + { CancelEventArgs e = new CancelEventArgs(); OnClosing(e); @@ -663,11 +769,14 @@ namespace OpenTK.Platform.MacOS { return; OnClosed(); + Dispose(); } - public WindowState WindowState { - get { + public WindowState WindowState + { + get + { if (windowState == WindowState.Fullscreen) return WindowState.Fullscreen; @@ -675,11 +784,14 @@ namespace OpenTK.Platform.MacOS { return WindowState.Minimized; if (Carbon.API.IsWindowInStandardState(window.WindowRef)) + { return WindowState.Maximized; + } return WindowState.Normal; } - set { + set + { if (value == WindowState) return; @@ -688,7 +800,8 @@ namespace OpenTK.Platform.MacOS { windowState = value; - if (oldState == WindowState.Fullscreen) { + if (oldState == WindowState.Fullscreen) + { window.goWindowedHack = true; // when returning from full screen, wait until the context is updated @@ -708,8 +821,9 @@ namespace OpenTK.Platform.MacOS { private void SetCarbonWindowState() { CarbonPoint idealSize; OSStatus err; - - switch (windowState) { + + switch (windowState) + { case WindowState.Fullscreen: window.goFullScreenHack = true; break; @@ -724,7 +838,8 @@ namespace OpenTK.Platform.MacOS { break; case WindowState.Normal: - if (WindowState == WindowState.Maximized) { + if (WindowState == WindowState.Maximized) + { idealSize = new CarbonPoint(); err = API.ZoomWindowIdeal(window.WindowRef, (short)WindowPartCode.inZoomIn, ref idealSize); API.CheckReturn( err ); @@ -736,53 +851,66 @@ namespace OpenTK.Platform.MacOS { API.CheckReturn( err ); break; } - + OnWindowStateChanged(); OnResize(); } - private void OnKeyPress(KeyPressEventArgs keyPressArgs) { + #region --- Event wrappers --- + + private void OnKeyPress(KeyPressEventArgs keyPressArgs) + { if (KeyPress != null) KeyPress(this, keyPressArgs); } - private void OnWindowStateChanged() { + + private void OnWindowStateChanged() + { if (WindowStateChanged != null) WindowStateChanged(this, EventArgs.Empty); } - protected virtual void OnClosing(CancelEventArgs e) { + protected virtual void OnClosing(CancelEventArgs e) + { if (Closing != null) Closing(this, e); } - protected virtual void OnClosed() { + protected virtual void OnClosed() + { if (Closed != null) Closed(this, EventArgs.Empty); } - private void OnMouseLeave() { + + private void OnMouseLeave() + { if (MouseLeave != null) MouseLeave(this, EventArgs.Empty); } - private void OnMouseEnter() { + private void OnMouseEnter() + { if (MouseEnter != null) MouseEnter(this, EventArgs.Empty); } - private void OnActivate() { - isActive = true; + private void OnActivate() + { + mIsActive = true; if (FocusedChanged != null) FocusedChanged(this, EventArgs.Empty); } - - private void OnDeactivate() { - isActive = false; + private void OnDeactivate() + { + mIsActive = false; if (FocusedChanged != null) FocusedChanged(this, EventArgs.Empty); } + #endregion + public event EventHandler Load; public event EventHandler Unload; public event EventHandler Move; @@ -799,9 +927,11 @@ namespace OpenTK.Platform.MacOS { public event EventHandler KeyPress; public event EventHandler MouseEnter; public event EventHandler MouseLeave; - + #endregion + #region IInputDriver Members + KeyboardDevice keyboard = new KeyboardDevice(); MouseDevice mouse = new MouseDevice(); @@ -840,5 +970,7 @@ namespace OpenTK.Platform.MacOS { CG.CGDisplayHideCursor(CG.CGMainDisplayID()); } } + + #endregion } -} +} \ No newline at end of file diff --git a/OpenTK/Platform/MacOS/CarbonWindowInfo.cs b/OpenTK/Platform/MacOS/CarbonWindowInfo.cs index 0c83f6e28..02dcb7393 100644 --- a/OpenTK/Platform/MacOS/CarbonWindowInfo.cs +++ b/OpenTK/Platform/MacOS/CarbonWindowInfo.cs @@ -26,33 +26,86 @@ #endregion using System; +using System.Collections.Generic; +using System.Text; -namespace OpenTK.Platform.MacOS { - +namespace OpenTK.Platform.MacOS +{ /// \internal - /// Describes a Carbon window. - sealed class CarbonWindowInfo : IWindowInfo { - - public IntPtr WindowRef; + /// + /// Describes a Carbon window. + /// + sealed class CarbonWindowInfo : IWindowInfo + { + IntPtr windowRef; + bool ownHandle = false; bool disposed = false; internal bool goFullScreenHack = false; internal bool goWindowedHack = false; - internal CarbonGLNative nativeWindow; - public CarbonWindowInfo( IntPtr windowRef, CarbonGLNative nativeWindow ) { - this.WindowRef = windowRef; - this.nativeWindow = nativeWindow; + #region Constructors + + /// + /// Constructs a new instance with the specified parameters. + /// + /// A valid Carbon window reference. + /// + public CarbonWindowInfo(IntPtr windowRef, bool ownHandle) + { + this.windowRef = windowRef; + this.ownHandle = ownHandle; } - public override string ToString() { - return String.Format("CarbonWindowInfo: Handle {0}", WindowRef); + #endregion + + #region Public Members + + /// + /// Gets the window reference for this instance. + /// + internal IntPtr WindowRef + { + get { return this.windowRef; } } + /// Returns a System.String that represents the current window. + /// A System.String that represents the current window. + public override string ToString() + { + return String.Format("MacOS.CarbonWindowInfo: Handle {0}", WindowRef); + } + + #endregion + + // TODO: I have no idea if this is right. public IntPtr WinHandle { - get { return WindowRef; } + get { return windowRef; } } + #region IDisposable Members + public void Dispose() { + Dispose(true); } + + void Dispose(bool disposing) { + if (disposed) + return; + + if (ownHandle) + { + Debug.Print("Disposing window {0}.", windowRef); + Carbon.API.DisposeWindow(this.windowRef); + windowRef = IntPtr.Zero; + } + + disposed = true; + } + + ~CarbonWindowInfo() { + Dispose(false); + } + + #endregion } -} +} \ No newline at end of file diff --git a/OpenTK/Platform/MacOS/EventInfo.cs b/OpenTK/Platform/MacOS/EventInfo.cs deleted file mode 100644 index cc4e7960f..000000000 --- a/OpenTK/Platform/MacOS/EventInfo.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// -// xCSCarbon -// -// Created by Erik Ylvisaker on 3/17/08. -// Copyright 2008 __MyCompanyName__. All rights reserved. -// -// - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace OpenTK.Platform.MacOS.Carbon -{ - internal struct EventInfo { - - internal EventInfo(IntPtr eventRef) { - EventClass = API.GetEventClass(eventRef); - EventKind = API.GetEventKind(eventRef); - } - - public uint EventKind; - public EventClass EventClass; - - public override string ToString() { - return "Event class " + EventClass + ", kind: " + EventKind; - } - } -}