2009-02-22 10:43:35 +00:00
#region - - - License - - -
/ * Copyright ( c ) 2006 , 2007 Stefanos Apostolopoulos
* See license . txt for license info
* /
#endregion
#region - - - Using Directives - - -
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.Windows.Forms ;
using System.Runtime.InteropServices ;
using System.Reflection ;
using System.Diagnostics ;
2009-08-14 13:13:28 +00:00
using OpenTK.Graphics ;
2009-02-22 10:43:35 +00:00
#endregion
namespace OpenTK.Platform
{
/// <summary>
/// Provides cross-platform utilities to help interact with the underlying platform.
/// </summary>
public static class Utilities
{
#region internal static bool ThrowOnX11Error
static bool throw_on_error ;
internal static bool ThrowOnX11Error
{
get { return throw_on_error ; }
set
{
if ( value & & ! throw_on_error )
{
Type . GetType ( "System.Windows.Forms.XplatUIX11, System.Windows.Forms" )
. GetField ( "ErrorExceptions" , System . Reflection . BindingFlags . Static |
System . Reflection . BindingFlags . NonPublic )
. SetValue ( null , true ) ;
throw_on_error = true ;
}
else if ( ! value & & throw_on_error )
{
Type . GetType ( "System.Windows.Forms.XplatUIX11, System.Windows.Forms" )
. GetField ( "ErrorExceptions" , System . Reflection . BindingFlags . Static |
System . Reflection . BindingFlags . NonPublic )
. SetValue ( null , false ) ;
throw_on_error = false ;
}
}
}
#endregion
#region internal static void LoadExtensions ( Type type )
delegate Delegate LoadDelegateFunction ( string name , Type signature ) ;
/// <internal />
/// <summary>Loads all extensions for the specified class. This function is intended
/// for OpenGL, Wgl, Glx, OpenAL etc.</summary>
/// <param name="type">The class to load extensions for.</param>
/// <remarks>
/// <para>The Type must contain a nested class called "Delegates".</para>
/// <para>
/// The Type must also implement a static function called LoadDelegate with the
/// following signature:
/// <code>static Delegate LoadDelegate(string name, Type signature)</code>
/// </para>
/// <para>This function allocates memory.</para>
/// </remarks>
internal static void LoadExtensions ( Type type )
{
// Using reflection is more than 3 times faster than directly loading delegates on the first
// run, probably due to code generation overhead. Subsequent runs are faster with direct loading
// than with reflection, but the first time is more significant.
int supported = 0 ;
2009-03-07 10:20:55 +00:00
Type extensions_class = type . GetNestedType ( "Delegates" , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ;
2009-02-22 10:43:35 +00:00
if ( extensions_class = = null )
throw new InvalidOperationException ( "The specified type does not have any loadable extensions." ) ;
2009-03-07 10:20:55 +00:00
FieldInfo [ ] delegates = extensions_class . GetFields ( BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ;
2009-02-22 10:43:35 +00:00
if ( delegates = = null )
throw new InvalidOperationException ( "The specified type does not have any loadable extensions." ) ;
2009-03-07 10:20:55 +00:00
MethodInfo load_delegate_method_info = type . GetMethod ( "LoadDelegate" , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ;
2009-02-22 10:43:35 +00:00
if ( load_delegate_method_info = = null )
throw new InvalidOperationException ( type . ToString ( ) + " does not contain a static LoadDelegate method." ) ;
LoadDelegateFunction LoadDelegate = ( LoadDelegateFunction ) Delegate . CreateDelegate (
typeof ( LoadDelegateFunction ) , load_delegate_method_info ) ;
2009-05-10 04:49:31 +00:00
2009-02-22 10:43:35 +00:00
Debug . Write ( "Load extensions for " + type . ToString ( ) + "... " ) ;
System . Diagnostics . Stopwatch time = new System . Diagnostics . Stopwatch ( ) ;
time . Reset ( ) ;
time . Start ( ) ;
foreach ( FieldInfo f in delegates )
{
Delegate d = LoadDelegate ( f . Name , f . FieldType ) ;
if ( d ! = null )
+ + supported ;
f . SetValue ( null , d ) ;
}
2009-03-07 10:20:55 +00:00
FieldInfo rebuildExtensionList = type . GetField ( "rebuildExtensionList" , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ;
2009-02-22 10:43:35 +00:00
if ( rebuildExtensionList ! = null )
rebuildExtensionList . SetValue ( null , true ) ;
time . Stop ( ) ;
Debug . Print ( "{0} extensions loaded in {1} ms." , supported , time . ElapsedMilliseconds ) ;
time . Reset ( ) ;
}
#endregion
2009-03-07 10:20:55 +00:00
#region internal static bool TryLoadExtension ( Type type , string extension )
2009-02-22 10:43:35 +00:00
/// <internal />
/// <summary>Loads the specified extension for the specified class. This function is intended
/// for OpenGL, Wgl, Glx, OpenAL etc.</summary>
/// <param name="type">The class to load extensions for.</param>
/// <param name="extension">The extension to load.</param>
/// <remarks>
/// <para>The Type must contain a nested class called "Delegates".</para>
/// <para>
/// The Type must also implement a static function called LoadDelegate with the
/// following signature:
/// <code>static Delegate LoadDelegate(string name, Type signature)</code>
/// </para>
/// <para>This function allocates memory.</para>
/// </remarks>
internal static bool TryLoadExtension ( Type type , string extension )
{
2009-03-07 10:20:55 +00:00
Type extensions_class = type . GetNestedType ( "Delegates" , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ;
2009-02-22 10:43:35 +00:00
if ( extensions_class = = null )
{
Debug . Print ( type . ToString ( ) , " does not contain extensions." ) ;
return false ;
}
LoadDelegateFunction LoadDelegate = ( LoadDelegateFunction ) Delegate . CreateDelegate ( typeof ( LoadDelegateFunction ) ,
2009-03-07 10:20:55 +00:00
type . GetMethod ( "LoadDelegate" , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ) ;
2009-02-22 10:43:35 +00:00
if ( LoadDelegate = = null )
{
Debug . Print ( type . ToString ( ) , " does not contain a static LoadDelegate method." ) ;
return false ;
}
2009-03-07 10:20:55 +00:00
FieldInfo f = extensions_class . GetField ( extension , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ;
2009-02-22 10:43:35 +00:00
if ( f = = null )
{
Debug . Print ( "Extension \"" , extension , "\" not found in " , type . ToString ( ) ) ;
return false ;
}
Delegate old = f . GetValue ( null ) as Delegate ;
Delegate @new = LoadDelegate ( f . Name , f . FieldType ) ;
2009-05-11 10:31:50 +00:00
if ( ( old ! = null ? old . Target : null ) ! = ( @new ! = null ? @new . Target : null ) )
2009-02-22 10:43:35 +00:00
{
f . SetValue ( null , @new ) ;
2009-03-07 10:20:55 +00:00
FieldInfo rebuildExtensionList = type . GetField ( "rebuildExtensionList" , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ;
2009-02-22 10:43:35 +00:00
if ( rebuildExtensionList ! = null )
rebuildExtensionList . SetValue ( null , true ) ;
}
return @new ! = null ;
}
#endregion
#region public bool IsIdle
interface IIsIdle { bool IsIdle { get ; } }
class X11IsIdle : IIsIdle
{
public bool IsIdle
{
get
{
return X11 . API . Pending ( IntPtr . Zero ) = = 0 ;
}
}
}
class WindowsIsIdle : IIsIdle
{
Windows . MSG msg ;
public bool IsIdle
{
get
{
return ! Windows . Functions . PeekMessage ( ref msg , IntPtr . Zero , 0 , 0 , 0 ) ;
}
}
}
static IIsIdle isIdleImpl =
System . Environment . OSVersion . Platform = = PlatformID . Unix ?
( IIsIdle ) new X11IsIdle ( ) : ( IIsIdle ) new WindowsIsIdle ( ) ;
public static bool IsIdle
{
get
{
return isIdleImpl . IsIdle ;
}
}
#endregion
2009-05-10 04:49:31 +00:00
#region - - - Creating a Graphics Context - - -
/// <summary>
2009-06-02 15:49:39 +00:00
/// Creates an IGraphicsContext instance for the specified window.
2009-05-10 04:49:31 +00:00
/// </summary>
2009-06-02 15:49:39 +00:00
/// <param name="mode">The GraphicsMode for the GraphicsContext.</param>
/// <param name="window">An IWindowInfo instance describing the parent window for this IGraphicsContext.</param>
/// <param name="major">The major OpenGL version number for this IGraphicsContext.</param>
/// <param name="minor">The minor OpenGL version number for this IGraphicsContext.</param>
/// <param name="flags">A bitwise collection of GraphicsContextFlags with specific options for this IGraphicsContext.</param>
/// <returns>A new IGraphicsContext instance.</returns>
2009-08-14 13:13:28 +00:00
public static IGraphicsContext CreateGraphicsContext (
GraphicsMode mode , IWindowInfo window ,
int major , int minor , GraphicsContextFlags flags )
2009-05-10 04:49:31 +00:00
{
2009-08-14 13:13:28 +00:00
GraphicsContext context = new GraphicsContext ( mode , window , major , minor , flags ) ;
2009-06-02 15:49:39 +00:00
context . MakeCurrent ( window ) ;
2009-05-10 04:49:31 +00:00
2009-08-14 13:13:28 +00:00
( context as IGraphicsContextInternal ) . LoadAll ( ) ;
2009-05-10 04:49:31 +00:00
return context ;
}
/// <summary>
2009-06-02 15:49:39 +00:00
/// Creates an IGraphicsContext instance for the specified System.Windows.Forms.Control.
2009-05-10 04:49:31 +00:00
/// </summary>
2009-06-02 15:49:39 +00:00
/// <param name="mode">The GraphicsMode for the GraphicsContext.</param>
/// <param name="cntrl">A System.Windows.Forms.Control.</param>
/// <param name="context">A new IGraphicsContext instance.</param>
/// <param name="info">An IWindowInfo instance for the specified cntrl.</param>
2009-07-19 17:50:41 +00:00
[Obsolete("Create the IWindowInfo object first by calling CreateWindowInfo, then use the CreateGraphicsContext overload which takes major, minor and flags parameters.")]
2009-08-14 13:13:28 +00:00
public static void CreateGraphicsContext ( GraphicsMode mode , Control cntrl ,
out IGraphicsContext context , out IWindowInfo info )
2009-05-10 04:49:31 +00:00
{
CreateGraphicsContext ( mode , cntrl . Handle , out context , out info ) ;
}
/// <summary>
2009-06-02 15:49:39 +00:00
/// Creates an IGraphicsContext instance for the specified System.Windows.Forms.Control.
2009-05-10 04:49:31 +00:00
/// </summary>
2009-06-02 15:49:39 +00:00
/// <param name="mode">The GraphicsMode for the GraphicsContext.</param>
/// <param name="cntrlHandle">A System.IntPtr that contains the handle for a System.Windows.Forms.Control.</param>
/// <param name="context">A new IGraphicsContext instance.</param>
/// <param name="info">An IWindowInfo instance for the specified ctrl.</param>
2009-07-19 17:50:41 +00:00
[Obsolete("Create the IWindowInfo object first by calling CreateWindowInfo, then use the CreateGraphicsContext overload which takes major, minor and flags parameters.")]
2009-08-14 13:13:28 +00:00
public static void CreateGraphicsContext ( GraphicsMode mode , IntPtr cntrlHandle ,
out IGraphicsContext context , out IWindowInfo info )
2009-05-10 04:49:31 +00:00
{
2009-08-19 14:17:47 +00:00
info = CreateWindowInfo ( mode , cntrlHandle , true ) ;
2009-05-10 04:49:31 +00:00
2009-08-14 13:13:28 +00:00
context = new GraphicsContext ( mode , info ) ;
2009-02-22 10:43:35 +00:00
context . MakeCurrent ( info ) ;
2009-08-14 13:13:28 +00:00
( context as IGraphicsContextInternal ) . LoadAll ( ) ;
2009-05-10 04:49:31 +00:00
}
#region - - - CreateWindowInfo - - -
2009-02-22 10:43:35 +00:00
/// <summary>
/// Creates an object which implements the IWindowInfo interface for the platform
/// currently running on.
/// </summary>
2009-03-25 21:53:12 +00:00
/// <param name="mode">The desired GraphicsMode for this window.</param>
2009-02-22 10:43:35 +00:00
/// <param name="controlHandle">The handle to the control, obtained from Control.Handle.</param>
2009-08-19 14:17:47 +00:00
/// <param name="isControl">Set to true if this is a Windows.Forms control.</param>
2009-02-22 10:43:35 +00:00
/// <returns></returns>
2009-08-19 14:17:47 +00:00
public static IWindowInfo CreateWindowInfo ( GraphicsMode mode , IntPtr controlHandle , bool isControl )
2009-02-22 10:43:35 +00:00
{
if ( Configuration . RunningOnWindows ) return CreateWinWindowInfo ( controlHandle ) ;
2009-08-19 14:17:47 +00:00
else if ( Configuration . RunningOnX11 ) return CreateX11WindowInfo ( mode , controlHandle , isControl ) ;
else if ( Configuration . RunningOnMacOS ) return CreateMacOSCarbonWindowInfo ( controlHandle , isControl ) ;
2009-02-22 10:43:35 +00:00
else
throw new PlatformNotSupportedException ( "Refer to http://www.opentk.com for more information." ) ;
}
#endregion
#region - - - X11 Platform - specific implementation - - -
2009-08-19 14:17:47 +00:00
private static IWindowInfo CreateX11WindowInfo ( GraphicsMode mode , IntPtr controlHandle , bool isControl )
2009-02-22 10:43:35 +00:00
{
Platform . X11 . X11WindowInfo window = new OpenTK . Platform . X11 . X11WindowInfo ( ) ;
window . WindowHandle = controlHandle ;
2009-08-19 14:17:47 +00:00
if ( isControl )
{
Type xplatui = Type . GetType ( "System.Windows.Forms.XplatUIX11, System.Windows.Forms" ) ;
if ( xplatui = = null ) throw new PlatformNotSupportedException (
"System.Windows.Forms.XplatUIX11 missing. Unsupported platform or Mono runtime version, aborting." ) ;
// get the required handles from the X11 API.
window . Display = ( IntPtr ) GetStaticFieldValue ( xplatui , "DisplayHandle" ) ;
window . RootWindow = ( IntPtr ) GetStaticFieldValue ( xplatui , "RootWindow" ) ;
window . Screen = ( int ) GetStaticFieldValue ( xplatui , "ScreenNo" ) ;
// get the X11 Visual info for the display.
Platform . X11 . XVisualInfo info = new Platform . X11 . XVisualInfo ( ) ;
if ( ! mode . Index . HasValue )
throw new GraphicsModeException ( "Invalid or unsupported GraphicsMode." ) ;
info . VisualID = mode . Index . Value ;
int dummy ;
window . VisualInfo = ( Platform . X11 . XVisualInfo ) Marshal . PtrToStructure (
Platform . X11 . Functions . XGetVisualInfo ( window . Display , Platform . X11 . XVisualInfoMask . ID ,
ref info , out dummy ) , typeof ( Platform . X11 . XVisualInfo ) ) ;
// set the X11 colormap.
SetStaticFieldValue ( xplatui , "CustomVisual" , window . VisualInfo . Visual ) ;
SetStaticFieldValue ( xplatui , "CustomColormap" ,
Platform . X11 . Functions . XCreateColormap ( window . Display , window . RootWindow , window . VisualInfo . Visual , 0 ) ) ;
}
else
{
}
2009-02-22 10:43:35 +00:00
return window ;
}
#endregion
#region - - - Windows Platform - specific implementation - - -
private static IWindowInfo CreateWinWindowInfo ( IntPtr controlHandle )
{
return new OpenTK . Platform . Windows . WinWindowInfo ( controlHandle , null ) ;
}
#endregion
#region - - - Mac OS X Platform - specific implementation - - -
2009-08-19 14:17:47 +00:00
private static IWindowInfo CreateMacOSCarbonWindowInfo ( IntPtr controlHandle , bool isControl )
2009-02-22 10:43:35 +00:00
{
2009-08-19 14:17:47 +00:00
return new OpenTK . Platform . MacOS . CarbonWindowInfo ( controlHandle , false , isControl ) ;
2009-02-22 10:43:35 +00:00
}
#endregion
#region - - - Utility functions for reading / writing non - public static fields through reflection - - -
private static object GetStaticFieldValue ( Type type , string fieldName )
{
return type . GetField ( fieldName ,
System . Reflection . BindingFlags . Static | System . Reflection . BindingFlags . NonPublic ) . GetValue ( null ) ;
}
private static void SetStaticFieldValue ( Type type , string fieldName , object value )
{
type . GetField ( fieldName ,
System . Reflection . BindingFlags . Static | System . Reflection . BindingFlags . NonPublic ) . SetValue ( null , value ) ;
}
#endregion
#endregion
}
}