Browse Source

Merge branch 'master' into angle-display

# Conflicts:
#	src/Avalonia.OpenGL/EglDisplay.cs
pull/4624/head
Dan Walmsley 6 years ago
parent
commit
d6c7903ba2
  1. 7
      azure-pipelines.yml
  2. 10
      src/Avalonia.Controls/ColumnDefinitions.cs
  3. 24
      src/Avalonia.Controls/Repeater/ItemsRepeater.cs
  4. 51
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs
  5. 4
      src/Avalonia.Layout/Layoutable.cs
  6. 2
      src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
  7. 5
      src/Avalonia.OpenGL/AngleOptions.cs
  8. 3
      src/Avalonia.OpenGL/EglConsts.cs
  9. 6
      src/Skia/Avalonia.Skia/SkiaOptions.cs
  10. 2
      src/Windows/Avalonia.Win32/WindowImpl.cs
  11. 31
      tests/Avalonia.LeakTests/ControlTests.cs

7
azure-pipelines.yml

@ -56,13 +56,6 @@ jobs:
xcodeVersion: '10' # Options: 8, 9, default, specifyPath xcodeVersion: '10' # Options: 8, 9, default, specifyPath
args: '-derivedDataPath ./' args: '-derivedDataPath ./'
- task: CmdLine@2
displayName: 'Install CastXML'
inputs:
script: |
brew update
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8a004a91a7fcd3f6620d5b01b6541ff0a640ffba/Formula/castxml.rb
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Nuke' displayName: 'Install Nuke'
inputs: inputs:

10
src/Avalonia.Controls/ColumnDefinitions.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Text;
using Avalonia.Collections; using Avalonia.Collections;
namespace Avalonia.Controls namespace Avalonia.Controls
@ -13,7 +14,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ColumnDefinitions"/> class. /// Initializes a new instance of the <see cref="ColumnDefinitions"/> class.
/// </summary> /// </summary>
public ColumnDefinitions() : base () public ColumnDefinitions()
{ {
} }
@ -27,6 +28,11 @@ namespace Avalonia.Controls
AddRange(GridLength.ParseLengths(s).Select(x => new ColumnDefinition(x))); AddRange(GridLength.ParseLengths(s).Select(x => new ColumnDefinition(x)));
} }
public override string ToString()
{
return string.Join(",", this.Select(x => x.Width));
}
/// <summary> /// <summary>
/// Parses a string representation of column definitions collection. /// Parses a string representation of column definitions collection.
/// </summary> /// </summary>
@ -34,4 +40,4 @@ namespace Avalonia.Controls
/// <returns>The <see cref="ColumnDefinitions"/>.</returns> /// <returns>The <see cref="ColumnDefinitions"/>.</returns>
public static ColumnDefinitions Parse(string s) => new ColumnDefinitions(s); public static ColumnDefinitions Parse(string s) => new ColumnDefinitions(s);
} }
} }

24
src/Avalonia.Controls/Repeater/ItemsRepeater.cs

@ -7,10 +7,10 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Specialized; using System.Collections.Specialized;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.Utilities;
using Avalonia.VisualTree; using Avalonia.VisualTree;
namespace Avalonia.Controls namespace Avalonia.Controls
@ -681,8 +681,15 @@ namespace Avalonia.Controls
if (oldValue != null) if (oldValue != null)
{ {
oldValue.UninitializeForContext(LayoutContext); oldValue.UninitializeForContext(LayoutContext);
oldValue.MeasureInvalidated -= InvalidateMeasureForLayout;
oldValue.ArrangeInvalidated -= InvalidateArrangeForLayout; WeakEventHandlerManager.Unsubscribe<EventArgs, ItemsRepeater>(
oldValue,
nameof(AttachedLayout.MeasureInvalidated),
InvalidateMeasureForLayout);
WeakEventHandlerManager.Unsubscribe<EventArgs, ItemsRepeater>(
oldValue,
nameof(AttachedLayout.ArrangeInvalidated),
InvalidateArrangeForLayout);
// Walk through all the elements and make sure they are cleared // Walk through all the elements and make sure they are cleared
foreach (var element in Children) foreach (var element in Children)
@ -699,8 +706,15 @@ namespace Avalonia.Controls
if (newValue != null) if (newValue != null)
{ {
newValue.InitializeForContext(LayoutContext); newValue.InitializeForContext(LayoutContext);
newValue.MeasureInvalidated += InvalidateMeasureForLayout;
newValue.ArrangeInvalidated += InvalidateArrangeForLayout; WeakEventHandlerManager.Subscribe<AttachedLayout, EventArgs, ItemsRepeater>(
newValue,
nameof(AttachedLayout.MeasureInvalidated),
InvalidateMeasureForLayout);
WeakEventHandlerManager.Subscribe<AttachedLayout, EventArgs, ItemsRepeater>(
newValue,
nameof(AttachedLayout.ArrangeInvalidated),
InvalidateArrangeForLayout);
} }
bool isVirtualizingLayout = newValue != null && newValue is VirtualizingLayout; bool isVirtualizingLayout = newValue != null && newValue is VirtualizingLayout;

51
src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs

@ -8,8 +8,8 @@ namespace Avalonia.Diagnostics.ViewModels
internal abstract class PropertyViewModel : ViewModelBase internal abstract class PropertyViewModel : ViewModelBase
{ {
private const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static; private const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
private static readonly Type[] StringParameter = new[] { typeof(string) }; private static readonly Type[] StringParameter = { typeof(string) };
private static readonly Type[] StringIFormatProviderParameters = new[] { typeof(string), typeof(IFormatProvider) }; private static readonly Type[] StringIFormatProviderParameters = { typeof(string), typeof(IFormatProvider) };
public abstract object Key { get; } public abstract object Key { get; }
public abstract string Name { get; } public abstract string Name { get; }
@ -26,35 +26,46 @@ namespace Avalonia.Diagnostics.ViewModels
} }
var converter = TypeDescriptor.GetConverter(value); var converter = TypeDescriptor.GetConverter(value);
return converter?.ConvertToString(value) ?? value.ToString();
//CollectionConverter does not deliver any important information. It just displays "(Collection)".
if (!converter.CanConvertTo(typeof(string)) ||
converter.GetType() == typeof(CollectionConverter))
{
return value.ToString();
}
return converter.ConvertToString(value);
} }
protected static object ConvertFromString(string s, Type targetType) private static object InvokeParse(string s, Type targetType)
{ {
var converter = TypeDescriptor.GetConverter(targetType); var method = targetType.GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null);
if (converter != null && converter.CanConvertFrom(typeof(string))) if (method != null)
{ {
return converter.ConvertFrom(null, CultureInfo.InvariantCulture, s); return method.Invoke(null, new object[] { s, CultureInfo.InvariantCulture });
} }
else
method = targetType.GetMethod("Parse", PublicStatic, null, StringParameter, null);
if (method != null)
{ {
var method = targetType.GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null); return method.Invoke(null, new object[] { s });
}
if (method != null) throw new InvalidCastException("Unable to convert value.");
{ }
return method.Invoke(null, new object[] { s, CultureInfo.InvariantCulture });
}
method = targetType.GetMethod("Parse", PublicStatic, null, StringParameter, null); protected static object ConvertFromString(string s, Type targetType)
{
var converter = TypeDescriptor.GetConverter(targetType);
if (method != null) if (converter.CanConvertFrom(typeof(string)))
{ {
return method.Invoke(null, new object[] { s }); return converter.ConvertFrom(null, CultureInfo.InvariantCulture, s);
}
} }
throw new InvalidCastException("Unable to convert value."); return InvokeParse(s, targetType);
} }
} }
} }

4
src/Avalonia.Layout/Layoutable.cs

@ -758,8 +758,6 @@ namespace Avalonia.Layout
protected override void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) protected override void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e)
{ {
base.OnDetachedFromVisualTreeCore(e);
if (e.Root is ILayoutRoot r) if (e.Root is ILayoutRoot r)
{ {
if (_layoutUpdated is object) if (_layoutUpdated is object)
@ -772,6 +770,8 @@ namespace Avalonia.Layout
r.LayoutManager.UnregisterEffectiveViewportListener(this); r.LayoutManager.UnregisterEffectiveViewportListener(this);
} }
} }
base.OnDetachedFromVisualTreeCore(e);
} }
/// <summary> /// <summary>

2
src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs

@ -25,7 +25,7 @@ namespace Avalonia.OpenGL.Angle
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll"); throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll");
var allowedApis = AvaloniaLocator.Current.GetService<AngleOptions>()?.AllowedPlatformApis var allowedApis = AvaloniaLocator.Current.GetService<AngleOptions>()?.AllowedPlatformApis
?? new List<AngleOptions.PlatformApi> {AngleOptions.PlatformApi.DirectX9}; ?? new [] { AngleOptions.PlatformApi.DirectX11, AngleOptions.PlatformApi.DirectX9 };
foreach (var platformApi in allowedApis) foreach (var platformApi in allowedApis)
{ {

5
src/Avalonia.OpenGL/AngleOptions.cs

@ -10,9 +10,6 @@ namespace Avalonia.OpenGL
DirectX11 DirectX11
} }
public List<PlatformApi> AllowedPlatformApis = new List<PlatformApi> public IList<PlatformApi> AllowedPlatformApis { get; set; } = null;
{
PlatformApi.DirectX9
};
} }
} }

3
src/Avalonia.OpenGL/EglConsts.cs

@ -186,6 +186,9 @@ namespace Avalonia.OpenGL
public const int EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206; public const int EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A; public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE = 0x345E; public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE = 0x345E;
public const int EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE = 0x320D;
public const int EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE = 0x320E;
//EGL_ANGLE_platform_angle_d3d //EGL_ANGLE_platform_angle_d3d
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209; public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209;

6
src/Skia/Avalonia.Skia/SkiaOptions.cs

@ -16,6 +16,10 @@ namespace Avalonia
/// <summary> /// <summary>
/// The maximum number of bytes for video memory to store textures and resources. /// The maximum number of bytes for video memory to store textures and resources.
/// </summary> /// </summary>
public long? MaxGpuResourceSizeBytes { get; set; } /// <remarks>
/// This is set by default to the recommended value for Avalonia.
/// Setting this to null will give you the default Skia value.
/// </remarks>
public long? MaxGpuResourceSizeBytes { get; set; } = 1024 * 600 * 4 * 12; // ~28mb 12x 1024 x 600 textures.
} }
} }

2
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -1007,10 +1007,12 @@ namespace Avalonia.Win32
if (newProperties.IsResizable) if (newProperties.IsResizable)
{ {
style |= WindowStyles.WS_SIZEFRAME; style |= WindowStyles.WS_SIZEFRAME;
style |= WindowStyles.WS_MAXIMIZEBOX;
} }
else else
{ {
style &= ~WindowStyles.WS_SIZEFRAME; style &= ~WindowStyles.WS_SIZEFRAME;
style &= ~WindowStyles.WS_MAXIMIZEBOX;
} }
SetStyle(style); SetStyle(style);

31
tests/Avalonia.LeakTests/ControlTests.cs

@ -552,6 +552,37 @@ namespace Avalonia.LeakTests
} }
} }
[Fact]
public void ItemsRepeater_Is_Freed()
{
using (Start())
{
Func<Window> run = () =>
{
var window = new Window
{
Content = new ItemsRepeater(),
};
window.Show();
window.LayoutManager.ExecuteInitialLayoutPass();
Assert.IsType<ItemsRepeater>(window.Presenter.Child);
window.Content = null;
window.LayoutManager.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
return window;
};
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<ItemsRepeater>()).ObjectsCount));
}
}
private IDisposable Start() private IDisposable Start()
{ {
return UnitTestApplication.Start(TestServices.StyledWindow.With( return UnitTestApplication.Start(TestServices.StyledWindow.With(

Loading…
Cancel
Save