Backends can now opt-in to automatic disposal of resources in the
UI thread.
This commit is contained in:
Lluis Sanchez 2013-06-25 13:18:17 +02:00
Родитель 6842df4ec2
Коммит 3cf1b0031e
23 изменённых файлов: 279 добавлений и 70 удалений

Просмотреть файл

@ -36,7 +36,7 @@ namespace Xwt.CairoBackend
return new Cairo.LinearGradient (x0, y0, x1, y1);
}
public override void DisposeLinear (object backend)
public override void Dispose (object backend)
{
((IDisposable)backend).Dispose ();
}
@ -46,11 +46,6 @@ namespace Xwt.CairoBackend
return new Cairo.RadialGradient (cx0, cy0, radius0, cx1, cy1, radius1);
}
public override void DisposeRadial (object backend)
{
((IDisposable)backend).Dispose ();
}
public override void AddColorStop (object backend, double position, Xwt.Drawing.Color color)
{
Cairo.Gradient g = (Cairo.Gradient) backend;

Просмотреть файл

@ -201,7 +201,7 @@ namespace Xwt.GtkBackend
return new Point (pos.X, pos.Y);
}
public override void DisposeBackend (object backend)
public override void Dispose (object backend)
{
var tl = (IDisposable) backend;
tl.Dispose ();

Просмотреть файл

@ -44,7 +44,7 @@ namespace Xwt.Mac
};
}
public override void DisposeLinear (object backend)
public override void Dispose (object backend)
{
}
@ -59,10 +59,6 @@ namespace Xwt.Mac
};
}
public override void DisposeRadial (object backend)
{
}
public override void AddColorStop (object backend, double position, Xwt.Drawing.Color color)
{
GradientInfo gr = (GradientInfo) backend;

Просмотреть файл

@ -205,7 +205,7 @@ namespace Xwt.Mac
return new Point (0,0);
}
public override void DisposeBackend (object backend)
public override void Dispose (object backend)
{
// nothing
}

Просмотреть файл

@ -47,7 +47,7 @@ namespace Xwt.WPFBackend
};
}
public override void DisposeLinear (object backend)
public override void Dispose (object backend)
{
}
@ -62,10 +62,6 @@ namespace Xwt.WPFBackend
};
}
public override void DisposeRadial (object backend)
{
}
public override void AddColorStop (object backend, double position, Color color)
{
((GradientBrush)backend).GradientStops.Add (new GradientStop (color.ToWpfColor (), position));

Просмотреть файл

@ -0,0 +1,41 @@
//
// ResourceBackendHandler.cs
//
// Author:
// Lluis Sanchez <lluis@xamarin.com>
//
// Copyright (c) 2013 Xamarin Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
namespace Xwt.Backends
{
public class DisposableResourceBackendHandler: BackendHandler
{
public virtual bool DisposeHandleOnUiThread {
get { return false; }
}
public virtual void Dispose (object backend)
{
}
}
}

Просмотреть файл

@ -29,7 +29,7 @@ using Xwt.Drawing;
namespace Xwt.Backends
{
public abstract class DrawingPathBackendHandler: BackendHandler
public abstract class DrawingPathBackendHandler: DisposableResourceBackendHandler
{
public abstract void Arc (object backend, double xc, double yc, double radius, double angle1, double angle2);
@ -58,8 +58,6 @@ namespace Xwt.Backends
public abstract void AppendPath (object backend, object otherBackend);
public abstract bool IsPointInFill (object backend, double x, double y);
public abstract void Dispose (object backend);
}
}

Просмотреть файл

@ -29,12 +29,10 @@ using Xwt.Drawing;
namespace Xwt.Backends
{
public abstract class GradientBackendHandler: BackendHandler
public abstract class GradientBackendHandler: DisposableResourceBackendHandler
{
public abstract object CreateLinear (double x0, double y0, double x1, double y1);
public abstract void DisposeLinear (object backend);
public abstract object CreateRadial (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1);
public abstract void DisposeRadial (object backend);
public abstract void AddColorStop (object backend, double position, Color color);
}
}

Просмотреть файл

@ -32,17 +32,13 @@ using System.Collections.Generic;
namespace Xwt.Backends
{
public abstract class ImageBackendHandler: BackendHandler
public abstract class ImageBackendHandler: DisposableResourceBackendHandler
{
public virtual object CreateBackend ()
{
throw new NotSupportedException ();
}
public virtual void Dispose (object backend)
{
}
public virtual object LoadFromResource (Assembly asm, string name)
{
using (var s = asm.GetManifestResourceStream (name)) {

Просмотреть файл

@ -28,12 +28,11 @@ using Xwt.Drawing;
namespace Xwt.Backends
{
public abstract class ImageBuilderBackendHandler: BackendHandler
public abstract class ImageBuilderBackendHandler: DisposableResourceBackendHandler
{
public abstract object CreateImageBuilder (int width, int height, ImageFormat format);
public abstract object CreateContext (object backend);
public abstract object CreateImage (object backend);
public abstract void Dispose (object backend);
}
}

Просмотреть файл

@ -27,10 +27,9 @@ using System;
namespace Xwt.Backends
{
public abstract class ImagePatternBackendHandler: BackendHandler
public abstract class ImagePatternBackendHandler: DisposableResourceBackendHandler
{
public abstract object Create (ImageDescription img);
public abstract void Dispose (object backend);
}
}

Просмотреть файл

@ -0,0 +1,103 @@
//
// ResourceManager.cs
//
// Author:
// Lluis Sanchez <lluis@xamarin.com>
//
// Copyright (c) 2013 Xamarin Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
namespace Xwt.Backends
{
static class ResourceManager
{
static bool finalized;
static Dictionary<object,Action<object>> resources = new Dictionary<object,Action<object>> ();
static Dictionary<object,Action<object>> freedResources = new Dictionary<object,Action<object>> ();
public static void RegisterResource (object res, Action<object> disposeCallback = null)
{
if (finalized)
return;
lock (resources)
resources [res] = disposeCallback;
}
public static bool FreeResource (object res)
{
if (finalized || res == null)
return true;
lock (resources) {
Action<object> disposer;
if (!resources.TryGetValue (res, out disposer))
return false;
resources.Remove (res);
if (System.Threading.Thread.CurrentThread == Application.UIThread) {
DisposeResource (res, disposer);
} else {
lock (freedResources) {
if (freedResources.Count == 0)
Application.Invoke (DisposeResources);
freedResources [res] = disposer;
}
}
return true;
}
}
static void DisposeResource (object res, Action<object> disposer)
{
try {
if (disposer != null)
disposer (res);
else if (res is IDisposable)
((IDisposable)res).Dispose ();
} catch (Exception ex) {
Application.NotifyException (ex);
}
}
internal static void DisposeResources ()
{
lock (freedResources) {
if (finalized)
return;
foreach (var r in freedResources) {
DisposeResource (r.Key, r.Value);
}
freedResources.Clear ();
}
}
internal static void Dispose ()
{
lock (freedResources) {
DisposeResources ();
finalized = true;
}
}
}
}

Просмотреть файл

@ -31,7 +31,7 @@ using System.Collections.Generic;
namespace Xwt.Backends
{
public abstract class TextLayoutBackendHandler: BackendHandler
public abstract class TextLayoutBackendHandler: DisposableResourceBackendHandler
{
public abstract object Create ();
@ -43,7 +43,6 @@ namespace Xwt.Backends
public abstract Size GetSize (object backend);
public abstract int GetIndexFromCoordinates (object backend, double x, double y);
public abstract Point GetCoordinateFromIndex (object backend, int index);
public abstract void DisposeBackend (object backend);
public abstract void AddAttribute (object backend, TextAttribute attribute);
public abstract void ClearAttributes (object backend);

Просмотреть файл

@ -36,11 +36,36 @@ namespace Xwt.Drawing
{
handler = Toolkit.CurrentEngine.VectorImageRecorderContextHandler;
Backend = handler.CreatePath ();
Init ();
}
internal DrawingPath (object backend, Toolkit toolkit, DrawingPathBackendHandler h): base (backend, toolkit)
{
handler = h;
Init ();
}
void Init ()
{
if (handler.DisposeHandleOnUiThread)
ResourceManager.RegisterResource (Backend, handler.Dispose);
else
GC.SuppressFinalize (this);
}
public void Dispose ()
{
if (handler.DisposeHandleOnUiThread) {
GC.SuppressFinalize (this);
ResourceManager.FreeResource (Backend);
}
else
handler.Dispose (Backend);
}
~DrawingPath ()
{
ResourceManager.FreeResource (Backend);
}
/// <summary>
@ -318,11 +343,6 @@ namespace Xwt.Drawing
{
return handler.IsPointInFill (Backend, x, y);
}
public void Dispose ()
{
handler.Dispose (Backend);
}
}
}

Просмотреть файл

@ -488,6 +488,9 @@ namespace Xwt.Drawing
{
this.backend = backend;
this.toolkit = toolkit;
if (toolkit.ImageBackendHandler.DisposeHandleOnUiThread)
ResourceManager.RegisterResource (backend, toolkit.ImageBackendHandler.Dispose);
}
public void AddReference ()
@ -497,8 +500,15 @@ namespace Xwt.Drawing
public void ReleaseReference (bool disposing)
{
if (System.Threading.Interlocked.Decrement (ref referenceCount) == 0 && disposing)
toolkit.ImageBackendHandler.Dispose (backend);
if (System.Threading.Interlocked.Decrement (ref referenceCount) == 0) {
if (disposing) {
if (toolkit.ImageBackendHandler.DisposeHandleOnUiThread)
ResourceManager.FreeResource (backend);
else
toolkit.ImageBackendHandler.Dispose (backend);
} else
ResourceManager.FreeResource (backend);
}
}
}
}

Просмотреть файл

@ -33,14 +33,8 @@ namespace Xwt.Drawing
{
public ImagePattern (Image image)
{
Backend = ToolkitEngine.ImagePatternBackendHandler.Create (image != null ? image.ImageDescription : ImageDescription.Null);
SetBackend (ToolkitEngine.ImagePatternBackendHandler, ToolkitEngine.ImagePatternBackendHandler.Create (image != null ? image.ImageDescription : ImageDescription.Null));
}
public override void Dispose ()
{
ToolkitEngine.ImagePatternBackendHandler.Dispose (Backend);
}
}
}

Просмотреть файл

@ -33,12 +33,7 @@ namespace Xwt.Drawing
{
public LinearGradient (double xStart, double yStart, double xEnd, double yEnd)
{
Backend = ToolkitEngine.GradientBackendHandler.CreateLinear (xStart, yStart, xEnd, yEnd);
}
public override void Dispose ()
{
ToolkitEngine.GradientBackendHandler.DisposeLinear (Backend);
SetBackend (ToolkitEngine.GradientBackendHandler, ToolkitEngine.GradientBackendHandler.CreateLinear (xStart, yStart, xEnd, yEnd));
}
}
}

Просмотреть файл

@ -25,16 +25,41 @@
// THE SOFTWARE.
using System;
using Xwt.Backends;
namespace Xwt.Drawing
{
public abstract class Pattern: XwtObject, IDisposable
{
DisposableResourceBackendHandler handler;
internal Pattern ()
{
}
public abstract void Dispose ();
internal void SetBackend (DisposableResourceBackendHandler handler, object backend)
{
Backend = backend;
this.handler = handler;
if (handler.DisposeHandleOnUiThread)
ResourceManager.RegisterResource (backend, handler.Dispose);
else
GC.SuppressFinalize (this);
}
~Pattern ()
{
ResourceManager.FreeResource (Backend);
}
public void Dispose ()
{
if (handler.DisposeHandleOnUiThread) {
GC.SuppressFinalize (this);
ResourceManager.FreeResource (Backend);
} else
handler.Dispose (Backend);
}
}
}

Просмотреть файл

@ -33,12 +33,7 @@ namespace Xwt.Drawing
{
public RadialGradient (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1)
{
Backend = ToolkitEngine.GradientBackendHandler.CreateRadial (cx0, cy0, radius0, cx1, cy1, radius1);
}
public override void Dispose ()
{
ToolkitEngine.GradientBackendHandler.DisposeRadial (Backend);
SetBackend (ToolkitEngine.GradientBackendHandler, ToolkitEngine.GradientBackendHandler.CreateRadial (cx0, cy0, radius0, cx1, cy1, radius1));
}
}
}

Просмотреть файл

@ -48,6 +48,7 @@ namespace Xwt.Drawing
handler = ToolkitEngine.TextLayoutBackendHandler;
Backend = handler.Create ();
Font = Font.SystemFont;
Setup ();
}
public TextLayout (Canvas canvas)
@ -56,6 +57,7 @@ namespace Xwt.Drawing
handler = ToolkitEngine.TextLayoutBackendHandler;
Backend = handler.Create ();
Font = canvas.Font;
Setup ();
}
internal TextLayout (Toolkit tk)
@ -63,6 +65,29 @@ namespace Xwt.Drawing
ToolkitEngine = tk;
handler = ToolkitEngine.TextLayoutBackendHandler;
Backend = handler.Create ();
Setup ();
}
void Setup ()
{
if (handler.DisposeHandleOnUiThread)
ResourceManager.RegisterResource (Backend, handler.Dispose);
else
GC.SuppressFinalize (this);
}
public void Dispose ()
{
if (handler.DisposeHandleOnUiThread) {
GC.SuppressFinalize (this);
ResourceManager.FreeResource (Backend);
} else
handler.Dispose (Backend);
}
~TextLayout ()
{
ResourceManager.FreeResource (Backend);
}
internal TextLayoutData GetData ()
@ -255,11 +280,6 @@ namespace Xwt.Drawing
{
AddAttribute (new StrikethroughTextAttribute () { StartIndex = startIndex, Count = count});
}
public void Dispose ()
{
handler.DisposeBackend (Backend);
}
}
public enum TextTrimming {

Просмотреть файл

@ -116,14 +116,31 @@ namespace Xwt.Drawing
public override object CreateNativeBackend ()
{
imageBuilder = toolkit.ImageBuilderBackendHandler.CreateImageBuilder ((int)width, (int)height, ImageFormat.ARGB32);
if (toolkit.ImageBuilderBackendHandler.DisposeHandleOnUiThread)
ResourceManager.RegisterResource (imageBuilder);
else
GC.SuppressFinalize (this);
return toolkit.ImageBuilderBackendHandler.CreateContext (imageBuilder);
}
~VectorContextBackend ()
{
if (imageBuilder != null)
ResourceManager.FreeResource (imageBuilder);
}
public override void Dispose ()
{
base.Dispose ();
if (imageBuilder != null)
toolkit.ImageBuilderBackendHandler.Dispose (imageBuilder);
if (imageBuilder != null) {
if (toolkit.ImageBuilderBackendHandler.DisposeHandleOnUiThread) {
GC.SuppressFinalize (this);
ResourceManager.FreeResource (imageBuilder);
}
else
toolkit.ImageBuilderBackendHandler.Dispose (imageBuilder);
}
}
}

Просмотреть файл

@ -414,6 +414,8 @@
<Compile Include="Xwt\TableCalc.cs" />
<Compile Include="Xwt\VSlider.cs" />
<Compile Include="Xwt\HSlider.cs" />
<Compile Include="Xwt.Backends\ResourceManager.cs" />
<Compile Include="Xwt.Backends\DisposableResourceBackendHandler.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup />

Просмотреть файл

@ -102,7 +102,18 @@ namespace Xwt
engine.ExitApplication ();
});
}
/// <summary>
/// <summary>
/// Releases all resource used by the application
/// </summary>
/// <remarks>This method must be called before the application process ends</remarks>
public static void Dispose ()
{
ResourceManager.Dispose ();
}
/// <summary>
/// Invokes an action in the GUI thread
/// </summary>
/// <param name='action'>