From 3b5f6170d1a5db47ac94944af4a01e9c6955f8b1 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 24 Jan 2025 23:06:59 -0600 Subject: [PATCH] misc: chore: move Rainbow updating to a separate task started/stopped as needed update gommon & use the Event class from it to allow easily clearing all handlers when the apphost exits to avoid leftover invalid event handlers in the rainbow event handler list. More robust config application logic to ensure what needs to happen only happens once --- Directory.Packages.props | 2 +- src/Ryujinx.Common/Utilities/Rainbow.cs | 66 ++++++++++++++++--------- src/Ryujinx.Input.SDL2/SDL2Gamepad.cs | 23 ++++++--- src/Ryujinx.SDL2.Common/SDL2Driver.cs | 2 - src/Ryujinx/AppHost.cs | 6 +++ 5 files changed, 68 insertions(+), 31 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index c2ac358ed..f1d7cac61 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -42,7 +42,7 @@ - + diff --git a/src/Ryujinx.Common/Utilities/Rainbow.cs b/src/Ryujinx.Common/Utilities/Rainbow.cs index 2c2ea7bfd..3b49872c2 100644 --- a/src/Ryujinx.Common/Utilities/Rainbow.cs +++ b/src/Ryujinx.Common/Utilities/Rainbow.cs @@ -1,40 +1,62 @@ -using System; +using Gommon; +using System; using System.Drawing; +using System.Threading.Tasks; namespace Ryujinx.Common.Utilities { - public class Rainbow + public static class Rainbow { + public static bool CyclingEnabled { get; set; } + + public static void Enable() + { + if (!CyclingEnabled) + { + CyclingEnabled = true; + Executor.ExecuteBackgroundAsync(async () => + { + while (CyclingEnabled) + { + await Task.Delay(15); + Tick(); + } + }); + } + } + + public static void Disable() + { + CyclingEnabled = false; + } + + public static float Speed { get; set; } = 1; public static Color Color { get; private set; } = Color.Blue; - private static float _lastHue; - public static void Tick() { - float currentHue = Color.GetHue(); - float nextHue = currentHue; - - if (currentHue >= 360) - nextHue = 0; - else - nextHue += Speed; + Color = HsbToRgb((Color.GetHue() + Speed) / 360); - Color = HsbToRgb( - nextHue / 360, - 1, - 1 - ); - - _lastHue = currentHue; - - RainbowColorUpdated?.Invoke(Color.ToArgb()); + UpdatedHandler.Call(Color.ToArgb()); } - public static event Action RainbowColorUpdated; + public static void Reset() + { + Color = Color.Blue; + UpdatedHandler.Clear(); + } - private static Color HsbToRgb(float hue, float saturation, float brightness) + public static event Action Updated + { + add => UpdatedHandler.Add(value); + remove => UpdatedHandler.Remove(value); + } + + internal static Event UpdatedHandler = new(); + + private static Color HsbToRgb(float hue, float saturation = 1, float brightness = 1) { int r = 0, g = 0, b = 0; if (saturation == 0) diff --git a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs b/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs index a73d7c730..3ed2880ce 100644 --- a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs +++ b/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs @@ -148,6 +148,8 @@ namespace Ryujinx.Input.SDL2 { if (disposing && _gamepadHandle != nint.Zero) { + Rainbow.Updated -= RainbowColorChanged; + SDL_GameControllerClose(_gamepadHandle); _gamepadHandle = nint.Zero; @@ -232,6 +234,8 @@ namespace Ryujinx.Input.SDL2 SetLed((uint)packedRgb); } + + private bool _rainbowColorEnabled; public void SetConfiguration(InputConfig configuration) { @@ -243,13 +247,20 @@ namespace Ryujinx.Input.SDL2 { if (_configuration.Led.TurnOffLed) (this as IGamepad).ClearLed(); - else if (_configuration.Led.UseRainbow) - Rainbow.RainbowColorUpdated += RainbowColorChanged; - else - SetLed(_configuration.Led.LedColor); + else switch (_configuration.Led.UseRainbow) + { + case true when !_rainbowColorEnabled: + Rainbow.Updated += RainbowColorChanged; + _rainbowColorEnabled = true; + break; + case false when _rainbowColorEnabled: + Rainbow.Updated -= RainbowColorChanged; + _rainbowColorEnabled = false; + break; + } - if (!_configuration.Led.UseRainbow) - Rainbow.RainbowColorUpdated -= RainbowColorChanged; + if (!_configuration.Led.TurnOffLed && !_rainbowColorEnabled) + SetLed(_configuration.Led.LedColor); } _buttonsUserMapping.Clear(); diff --git a/src/Ryujinx.SDL2.Common/SDL2Driver.cs b/src/Ryujinx.SDL2.Common/SDL2Driver.cs index 47c5e60c5..047ccbebf 100644 --- a/src/Ryujinx.SDL2.Common/SDL2Driver.cs +++ b/src/Ryujinx.SDL2.Common/SDL2Driver.cs @@ -168,8 +168,6 @@ namespace Ryujinx.SDL2.Common HandleSDLEvent(ref evnt); } }); - - Rainbow.Tick(); waitHandle.Wait(WaitTimeMs); } diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index 31f27a965..65c279fc4 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -501,6 +501,8 @@ namespace Ryujinx.Ava _renderingThread.Start(); _viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value; + + Rainbow.Enable(); MainLoop(); @@ -590,7 +592,11 @@ namespace Ryujinx.Ava foreach (IGamepad gamepad in RyujinxApp.MainWindow.InputManager.GamepadDriver.GetGamepads()) { gamepad?.ClearLed(); + gamepad?.Dispose(); } + + Rainbow.Disable(); + Rainbow.Reset(); _isStopped = true; Stop();