148 lines
4.3 KiB
C#

using Dashboard.Collections;
using Dashboard.Windowing;
namespace Dashboard.Pal
{
public abstract class AppContext : IContextBase<AppContext, IAppContextExtension>
{
public abstract string DriverName { get; }
public abstract string DriverVendor { get; }
public abstract Version DriverVersion { get; }
public virtual string AppTitle { get; set; } = "Dashboard Application";
public bool IsInitialized { get; private set; } = false;
public bool IsDisposed { get; private set; } = false;
public IContextDebugger? Debugger { get; set; }
private readonly TypeDictionary<IAppContextExtension> _extensions =
new TypeDictionary<IAppContextExtension>(true);
private readonly TypeDictionary<IAppContextExtension, Func<IAppContextExtension>> _preloadedExtensions =
new TypeDictionary<IAppContextExtension, Func<IAppContextExtension>>(true);
~AppContext()
{
InvokeDispose(false);
}
public void Initialize()
{
if (IsInitialized)
return;
IsInitialized = true;
InitializeInternal();
}
protected virtual void InitializeInternal()
{
}
public virtual void RunEvents(bool wait)
{
if (!IsInitialized)
Initialize();
}
public void Run() => Run(true, CancellationToken.None);
public void Run(bool wait) => Run(wait, CancellationToken.None);
public void Run(bool waitForEvents, CancellationToken token)
{
InitializeInternal();
while (!token.IsCancellationRequested)
{
RunEvents(waitForEvents);
}
}
#region Window API
/// <summary>
/// Creates a window. It could be a virtual window, or a physical window.
/// </summary>
/// <returns>A window.</returns>
public abstract IWindow CreateWindow();
/// <summary>
/// Always creates a physical window.
/// </summary>
/// <returns>A physical window.</returns>
public abstract IPhysicalWindow CreatePhysicalWindow();
/// <summary>
/// Create a physical window with a window manager.
/// </summary>
/// <returns>A physical window with the given window manager.</returns>
public IPhysicalWindow CreatePhysicalWindow(IWindowManager wm)
{
IPhysicalWindow window = CreatePhysicalWindow();
window.WindowManager = wm;
return window;
}
#endregion
public bool IsExtensionAvailable<T>() where T : IAppContextExtension
{
return _extensions.Contains<T>() || _preloadedExtensions.Contains<T>();
}
public bool ExtensionPreload<T>() where T : IAppContextExtension, new()
{
return _preloadedExtensions.Add<T>(() => new T());
}
public T ExtensionRequire<T>() where T : IAppContextExtension, new()
{
T? extension = default;
if (_extensions.TryGet(out extension))
return extension;
lock (_extensions)
{
if (_extensions.TryGet(out extension))
return extension;
if (_preloadedExtensions.Remove<T>(out Func<IAppContextExtension>? loader))
{
extension = (T)loader!();
}
else
{
extension = new T();
}
_extensions.Add(extension);
extension.Require(this);
}
return extension;
}
protected virtual void Dispose(bool isDisposing)
{
if (!isDisposing) return;
foreach (IAppContextExtension extension in _extensions)
{
extension.Dispose();
}
GC.SuppressFinalize(this);
}
private void InvokeDispose(bool isDisposing)
{
if (IsDisposed) return;
IsDisposed = true;
Dispose(isDisposing);
}
public void Dispose() => InvokeDispose(true);
}
}