(ded4a3e0a) v0.9.0.7
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,248 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Xna.Framework.Audio;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
internal class SdlGamePlatform : GamePlatform
|
||||
{
|
||||
public override GameRunBehavior DefaultRunBehavior
|
||||
{
|
||||
get { return GameRunBehavior.Synchronous; }
|
||||
}
|
||||
|
||||
private readonly Game _game;
|
||||
private readonly List<Keys> _keys;
|
||||
|
||||
private int _isExiting;
|
||||
private SdlGameWindow _view;
|
||||
|
||||
public SdlGamePlatform(Game game)
|
||||
: base(game)
|
||||
{
|
||||
_game = game;
|
||||
_keys = new List<Keys>();
|
||||
Keyboard.SetKeys(_keys);
|
||||
|
||||
Sdl.Version sversion;
|
||||
Sdl.GetVersion(out sversion);
|
||||
|
||||
Sdl.Major = sversion.Major;
|
||||
Sdl.Minor = sversion.Minor;
|
||||
Sdl.Patch = sversion.Patch;
|
||||
|
||||
var version = 100 * Sdl.Major + 10 * Sdl.Minor + Sdl.Patch;
|
||||
|
||||
if (version <= 204)
|
||||
Debug.WriteLine ("Please use SDL 2.0.5 or higher.");
|
||||
|
||||
// Needed so VS can debug the project on Windows
|
||||
if (version >= 205 && CurrentPlatform.OS == OS.Windows && Debugger.IsAttached)
|
||||
Sdl.SetHint("SDL_WINDOWS_DISABLE_THREAD_NAMING", "1");
|
||||
|
||||
Sdl.Init((int)(
|
||||
Sdl.InitFlags.Video |
|
||||
Sdl.InitFlags.Joystick |
|
||||
Sdl.InitFlags.GameController |
|
||||
Sdl.InitFlags.Haptic
|
||||
));
|
||||
|
||||
Sdl.DisableScreenSaver();
|
||||
|
||||
GamePad.InitDatabase();
|
||||
Window = _view = new SdlGameWindow(_game);
|
||||
}
|
||||
|
||||
public override void BeforeInitialize ()
|
||||
{
|
||||
SdlRunLoop();
|
||||
|
||||
base.BeforeInitialize ();
|
||||
}
|
||||
|
||||
protected override void OnIsMouseVisibleChanged()
|
||||
{
|
||||
_view.SetCursorVisible(_game.IsMouseVisible);
|
||||
}
|
||||
|
||||
internal override void OnPresentationChanged(PresentationParameters pp)
|
||||
{
|
||||
var displayIndex = Sdl.Window.GetDisplayIndex(Window.Handle);
|
||||
var displayName = Sdl.Display.GetDisplayName(displayIndex);
|
||||
BeginScreenDeviceChange(pp.IsFullScreen);
|
||||
EndScreenDeviceChange(displayName, pp.BackBufferWidth, pp.BackBufferHeight);
|
||||
}
|
||||
|
||||
public override void RunLoop()
|
||||
{
|
||||
Sdl.Window.Show(Window.Handle);
|
||||
|
||||
while (true)
|
||||
{
|
||||
SdlRunLoop();
|
||||
Game.Tick();
|
||||
Threading.Run();
|
||||
#if OPENGL
|
||||
GraphicsDevice.DisposeContexts();
|
||||
#endif
|
||||
|
||||
if (_isExiting > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SdlRunLoop()
|
||||
{
|
||||
Sdl.Event ev;
|
||||
|
||||
while (Sdl.PollEvent(out ev) == 1)
|
||||
{
|
||||
if (ev.Type == Sdl.EventType.Quit)
|
||||
_isExiting++;
|
||||
else if (ev.Type == Sdl.EventType.JoyDeviceAdded)
|
||||
Joystick.AddDevice(ev.JoystickDevice.Which);
|
||||
else if (ev.Type == Sdl.EventType.ControllerDeviceRemoved)
|
||||
GamePad.RemoveDevice(ev.ControllerDevice.Which);
|
||||
else if (ev.Type == Sdl.EventType.JoyDeviceRemoved)
|
||||
Joystick.RemoveDevice(ev.JoystickDevice.Which);
|
||||
else if (ev.Type == Sdl.EventType.MouseWheel)
|
||||
{
|
||||
const int wheelDelta = 120;
|
||||
Mouse.ScrollY += ev.Wheel.Y * wheelDelta;
|
||||
Mouse.ScrollX += ev.Wheel.X * wheelDelta;
|
||||
}
|
||||
else if (ev.Type == Sdl.EventType.MouseMotion)
|
||||
{
|
||||
Window.MouseState.X = ev.Motion.X;
|
||||
Window.MouseState.Y = ev.Motion.Y;
|
||||
}
|
||||
else if (ev.Type == Sdl.EventType.KeyDown)
|
||||
{
|
||||
var key = KeyboardUtil.ToXna(ev.Key.Keysym.Sym);
|
||||
|
||||
if (!_keys.Contains(key))
|
||||
_keys.Add(key);
|
||||
char character = KeyboardUtil.ApplyModifiers((char)ev.Key.Keysym.Sym, ev.Key.Keysym.Mod);
|
||||
if (char.IsControl(character))
|
||||
_view.CallTextInput(character, key);
|
||||
}
|
||||
else if (ev.Type == Sdl.EventType.KeyUp)
|
||||
{
|
||||
var key = KeyboardUtil.ToXna(ev.Key.Keysym.Sym);
|
||||
_keys.Remove(key);
|
||||
}
|
||||
else if (ev.Type == Sdl.EventType.TextInput)
|
||||
{
|
||||
int len = 0;
|
||||
string text = String.Empty;
|
||||
unsafe
|
||||
{
|
||||
while (Marshal.ReadByte ((IntPtr)ev.Text.Text, len) != 0) {
|
||||
len++;
|
||||
}
|
||||
var buffer = new byte [len];
|
||||
Marshal.Copy ((IntPtr)ev.Text.Text, buffer, 0, len);
|
||||
text = System.Text.Encoding.UTF8.GetString (buffer);
|
||||
}
|
||||
if (text.Length == 0)
|
||||
continue;
|
||||
foreach (var c in text)
|
||||
{
|
||||
var key = KeyboardUtil.ToXna((int)c);
|
||||
_view.CallTextInput(c, key);
|
||||
}
|
||||
}
|
||||
else if (ev.Type == Sdl.EventType.WindowEvent)
|
||||
{
|
||||
if (ev.Window.WindowID == _view.Id)
|
||||
{
|
||||
if (ev.Window.EventID == Sdl.Window.EventId.Resized || ev.Window.EventID == Sdl.Window.EventId.SizeChanged)
|
||||
_view.ClientResize(ev.Window.Data1, ev.Window.Data2);
|
||||
else if (ev.Window.EventID == Sdl.Window.EventId.FocusGained)
|
||||
IsActive = true;
|
||||
else if (ev.Window.EventID == Sdl.Window.EventId.FocusLost)
|
||||
IsActive = false;
|
||||
else if (ev.Window.EventID == Sdl.Window.EventId.Moved)
|
||||
_view.Moved();
|
||||
else if (ev.Window.EventID == Sdl.Window.EventId.Close)
|
||||
_isExiting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void StartRunLoop()
|
||||
{
|
||||
throw new NotSupportedException("The desktop platform does not support asynchronous run loops");
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
Interlocked.Increment(ref _isExiting);
|
||||
}
|
||||
|
||||
public override bool BeforeUpdate(GameTime gameTime)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool BeforeDraw(GameTime gameTime)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void EnterFullScreen()
|
||||
{
|
||||
}
|
||||
|
||||
public override void ExitFullScreen()
|
||||
{
|
||||
}
|
||||
|
||||
public override void BeginScreenDeviceChange(bool willBeFullScreen)
|
||||
{
|
||||
_view.BeginScreenDeviceChange(willBeFullScreen);
|
||||
}
|
||||
|
||||
public override void EndScreenDeviceChange(string screenDeviceName, int clientWidth, int clientHeight)
|
||||
{
|
||||
_view.EndScreenDeviceChange(screenDeviceName, clientWidth, clientHeight);
|
||||
}
|
||||
|
||||
public override void Log(string message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
public override void Present()
|
||||
{
|
||||
if (Game.GraphicsDevice != null)
|
||||
Game.GraphicsDevice.Present();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (_view != null)
|
||||
{
|
||||
_view.Dispose();
|
||||
_view = null;
|
||||
|
||||
Joystick.CloseDevices();
|
||||
|
||||
Sdl.Quit();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
internal class SdlGameWindow : GameWindow, IDisposable
|
||||
{
|
||||
public override bool AllowUserResizing
|
||||
{
|
||||
get { return !IsBorderless && _resizable; }
|
||||
set
|
||||
{
|
||||
if (Sdl.Patch > 4)
|
||||
Sdl.Window.SetResizable(_handle, value);
|
||||
else
|
||||
throw new Exception("SDL 2.0.4 does not support changing resizable parameter of the window after it's already been created, please use a newer version of it.");
|
||||
|
||||
_resizable = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override Rectangle ClientBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
Sdl.Window.GetPosition(Handle, out x, out y);
|
||||
return new Rectangle(x, y, _width, _height);
|
||||
}
|
||||
}
|
||||
|
||||
public override Point Position
|
||||
{
|
||||
get
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
|
||||
if (!IsFullScreen)
|
||||
Sdl.Window.GetPosition(Handle, out x, out y);
|
||||
|
||||
return new Point(x, y);
|
||||
}
|
||||
set
|
||||
{
|
||||
Sdl.Window.SetPosition(Handle, value.X, value.Y);
|
||||
_wasMoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override DisplayOrientation CurrentOrientation
|
||||
{
|
||||
get { return DisplayOrientation.Default; }
|
||||
}
|
||||
|
||||
public override IntPtr Handle
|
||||
{
|
||||
get { return _handle; }
|
||||
}
|
||||
|
||||
#if WINDOWS
|
||||
public override IntPtr Hwnd
|
||||
{
|
||||
get { return sysWMInfo.window; }
|
||||
}
|
||||
#endif
|
||||
|
||||
public override string ScreenDeviceName
|
||||
{
|
||||
get { return _screenDeviceName; }
|
||||
}
|
||||
|
||||
public override bool IsBorderless
|
||||
{
|
||||
get { return _borderless; }
|
||||
set
|
||||
{
|
||||
Sdl.Window.SetBordered(_handle, value ? 0 : 1);
|
||||
_borderless = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameWindow Instance;
|
||||
public uint? Id;
|
||||
public bool IsFullScreen;
|
||||
|
||||
internal readonly Game _game;
|
||||
private IntPtr _handle, _icon;
|
||||
private Sdl.Window.SDL_SysWMinfo sysWMInfo;
|
||||
private bool _disposed;
|
||||
private bool _resizable, _borderless, _willBeFullScreen, _mouseVisible, _hardwareSwitch;
|
||||
private string _screenDeviceName;
|
||||
private int _width, _height;
|
||||
private bool _wasMoved, _supressMoved;
|
||||
|
||||
public SdlGameWindow(Game game)
|
||||
{
|
||||
_game = game;
|
||||
_screenDeviceName = "";
|
||||
|
||||
Instance = this;
|
||||
|
||||
_width = GraphicsDeviceManager.DefaultBackBufferWidth;
|
||||
_height = GraphicsDeviceManager.DefaultBackBufferHeight;
|
||||
|
||||
Sdl.SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0");
|
||||
Sdl.SetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1");
|
||||
|
||||
// when running NUnit tests entry assembly can be null
|
||||
if (Assembly.GetEntryAssembly() != null)
|
||||
{
|
||||
using (
|
||||
var stream =
|
||||
Assembly.GetEntryAssembly().GetManifestResourceStream(Assembly.GetEntryAssembly().EntryPoint.DeclaringType.Namespace + ".Icon.bmp") ??
|
||||
Assembly.GetEntryAssembly().GetManifestResourceStream("Icon.bmp") ??
|
||||
Assembly.GetExecutingAssembly().GetManifestResourceStream("MonoGame.bmp"))
|
||||
{
|
||||
if (stream != null)
|
||||
using (var br = new BinaryReader(stream))
|
||||
{
|
||||
try
|
||||
{
|
||||
var src = Sdl.RwFromMem(br.ReadBytes((int)stream.Length), (int)stream.Length);
|
||||
_icon = Sdl.LoadBMP_RW(src, 1);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_handle = Sdl.Window.Create("", 0, 0,
|
||||
GraphicsDeviceManager.DefaultBackBufferWidth, GraphicsDeviceManager.DefaultBackBufferHeight,
|
||||
Sdl.Window.State.Hidden);
|
||||
}
|
||||
|
||||
internal void CreateWindow()
|
||||
{
|
||||
var initflags =
|
||||
#if OPENGL
|
||||
Sdl.Window.State.OpenGL |
|
||||
#endif
|
||||
Sdl.Window.State.Hidden |
|
||||
Sdl.Window.State.InputFocus |
|
||||
Sdl.Window.State.MouseFocus;
|
||||
|
||||
if (_handle != IntPtr.Zero)
|
||||
Sdl.Window.Destroy(_handle);
|
||||
|
||||
var winx = Sdl.Window.PosCentered;
|
||||
var winy = Sdl.Window.PosCentered;
|
||||
|
||||
// if we are on Linux, start on the current screen
|
||||
if (CurrentPlatform.OS == OS.Linux)
|
||||
{
|
||||
winx |= GetMouseDisplay();
|
||||
winy |= GetMouseDisplay();
|
||||
}
|
||||
|
||||
_handle = Sdl.Window.Create(AssemblyHelper.GetDefaultWindowTitle(),
|
||||
winx, winy, _width, _height, initflags);
|
||||
|
||||
Id = Sdl.Window.GetWindowId(_handle);
|
||||
Sdl.Window.GetWindowWMInfo(_handle, ref sysWMInfo);
|
||||
|
||||
if (_icon != IntPtr.Zero)
|
||||
Sdl.Window.SetIcon(_handle, _icon);
|
||||
|
||||
Sdl.Window.SetBordered(_handle, _borderless ? 0 : 1);
|
||||
Sdl.Window.SetResizable(_handle, _resizable);
|
||||
|
||||
SetCursorVisible(_mouseVisible);
|
||||
}
|
||||
|
||||
~SdlGameWindow()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
private static int GetMouseDisplay()
|
||||
{
|
||||
var rect = new Sdl.Rectangle();
|
||||
|
||||
int x, y;
|
||||
Sdl.Mouse.GetGlobalState(out x, out y);
|
||||
|
||||
var displayCount = Sdl.Display.GetNumVideoDisplays();
|
||||
for (var i = 0; i < displayCount; i++)
|
||||
{
|
||||
Sdl.Display.GetBounds(i, out rect);
|
||||
|
||||
if (x >= rect.X && x < rect.X + rect.Width &&
|
||||
y >= rect.Y && y < rect.Y + rect.Height)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void SetCursorVisible(bool visible)
|
||||
{
|
||||
_mouseVisible = visible;
|
||||
Sdl.Mouse.ShowCursor(visible ? 1 : 0);
|
||||
}
|
||||
|
||||
public override void BeginScreenDeviceChange(bool willBeFullScreen)
|
||||
{
|
||||
_willBeFullScreen = willBeFullScreen;
|
||||
}
|
||||
|
||||
public override void EndScreenDeviceChange(string screenDeviceName, int clientWidth, int clientHeight)
|
||||
{
|
||||
_screenDeviceName = screenDeviceName;
|
||||
|
||||
var prevBounds = ClientBounds;
|
||||
|
||||
if (_willBeFullScreen != IsFullScreen || _hardwareSwitch != _game.graphicsDeviceManager.HardwareModeSwitch)
|
||||
{
|
||||
var fullscreenFlag = _game.graphicsDeviceManager.HardwareModeSwitch ? Sdl.Window.State.Fullscreen : Sdl.Window.State.FullscreenDesktop;
|
||||
Sdl.Window.SetFullscreen(Handle, (_willBeFullScreen) ? fullscreenFlag : 0);
|
||||
_borderless = _willBeFullScreen;
|
||||
Sdl.Window.SetBordered(Handle, _borderless ? 0 : 1);
|
||||
_hardwareSwitch = _game.graphicsDeviceManager.HardwareModeSwitch;
|
||||
}
|
||||
// If going to exclusive full-screen mode, force the window to minimize on focus loss (Windows only)
|
||||
if (CurrentPlatform.OS == OS.Windows)
|
||||
{
|
||||
Sdl.SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", _willBeFullScreen && _hardwareSwitch ? "1" : "0");
|
||||
}
|
||||
|
||||
var displayIndex = Sdl.Window.GetDisplayIndex(Handle);
|
||||
|
||||
Sdl.Rectangle displayRect;
|
||||
Sdl.Display.GetBounds(displayIndex, out displayRect);
|
||||
|
||||
if (!_willBeFullScreen || _game.graphicsDeviceManager.HardwareModeSwitch)
|
||||
{
|
||||
Sdl.Window.SetSize(Handle, clientWidth, clientHeight);
|
||||
_width = clientWidth;
|
||||
_height = clientHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Sdl.Window.SetSize(Handle, displayRect.Width, displayRect.Height);
|
||||
_width = displayRect.Width;
|
||||
_height = displayRect.Height;
|
||||
}
|
||||
|
||||
Sdl.Window.GetSize(Handle, out _width, out _height);
|
||||
|
||||
_game.GraphicsDevice.PresentationParameters.BackBufferWidth = _width;
|
||||
_game.GraphicsDevice.PresentationParameters.BackBufferHeight = _height;
|
||||
_game.GraphicsDevice.Viewport = new Viewport(0, 0, _width, _height);
|
||||
|
||||
OnClientSizeChanged();
|
||||
|
||||
int ignore, minx = 0, miny = 0;
|
||||
Sdl.Window.GetBorderSize(_handle, out miny, out minx, out ignore, out ignore);
|
||||
|
||||
var centerX = Math.Max(prevBounds.X + ((prevBounds.Width - clientWidth) / 2), minx);
|
||||
var centerY = Math.Max(prevBounds.Y + ((prevBounds.Height - clientHeight) / 2), miny);
|
||||
|
||||
if (IsFullScreen && !_willBeFullScreen)
|
||||
{
|
||||
// We need to get the display information again in case
|
||||
// the resolution of it was changed.
|
||||
Sdl.Display.GetBounds (displayIndex, out displayRect);
|
||||
|
||||
// This centering only occurs when exiting fullscreen
|
||||
// so it should center the window on the current display.
|
||||
centerX = displayRect.X + displayRect.Width / 2 - clientWidth / 2;
|
||||
centerY = displayRect.Y + displayRect.Height / 2 - clientHeight / 2;
|
||||
}
|
||||
|
||||
// If this window is resizable, there is a bug in SDL 2.0.4 where
|
||||
// after the window gets resized, window position information
|
||||
// becomes wrong (for me it always returned 10 8). Solution is
|
||||
// to not try and set the window position because it will be wrong.
|
||||
if ((Sdl.Patch > 4 || !AllowUserResizing) && !_wasMoved)
|
||||
Sdl.Window.SetPosition(Handle, centerX, centerY);
|
||||
|
||||
Sdl.Window.Show(Handle);
|
||||
Sdl.Window.Raise(Handle);
|
||||
|
||||
Sdl.Window.SetGrab(Handle, _willBeFullScreen && _hardwareSwitch);
|
||||
|
||||
if (IsFullScreen != _willBeFullScreen)
|
||||
OnClientSizeChanged();
|
||||
|
||||
IsFullScreen = _willBeFullScreen;
|
||||
|
||||
_supressMoved = true;
|
||||
}
|
||||
|
||||
internal void Moved()
|
||||
{
|
||||
if (_supressMoved)
|
||||
{
|
||||
_supressMoved = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_wasMoved = true;
|
||||
}
|
||||
|
||||
public void ClientResize(int width, int height)
|
||||
{
|
||||
// SDL reports many resize events even if the Size didn't change.
|
||||
// Only call the code below if it actually changed.
|
||||
if (_game.GraphicsDevice.PresentationParameters.BackBufferWidth == width &&
|
||||
_game.GraphicsDevice.PresentationParameters.BackBufferHeight == height) {
|
||||
return;
|
||||
}
|
||||
_game.GraphicsDevice.PresentationParameters.BackBufferWidth = width;
|
||||
_game.GraphicsDevice.PresentationParameters.BackBufferHeight = height;
|
||||
_game.GraphicsDevice.Viewport = new Viewport(0, 0, width, height);
|
||||
|
||||
Sdl.Window.GetSize(Handle, out _width, out _height);
|
||||
|
||||
OnClientSizeChanged();
|
||||
}
|
||||
|
||||
public void CallTextInput(char c, Keys key = Keys.None)
|
||||
{
|
||||
OnTextInput(this, new TextInputEventArgs(c, key));
|
||||
}
|
||||
|
||||
protected internal override void SetSupportedOrientations(DisplayOrientation orientations)
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
|
||||
protected override void SetTitle(string title)
|
||||
{
|
||||
Sdl.Window.SetTitle(_handle, title);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
Sdl.Window.Destroy(_handle);
|
||||
_handle = IntPtr.Zero;
|
||||
|
||||
if (_icon != IntPtr.Zero)
|
||||
Sdl.FreeSurface(_icon);
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user