diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 1c6a68c82e..69e795569a 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -309,6 +309,9 @@ namespace OpenRA using (new PerfTimer("LoadMaps")) ModData.MapCache.LoadMaps(); + if (Cursor != null) + Cursor.Dispose(); + if (Settings.Graphics.HardwareCursors) { try diff --git a/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs b/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs index 2c866d194f..ab622f7e53 100755 --- a/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs +++ b/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs @@ -106,11 +106,14 @@ namespace OpenRA.Renderer.Sdl2 public IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot) { - var c = new SDL2HardwareCursor(size, data, hotspot); - if (c.Cursor == IntPtr.Zero) - throw new InvalidDataException("Failed to create hardware cursor `{0}`: {1}".F(name, SDL.SDL_GetError())); - - return c; + try + { + return new SDL2HardwareCursor(size, data, hotspot); + } + catch (Exception ex) + { + throw new InvalidDataException("Failed to create hardware cursor `{0}`".F(name), ex); + } } public void SetHardwareCursor(IHardwareCursor cursor) @@ -125,24 +128,57 @@ namespace OpenRA.Renderer.Sdl2 } } - class SDL2HardwareCursor : IHardwareCursor + sealed class SDL2HardwareCursor : IHardwareCursor { - public readonly IntPtr Cursor; - readonly IntPtr surface; + public IntPtr Cursor { get; private set; } + IntPtr surface; public SDL2HardwareCursor(Size size, byte[] data, int2 hotspot) { - surface = SDL.SDL_CreateRGBSurface(0, size.Width, size.Height, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + try + { + surface = SDL.SDL_CreateRGBSurface(0, size.Width, size.Height, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + if (surface == IntPtr.Zero) + throw new InvalidDataException("Failed to create surface: {0}".F(SDL.SDL_GetError())); - var sur = (SDL2.SDL.SDL_Surface)Marshal.PtrToStructure(surface, typeof(SDL2.SDL.SDL_Surface)); - Marshal.Copy(data, 0, sur.pixels, data.Length); - Cursor = SDL.SDL_CreateColorCursor(surface, hotspot.X, hotspot.Y); + var sur = (SDL2.SDL.SDL_Surface)Marshal.PtrToStructure(surface, typeof(SDL2.SDL.SDL_Surface)); + Marshal.Copy(data, 0, sur.pixels, data.Length); + + Cursor = SDL.SDL_CreateColorCursor(surface, hotspot.X, hotspot.Y); + if (Cursor == IntPtr.Zero) + throw new InvalidDataException("Failed to create cursor: {0}".F(SDL.SDL_GetError())); + } + catch + { + Dispose(); + throw; + } + } + + ~SDL2HardwareCursor() + { + Game.RunAfterTick(() => Dispose(false)); } public void Dispose() { - SDL.SDL_FreeCursor(Cursor); - SDL.SDL_FreeSurface(surface); + Game.RunAfterTick(() => Dispose(true)); + GC.SuppressFinalize(this); + } + + void Dispose(bool disposing) + { + if (Cursor != IntPtr.Zero) + { + SDL.SDL_FreeCursor(Cursor); + Cursor = IntPtr.Zero; + } + + if (surface != IntPtr.Zero) + { + SDL.SDL_FreeSurface(surface); + surface = IntPtr.Zero; + } } }