Show task bar progress bar for loading progress

Using the new API in SDL 3.4.0
This commit is contained in:
PJB3005
2026-01-18 23:29:09 +01:00
parent 36e5f10511
commit 02b64b7386
9 changed files with 88 additions and 0 deletions

View File

@@ -601,6 +601,11 @@ namespace Robust.Client.Graphics.Clyde
_clyde._windowing!.TextInputStop(Reg);
}
public void SetWindowProgress(WindowProgressState state, float value)
{
_clyde._windowing!.WindowSetProgress(Reg, state, value);
}
public nint? WindowsHWnd => _clyde._windowing!.WindowGetWin32Window(Reg);
}

View File

@@ -91,6 +91,8 @@ namespace Robust.Client.Graphics.Clyde
private bool _earlyGLInit;
private bool _threadWindowApi;
public bool IsInitialized { get; private set; }
public Clyde()
{
_currentBoundRenderTarget = default!;
@@ -183,6 +185,8 @@ namespace Robust.Client.Graphics.Clyde
if (!InitMainWindowAndRenderer())
return false;
IsInitialized = true;
return true;
}

View File

@@ -27,6 +27,7 @@ namespace Robust.Client.Graphics.Clyde
internal sealed class ClydeHeadless : IClydeInternal
{
// Would it make sense to report a fake resolution like 720p here so code doesn't break? idk.
public bool IsInitialized { get; private set; }
public IClydeWindow MainWindow { get; }
public Vector2i ScreenSize => (1280, 720);
public IEnumerable<IClydeWindow> AllWindows => _windows;
@@ -172,6 +173,7 @@ namespace Robust.Client.Graphics.Clyde
public bool InitializePostWindowing()
{
IsInitialized = true;
return true;
}
@@ -583,6 +585,11 @@ namespace Robust.Client.Graphics.Clyde
public event Action<WindowDestroyedEventArgs>? Destroyed;
public event Action<WindowResizedEventArgs>? Resized { add { } remove { } }
public void SetWindowProgress(WindowProgressState state, float value)
{
// Nop.
}
public void TextInputSetRect(UIBox2i rect, int cursor)
{
// Nop.

View File

@@ -42,6 +42,7 @@ namespace Robust.Client.Graphics.Clyde
void WindowSetSize(WindowReg window, Vector2i size);
void WindowSetVisible(WindowReg window, bool visible);
void WindowRequestAttention(WindowReg window);
void WindowSetProgress(WindowReg reg, WindowProgressState state, float value);
void WindowSwapBuffers(WindowReg window);
uint? WindowGetX11Id(WindowReg window);
nint? WindowGetX11Display(WindowReg window);

View File

@@ -21,6 +21,7 @@ internal partial class Clyde
private sealed partial class Sdl3WindowingImpl
{
private int _nextWindowId = 1;
private bool _progressUnavailable;
public (WindowReg?, string? error) WindowCreate(
GLContextSpec? spec,
@@ -461,6 +462,42 @@ internal partial class Clyde
_sawmill.Error("Failed to flash window: {error}", SDL.SDL_GetError());
}
public void WindowSetProgress(WindowReg window, WindowProgressState state, float value)
{
SendCmd(new CmdWinSetProgress
{
Window = WinPtr(window),
State = (SDL.SDL_ProgressState)state,
Value = value
});
}
private void WinThreadWinSetProgress(CmdWinSetProgress cmd)
{
if (_progressUnavailable)
return;
try
{
var res = SDL.SDL_SetWindowProgressState(cmd.Window, cmd.State);
if (!res)
{
_sawmill.Error("Failed to set window progress state: {error}", SDL.SDL_GetError());
return;
}
res = SDL.SDL_SetWindowProgressValue(cmd.Window, cmd.Value);
if (!res)
_sawmill.Error("Failed to set window progress value: {error}", SDL.SDL_GetError());
}
catch (EntryPointNotFoundException)
{
// Allowing it to fail means I don't have to update the launcher immediately :)
_progressUnavailable = true;
_sawmill.Debug("SDL3 progress APIs unavailable");
}
}
public unsafe void WindowSwapBuffers(WindowReg window)
{
var reg = (Sdl3WindowReg)window;

View File

@@ -93,6 +93,10 @@ internal partial class Clyde
WinThreadWinRequestAttention(cmd);
break;
case CmdWinSetProgress cmd:
WinThreadWinSetProgress(cmd);
break;
case CmdWinSetSize cmd:
WinThreadWinSetSize(cmd);
break;
@@ -261,6 +265,13 @@ internal partial class Clyde
public nint Window;
}
private sealed class CmdWinSetProgress : CmdBase
{
public nint Window;
public SDL.SDL_ProgressState State;
public float Value;
}
private sealed class CmdWinSetSize : CmdBase
{
public nint Window;

View File

@@ -18,6 +18,8 @@ namespace Robust.Client.Graphics
[NotContentImplementable]
public interface IClyde
{
internal bool IsInitialized { get; }
IClydeWindow MainWindow { get; }
IRenderTarget MainWindowRenderTarget => MainWindow.RenderTarget;

View File

@@ -2,6 +2,7 @@
using System.Numerics;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using SDL3;
namespace Robust.Client.Graphics
{
@@ -43,6 +44,8 @@ namespace Robust.Client.Graphics
/// </summary>
event Action<WindowResizedEventArgs> Resized;
internal void SetWindowProgress(WindowProgressState state, float value);
/// <summary>
/// Set the active text input area in window pixel coordinates.
/// </summary>
@@ -68,6 +71,15 @@ namespace Robust.Client.Graphics
void TextInputStop();
}
internal enum WindowProgressState : byte
{
None = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_NONE,
Indeterminate = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_INDETERMINATE,
Normal = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_NORMAL,
Paused = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_PAUSED,
Error = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_ERROR
}
[NotContentImplementable]
internal interface IClydeWindowInternal : IClydeWindow
{

View File

@@ -118,6 +118,13 @@ internal sealed class LoadingScreenManager : ILoadingScreenManager
_currentSectionName = sectionName;
if (_clyde.IsInitialized)
{
_clyde.MainWindow.SetWindowProgress(
WindowProgressState.Normal,
_currentSection / (float)_numberOfLoadingSections);
}
if (!dontRender)
{
// This ensures that if the screen was resized or something the new size is properly updated to clyde.
@@ -176,6 +183,8 @@ internal sealed class LoadingScreenManager : ILoadingScreenManager
if (_currentSection != _numberOfLoadingSections)
_sawmill.Error($"The number of seen loading sections isn't equal to the total number of loading sections! Seen: {_currentSection}, Total: {_numberOfLoadingSections}");
_clyde.MainWindow.SetWindowProgress(WindowProgressState.None, 1);
_finished = true;
}