Cleaner startup sequence

OpenTK.Toolkit will now initialize OpenTK.Configuration and
OpenTK.Platform.Factory explicitly. It can also receive an optional
ToolkitOptions parameter to influence the OpenTK.Platform implementation
that will be chosen. Finally, it explicitly implements IDisposable to
clean up after itself.
This commit is contained in:
Stefanos A. 2013-11-12 20:34:53 +01:00
parent 663864f083
commit b9fcf7c3c3
2 changed files with 123 additions and 21 deletions

View file

@ -47,14 +47,24 @@ namespace OpenTK.Platform
static Factory()
{
if (Configuration.Sdl2Supported) Default = new SDL2.Sdl2Factory();
// Ensure we are correctly initialized.
Toolkit.Init();
// Create regular platform backend
if (Configuration.RunningOnSdl2) Default = new SDL2.Sdl2Factory();
else if (Configuration.RunningOnWindows) Default = new Windows.WinFactory();
else if (Configuration.RunningOnMacOS) Default = new MacOS.MacOSFactory();
else if (Configuration.RunningOnX11) Default = new X11.X11Factory();
else Default = new UnsupportedPlatform();
if (Configuration.Sdl2Supported)
// Create embedded platform backend for EGL / OpenGL ES.
// Todo: we could probably delay this until the embedded
// factory is actually accessed. This might improve startup
// times slightly.
if (Configuration.RunningOnSdl2)
{
// SDL supports both EGL and desktop backends
// using the same API.
Embedded = Default;
}
else if (Egl.Egl.IsSupported)

View file

@ -2,7 +2,7 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
// Copyright (c) 2006 - 2013 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
@ -29,64 +29,156 @@ using System;
using System.Collections.Generic;
using System.Text;
using OpenTK.Platform;
using System.Diagnostics;
namespace OpenTK
{
/// <summary>
/// Provides static methods to manage an OpenTK application.
/// </summary>
public sealed class Toolkit
public sealed class Toolkit : IDisposable
{
static Factory platform_factory;
Factory platform_factory;
static Toolkit toolkit;
volatile static bool initialized;
static readonly object InitLock = new object();
#region Constructors
Toolkit() { }
Toolkit(Factory factory)
{
if (factory == null)
throw new ArgumentNullException("factory");
platform_factory = factory;
}
#endregion
#region Public Members
/// <summary>
/// Initializes OpenTK. This method is necessary only if you are using OpenTK
/// alongside a different windowing toolkit (e.g. GTK#) and should be the very
/// first method called by your application (i.e. calling this method should be
/// the very first statement executed by the "Main" method).
/// Initializes OpenTK with default options.
/// </summary>
/// <remarks>
/// Some windowing toolkits do not configure the underlying platform
/// <para>
/// You *must* call this method if you are combining OpenTK with a
/// third-party windowing toolkit (e.g. GTK#). In this case, this should be the
/// first method called by your application:
/// <code>
/// static void Main()
/// {
/// OpenTK.Toolkit.Init();
/// ...
/// }
/// </code>
/// </para>
/// <para>
/// The reason is that some toolkits do not configure the underlying platform
/// correctly or configure it in a way that is incompatible with OpenTK.
/// Calling this method first ensures that OpenTK is given the chance to
/// initialize itself and configure the platform correctly.
/// </para>
/// </remarks>
/// <returns>
/// An IDisposable instance that you can use to dispose of the resources
/// consumed by OpenTK.
/// </returns>
public static IDisposable Init()
{
return Init(ToolkitOptions.Default);
}
/// <summary>
/// Initializes OpenTK with the specified options. Use this method
/// to influence the OpenTK.Platform implementation that will be used.
/// </summary>
/// <remarks>
/// <para>
/// You *must* call this method if you are combining OpenTK with a
/// third-party windowing toolkit (e.g. GTK#). In this case, this should be the
/// first method called by your application:
/// <code>
/// static void Main()
/// {
/// OpenTK.Toolkit.Init();
/// ...
/// }
/// </code>
/// </para>
/// <para>
/// The reason is that some toolkits do not configure the underlying platform
/// correctly or configure it in a way that is incompatible with OpenTK.
/// Calling this method first ensures that OpenTK is given the chance to
/// initialize itself and configure the platform correctly.
/// </para>
/// </remarks>
/// <param name="options">A <c>ToolkitOptions</c> instance
/// containing the desired options.</param>
/// <returns>
/// An IDisposable instance that you can use to dispose of the resources
/// consumed by OpenTK.
/// </returns>
public static IDisposable Init(ToolkitOptions options)
{
if (options == null)
throw new ArgumentNullException("options");
lock (InitLock)
{
if (!initialized)
{
initialized = true;
Configuration.Init();
// The actual initialization takes place in the platform-specific factory
// constructors.
platform_factory = new Platform.Factory();
AppDomain.CurrentDomain.DomainUnload += Deinit;
Configuration.Init(options);
// The actual initialization takes place in the
// platform-specific factory constructors.
toolkit = new Toolkit(new Factory());
}
return platform_factory;
return toolkit;
}
}
#endregion
#region Private Members
#region IDisposable Members
static void Deinit(object sender, EventArgs e)
/// <summary>
/// Disposes of the resources consumed by this instance.
/// </summary>
public void Dispose()
{
AppDomain.CurrentDomain.DomainUnload -= Deinit;
platform_factory.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool manual)
{
if (manual)
{
lock (InitLock)
{
platform_factory.Dispose();
platform_factory = null;
toolkit = null;
initialized = false;
}
}
else
{
Debug.Print("OpenTK.Toolkit leaked, did you forget to call Dispose()?");
platform_factory = null;
toolkit = null;
initialized = false;
}
}
/// <summary>
/// Finalizes this instance.
/// </summary>
~Toolkit()
{
Dispose(false);
}
#endregion