Skip to content

Commit

Permalink
Some more work
Browse files Browse the repository at this point in the history
Will be pausing here as I need to change the bindings, and to be honest I don't want to do that without doing the SilkTouch refactor first.
  • Loading branch information
Perksey committed Sep 6, 2024
1 parent 8bfba2b commit e01289e
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 19 deletions.
4 changes: 2 additions & 2 deletions sources/Windowing/Common/Configuration/ThreadConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ public void ConfigureHost<THandle, THost>(THandle handle)
handle,
new SurfaceProperty
{
PropertyName = SurfacePropertyName.UseSeparateEventThread,
PropertyName = SurfacePropertyName.UseSeparateEventThreadBoolean,
Boolean = UseSeparateEventThread
}
);
THost.SetSurfaceProperty(
handle,
new SurfaceProperty
{
PropertyName = SurfacePropertyName.UseBufferedEventLoop,
PropertyName = SurfacePropertyName.UseBufferedEventLoopBoolean,
Boolean = UseBufferedEventLoop
}
);
Expand Down
37 changes: 36 additions & 1 deletion sources/Windowing/Common/Hosting/HostEventKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,40 @@ public enum HostEventKind
/// <summary>
/// A property changed on one of the hosted surfaces.
/// </summary>
SurfacePropertyChanged
SurfacePropertyChanged,

/// <summary>
/// The user has requested termination.
/// </summary>
AppLifecycleTerminationRequested,

/// <summary>
/// The application is quitting irrevocably.
/// </summary>
AppLifecycleTerminating,

/// <summary>
/// The application has received a low memory warning from the OS.
/// </summary>
AppLifecycleLowMemoryWarning,

/// <summary>
/// The application is going into the background.
/// </summary>
AppLifecyclePausing,

/// <summary>
/// The application has gone into the background.
/// </summary>
AppLifecyclePaused,

/// <summary>
/// The application is going into the foreground.
/// </summary>
AppLifecycleResuming,

/// <summary>
/// The application ahs gone into the foreground.
/// </summary>
AppLifecycleResumed
}
4 changes: 2 additions & 2 deletions sources/Windowing/Common/Hosting/ISurfaceHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,15 @@ static abstract void SetSurfaceProperty<T>(T handle, SurfaceProperty property)

/// <summary>
/// Pumps the event queue and determines whether there is an event to handle. <see cref="AcknowledgeEvent"/> must be
/// used after the event is inspected, otherwise subsequent calls will return <c>false</c>.
/// used after the event is inspected, otherwise subsequent calls will return <see cref="HostEventKind.None"/>.
/// </summary>
/// <param name="pump">The event pump.</param>
/// <param name="event">
/// An implementation-defined integer identifying the event received. This should be maintained across calls to the
/// event pump to ensure the correct event is subsequently received from the event pump. Must only be modified upon
/// a successful query.
/// </param>
/// <returns>True if an event has been taken from the event queue, false otherwise.</returns>
/// <returns>The event kind if an event has been taken from the event queue, false otherwise.</returns>
/// <remarks>This must be called on the main thread.</remarks>
static abstract HostEventKind QueryEvent(EventPumpHandle pump, ref int @event);

Expand Down
4 changes: 2 additions & 2 deletions sources/Windowing/Common/Hosting/SurfacePropertyName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public enum SurfacePropertyName : byte
/// <summary>
/// Whether events should be pumped on a separate thread to the root surface.
/// </summary>
UseSeparateEventThread = 0b0100_0010,
UseSeparateEventThreadBoolean = 0b0100_0010,

/// <summary>
/// Whether events should be buffered instead of serialized (i.e. don't wait for all surfaces to read an event
/// before polling for another event)
/// </summary>
UseBufferedEventLoop = 0b0100_0011
UseBufferedEventLoopBoolean = 0b0100_0011
}
105 changes: 97 additions & 8 deletions sources/Windowing/Common/Surface`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Silk.NET.Windowing;
/// Represents an abstract surface from which operating system events can be received and to which user graphics can be
/// drawn using the capabilities provided by the platform.
/// </summary>
public sealed class Surface<TImpl> : Surface, IHostActor
public sealed class Surface<TImpl> : Surface
where TImpl : ISurfaceHost
{
internal Surface() { }
Expand Down Expand Up @@ -46,28 +46,117 @@ internal static Surface<TImpl> Create(RequestHandle req) =>
private RequestHandle Request { get; set; }

/// <inheritdoc />
public override void Launch<T>(T actor) => TImpl.LaunchMainSurface(Request, this);
public override void Launch<T>(T actor) =>
TImpl.LaunchMainSurface(Request, new ActorRouter<T>(this, actor));

/// <inheritdoc />
public override void Launch() => Launch(this);

class ActorRouter<TActor>(Surface<TImpl> self, TActor actor) : IHostActor
where TActor : ISurfaceActor
{
private EventPumpHandle _eventPump;
private int _event;

public void HandleInit(SurfaceHandle surface)
{
if (self.Handle == default)
{
self.Handle = surface;
_eventPump = TImpl.CreateEventPump(surface);
actor.HandleCreated();
}
}

public void HandleTick()
{
if (self.Handle == default || _eventPump == default)
{
// misbehaving impl?
return;
}

var eventBefore = _event;
var eventKind = TImpl.QueryEvent(_eventPump, ref _event);
if (eventKind == HostEventKind.None)
{
return;
}

// these may be the same if the last tick threw an exception and somehow we're continuing past it. in this
// case, we acknowledge the dangling event and just move on.
if (eventBefore != _event)
{
switch (eventKind)
{
case HostEventKind.SurfacePropertyChanged:
{
var property = TImpl.GetEventPropertyChanged(_eventPump, _event);
switch (property.PropertyName)
{
case SurfacePropertyName.ClientSizeVector2:
{
actor.HandleClientSizeChanged(property.Float);
break;
}
case SurfacePropertyName.UseSeparateEventThreadBoolean:
case SurfacePropertyName.UseBufferedEventLoopBoolean:
{
break;
}
}
break;
}
}
}

TImpl.AcknowledgeEvent(_eventPump, _event);
}

public void HandleQuit(SurfaceHandle surface)
{
if (self.Handle != surface)
{
return;
}

actor.HandleTerminating();
self.Handle = default;
}

private void Reset()
{
if (_eventPump != default)
{
TImpl.DestroyEventPump(_eventPump);
_eventPump = default;
}

if (self.Handle == default)
{
TImpl.TerminateSurface(self.Handle);
self.Handle = default; // this surface is effectively forgotten at this point
}
}

// shouldn't ever do anything, as the only reason we'd be destructing is if the backend forgot about this actor
// which means it's quit already
~ActorRouter() => Reset();
}

/// <inheritdoc />
public override void Dispose()
{
if (Request.Value is not 0)
{
TImpl.DestroySurfaceRequest(Request);
Request = default;
}

if (Handle.Value is not 0)
{
TImpl.TerminateSurface(Handle);
// Handle = default will happen in ActorRouter.Reset (in theory)
}
}

void IHostActor.HandleInit(SurfaceHandle surface) => throw new NotImplementedException();

void IHostActor.HandleTick() => throw new NotImplementedException();

void IHostActor.HandleQuit(SurfaceHandle surface) => throw new NotImplementedException();
}
152 changes: 148 additions & 4 deletions sources/Windowing/Windowing/ReferenceImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,17 +159,161 @@ public static void SetSurfaceProperty<T>(T handle, SurfaceProperty property)
/// <inheritdoc />
public static void DestroyEventPump(EventPumpHandle pump) { }

private static Event _event;

/// <inheritdoc />
public static HostEventKind QueryEvent(EventPumpHandle pump, ref int @event) =>
throw new NotImplementedException();
public static HostEventKind QueryEvent(EventPumpHandle pump, ref int @event)
{
var ts = unchecked((int)_event.Common.Timestamp);
if (ts != 0 && @event == ts)
{
return HostEventKind.None;
}

if (!Sdl.PollEvent(_event.AsRef()))
{
return HostEventKind.None;
}

return (EventType)_event.Type switch
{
EventType.Quit => HostEventKind.AppLifecycleTerminationRequested,
EventType.Terminating => HostEventKind.AppLifecycleTerminating,
EventType.LowMemory => HostEventKind.AppLifecycleLowMemoryWarning,
EventType.WillEnterBackground => HostEventKind.AppLifecyclePausing,
EventType.DidEnterBackground => HostEventKind.AppLifecyclePaused,
EventType.WillEnterForeground => HostEventKind.AppLifecycleResuming,
EventType.DidEnterForeground => HostEventKind.AppLifecycleResumed,
// ???
EventType.LocaleChanged
or EventType.SystemThemeChanged
=> HostEventKind.None,
// TODO monitor API
EventType.DisplayOrientation
or EventType.DisplayAdded
or EventType.DisplayRemoved
or EventType.DisplayMoved
or EventType.DisplayContentScaleChanged
or EventType.DisplayHdrStateChanged
=> HostEventKind.None,
EventType.WindowShown
or EventType.WindowHidden
or EventType.WindowMoved
or EventType.WindowResized
or EventType.WindowPixelSizeChanged
or EventType.WindowMinimized
or EventType.WindowMaximized
or EventType.WindowRestored
or EventType.WindowMouseEnter
or EventType.WindowMouseLeave
or EventType.WindowFocusGained
or EventType.WindowFocusLost
or EventType.WindowCloseRequested
or EventType.WindowTakeFocus
or EventType.WindowHitTest
or EventType.WindowIccprofChanged
or EventType.WindowDisplayChanged
or EventType.WindowDisplayScaleChanged
or EventType.WindowOccluded
or EventType.WindowEnterFullscreen
or EventType.WindowLeaveFullscreen
or EventType.WindowPenEnter
or EventType.WindowPenLeave
or EventType.DropFile // TODO drag and drop
or EventType.DropText // TODO drag and drop
or EventType.DropBegin // TODO drag and drop
or EventType.DropComplete // TODO drag and drop
or EventType.DropPosition // TODO drag and drop
=> HostEventKind.SurfacePropertyChanged, // TODO
// Not exposing this one right now, Tick should be invoked which means we'll redraw if we need to.
EventType.WindowExposed
=> HostEventKind.None,
EventType.WindowDestroyed => HostEventKind.AppLifecycleTerminating,
EventType.KeyDown
or EventType.KeyUp
or EventType.TextEditing
or EventType.TextInput
or EventType.KeymapChanged
or EventType.KeyboardAdded
or EventType.KeyboardRemoved
or EventType.MouseMotion
or EventType.MouseButtonDown
or EventType.MouseButtonUp
or EventType.MouseWheel
or EventType.MouseAdded
or EventType.MouseRemoved
or EventType.JoystickAxisMotion
or EventType.JoystickBallMotion
or EventType.JoystickHatMotion
or EventType.JoystickButtonDown
or EventType.JoystickButtonUp
or EventType.JoystickAdded
or EventType.JoystickRemoved
or EventType.JoystickBatteryUpdated
or EventType.JoystickUpdateComplete
or EventType.GamepadAxisMotion
or EventType.GamepadButtonDown
or EventType.GamepadButtonUp
or EventType.GamepadAdded
or EventType.GamepadRemoved
or EventType.GamepadRemapped
or EventType.GamepadTouchpadDown
or EventType.GamepadTouchpadMotion
or EventType.GamepadTouchpadUp
or EventType.GamepadSensorUpdate
or EventType.GamepadUpdateComplete
or EventType.GamepadSteamHandleUpdated
=> HostEventKind.None,
// TODO touch API in the input HLU one day?
EventType.FingerDown
or EventType.FingerUp
or EventType.FingerMotion
or EventType.ClipboardUpdate
=> HostEventKind.None,
// don't care about these
EventType.AudioDeviceAdded
or EventType.AudioDeviceRemoved
or EventType.AudioDeviceFormatChanged
=> HostEventKind.None,
// TODO drawing API in the input HLU one day?
EventType.SensorUpdate
or EventType.PenDown
or EventType.PenUp
or EventType.PenMotion
or EventType.PenButtonDown
or EventType.PenButtonUp
=> HostEventKind.None,
// TODO camera API in the input HLU one day?
EventType.CameraDeviceAdded
or EventType.CameraDeviceRemoved
or EventType.CameraDeviceApproved
or EventType.CameraDeviceDenied
=> HostEventKind.None,
// don't care about these
EventType.RenderTargetsReset
or EventType.RenderDeviceReset
=> HostEventKind.None,
// EventType.PollSentinel => expr,
// EventType.User => expr,
// EventType.Last => expr,
// EventType.EnumPadding => expr,
_ => HostEventKind.None
};
}

/// <inheritdoc />
public static SurfaceHandle GetEventSurface(EventPumpHandle pump, int @event) =>
throw new NotImplementedException();

/// <inheritdoc />
public static void AcknowledgeEvent(EventPumpHandle pump, int @event) =>
throw new NotImplementedException();
public static void AcknowledgeEvent(EventPumpHandle pump, int @event)
{
var ts = unchecked((int)_event.Common.Timestamp);
if (ts != 0 && @event == ts)
{
_event = default;
}
}

/// <inheritdoc />
public static SurfaceProperty GetEventPropertyChanged(EventPumpHandle pump, int @event) =>
Expand Down

0 comments on commit e01289e

Please sign in to comment.