Prevent leaking of hardware cursors.
Added the lacking finialization machinery, ensured disposal under exceptional circumstances and also ensure the game calls dispose on old cursors before creating new ones.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user