[Mac] Migrated AglContext to OpenTK.GLControl

This commit is contained in:
thefiddler 2014-04-24 01:14:40 +02:00
parent 3475582c30
commit cdd88e6f7e
20 changed files with 567 additions and 1600 deletions

View file

@ -377,8 +377,7 @@ namespace OpenTK.Platform.MacOS
if (retval == 0)
{
AglError err = GetError();
throw new MacOSException(err, ErrorString(err));
throw new Exception(ErrorString(err));
}
}
[DllImport(agl)] static extern byte aglSetOffScreen(AGLContext ctx, int width, int height, int rowbytes, IntPtr baseaddr);
@ -398,7 +397,7 @@ namespace OpenTK.Platform.MacOS
Debug.Print(ErrorString(err));
Debug.Unindent();
throw new MacOSException(err, ErrorString(err));
throw new Exception(ErrorString(err));
}
}
/*

View file

@ -42,318 +42,199 @@ namespace OpenTK.Platform.MacOS
using AGLContext = IntPtr;
using AGLPbuffer = IntPtr;
class AglContext : DesktopGraphicsContext
/// <summary>
/// AGL context implementation for WinForms compatibility.
/// </summary>
class AglContext : IGraphicsContext, IGraphicsContextInternal
{
// Todo: keep track of which display adapter was specified when the context was created.
// IntPtr displayID;
ContextHandle Handle;
GraphicsMode mode;
IWindowInfo carbonWindow;
IGraphicsContext dummyContext; // for extension loading
bool disposed;
bool error_checking;
CarbonWindowInfo carbonWindow;
IntPtr shareContextRef;
bool mIsFullscreen = false;
readonly GetInt XOffset;
readonly GetInt YOffset;
public AglContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext)
public AglContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext,
GetInt xoffset, GetInt yoffset)
{
Debug.Print("Context Type: {0}", shareContext);
Debug.Print("Share context: {0}", shareContext);
Debug.Print("Window info: {0}", window);
IntPtr shareContextRef = IntPtr.Zero;
XOffset = xoffset;
YOffset = yoffset;
carbonWindow = window;
this.carbonWindow = (CarbonWindowInfo)window;
if (shareContext is AglContext)
{
shareContextRef = ((AglContext)shareContext).Handle.Handle;
if (shareContext is GraphicsContext)
}
else if (shareContext is GraphicsContext)
{
ContextHandle shareHandle = shareContext != null ? (shareContext as IGraphicsContextInternal).Context : (ContextHandle)IntPtr.Zero;
shareContextRef = shareHandle.Handle;
}
if (shareContextRef == IntPtr.Zero)
{
Debug.Print("No context sharing will take place.");
}
CreateContext(mode, carbonWindow, shareContextRef, true);
}
public AglContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext)
{
if (handle == ContextHandle.Zero)
throw new ArgumentException("handle");
if (window == null)
throw new ArgumentNullException("window");
Handle = handle;
carbonWindow = (CarbonWindowInfo)window;
}
private void AddPixelAttrib(List<int> aglAttributes, Agl.PixelFormatAttribute pixelFormatAttribute)
{
Debug.Print(pixelFormatAttribute.ToString());
aglAttributes.Add((int)pixelFormatAttribute);
}
private void AddPixelAttrib(List<int> aglAttributes, Agl.PixelFormatAttribute pixelFormatAttribute, int value)
{
Debug.Print("{0} : {1}", pixelFormatAttribute, value);
aglAttributes.Add((int)pixelFormatAttribute);
aglAttributes.Add(value);
}
void CreateContext(GraphicsMode mode, CarbonWindowInfo carbonWindow, IntPtr shareContextRef, bool fullscreen)
void CreateContext(GraphicsMode mode, IWindowInfo carbonWindow, IntPtr shareContextRef, bool fullscreen)
{
Debug.Print("AGL pixel format attributes:");
AGLPixelFormat myAGLPixelFormat;
// Choose a pixel format with the attributes we specified.
IntPtr gdevice;
IntPtr cgdevice = GetQuartzDevice(carbonWindow);
if (cgdevice == IntPtr.Zero)
cgdevice = (IntPtr)DisplayDevice.Default.Id;
OSStatus status = Carbon.API.DMGetGDeviceByDisplayID(cgdevice, out gdevice, false);
if (status != OSStatus.NoError)
throw new MacOSException(status, "DMGetGDeviceByDisplayID failed.");
IGraphicsMode selector = new MacOSGraphicsMode(gdevice);
// Choose a pixel format with the attributes we specified.
AGLPixelFormat pixelformat;
AglGraphicsMode selector = new AglGraphicsMode();
Mode = selector.SelectGraphicsMode(
mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
mode.AccumulatorFormat, mode.Buffers, mode.Stereo);
mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
out pixelformat);
MyAGLReportError("aglChoosePixelFormat");
Debug.Print("Creating AGL context. Sharing with {0}", shareContextRef);
myAGLPixelFormat = Mode.Index.Value;
// create the context and share it with the share reference.
Handle = new ContextHandle(Agl.aglCreateContext(myAGLPixelFormat, shareContextRef));
Handle = new ContextHandle(Agl.aglCreateContext(pixelformat, shareContextRef));
MyAGLReportError("aglCreateContext");
// Free the pixel format from memory.
Agl.aglDestroyPixelFormat(myAGLPixelFormat);
Agl.aglDestroyPixelFormat(pixelformat);
MyAGLReportError("aglDestroyPixelFormat");
Debug.Print("IsControl: {0}", carbonWindow.IsControl);
SetDrawable(carbonWindow);
SetBufferRect(carbonWindow);
Update(carbonWindow);
MakeCurrent(carbonWindow);
Debug.Print("context: {0}", Handle.Handle);
dummyContext = new GraphicsContext(Handle,
GetAddress,
delegate()
{
return new ContextHandle(Agl.aglGetCurrentContext());
});
}
private IntPtr GetQuartzDevice(CarbonWindowInfo carbonWindow)
void SetBufferRect(IWindowInfo carbonWindow)
{
IntPtr windowRef = carbonWindow.Handle;
if (CarbonGLNative.WindowRefMap.ContainsKey(windowRef) == false)
return IntPtr.Zero;
WeakReference nativeRef = CarbonGLNative.WindowRefMap[windowRef];
if (nativeRef.IsAlive == false)
return IntPtr.Zero;
CarbonGLNative window = nativeRef.Target as CarbonGLNative;
if (window == null)
return IntPtr.Zero;
return QuartzDisplayDeviceDriver.HandleTo(window.TargetDisplayDevice);
}
Rect rect = API.GetControlBounds(carbonWindow.Handle);
void SetBufferRect(CarbonWindowInfo carbonWindow)
{
if (carbonWindow.IsControl == false)
return;
Rect rect = API.GetControlBounds(carbonWindow.WindowHandle);
Debug.Print("Setting buffer_rect for control.");
Debug.Print("MacOS Coordinate Rect: {0}", rect);
int[] glrect = new int[4];
if (carbonWindow.XOffset != null)
glrect[0] = rect.X + carbonWindow.XOffset();
if (XOffset != null)
glrect[0] = rect.X + XOffset();
else
glrect[0] = rect.X;
if (carbonWindow.YOffset != null)
glrect[1] = rect.Y + carbonWindow.YOffset();
if (YOffset != null)
glrect[1] = rect.Y + YOffset();
else
glrect[1] = rect.Y;
glrect[2] = rect.Width;
glrect[3] = rect.Height;
Agl.aglSetInteger(Handle.Handle, Agl.ParameterNames.AGL_BUFFER_RECT, glrect);
MyAGLReportError("aglSetInteger");
Agl.aglEnable(Handle.Handle, Agl.ParameterNames.AGL_BUFFER_RECT);
MyAGLReportError("aglEnable");
}
void SetDrawable(CarbonWindowInfo carbonWindow)
void SetDrawable(IWindowInfo carbonWindow)
{
IntPtr windowPort = GetWindowPortForWindowInfo(carbonWindow);
//Debug.Print("Setting drawable for context {0} to window port: {1}", Handle.Handle, windowPort);
Agl.aglSetDrawable(Handle.Handle, windowPort);
MyAGLReportError("aglSetDrawable");
}
private static IntPtr GetWindowPortForWindowInfo(CarbonWindowInfo carbonWindow)
private static IntPtr GetWindowPortForWindowInfo(IWindowInfo carbonWindow)
{
IntPtr windowPort;
if (carbonWindow.IsControl)
{
IntPtr controlOwner = API.GetControlOwner(carbonWindow.Handle);
windowPort = API.GetWindowPort(controlOwner);
}
else
{
windowPort = API.GetWindowPort(carbonWindow.Handle);
}
IntPtr controlOwner = API.GetControlOwner(carbonWindow.Handle);
windowPort = API.GetWindowPort(controlOwner);
return windowPort;
}
public override void Update(IWindowInfo window)
{
CarbonWindowInfo carbonWindow = (CarbonWindowInfo)window;
if (carbonWindow.GoFullScreenHack)
{
carbonWindow.GoFullScreenHack = false;
CarbonGLNative wind = GetCarbonWindow(carbonWindow);
if (wind != null)
wind.SetFullscreen(this);
else
Debug.Print("Could not find window!");
return;
}
else if (carbonWindow.GoWindowedHack)
{
carbonWindow.GoWindowedHack = false;
CarbonGLNative wind = GetCarbonWindow(carbonWindow);
if (wind != null)
wind.UnsetFullscreen(this);
else
Debug.Print("Could not find window!");
}
if (mIsFullscreen)
return;
SetDrawable(carbonWindow);
SetBufferRect(carbonWindow);
public void Update(IWindowInfo window)
{
SetDrawable(window);
SetBufferRect(window);
Agl.aglUpdateContext(Handle.Handle);
}
private CarbonGLNative GetCarbonWindow(CarbonWindowInfo carbonWindow)
{
WeakReference r = CarbonGLNative.WindowRefMap[carbonWindow.Handle];
if (r.IsAlive)
{
return (CarbonGLNative)r.Target;
}
else
return null;
}
void MyAGLReportError(string function)
{
Agl.AglError err = Agl.GetError();
if (err != Agl.AglError.NoError)
throw new MacOSException((OSStatus)err, string.Format("AGL Error from function {0}: {1} {2}", function, err, Agl.ErrorString(err)));
throw new Exception(String.Format(
"AGL Error from function {0}: {1} {2}",
function, err, Agl.ErrorString(err)));
}
bool firstFullScreen = false;
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, Handle.Handle);
CG.DisplayCapture(GetQuartzDevice(info));
Agl.aglSetFullScreen(Handle.Handle, wind.TargetDisplayDevice.Width, wind.TargetDisplayDevice.Height, 0, 0);
MakeCurrent(info);
width = wind.TargetDisplayDevice.Width;
height = wind.TargetDisplayDevice.Height;
// This is a weird hack to workaround a bug where the first time a context
// is made fullscreen, we just end up with a blank screen. So we undo it as fullscreen
// and redo it as fullscreen.
if (firstFullScreen == false)
{
firstFullScreen = true;
UnsetFullScreen(info);
SetFullScreen(info, out width, out height);
}
mIsFullscreen = true;
}
internal void UnsetFullScreen(CarbonWindowInfo windowInfo)
{
Debug.Print("Unsetting AGL fullscreen.");
Agl.aglSetDrawable(Handle.Handle, IntPtr.Zero);
Agl.aglUpdateContext(Handle.Handle);
CG.DisplayRelease(GetQuartzDevice(windowInfo));
Debug.Print("Resetting drawable.");
SetDrawable(windowInfo);
mIsFullscreen = false;
}
#region IGraphicsContext Members
bool firstSwap = false;
public override void SwapBuffers()
bool firstSwap = true;
public void SwapBuffers()
{
// this is part of the hack to avoid dropping the first frame when
// using multiple GLControls.
if (firstSwap == false && carbonWindow.IsControl)
if (firstSwap)
{
Debug.WriteLine("--> Resetting drawable. <--");
firstSwap = true;
firstSwap = false;
SetDrawable(carbonWindow);
Update(carbonWindow);
}
Agl.aglSwapBuffers(Handle.Handle);
MyAGLReportError("aglSwapBuffers");
}
public override void MakeCurrent(IWindowInfo window)
public void MakeCurrent(IWindowInfo window)
{
if (Agl.aglSetCurrentContext(Handle.Handle) == false)
MyAGLReportError("aglSetCurrentContext");
}
public override bool IsCurrent
public bool IsCurrent
{
get { return (Handle.Handle == Agl.aglGetCurrentContext()); }
}
public override int SwapInterval
public int SwapInterval
{
get {
get
{
int swap_interval = 0;
if (Agl.aglGetInteger(Handle.Handle, Agl.ParameterNames.AGL_SWAP_INTERVAL, out swap_interval))
{
@ -372,6 +253,64 @@ namespace OpenTK.Platform.MacOS
}
}
public GraphicsMode Mode
{
get
{
return mode;
}
set
{
mode = value;
}
}
public void LoadAll()
{
dummyContext.LoadAll();
}
public bool IsDisposed
{
get
{
return disposed;
}
}
public bool VSync
{
get
{
return SwapInterval != 0;
}
set
{
SwapInterval = value ? 1 : 0;
}
}
public GraphicsMode GraphicsMode
{
get
{
return mode;
}
}
public bool ErrorChecking
{
get
{
return error_checking;
}
set
{
error_checking = value;
}
}
#endregion
#region IDisposable Members
@ -381,7 +320,7 @@ namespace OpenTK.Platform.MacOS
Dispose(false);
}
public override void Dispose()
public void Dispose()
{
Dispose(true);
}
@ -390,13 +329,13 @@ namespace OpenTK.Platform.MacOS
{
if (IsDisposed || Handle.Handle == IntPtr.Zero)
return;
Debug.Print("Disposing of AGL context.");
Agl.aglSetCurrentContext(IntPtr.Zero);
//Debug.Print("Setting drawable to null for context {0}.", Handle.Handle);
//Agl.aglSetDrawable(Handle.Handle, IntPtr.Zero);
// I do not know MacOS allows us to destroy a context from a separate thread,
// like the finalizer thread. It's untested, but worst case is probably
// an exception on application exit, which would be logged to the console.
@ -410,34 +349,50 @@ namespace OpenTK.Platform.MacOS
Handle = ContextHandle.Zero;
return;
}
// failed to destroy context.
Debug.WriteLine("Failed to destroy context.");
Debug.WriteLine(Agl.ErrorString(Agl.GetError()));
// don't throw an exception from the finalizer thread.
if (disposing)
{
throw new MacOSException((OSStatus)Agl.GetError(), Agl.ErrorString(Agl.GetError()));
throw new Exception(Agl.ErrorString(Agl.GetError()));
}
IsDisposed = true;
disposed = true;
}
#endregion
#region IGraphicsContextInternal Members
public override IntPtr GetAddress(string function)
public IntPtr GetAddress(string function)
{
return NS.GetAddress(function);
}
public override IntPtr GetAddress(IntPtr function)
public IntPtr GetAddress(IntPtr function)
{
return NS.GetAddress(function);
}
public IGraphicsContext Implementation
{
get
{
return this;
}
}
public ContextHandle Context
{
get
{
return Handle;
}
}
#endregion
}
}

View file

@ -33,46 +33,23 @@ using OpenTK.Graphics;
namespace OpenTK.Platform.MacOS
{
using Carbon;
class MacOSGraphicsMode : IGraphicsMode
class AglGraphicsMode
{
readonly IntPtr Device;
public MacOSGraphicsMode(IntPtr device)
{
Device = device;
}
#region IGraphicsMode Members
public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil,
int samples, ColorFormat accum, int buffers, bool stereo)
int samples, ColorFormat accum, int buffers, bool stereo, out IntPtr pixelformat)
{
IntPtr pixelformat;
do
{
pixelformat = SelectPixelFormat(
color, depth, stencil, samples, accum, buffers, stereo,
true, Device);
Agl.AglError err = Agl.GetError();
if (pixelformat == IntPtr.Zero || err == Agl.AglError.BadPixelFormat)
{
Debug.Print("Failed to create full screen pixel format.");
Debug.Print("Trying again to create a non-fullscreen pixel format.");
pixelformat = SelectPixelFormat(
color, depth, stencil, samples, accum, buffers, stereo,
false, IntPtr.Zero);
}
color, depth, stencil, samples, accum, buffers, stereo);
if (pixelformat == IntPtr.Zero)
{
if (!Utilities.RelaxGraphicsMode(
if (!RelaxGraphicsMode(
ref color, ref depth, ref stencil, ref samples, ref accum,
ref buffers, ref stereo))
{
throw new GraphicsModeException("Requested GraphicsMode not available.");
throw new GraphicsModeException("Requested GraphicsMode not available, error: " + Agl.GetError());
}
}
}
@ -81,10 +58,76 @@ namespace OpenTK.Platform.MacOS
return GetGraphicsModeFromPixelFormat(pixelformat);
}
#endregion
#region Internal Members
static bool RelaxGraphicsMode(ref ColorFormat color, ref int depth, ref int stencil, ref int samples, ref ColorFormat accum, ref int buffers, ref bool stereo)
{
// Parameters are relaxed in order of importance.
// - Accumulator buffers are way outdated as a concept,
// so they go first.
// - Triple+ buffering is generally not supported by the
// core WGL/GLX/AGL/CGL/EGL specs, so we clamp
// to double-buffering as a second step. (If this doesn't help
// we will also fall back to undefined single/double buffering
// as a last resort).
// - AA samples are an easy way to increase compatibility
// so they go next.
// - Stereoscopic is only supported on very few GPUs
// (Quadro/FirePro series) so it goes next.
// - The rest of the parameters then follow.
if (accum != 0)
{
accum = 0;
return true;
}
if (buffers > 2)
{
buffers = 2;
return true;
}
if (samples > 0)
{
samples = Math.Max(samples - 1, 0);
return true;
}
if (stereo)
{
stereo = false;
return true;
}
if (stencil != 0)
{
stencil = 0;
return true;
}
if (depth != 0)
{
depth = 0;
return true;
}
if (color != 24)
{
color = 24;
return true;
}
if (buffers != 0)
{
buffers = 0;
return true;
}
// no parameters left to relax, fail
return false;
}
GraphicsMode GetGraphicsModeFromPixelFormat(IntPtr pixelformat)
{
int r, g, b, a;
@ -104,12 +147,12 @@ namespace OpenTK.Platform.MacOS
Agl.aglDescribePixelFormat(pixelformat, Agl.PixelFormatAttribute.AGL_DOUBLEBUFFER, out buffers);
Agl.aglDescribePixelFormat(pixelformat, Agl.PixelFormatAttribute.AGL_STEREO, out stereo);
return new GraphicsMode(pixelformat, new ColorFormat(r, g, b, a),
return new GraphicsMode(new ColorFormat(r, g, b, a),
depth, stencil, samples, new ColorFormat(ar, ag, ab, aa), buffers + 1, stereo != 0);
}
IntPtr SelectPixelFormat(ColorFormat color, int depth, int stencil, int samples,
ColorFormat accum, int buffers, bool stereo, bool fullscreen, IntPtr device)
ColorFormat accum, int buffers, bool stereo)
{
List<int> attribs = new List<int>();
@ -144,7 +187,7 @@ namespace OpenTK.Platform.MacOS
attribs.Add((int)Agl.PixelFormatAttribute.AGL_DOUBLEBUFFER);
}
if (stencil > 1)
if (stencil > 0)
{
attribs.Add((int)Agl.PixelFormatAttribute.AGL_STENCIL_SIZE);
attribs.Add(stencil);
@ -175,23 +218,10 @@ namespace OpenTK.Platform.MacOS
attribs.Add((int)Agl.PixelFormatAttribute.AGL_STEREO);
}
if (fullscreen)
{
attribs.Add((int)Agl.PixelFormatAttribute.AGL_FULLSCREEN);
}
attribs.Add(0);
attribs.Add(0);
IntPtr pixelformat = IntPtr.Zero;
if (device != IntPtr.Zero)
{
pixelformat = Agl.aglChoosePixelFormat(ref device, 0, attribs.ToArray());
}
else
{
pixelformat = Agl.aglChoosePixelFormat(IntPtr.Zero, 0, attribs.ToArray());
}
IntPtr pixelformat = Agl.aglChoosePixelFormat(IntPtr.Zero, 0, attribs.ToArray());
return pixelformat;
}

160
Source/GLControl/Carbon.cs Normal file
View file

@ -0,0 +1,160 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS.Carbon
{
internal enum OSStatus
{
NoError = 0,
ParameterError = -50, /*error in user parameter list*/
NoHardwareError = -200, /*Sound Manager Error Returns*/
NotEnoughHardwareError = -201, /*Sound Manager Error Returns*/
UserCanceledError = -128,
QueueError = -1, /*queue element not found during deletion*/
VTypErr = -2, /*invalid queue element*/
CorErr = -3, /*core routine number out of range*/
UnimpErr = -4, /*unimplemented core routine*/
SlpTypeErr = -5, /*invalid queue element*/
SeNoDB = -8, /*no debugger installed to handle debugger command*/
ControlErr = -17, /*I/O System Errors*/
StatusErr = -18, /*I/O System Errors*/
ReadErr = -19, /*I/O System Errors*/
WritErr = -20, /*I/O System Errors*/
BadUnitErr = -21, /*I/O System Errors*/
UnitEmptyErr = -22, /*I/O System Errors*/
OpenErr = -23, /*I/O System Errors*/
ClosErr = -24, /*I/O System Errors*/
DRemovErr = -25, /*tried to remove an open driver*/
DInstErr = -26, /*DrvrInstall couldn't find driver in resources*/
// Window Manager result codes.
InvalidWindowPtr = -5600,
UnsupportedWindowAttributesForClass = -5601,
WindowDoesNotHaveProxy = -5602,
WindowPropertyNotFound = -5604,
UnrecognizedWindowClass = -5605,
CorruptWindowDescription = -5606,
UserWantsToDragWindow = -5607,
WindowsAlreadyInitialized = -5608,
FloatingWindowsNotInitialized = -5609,
WindowNotFound = -5610,
WindowDoesNotFitOnscreen = -5611,
WindowAttributeImmutable = -5612,
WindowAttributesConflict = -5613,
WindowManagerInternalError = -5614,
WindowWrongState = -5615,
WindowGroupInvalid = -5616,
WindowAppModalStateAlreadyExists = -5617,
WindowNoAppModalState = -5618,
WindowDoesntSupportFocus = -30583,
WindowRegionCodeInvalid = -30593,
// Event Manager result codes
EventAlreadyPosted = -9860,
EventTargetBusy = -9861,
EventDeferAccessibilityEvent = -9865,
EventInternalError = -9868,
EventParameterNotFound = -9870,
EventNotHandled = -9874,
EventLoopTimedOut = -9875,
EventLoopQuit = -9876,
EventNotInQueue = -9877,
HotKeyExists = -9878,
EventPassToNextTarget = -9880
}
[StructLayout(LayoutKind.Sequential)]
internal struct Rect
{
short top;
short left;
short bottom;
short right;
internal Rect(int left, int top, int width, int height)
: this((short)left, (short)top, (short)width, (short)height)
{
}
internal Rect(short _left, short _top, short _width, short _height)
{
top = _top;
left = _left;
bottom = (short)(_top + _height);
right = (short)(_left + _width);
}
internal short X
{
get { return left; }
set
{
short width = Width;
left = value;
right = (short)(left + width);
}
}
internal short Y
{
get { return top; }
set
{
short height = Height;
top = value;
bottom = (short)(top + height);
}
}
internal short Width
{
get { return (short)(right - left); }
set { right = (short)(left + value); }
}
internal short Height
{
get { return (short)(bottom - top); }
set { bottom = (short)(top + value); }
}
public override string ToString()
{
return string.Format(
"Rect: [{0}, {1}, {2}, {3}]", X, Y, Width, Height);
}
public Rectangle ToRectangle()
{
return new Rectangle(X, Y, Width, Height);
}
}
class API
{
const string carbon = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon";
[DllImport(carbon)]
internal unsafe static extern OSStatus DMGetGDeviceByDisplayID(
IntPtr displayID, out IntPtr displayDevice, Boolean failToMain);
[DllImport(carbon)]
static extern IntPtr GetControlBounds(IntPtr control, out Rect bounds);
internal static Rect GetControlBounds(IntPtr control)
{
Rect retval;
GetControlBounds(control, out retval);
return retval;
}
[DllImport(carbon)]
internal static extern IntPtr GetControlOwner(IntPtr control);
[DllImport(carbon)]
internal static extern IntPtr GetWindowPort(IntPtr windowRef);
}
}

View file

@ -32,6 +32,7 @@ using System.Windows.Forms;
using OpenTK.Graphics;
using OpenTK.Platform;
using OpenTK.Platform.MacOS;
namespace OpenTK
{
@ -46,7 +47,7 @@ namespace OpenTK
this.mode = mode;
this.control = owner;
window_info = Utilities.CreateMacOSCarbonWindowInfo(control.Handle, false, true, GetXOffset, GetYOffset);
window_info = Utilities.CreateMacOSCarbonWindowInfo(control.Handle, false, true);
}
private int GetXOffset()
@ -70,7 +71,8 @@ namespace OpenTK
public IGraphicsContext CreateContext(int major, int minor, GraphicsContextFlags flags)
{
return new GraphicsContext(mode, WindowInfo, major, minor, flags);
// AGL does not support OpenGL profiles
return new AglContext(mode, WindowInfo, GraphicsContext.CurrentContext, GetXOffset, GetYOffset);
}
// TODO: Fix this

113
Source/GLControl/NS.cs Normal file
View file

@ -0,0 +1,113 @@
#region License
//
// NS.cs
//
// Author:
// Stefanos A. <stapostol@gmail.com>
//
// Copyright (c) 2006-2013 Stefanos Apostolopoulos
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#endregion
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
internal class NS
{
const string Library = "libdl.dylib";
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
static extern bool NSIsSymbolNameDefined(string s);
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
static extern bool NSIsSymbolNameDefined(IntPtr s);
[DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
static extern IntPtr NSLookupAndBindSymbol(string s);
[DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
static extern IntPtr NSLookupAndBindSymbol(IntPtr s);
[DllImport(Library, EntryPoint = "NSAddressOfSymbol")]
static extern IntPtr NSAddressOfSymbol(IntPtr symbol);
[DllImport(Library)]
private static extern IntPtr dlopen(String fileName, int flags);
[DllImport(Library)]
private static extern int dlclose(IntPtr handle);
[DllImport (Library)]
private static extern IntPtr dlsym (IntPtr handle, string symbol);
public static IntPtr GetAddress(string function)
{
// Instead of allocating and combining strings in managed memory
// we do that directly in unmanaged memory. This way, we avoid
// 2 string allocations every time this function is called.
// must add a '_' prefix and null-terminate the function name,
// hence we allocate +2 bytes
IntPtr ptr = Marshal.AllocHGlobal(function.Length + 2);
try
{
Marshal.WriteByte(ptr, (byte)'_');
for (int i = 0; i < function.Length; i++)
{
Marshal.WriteByte(ptr, i + 1, (byte)function[i]);
}
Marshal.WriteByte(ptr, function.Length + 1, 0); // null-terminate
IntPtr symbol = GetAddress(ptr);
return symbol;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
public static IntPtr GetAddress(IntPtr function)
{
IntPtr symbol = IntPtr.Zero;
if (NSIsSymbolNameDefined(function))
{
symbol = NSLookupAndBindSymbol(function);
if (symbol != IntPtr.Zero)
symbol = NSAddressOfSymbol(symbol);
}
return symbol;
}
public static IntPtr GetSymbol(IntPtr handle, string symbol)
{
return dlsym(handle, symbol);
}
public static IntPtr LoadLibrary(string fileName)
{
const int RTLD_NOW = 2;
return dlopen(fileName, RTLD_NOW);
}
public static void FreeLibrary(IntPtr handle)
{
dlclose(handle);
}
}
}

View file

@ -162,6 +162,22 @@
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Agl.cs">
<DependentUpon>CarbonGLControl.cs</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="AglContext.cs">
<DependentUpon>CarbonGLControl.cs</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="AglGraphicsMode.cs">
<DependentUpon>CarbonGLControl.cs</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Carbon.cs" />
<Compile Include="NS.cs">
<DependentUpon>CarbonGLControl.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\OpenTK.snk">

View file

@ -282,9 +282,6 @@
<Compile Include="Platform\MacOS\EventInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\MacOSGraphicsMode.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\MacOSFactory.cs">
<SubType>Code</SubType>
</Compile>
@ -294,42 +291,12 @@
<Compile Include="Platform\MacOS\MacOSKeyMap.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonGLNative.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Application.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\AglContext.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\QuartzDisplayDeviceDriver.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonInput.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonWindowInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonBindings\CarbonAPI.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonBindings\SpeechChannel.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonBindings\QuartzDisplayServicesAPI.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonBindings\MacOSKeys.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonBindings\Agl.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\CarbonBindings\CoreFoundation.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\Windows\WinRawKeyboard.cs">
<SubType>Code</SubType>
</Compile>
@ -820,7 +787,25 @@
<Compile Include="Platform\MacOS\Cocoa\NSEventModifierMask.cs" />
<Compile Include="Platform\MacOS\Cocoa\NSTrackingAreaOptions.cs" />
<Compile Include="Platform\MacOS\Cocoa\NSApplicationPresentationOptions.cs" />
<Compile Include="Platform\MacOS\CarbonBindings\Cgl.cs" />
<Compile Include="Platform\MacOS\CarbonWindowInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\CarbonAPI.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\SpeechChannel.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\QuartzDisplayServicesAPI.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\MacOSKeys.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\CoreFoundation.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\Cgl.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>

View file

@ -39,7 +39,6 @@ namespace OpenTK.Platform.MacOS.Carbon
{
static bool mInitialized = false;
static IntPtr uppHandler;
static CarbonGLNative eventHandler;
static int osMajor, osMinor, osBugfix;
static Application()
@ -76,12 +75,6 @@ namespace OpenTK.Platform.MacOS.Carbon
API.SetFrontProcess(ref psn);
}
static internal CarbonGLNative WindowEventHandler
{
get { return eventHandler; }
set { eventHandler = value; }
}
static void ConnectEvents()
{
@ -131,36 +124,16 @@ namespace OpenTK.Platform.MacOS.Carbon
return OSStatus.EventNotHandled;
}
case EventClass.AppleEvent:
// only event here is the apple event.
Debug.Print("Processing apple event.");
API.ProcessAppleEvent(inEvent);
break;
case EventClass.Keyboard:
case EventClass.Mouse:
if (WindowEventHandler != null)
{
return WindowEventHandler.DispatchEvent(inCaller, inEvent, evt, userData);
}
break;
}
return OSStatus.EventNotHandled;
}
public static void Run(CarbonGLNative window)
{
window.Closed += MainWindowClosed;
window.Visible = true;
API.RunApplicationEventLoop();
window.Closed -= MainWindowClosed;
}
static void MainWindowClosed(object sender, EventArgs e)
{
Debug.Print("Quitting application event loop.");

File diff suppressed because it is too large Load diff

View file

@ -1,122 +0,0 @@
#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace OpenTK.Platform.MacOS
{
using Input;
class CarbonInput : IInputDriver, IInputDriver2
{
List<KeyboardDevice> dummy_keyboard_list = new List<KeyboardDevice>(1);
List<MouseDevice> dummy_mice_list = new List<MouseDevice>(1);
List<JoystickDevice> dummy_joystick_list = new List<JoystickDevice>(1);
internal CarbonInput()
{
dummy_mice_list.Add(new MouseDevice());
dummy_keyboard_list.Add(new KeyboardDevice());
dummy_joystick_list.Add(new JoystickDevice<object>(0, 0, 0));
}
#region IInputDriver Members
public void Poll()
{
}
#endregion
#region IKeyboardDriver Members
public IList<KeyboardDevice> Keyboard
{
get { return dummy_keyboard_list; }
}
#endregion
#region IMouseDriver Members
public IList<MouseDevice> Mouse
{
get { return dummy_mice_list; }
}
#endregion
#region IJoystickDriver Members
public IList<JoystickDevice> Joysticks
{
get { return dummy_joystick_list; }
}
#endregion
#region IDisposable Members
public void Dispose()
{
}
#endregion
public IMouseDriver2 MouseDriver
{
get
{
throw new NotImplementedException();
}
}
public IKeyboardDriver2 KeyboardDriver
{
get
{
throw new NotImplementedException();
}
}
public IGamePadDriver GamePadDriver
{
get
{
throw new NotImplementedException();
}
}
public IJoystickDriver2 JoystickDriver
{
get { throw new NotImplementedException(); }
}
}
}

View file

@ -32,13 +32,6 @@ using System.Text;
namespace OpenTK.Platform.MacOS
{
/// <summary>
/// This delegate represents any method that takes no arguments and returns an int.
/// I would have used Func but that requires .NET 4
/// </summary>
/// <returns>The int value that your method returns</returns>
public delegate int GetInt();
/// \internal
/// <summary>
/// Describes a Carbon window.
@ -48,7 +41,7 @@ namespace OpenTK.Platform.MacOS
IntPtr windowRef;
bool ownHandle = false;
bool disposed = false;
bool isControl = false;
bool isControl = true;
bool goFullScreenHack = false;
bool goWindowedHack = false;

View file

@ -47,7 +47,7 @@ namespace OpenTK.Platform.MacOS
{
this.errorCode = errorCode;
}
internal MacOSException(Agl.AglError errorCode, string message)
internal MacOSException(int errorCode, string message)
: base(message)
{
this.errorCode = (OSStatus)errorCode;

View file

@ -18,6 +18,16 @@ using OpenTK.Graphics;
namespace OpenTK.Platform
{
namespace MacOS
{
/// <summary>
/// This delegate represents any method that takes no arguments and returns an int.
/// I would have used Func but that requires .NET 4
/// </summary>
/// <returns>The int value that your method returns</returns>
public delegate int GetInt();
}
/// <summary>
/// Provides cross-platform utilities to help interact with the underlying platform.
/// </summary>