Browse Source

Merge branch 'master' into patch-1

pull/5377/head
Steven Kirk 5 years ago
committed by GitHub
parent
commit
eec7f4c8df
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .ncrunch/Avalonia.MicroCom.v3.ncrunchproject
  2. 3
      .ncrunch/Avalonia.Win32.v3.ncrunchproject
  3. 1
      .ncrunch/Direct3DInteropSample.v3.ncrunchproject
  4. 10
      native/Avalonia.Native/src/OSX/Screens.mm
  5. 1
      native/Avalonia.Native/src/OSX/common.h
  6. 10
      native/Avalonia.Native/src/OSX/main.mm
  7. 19
      native/Avalonia.Native/src/OSX/window.mm
  8. 16
      samples/ControlCatalog/Pages/ScreenPage.cs
  9. 13
      src/Avalonia.Controls/Button.cs
  10. 13
      src/Avalonia.Controls/MenuItem.cs
  11. 2
      src/Avalonia.Controls/Utils/AncestorFinder.cs
  12. 2
      src/Avalonia.Native/WindowImplBase.cs
  13. 5
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs
  14. 115
      tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs
  15. 7
      tests/Avalonia.Markup.Xaml.UnitTests/Converters/PointsListTypeConverterTests.cs
  16. 31
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/IgnoredDirectivesTests.cs

4
.ncrunch/Avalonia.MicroCom.v3.ncrunchproject

@ -1,5 +1,3 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
<Settings />
</ProjectConfiguration>

3
.ncrunch/Avalonia.Win32.v3.ncrunchproject

@ -1,5 +1,8 @@
<ProjectConfiguration>
<Settings>
<AdditionalFilesToIncludeForProject>
<Value>..\..\tools\MicroComGenerator\bin\Debug\netcoreapp3.1\**.*</Value>
</AdditionalFilesToIncludeForProject>
<HiddenComponentWarnings>
<Value>MissingOrIgnoredProjectReference</Value>
</HiddenComponentWarnings>

1
.ncrunch/Direct3DInteropSample.v3.ncrunchproject

@ -3,6 +3,7 @@
<HiddenComponentWarnings>
<Value>MissingOrIgnoredProjectReference</Value>
</HiddenComponentWarnings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
<PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
</Settings>
</ProjectConfiguration>

10
native/Avalonia.Native/src/OSX/Screens.mm

@ -5,12 +5,6 @@ class Screens : public ComSingleObject<IAvnScreens, &IID_IAvnScreens>
public:
FORWARD_IUNKNOWN()
private:
CGFloat PrimaryDisplayHeight()
{
return NSMaxY([[[NSScreen screens] firstObject] frame]);
}
public:
virtual HRESULT GetScreenCount (int* ret) override
{
@ -36,12 +30,12 @@ public:
ret->Bounds.Height = [screen frame].size.height;
ret->Bounds.Width = [screen frame].size.width;
ret->Bounds.X = [screen frame].origin.x;
ret->Bounds.Y = PrimaryDisplayHeight() - [screen frame].origin.y - ret->Bounds.Height;
ret->Bounds.Y = ConvertPointY(ToAvnPoint([screen frame].origin)).Y - ret->Bounds.Height;
ret->WorkingArea.Height = [screen visibleFrame].size.height;
ret->WorkingArea.Width = [screen visibleFrame].size.width;
ret->WorkingArea.X = [screen visibleFrame].origin.x;
ret->WorkingArea.Y = ret->Bounds.Height - [screen visibleFrame].origin.y - ret->WorkingArea.Height;
ret->WorkingArea.Y = ConvertPointY(ToAvnPoint([screen visibleFrame].origin)).Y - ret->WorkingArea.Height;
ret->PixelDensity = [screen backingScaleFactor];

1
native/Avalonia.Native/src/OSX/common.h

@ -34,6 +34,7 @@ extern NSApplicationActivationPolicy AvnDesiredActivationPolicy;
extern NSPoint ToNSPoint (AvnPoint p);
extern AvnPoint ToAvnPoint (NSPoint p);
extern AvnPoint ConvertPointY (AvnPoint p);
extern CGFloat PrimaryDisplayHeight();
extern NSSize ToNSSize (AvnSize s);
#ifdef DEBUG
#define NSDebugLog(...) NSLog(__VA_ARGS__)

10
native/Avalonia.Native/src/OSX/main.mm

@ -299,10 +299,14 @@ AvnPoint ToAvnPoint (NSPoint p)
AvnPoint ConvertPointY (AvnPoint p)
{
auto sw = [NSScreen.screens objectAtIndex:0].frame;
auto primaryDisplayHeight = NSMaxY([[[NSScreen screens] firstObject] frame]);
auto t = MAX(sw.origin.y, sw.origin.y + sw.size.height);
p.Y = t - p.Y;
p.Y = primaryDisplayHeight - p.Y;
return p;
}
CGFloat PrimaryDisplayHeight()
{
return NSMaxY([[[NSScreen screens] firstObject] frame]);
}

19
native/Avalonia.Native/src/OSX/window.mm

@ -1391,17 +1391,20 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[super viewDidChangeBackingProperties];
}
- (bool) ignoreUserInput
- (bool) ignoreUserInput:(bool)trigerInputWhenDisabled
{
auto parentWindow = objc_cast<AvnWindow>([self window]);
if(parentWindow == nil || ![parentWindow shouldTryToHandleEvents])
{
auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
if(window != nullptr)
if(trigerInputWhenDisabled)
{
window->WindowEvents->GotInputWhenDisabled();
auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
if(window != nullptr)
{
window->WindowEvents->GotInputWhenDisabled();
}
}
return TRUE;
@ -1412,7 +1415,9 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
- (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
{
if([self ignoreUserInput])
bool triggerInputWhenDisabled = type != Move;
if([self ignoreUserInput: triggerInputWhenDisabled])
{
return;
}
@ -1578,7 +1583,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
{
if([self ignoreUserInput])
if([self ignoreUserInput: false])
{
return;
}

16
samples/ControlCatalog/Pages/ScreenPage.cs

@ -29,7 +29,7 @@ namespace ControlCatalog.Pages
var screens = w.Screens.All;
var scaling = ((IRenderRoot)w).RenderScaling;
var drawBrush = Brushes.Green;
var drawBrush = Brushes.Black;
Pen p = new Pen(drawBrush);
if (screens != null)
foreach (Screen screen in screens)
@ -45,18 +45,16 @@ namespace ControlCatalog.Pages
screen.Bounds.Height / 10f);
Rect workingAreaRect = new Rect(screen.WorkingArea.X / 10f + Math.Abs(_leftMost), screen.WorkingArea.Y / 10f, screen.WorkingArea.Width / 10f,
screen.WorkingArea.Height / 10f);
context.DrawRectangle(p, boundsRect);
context.DrawRectangle(p, workingAreaRect);
FormattedText text = new FormattedText()
{
Typeface = Typeface.Default
};
text.Text = $"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}";
var text = new FormattedText() { Typeface = new Typeface("Arial"), FontSize = 18 };
text.Text = $"Bounds: {screen.Bounds.TopLeft} {screen.Bounds.Width}:{screen.Bounds.Height}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height), text);
text.Text = $"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
text.Text = $"WorkArea: {screen.WorkingArea.TopLeft} {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text);
text.Text = $"Scaling: {screen.PixelDensity * 100}%";
@ -69,7 +67,7 @@ namespace ControlCatalog.Pages
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 80), text);
}
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10, w.Bounds.Width / 10, w.Bounds.Height / 10));
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10f, w.Bounds.Width / 10, w.Bounds.Height / 10));
}
}
}

13
src/Avalonia.Controls/Button.cs

@ -80,6 +80,7 @@ namespace Avalonia.Controls
private ICommand _command;
private bool _commandCanExecute = true;
private KeyGesture _hotkey;
/// <summary>
/// Initializes static members of the <see cref="Button"/> class.
@ -207,6 +208,11 @@ namespace Avalonia.Controls
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
if (_hotkey != null) // Control attached again, set Hotkey to create a hotkey manager for this control
{
HotKey = _hotkey;
}
base.OnAttachedToLogicalTree(e);
if (Command != null)
@ -217,6 +223,13 @@ namespace Avalonia.Controls
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
// This will cause the hotkey manager to dispose the observer and the reference to this control
if (HotKey != null)
{
_hotkey = HotKey;
HotKey = null;
}
base.OnDetachedFromLogicalTree(e);
if (Command != null)

13
src/Avalonia.Controls/MenuItem.cs

@ -102,6 +102,7 @@ namespace Avalonia.Controls
private ICommand? _command;
private bool _commandCanExecute = true;
private Popup? _popup;
private KeyGesture _hotkey;
/// <summary>
/// Initializes static members of the <see cref="MenuItem"/> class.
@ -337,6 +338,11 @@ namespace Avalonia.Controls
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
if (_hotkey != null) // Control attached again, set Hotkey to create a hotkey manager for this control
{
HotKey = _hotkey;
}
base.OnAttachedToLogicalTree(e);
if (Command != null)
@ -347,6 +353,13 @@ namespace Avalonia.Controls
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
// This will cause the hotkey manager to dispose the observer and the reference to this control
if (HotKey != null)
{
_hotkey = HotKey;
HotKey = null;
}
base.OnDetachedFromLogicalTree(e);
if (Command != null)

2
src/Avalonia.Controls/Utils/AncestorFinder.cs

@ -47,6 +47,8 @@ namespace Avalonia.Controls.Utils
public void Dispose()
{
_child?.Dispose();
_subject.Dispose();
_disposable.Dispose();
}
}

2
src/Avalonia.Native/WindowImplBase.cs

@ -383,7 +383,7 @@ namespace Avalonia.Native
_native.BeginMoveDrag();
}
public Size MaxAutoSizeHint => Screen.AllScreens.Select(s => s.Bounds.Size.ToSize(s.PixelDensity))
public Size MaxAutoSizeHint => Screen.AllScreens.Select(s => s.Bounds.Size.ToSize(1))
.OrderByDescending(x => x.Width + x.Height).FirstOrDefault();
public void SetTopmost(bool value)

5
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs

@ -15,7 +15,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
if (d.Namespace == XamlNamespaces.Xaml2006)
{
if (d.Name == "Precompile" || d.Name == "Class")
if (d.Name == "Precompile" ||
d.Name == "Class" ||
d.Name == "FieldModifier" ||
d.Name == "ClassModifier")
no.Children.Remove(d);
}
}

115
tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs

@ -1,9 +1,14 @@
using Moq;
using System;
using System.Collections.Generic;
using Avalonia.Collections;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Moq;
using Xunit;
using System;
using Avalonia.Input.Raw;
@ -53,7 +58,115 @@ namespace Avalonia.Controls.UnitTests.Utils
HotKeyManager.SetHotKey(button, null);
Assert.Empty(tl.KeyBindings);
}
}
[Fact]
public void HotKeyManager_Should_Release_Reference_When_Control_Detached()
{
using (AvaloniaLocator.EnterScope())
{
var styler = new Mock<Styler>();
AvaloniaLocator.CurrentMutable
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
.Bind<IStyler>().ToConstant(styler.Object);
var gesture1 = new KeyGesture(Key.A, KeyModifiers.Control);
WeakReference reference = null;
var tl = new Window();
new Action(() =>
{
var button = new Button();
reference = new WeakReference(button, true);
tl.Content = button;
tl.Template = CreateWindowTemplate();
tl.ApplyTemplate();
tl.Presenter.ApplyTemplate();
HotKeyManager.SetHotKey(button, gesture1);
// Detach the button from the logical tree, so there is no reference to it
tl.Content = null;
tl.ApplyTemplate();
})();
// The button should be collected since it's detached from the listbox
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.Null(reference?.Target);
}
}
[Fact]
public void HotKeyManager_Should_Release_Reference_When_Control_In_Item_Template_Detached()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var styler = new Mock<Styler>();
AvaloniaLocator.CurrentMutable
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
.Bind<IStyler>().ToConstant(styler.Object);
var gesture1 = new KeyGesture(Key.A, KeyModifiers.Control);
var weakReferences = new List<WeakReference>();
var tl = new Window { SizeToContent = SizeToContent.WidthAndHeight, IsVisible = true };
var lm = tl.LayoutManager;
var keyGestures = new AvaloniaList<KeyGesture> { gesture1 };
var listBox = new ListBox
{
Width = 100,
Height = 100,
VirtualizationMode = ItemVirtualizationMode.None,
// Create a button with binding to the KeyGesture in the template and add it to references list
ItemTemplate = new FuncDataTemplate(typeof(KeyGesture), (o, scope) =>
{
var keyGesture = o as KeyGesture;
var button = new Button
{
DataContext = keyGesture, [!Button.HotKeyProperty] = new Binding("")
};
weakReferences.Add(new WeakReference(button, true));
return button;
})
};
// Add the listbox and render it
tl.Content = listBox;
lm.ExecuteInitialLayoutPass();
listBox.Items = keyGestures;
lm.ExecuteLayoutPass();
// Let the button detach when clearing the source items
keyGestures.Clear();
lm.ExecuteLayoutPass();
// Add it again to double check,and render
keyGestures.Add(gesture1);
lm.ExecuteLayoutPass();
keyGestures.Clear();
lm.ExecuteLayoutPass();
// The button should be collected since it's detached from the listbox
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.True(weakReferences.Count > 0);
foreach (var weakReference in weakReferences)
{
Assert.Null(weakReference.Target);
}
}
}

7
tests/Avalonia.Markup.Xaml.UnitTests/Converters/PointsListTypeConverterTests.cs

@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Avalonia.Controls.Shapes;
using Avalonia.Data;
using Avalonia.Markup.Xaml.Converters;
using Xunit;
@ -7,6 +9,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.Converters
{
public class PointsListTypeConverterTests
{
static PointsListTypeConverterTests()
{
RuntimeHelpers.RunClassConstructor(typeof(RelativeSource).TypeHandle);
}
[Theory]
[InlineData("1,2 3,4")]
[InlineData("1 2 3 4")]

31
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/IgnoredDirectivesTests.cs

@ -0,0 +1,31 @@
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.Xaml
{
public class IgnoredDirectivesTests : XamlTestBase
{
[Fact]
public void Ignored_Directives_Should_Compile()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
const string xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:sys='clr-namespace:System;assembly=netstandard'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<TextBlock x:Name='target' x:FieldModifier='Public' Text='Foo'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<TextBlock>("target");
window.ApplyTemplate();
target.ApplyTemplate();
Assert.Equal("Foo", target.Text);
}
}
}
}
Loading…
Cancel
Save