Browse Source

Merge remote-tracking branch 'origin/master' into fixes/list-selection-interactions

pull/11455/head
Max Katz 3 years ago
parent
commit
45381c3792
  1. 2
      packages/Avalonia/Avalonia.csproj
  2. 5
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  3. 2
      samples/GpuInterop/VulkanDemo/VulkanContext.cs
  4. 3
      samples/IntegrationTestApp/MainWindow.axaml
  5. 6
      samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs
  6. 4
      src/Avalonia.Base/Animation/Animatable.cs
  7. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  8. 2
      src/Avalonia.Base/AvaloniaPropertyExtensions.cs
  9. 2
      src/Avalonia.Base/Collections/Pooled/ClearMode.cs
  10. 2
      src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs
  11. 2
      src/Avalonia.Base/Collections/Pooled/PooledList.cs
  12. 2
      src/Avalonia.Base/Collections/Pooled/PooledStack.cs
  13. 2
      src/Avalonia.Base/Controls/ChildNameScope.cs
  14. 2
      src/Avalonia.Base/Data/Core/CommonPropertyNames.cs
  15. 2
      src/Avalonia.Base/Data/IndexerBinding.cs
  16. 2
      src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs
  17. 2
      src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs
  18. 2
      src/Avalonia.Base/EnumExtensions.cs
  19. 6
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  20. 56
      src/Avalonia.Base/Input/FocusManager.cs
  21. 36
      src/Avalonia.Base/Input/IFocusManager.cs
  22. 3
      src/Avalonia.Base/Input/IFocusScope.cs
  23. 4
      src/Avalonia.Base/Input/IInputElement.cs
  24. 8
      src/Avalonia.Base/Input/IInputRoot.cs
  25. 8
      src/Avalonia.Base/Input/IKeyboardDevice.cs
  26. 17
      src/Avalonia.Base/Input/InputElement.cs
  27. 4
      src/Avalonia.Base/Input/KeyboardDevice.cs
  28. 18
      src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
  29. 2
      src/Avalonia.Base/Input/MouseDevice.cs
  30. 6
      src/Avalonia.Base/Input/Navigation/TabNavigation.cs
  31. 2
      src/Avalonia.Base/Input/PenDevice.cs
  32. 2
      src/Avalonia.Base/Input/TouchDevice.cs
  33. 2
      src/Avalonia.Base/Interactivity/Interactive.cs
  34. 2
      src/Avalonia.Base/Logging/TraceLogSink.cs
  35. 2
      src/Avalonia.Base/Media/ArcSegment.cs
  36. 2
      src/Avalonia.Base/Media/BezierSegment .cs
  37. 2
      src/Avalonia.Base/Media/Imaging/Bitmap.cs
  38. 2
      src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
  39. 2
      src/Avalonia.Base/Media/LineSegment.cs
  40. 4
      src/Avalonia.Base/Media/PathSegment.cs
  41. 2
      src/Avalonia.Base/Media/PolyLineSegment.cs
  42. 2
      src/Avalonia.Base/Media/QuadraticBezierSegment .cs
  43. 1
      src/Avalonia.Base/Media/StreamGeometryContext.cs
  44. 2
      src/Avalonia.Base/Media/Transformation/TransformParser.cs
  45. 6
      src/Avalonia.Base/Platform/Storage/NameCollisionOption.cs
  46. 2
      src/Avalonia.Base/Rendering/ManagedDeferredRendererLock.cs
  47. 50
      src/Avalonia.Base/Rendering/RendererBase.cs
  48. 2
      src/Avalonia.Base/Rendering/Utilities/TileBrushCalculator.cs
  49. 3
      src/Avalonia.Base/Rendering/ZIndexComparer.cs
  50. 2
      src/Avalonia.Base/StyledElement.cs
  51. 2
      src/Avalonia.Base/Utilities/DisposableLock.cs
  52. 2
      src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs
  53. 2
      src/Avalonia.Base/Utilities/SingleOrDictionary.cs
  54. 2
      src/Avalonia.Base/Utilities/SingleOrQueue.cs
  55. 2
      src/Avalonia.Base/Utilities/ValueSingleOrList.cs
  56. 49
      src/Avalonia.Base/Utilities/WeakTimer.cs
  57. 2
      src/Avalonia.Base/Visual.cs
  58. 5
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  59. 4
      src/Avalonia.Controls.ItemsRepeater/Controls/RepeaterLayoutContext.cs
  60. 2
      src/Avalonia.Controls.ItemsRepeater/Controls/ViewManager.cs
  61. 2
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  62. 2
      src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs
  63. 2
      src/Avalonia.Controls/Calendar/Calendar.cs
  64. 3
      src/Avalonia.Controls/ComboBox.cs
  65. 4
      src/Avalonia.Controls/ContextMenu.cs
  66. 11
      src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs
  67. 6
      src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs
  68. 4
      src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs
  69. 11
      src/Avalonia.Controls/ItemsControl.cs
  70. 2
      src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
  71. 2
      src/Avalonia.Controls/Primitives/AccessText.cs
  72. 2
      src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
  73. 6
      src/Avalonia.Controls/Primitives/Popup.cs
  74. 2
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  75. 2
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  76. 2
      src/Avalonia.Controls/Primitives/TemplatedControl.cs
  77. 2
      src/Avalonia.Controls/Primitives/VisualLayerManager.cs
  78. 2
      src/Avalonia.Controls/TextBlock.cs
  79. 5
      src/Avalonia.Controls/TopLevel.cs
  80. 3
      src/Avalonia.Controls/TreeView.cs
  81. 2
      src/Avalonia.Controls/TreeViewItem.cs
  82. 2
      src/Avalonia.Controls/Viewbox.cs
  83. 14
      src/Avalonia.Controls/VirtualizingStackPanel.cs
  84. 4
      src/Avalonia.Controls/WindowBase.cs
  85. 8
      src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
  86. 5
      src/Avalonia.Themes.Fluent/Controls/ScrollViewer.xaml
  87. 5
      src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml
  88. 4
      src/Headless/Avalonia.Headless.Vnc/HeadlessVncFramebufferSource.cs
  89. 2
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  90. 6
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  91. 33
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  92. 4
      src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
  93. 1
      src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs
  94. 2
      src/Skia/Avalonia.Skia/Helpers/DrawingContextHelper.cs
  95. 4
      src/Skia/Avalonia.Skia/PictureRenderTarget.cs
  96. 2
      src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
  97. 2
      src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs
  98. 8
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  99. 2
      src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs
  100. 58
      tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs

2
packages/Avalonia/Avalonia.csproj

@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia.BuildServices" Version="0.0.15" />
<PackageReference Include="Avalonia.BuildServices" Version="0.0.16" />
<ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
<ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj">
<PrivateAssets>all</PrivateAssets>

5
samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs

@ -1,5 +1,4 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Avalonia.Controls;
@ -23,7 +22,7 @@ namespace ControlCatalog.Pages
$"Text was dragged {++textCount} times"), DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
SetupDnd("Custom", d => d.Set(CustomFormat, "Test123"), DragDropEffects.Move);
SetupDnd("Files", d => d.Set(DataFormats.Files, new[] { Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName }), DragDropEffects.Copy);
SetupDnd("Files", async d => d.Set(DataFormats.Files, new[] { await (VisualRoot as TopLevel)!.StorageProvider.TryGetFileFromPathAsync(Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName) }), DragDropEffects.Copy);
}
void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects)
@ -99,7 +98,7 @@ namespace ControlCatalog.Pages
{
if (item is IStorageFile file)
{
var content = await DialogsPage.ReadTextFromFile(file, 1000);
var content = await DialogsPage.ReadTextFromFile(file, 500);
contentStr += $"File {item.Name}:{Environment.NewLine}{content}{Environment.NewLine}{Environment.NewLine}";
}
else if (item is IStorageFolder folder)

2
samples/GpuInterop/VulkanDemo/VulkanContext.cs

@ -174,7 +174,7 @@ public unsafe class VulkanContext : IDisposable
for (uint queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++)
{
var family = familyProperties[queueFamilyIndex];
if (!family.QueueFlags.HasAllFlags(QueueFlags.GraphicsBit))
if (!family.QueueFlags.HasFlag(QueueFlags.GraphicsBit))
continue;

3
samples/IntegrationTestApp/MainWindow.axaml

@ -47,6 +47,9 @@
<Button Name="DisabledButton" IsEnabled="False">
Disabled Button
</Button>
<Button Name="EffectivelyDisabledButton" Command="{ReflectionBinding DoesntExist}">
Effectively Disabled Button
</Button>
<Button Name="BasicButton">
Basic Button
</Button>

6
samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs

@ -24,19 +24,19 @@ public class PlaygroundPageViewModel : ViewModelBase
public bool Multiple
{
get => _selectionMode.HasAnyFlag(SelectionMode.Multiple);
get => _selectionMode.HasFlag(SelectionMode.Multiple);
set => SetSelectionMode(SelectionMode.Multiple, value);
}
public bool Toggle
{
get => _selectionMode.HasAnyFlag(SelectionMode.Toggle);
get => _selectionMode.HasFlag(SelectionMode.Toggle);
set => SetSelectionMode(SelectionMode.Toggle, value);
}
public bool AlwaysSelected
{
get => _selectionMode.HasAnyFlag(SelectionMode.AlwaysSelected);
get => _selectionMode.HasFlag(SelectionMode.AlwaysSelected);
set => SetSelectionMode(SelectionMode.AlwaysSelected, value);
}

4
src/Avalonia.Base/Animation/Animatable.cs

@ -58,7 +58,7 @@ namespace Avalonia.Animation
/// This method should not be called from user code, it will be called automatically by the framework
/// when a control is added to the visual tree.
/// </remarks>
protected void EnableTransitions()
internal void EnableTransitions()
{
if (!_transitionsEnabled)
{
@ -83,7 +83,7 @@ namespace Avalonia.Animation
/// This method should not be called from user code, it will be called automatically by the framework
/// when a control is removed from the visual tree.
/// </remarks>
protected void DisableTransitions()
internal void DisableTransitions()
{
if (_transitionsEnabled)
{

1
src/Avalonia.Base/Avalonia.Base.csproj

@ -63,6 +63,7 @@
<InternalsVisibleTo Include="Avalonia.iOS, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Dialogs, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Diagnostics, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.LinuxFramebuffer, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="MiniMvvm, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="ControlCatalog, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />

2
src/Avalonia.Base/AvaloniaPropertyExtensions.cs

@ -7,7 +7,7 @@ namespace Avalonia
/// <summary>
/// Extensions for <see cref="AvaloniaProperty"/>.
/// </summary>
public static class AvaloniaPropertyExtensions
internal static class AvaloniaPropertyExtensions
{
/// <summary>
/// Checks if values of given property can affect rendering (via <see cref="IAffectsRender"/>).

2
src/Avalonia.Base/Collections/Pooled/ClearMode.cs

@ -9,7 +9,7 @@ namespace Avalonia.Collections.Pooled
/// what each option does before using anything other than the default
/// of Auto.
/// </summary>
public enum ClearMode
internal enum ClearMode
{
/// <summary>
/// <para><code>Auto</code> has different behavior depending on the host project's target framework.</para>

2
src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs

@ -11,7 +11,7 @@ namespace Avalonia.Collections.Pooled
/// </summary>
/// <typeparam name="T">The type of elements in the read-only pooled list.</typeparam>
public interface IReadOnlyPooledList<T> : IReadOnlyList<T>
internal interface IReadOnlyPooledList<T> : IReadOnlyList<T>
{
#pragma warning disable CS0419
/// <summary>

2
src/Avalonia.Base/Collections/Pooled/PooledList.cs

@ -29,7 +29,7 @@ namespace Avalonia.Collections.Pooled
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(ICollectionDebugView<>))]
[Serializable]
public class PooledList<T> : IList<T>, IReadOnlyPooledList<T>, IList, IDisposable, IDeserializationCallback
internal class PooledList<T> : IList<T>, IReadOnlyPooledList<T>, IList, IDisposable, IDeserializationCallback
{
// internal constant copied from Array.MaxArrayLength
private const int MaxArrayLength = 0x7FEFFFFF;

2
src/Avalonia.Base/Collections/Pooled/PooledStack.cs

@ -29,7 +29,7 @@ namespace Avalonia.Collections.Pooled
[DebuggerTypeProxy(typeof(StackDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class PooledStack<T> : IEnumerable<T>, ICollection, IReadOnlyCollection<T>, IDisposable, IDeserializationCallback
internal class PooledStack<T> : IEnumerable<T>, ICollection, IReadOnlyCollection<T>, IDisposable, IDeserializationCallback
{
[NonSerialized]
private ArrayPool<T> _pool;

2
src/Avalonia.Base/Controls/ChildNameScope.cs

@ -3,7 +3,7 @@ using Avalonia.Utilities;
namespace Avalonia.Controls
{
public class ChildNameScope : INameScope
internal class ChildNameScope : INameScope
{
private readonly INameScope _parentScope;
private readonly NameScope _inner = new NameScope();

2
src/Avalonia.Base/Data/Core/CommonPropertyNames.cs

@ -1,6 +1,6 @@
namespace Avalonia.Data.Core
{
public static class CommonPropertyNames
internal static class CommonPropertyNames
{
public const string IndexerName = "Item";
}

2
src/Avalonia.Base/Data/IndexerBinding.cs

@ -2,7 +2,7 @@
namespace Avalonia.Data
{
public class IndexerBinding : IBinding
internal class IndexerBinding : IBinding
{
public IndexerBinding(
AvaloniaObject source,

2
src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs

@ -5,7 +5,7 @@ namespace Avalonia.Diagnostics
/// <summary>
/// Provides a debug interface into <see cref="AvaloniaObject"/>.
/// </summary>
public interface IAvaloniaObjectDebug
internal interface IAvaloniaObjectDebug
{
/// <summary>
/// Gets the subscriber list for the <see cref="AvaloniaObject.PropertyChanged"/>

2
src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs

@ -8,7 +8,7 @@ namespace Avalonia.Diagnostics
/// Provides a debug interface into <see cref="INotifyCollectionChanged"/> subscribers on
/// <see cref="AvaloniaList{T}"/>
/// </summary>
public interface INotifyCollectionChangedDebug
internal interface INotifyCollectionChangedDebug
{
/// <summary>
/// Gets the subscriber list for the <see cref="INotifyCollectionChanged.CollectionChanged"/>

2
src/Avalonia.Base/EnumExtensions.cs

@ -6,7 +6,7 @@ namespace Avalonia
/// <summary>
/// Provides extension methods for enums.
/// </summary>
public static class EnumExtensions
internal static class EnumExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]

6
src/Avalonia.Base/Input/AccessKeyHandler.cs

@ -9,7 +9,7 @@ namespace Avalonia.Input
/// <summary>
/// Handles access keys for a window.
/// </summary>
public class AccessKeyHandler : IAccessKeyHandler
internal class AccessKeyHandler : IAccessKeyHandler
{
/// <summary>
/// Defines the AccessKeyPressed attached event.
@ -141,9 +141,11 @@ namespace Avalonia.Input
if (MainMenu == null || !MainMenu.IsOpen)
{
var focusManager = FocusManager.GetFocusManager(e.Source as IInputElement);
// TODO: Use FocusScopes to store the current element and restore it when context menu is closed.
// Save currently focused input element.
_restoreFocusElement = FocusManager.Instance?.Current;
_restoreFocusElement = focusManager?.GetFocusedElement();
// When Alt is pressed without a main menu, or with a closed main menu, show
// access key markers in the window (i.e. "_File").

56
src/Avalonia.Base/Input/FocusManager.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Avalonia.Interactivity;
using Avalonia.Metadata;
using Avalonia.VisualTree;
namespace Avalonia.Input
@ -10,6 +11,7 @@ namespace Avalonia.Input
/// <summary>
/// Manages focus for the application.
/// </summary>
[PrivateApi]
public class FocusManager : IFocusManager
{
/// <summary>
@ -29,15 +31,12 @@ namespace Avalonia.Input
RoutingStrategies.Tunnel);
}
/// <summary>
/// Gets the instance of the <see cref="IFocusManager"/>.
/// </summary>
public static IFocusManager? Instance => AvaloniaLocator.Current.GetService<IFocusManager>();
private IInputElement? Current => KeyboardDevice.Instance?.FocusedElement;
/// <summary>
/// Gets the currently focused <see cref="IInputElement"/>.
/// </summary>
public IInputElement? Current => KeyboardDevice.Instance?.FocusedElement;
public IInputElement? GetFocusedElement() => Current;
/// <summary>
/// Gets the current focus scope.
@ -54,7 +53,7 @@ namespace Avalonia.Input
/// <param name="control">The control to focus.</param>
/// <param name="method">The method by which focus was changed.</param>
/// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
public void Focus(
public bool Focus(
IInputElement? control,
NavigationMethod method = NavigationMethod.Unspecified,
KeyModifiers keyModifiers = KeyModifiers.None)
@ -67,7 +66,7 @@ namespace Avalonia.Input
if (scope != null)
{
Scope = scope;
SetFocusedElement(scope, control, method, keyModifiers);
return SetFocusedElement(scope, control, method, keyModifiers);
}
}
else if (Current != null)
@ -79,28 +78,29 @@ namespace Avalonia.Input
_focusScopes.TryGetValue(scope, out var element) &&
element != null)
{
Focus(element, method);
return;
return Focus(element, method);
}
}
if (Scope is object)
{
// Couldn't find a focus scope, clear focus.
SetFocusedElement(Scope, null);
return SetFocusedElement(Scope, null);
}
}
return false;
}
public IInputElement? GetFocusedElement(IInputElement e)
public void ClearFocus()
{
if (e is IFocusScope scope)
{
_focusScopes.TryGetValue(scope, out var result);
return result;
}
Focus(null);
}
return null;
public IInputElement? GetFocusedElement(IFocusScope scope)
{
_focusScopes.TryGetValue(scope, out var result);
return result;
}
/// <summary>
@ -114,7 +114,7 @@ namespace Avalonia.Input
/// If the specified scope is the current <see cref="Scope"/> then the keyboard focus
/// will change.
/// </remarks>
public void SetFocusedElement(
public bool SetFocusedElement(
IFocusScope scope,
IInputElement? element,
NavigationMethod method = NavigationMethod.Unspecified,
@ -124,7 +124,7 @@ namespace Avalonia.Input
if (element is not null && !CanFocus(element))
{
return;
return false;
}
if (_focusScopes.TryGetValue(scope, out var existingElement))
@ -144,6 +144,8 @@ namespace Avalonia.Input
{
KeyboardDevice.Instance?.SetFocusedElement(element, method, keyModifiers);
}
return true;
}
/// <summary>
@ -185,6 +187,20 @@ namespace Avalonia.Input
public static bool GetIsFocusScope(IInputElement e) => e is IFocusScope;
/// <summary>
/// Public API customers should use TopLevel.GetTopLevel(control).FocusManager.
/// But since we have split projects, we can't access TopLevel from Avalonia.Base.
/// That's why we need this helper method instead.
/// </summary>
internal static FocusManager? GetFocusManager(IInputElement? element)
{
// Element might not be a visual, and not attached to the root.
// But IFocusManager is always expected to be a FocusManager.
return (FocusManager?)((element as Visual)?.VisualRoot as IInputRoot)?.FocusManager
// In our unit tests some elements might not have a root. Remove when we migrate to headless tests.
?? (FocusManager?)AvaloniaLocator.Current.GetService<IFocusManager>();
}
/// <summary>
/// Checks if the specified element can be focused.
/// </summary>
@ -237,7 +253,7 @@ namespace Avalonia.Input
{
if (element is IInputElement inputElement && CanFocus(inputElement))
{
Instance?.Focus(inputElement, NavigationMethod.Pointer, ev.KeyModifiers);
inputElement.Focus(NavigationMethod.Pointer, ev.KeyModifiers);
break;
}

36
src/Avalonia.Base/Input/IFocusManager.cs

@ -11,40 +11,12 @@ namespace Avalonia.Input
/// <summary>
/// Gets the currently focused <see cref="IInputElement"/>.
/// </summary>
IInputElement? Current { get; }
IInputElement? GetFocusedElement();
/// <summary>
/// Gets the current focus scope.
/// Clears currently focused element.
/// </summary>
IFocusScope? Scope { get; }
/// <summary>
/// Focuses a control.
/// </summary>
/// <param name="control">The control to focus.</param>
/// <param name="method">The method by which focus was changed.</param>
/// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
void Focus(
IInputElement? control,
NavigationMethod method = NavigationMethod.Unspecified,
KeyModifiers keyModifiers = KeyModifiers.None);
/// <summary>
/// Notifies the focus manager of a change in focus scope.
/// </summary>
/// <param name="scope">The new focus scope.</param>
/// <remarks>
/// This should not be called by client code. It is called by an <see cref="IFocusScope"/>
/// when it activates, e.g. when a Window is activated.
/// </remarks>
void SetFocusScope(IFocusScope scope);
/// <summary>
/// Notifies the focus manager that a focus scope has been removed.
/// </summary>
/// <param name="scope">The focus scope to be removed.</param>
/// This should not be called by client code. It is called by an <see cref="IFocusScope"/>
/// when it deactivates or closes, e.g. when a Window is closed.
void RemoveFocusScope(IFocusScope scope);
[Unstable("This API might be removed in 11.x minor updates. Please consider focusing another element instead of removing focus at all for better UX.")]
void ClearFocus();
}
}

3
src/Avalonia.Base/Input/IFocusScope.cs

@ -1,5 +1,8 @@
using Avalonia.Metadata;
namespace Avalonia.Input
{
[NotClientImplementable]
public interface IFocusScope
{
}

4
src/Avalonia.Base/Input/IInputElement.cs

@ -119,7 +119,9 @@ namespace Avalonia.Input
/// <summary>
/// Focuses the control.
/// </summary>
void Focus();
/// <param name="method">The method by which focus was changed.</param>
/// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
bool Focus(NavigationMethod method = NavigationMethod.Unspecified, KeyModifiers keyModifiers = KeyModifiers.None);
/// <summary>
/// Gets the key bindings for the element.

8
src/Avalonia.Base/Input/IInputRoot.cs

@ -18,6 +18,14 @@ namespace Avalonia.Input
/// </summary>
IKeyboardNavigationHandler KeyboardNavigationHandler { get; }
/// <summary>
/// Gets focus manager of the root.
/// </summary>
/// <remarks>
/// Focus manager can be null only if application wasn't initialized yet.
/// </remarks>
IFocusManager? FocusManager { get; }
/// <summary>
/// Gets or sets the input element that the pointer is currently over.
/// </summary>

8
src/Avalonia.Base/Input/IKeyboardDevice.cs

@ -44,13 +44,7 @@ namespace Avalonia.Input
}
[NotClientImplementable]
public interface IKeyboardDevice : IInputDevice, INotifyPropertyChanged
public interface IKeyboardDevice : IInputDevice
{
IInputElement? FocusedElement { get; }
void SetFocusedElement(
IInputElement? element,
NavigationMethod method,
KeyModifiers modifiers);
}
}

17
src/Avalonia.Base/Input/InputElement.cs

@ -458,9 +458,10 @@ namespace Avalonia.Input
SetAndRaise(IsEffectivelyEnabledProperty, ref _isEffectivelyEnabled, value);
PseudoClasses.Set(":disabled", !value);
if (!IsEffectivelyEnabled && FocusManager.Instance?.Current == this)
if (!IsEffectivelyEnabled && FocusManager.GetFocusManager(this) is {} focusManager
&& Equals(focusManager.GetFocusedElement(), this))
{
FocusManager.Instance?.Focus(null);
focusManager.ClearFocus();
}
}
}
@ -491,12 +492,10 @@ namespace Avalonia.Input
public GestureRecognizerCollection GestureRecognizers
=> _gestureRecognizers ?? (_gestureRecognizers = new GestureRecognizerCollection(this));
/// <summary>
/// Focuses the control.
/// </summary>
public void Focus()
/// <inheritdoc />
public bool Focus(NavigationMethod method = NavigationMethod.Unspecified, KeyModifiers keyModifiers = KeyModifiers.None)
{
FocusManager.Instance?.Focus(this);
return FocusManager.GetFocusManager(this)?.Focus(this, method, keyModifiers) ?? false;
}
/// <inheritdoc/>
@ -506,7 +505,7 @@ namespace Avalonia.Input
if (IsFocused)
{
FocusManager.Instance?.Focus(null);
FocusManager.GetFocusManager(this)?.ClearFocus();
}
}
@ -649,7 +648,7 @@ namespace Avalonia.Input
}
else if (change.Property == IsVisibleProperty && !change.GetNewValue<bool>() && IsFocused)
{
FocusManager.Instance?.Focus(null);
FocusManager.GetFocusManager(this)?.ClearFocus();
}
}

4
src/Avalonia.Base/Input/KeyboardDevice.cs

@ -3,9 +3,11 @@ using System.Runtime.CompilerServices;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Avalonia.Interactivity;
using Avalonia.Metadata;
namespace Avalonia.Input
{
[PrivateApi]
public class KeyboardDevice : IKeyboardDevice, INotifyPropertyChanged
{
private IInputElement? _focusedElement;
@ -13,7 +15,7 @@ namespace Avalonia.Input
public event PropertyChangedEventHandler? PropertyChanged;
public static IKeyboardDevice? Instance => AvaloniaLocator.Current.GetService<IKeyboardDevice>();
internal static KeyboardDevice? Instance => AvaloniaLocator.Current.GetService<IKeyboardDevice>() as KeyboardDevice;
public IInputManager? InputManager => AvaloniaLocator.Current.GetService<IInputManager>();

18
src/Avalonia.Base/Input/KeyboardNavigationHandler.cs

@ -1,6 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Input.Navigation;
using Avalonia.Metadata;
using Avalonia.VisualTree;
namespace Avalonia.Input
@ -8,6 +9,7 @@ namespace Avalonia.Input
/// <summary>
/// Handles keyboard navigation for a window.
/// </summary>
[Unstable]
public class KeyboardNavigationHandler : IKeyboardNavigationHandler
{
/// <summary>
@ -75,20 +77,23 @@ namespace Avalonia.Input
/// <param name="direction">The direction to move.</param>
/// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
public void Move(
IInputElement element,
IInputElement? element,
NavigationDirection direction,
KeyModifiers keyModifiers = KeyModifiers.None)
{
element = element ?? throw new ArgumentNullException(nameof(element));
if (element is null && _owner is null)
{
return;
}
var next = GetNext(element, direction);
var next = GetNext(element ?? _owner!, direction);
if (next != null)
{
var method = direction == NavigationDirection.Next ||
direction == NavigationDirection.Previous ?
NavigationMethod.Tab : NavigationMethod.Directional;
FocusManager.Instance?.Focus(next, method, keyModifiers);
next.Focus(method, keyModifiers);
}
}
@ -99,10 +104,9 @@ namespace Avalonia.Input
/// <param name="e">The event args.</param>
protected virtual void OnKeyDown(object? sender, KeyEventArgs e)
{
var current = FocusManager.Instance?.Current;
if (current != null && e.Key == Key.Tab)
if (e.Key == Key.Tab)
{
var current = FocusManager.GetFocusManager(e.Source as IInputElement)?.GetFocusedElement();
var direction = (e.KeyModifiers & KeyModifiers.Shift) == 0 ?
NavigationDirection.Next : NavigationDirection.Previous;
Move(current, direction, e.KeyModifiers);

2
src/Avalonia.Base/Input/MouseDevice.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Avalonia.Reactive;
using Avalonia.Input.Raw;
using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Utilities;
#pragma warning disable CS0618
@ -11,6 +12,7 @@ namespace Avalonia.Input
/// <summary>
/// Represents a mouse device.
/// </summary>
[PrivateApi]
public class MouseDevice : IMouseDevice, IDisposable
{
private int _clickCount;

6
src/Avalonia.Base/Input/Navigation/TabNavigation.cs

@ -190,9 +190,11 @@ namespace Avalonia.Input.Navigation
private static IInputElement? FocusedElement(IInputElement? e)
{
// Focus delegation is enabled only if keyboard focus is outside the container
if (e != null && !e.IsKeyboardFocusWithin)
if (e != null && !e.IsKeyboardFocusWithin && e is IFocusScope scope)
{
var focusedElement = (FocusManager.Instance as FocusManager)?.GetFocusedElement(e);
var focusManager = FocusManager.GetFocusManager(e);
var focusedElement = focusManager?.GetFocusedElement(scope);
if (focusedElement != null)
{
if (!IsFocusScope(e))

2
src/Avalonia.Base/Input/PenDevice.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Avalonia.Input.Raw;
using Avalonia.Metadata;
using Avalonia.Platform;
#pragma warning disable CS0618
@ -11,6 +12,7 @@ namespace Avalonia.Input
/// <summary>
/// Represents a pen/stylus device.
/// </summary>
[PrivateApi]
public class PenDevice : IPenDevice, IDisposable
{
private readonly Dictionary<long, Pointer> _pointers = new();

2
src/Avalonia.Base/Input/TouchDevice.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Avalonia.Input.Raw;
using Avalonia.Metadata;
using Avalonia.Platform;
#pragma warning disable CS0618
@ -14,6 +15,7 @@ namespace Avalonia.Input
/// <remarks>
/// This class is supposed to be used on per-toplevel basis, don't use a shared one
/// </remarks>
[PrivateApi]
public class TouchDevice : IPointerDevice, IDisposable
{
private readonly Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>();

2
src/Avalonia.Base/Interactivity/Interactive.cs

@ -17,7 +17,7 @@ namespace Avalonia.Interactivity
/// <summary>
/// Gets the interactive parent of the object for bubbling and tunneling events.
/// </summary>
protected internal virtual Interactive? InteractiveParent => VisualParent as Interactive;
internal virtual Interactive? InteractiveParent => VisualParent as Interactive;
/// <summary>
/// Adds a handler for the specified routed event.

2
src/Avalonia.Base/Logging/TraceLogSink.cs

@ -6,7 +6,7 @@ using Avalonia.Utilities;
namespace Avalonia.Logging
{
public class TraceLogSink : ILogSink
internal class TraceLogSink : ILogSink
{
private readonly LogEventLevel _level;
private readonly IList<string>? _areas;

2
src/Avalonia.Base/Media/ArcSegment.cs

@ -95,7 +95,7 @@ namespace Avalonia.Media
set { SetValue(SweepDirectionProperty, value); }
}
protected internal override void ApplyTo(StreamGeometryContext ctx)
internal override void ApplyTo(StreamGeometryContext ctx)
{
ctx.ArcTo(Point, Size, RotationAngle, IsLargeArc, SweepDirection);
}

2
src/Avalonia.Base/Media/BezierSegment .cs

@ -56,7 +56,7 @@ namespace Avalonia.Media
set { SetValue(Point3Property, value); }
}
protected internal override void ApplyTo(StreamGeometryContext ctx)
internal override void ApplyTo(StreamGeometryContext ctx)
{
ctx.CubicBezierTo(Point1, Point2, Point3);
}

2
src/Avalonia.Base/Media/Imaging/Bitmap.cs

@ -173,7 +173,7 @@ namespace Avalonia.Media.Imaging
public virtual PixelFormat? Format => (PlatformImpl.Item as IReadableBitmapImpl)?.Format;
protected internal unsafe void CopyPixelsCore(PixelRect sourceRect, IntPtr buffer, int bufferSize, int stride,
private protected unsafe void CopyPixelsCore(PixelRect sourceRect, IntPtr buffer, int bufferSize, int stride,
ILockedFramebuffer fb)
{
if ((sourceRect.Width <= 0 || sourceRect.Height <= 0) && (sourceRect.X != 0 || sourceRect.Y != 0))

2
src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs

@ -21,7 +21,7 @@ namespace Avalonia.Media.Immutable
/// How the source rectangle will be stretched to fill the destination rect.
/// </param>
/// <param name="tileMode">The tile mode.</param>
protected internal ImmutableTileBrush(
private protected ImmutableTileBrush(
AlignmentX alignmentX,
AlignmentY alignmentY,
RelativeRect destinationRect,

2
src/Avalonia.Base/Media/LineSegment.cs

@ -22,7 +22,7 @@ namespace Avalonia.Media
set { SetValue(PointProperty, value); }
}
protected internal override void ApplyTo(StreamGeometryContext ctx)
internal override void ApplyTo(StreamGeometryContext ctx)
{
ctx.LineTo(Point);
}

4
src/Avalonia.Base/Media/PathSegment.cs

@ -2,6 +2,6 @@ namespace Avalonia.Media
{
public abstract class PathSegment : AvaloniaObject
{
protected internal abstract void ApplyTo(StreamGeometryContext ctx);
internal abstract void ApplyTo(StreamGeometryContext ctx);
}
}
}

2
src/Avalonia.Base/Media/PolyLineSegment.cs

@ -44,7 +44,7 @@ namespace Avalonia.Media
Points = new Points(points);
}
protected internal override void ApplyTo(StreamGeometryContext ctx)
internal override void ApplyTo(StreamGeometryContext ctx)
{
var points = Points;
if (points.Count > 0)

2
src/Avalonia.Base/Media/QuadraticBezierSegment .cs

@ -40,7 +40,7 @@ namespace Avalonia.Media
set { SetValue(Point2Property, value); }
}
protected internal override void ApplyTo(StreamGeometryContext ctx)
internal override void ApplyTo(StreamGeometryContext ctx)
{
ctx.QuadraticBezierTo(Point1, Point2);
}

1
src/Avalonia.Base/Media/StreamGeometryContext.cs

@ -10,7 +10,6 @@ namespace Avalonia.Media
/// of <see cref="StreamGeometryContext"/> is obtained by calling
/// <see cref="StreamGeometry.Open"/>.
/// </remarks>
/// TODO: This class is just a wrapper around IStreamGeometryContextImpl: is it needed?
public class StreamGeometryContext : IGeometryContext
{
private readonly IStreamGeometryContextImpl _impl;

2
src/Avalonia.Base/Media/Transformation/TransformParser.cs

@ -4,7 +4,7 @@ using Avalonia.Utilities;
namespace Avalonia.Media.Transformation
{
public static class TransformParser
internal static class TransformParser
{
private static readonly (string, TransformFunction)[] s_functionMapping =
{

6
src/Avalonia.Base/Platform/Storage/NameCollisionOption.cs

@ -1,6 +0,0 @@
namespace Avalonia.Platform.Storage;
public class NameCollisionOption
{
}

2
src/Avalonia.Base/Rendering/ManagedDeferredRendererLock.cs

@ -4,7 +4,7 @@ using Avalonia.Utilities;
namespace Avalonia.Rendering
{
public class ManagedDeferredRendererLock : DisposableLock, IDeferredRendererLock
internal class ManagedDeferredRendererLock : DisposableLock, IDeferredRendererLock
{
}

50
src/Avalonia.Base/Rendering/RendererBase.cs

@ -1,50 +0,0 @@
using System;
using System.Diagnostics;
using System.Globalization;
using Avalonia.Media;
namespace Avalonia.Rendering
{
public class RendererBase
{
private readonly bool _useManualFpsCounting;
private static int s_fontSize = 18;
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
private int _framesThisSecond;
private int _fps;
private TimeSpan _lastFpsUpdate;
public RendererBase(bool useManualFpsCounting = false)
{
_useManualFpsCounting = useManualFpsCounting;
}
protected void FpsTick() => _framesThisSecond++;
protected void RenderFps(DrawingContext context, Rect clientRect, int? layerCount)
{
var now = _stopwatch.Elapsed;
var elapsed = now - _lastFpsUpdate;
if (!_useManualFpsCounting)
++_framesThisSecond;
if (elapsed.TotalSeconds > 1)
{
_fps = (int)(_framesThisSecond / elapsed.TotalSeconds);
_framesThisSecond = 0;
_lastFpsUpdate = now;
}
var text = layerCount.HasValue ? FormattableString.Invariant($"Layers: {layerCount} FPS: {_fps:000}") : FormattableString.Invariant($"FPS: {_fps:000}");
var formattedText = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Typeface.Default, s_fontSize, Brushes.White);
var rect = new Rect(clientRect.Right - formattedText.Width, 0, formattedText.Width, formattedText.Height);
context.DrawRectangle(Brushes.Black, null, rect);
context.DrawText(formattedText, rect.TopLeft);
}
}
}

2
src/Avalonia.Base/Rendering/Utilities/TileBrushCalculator.cs

@ -2,7 +2,7 @@
namespace Avalonia.Rendering.Utilities
{
public class TileBrushCalculator
internal class TileBrushCalculator
{
private readonly Size _imageSize;
private readonly Rect _drawRect;

3
src/Avalonia.Base/Rendering/ZIndexComparer.cs

@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using Avalonia.VisualTree;
namespace Avalonia.Rendering
{
public class ZIndexComparer : IComparer<Visual>
internal class ZIndexComparer : IComparer<Visual>
{
public static readonly ZIndexComparer Instance = new ZIndexComparer();
public static readonly Comparison<Visual> ComparisonInstance = Instance.Compare;

2
src/Avalonia.Base/StyledElement.cs

@ -556,7 +556,7 @@ namespace Avalonia
/// Notifies child controls that a change has been made to resources that apply to them.
/// </summary>
/// <param name="e">The event args.</param>
protected virtual void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
internal virtual void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
if (_logicalChildren is object)
{

2
src/Avalonia.Base/Utilities/DisposableLock.cs

@ -3,7 +3,7 @@ using System.Threading;
namespace Avalonia.Utilities
{
public class DisposableLock
internal class DisposableLock
{
private readonly object _lock = new object();

2
src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs

@ -3,7 +3,7 @@ using Avalonia.Threading;
namespace Avalonia.Utilities
{
public class NonPumpingLockHelper
internal class NonPumpingLockHelper
{
public interface IHelperImpl
{

2
src/Avalonia.Base/Utilities/SingleOrDictionary.cs

@ -11,7 +11,7 @@ namespace Avalonia.Utilities
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
public class SingleOrDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
internal class SingleOrDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
where TKey : notnull
{
private KeyValuePair<TKey, TValue>? _singleValue;

2
src/Avalonia.Base/Utilities/SingleOrQueue.cs

@ -7,7 +7,7 @@ namespace Avalonia.Utilities
/// FIFO Queue optimized for holding zero or one items.
/// </summary>
/// <typeparam name="T">The type of items held in the queue.</typeparam>
public class SingleOrQueue<T>
internal class SingleOrQueue<T>
{
private T? _head;
private Queue<T>? _tail;

2
src/Avalonia.Base/Utilities/ValueSingleOrList.cs

@ -9,7 +9,7 @@ namespace Avalonia.Utilities
/// <remarks>
/// Once more than value has been added to this storage it will switch to using <see cref="List"/> internally.
/// </remarks>
public ref struct ValueSingleOrList<T>
internal ref struct ValueSingleOrList<T>
{
private bool _isSingleSet;

49
src/Avalonia.Base/Utilities/WeakTimer.cs

@ -1,49 +0,0 @@
using System;
using Avalonia.Threading;
namespace Avalonia.Utilities
{
public class WeakTimer
{
public interface IWeakTimerSubscriber
{
bool Tick();
}
private readonly WeakReference<IWeakTimerSubscriber> _subscriber;
private DispatcherTimer _timer;
public WeakTimer(IWeakTimerSubscriber subscriber)
{
_subscriber = new WeakReference<IWeakTimerSubscriber>(subscriber);
_timer = new DispatcherTimer();
_timer.Tick += delegate { OnTick(); };
}
private void OnTick()
{
if (!_subscriber.TryGetTarget(out var subscriber) || !subscriber.Tick())
Stop();
}
public TimeSpan Interval
{
get { return _timer.Interval; }
set { _timer.Interval = value; }
}
public void Start() => _timer.Start();
public void Stop() => _timer.Stop();
public static WeakTimer StartWeakTimer(IWeakTimerSubscriber subscriber, TimeSpan interval)
{
var timer = new WeakTimer(subscriber) {Interval = interval};
timer.Start();
return timer;
}
}
}

2
src/Avalonia.Base/Visual.cs

@ -321,7 +321,7 @@ namespace Avalonia
internal RenderOptions RenderOptions { get; set; }
public bool HasNonUniformZIndexChildren { get; private set; }
internal bool HasNonUniformZIndexChildren { get; private set; }
/// <summary>
/// Gets a value indicating whether this control is attached to a visual root.

5
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -3958,7 +3958,7 @@ namespace Avalonia.Controls
{
bool focusLeftDataGrid = true;
bool dataGridWillReceiveRoutedEvent = true;
Visual focusedObject = FocusManager.Instance.Current as Visual;
Visual focusedObject = FocusManager.GetFocusManager(this)?.GetFocusedElement() as Visual;
DataGridColumn editingColumn = null;
while (focusedObject != null)
@ -4865,7 +4865,8 @@ namespace Avalonia.Controls
if (!ctrl)
{
// If Enter was used by a TextBox, we shouldn't handle the key
if (FocusManager.Instance.Current is TextBox focusedTextBox && focusedTextBox.AcceptsReturn)
if (FocusManager.GetFocusManager(this)?.GetFocusedElement() is TextBox focusedTextBox
&& focusedTextBox.AcceptsReturn)
{
return false;
}

4
src/Avalonia.Controls.ItemsRepeater/Controls/RepeaterLayoutContext.cs

@ -53,8 +53,8 @@ namespace Avalonia.Controls
{
return _owner.GetElementImpl(
index,
options.HasAllFlags(ElementRealizationOptions.ForceCreate),
options.HasAllFlags(ElementRealizationOptions.SuppressAutoRecycle));
options.HasFlag(ElementRealizationOptions.ForceCreate),
options.HasFlag(ElementRealizationOptions.SuppressAutoRecycle));
}
protected override object GetItemAtCore(int index) => _owner.ItemsSourceView!.GetAt(index)!;

2
src/Avalonia.Controls.ItemsRepeater/Controls/ViewManager.cs

@ -695,7 +695,7 @@ namespace Avalonia.Controls
{
Control? focusedElement = null;
if (FocusManager.Instance?.Current is Visual child)
if (TopLevel.GetTopLevel(_owner)?.FocusManager?.GetFocusedElement() is Visual child)
{
var parent = child.GetVisualParent();
var owner = _owner;

2
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -762,7 +762,7 @@ namespace Avalonia.Controls
/// otherwise, false.</returns>
protected bool HasFocus()
{
Visual? focused = FocusManager.Instance?.Current as Visual;
Visual? focused = FocusManager.GetFocusManager(this)?.GetFocusedElement() as Visual;
while (focused != null)
{

2
src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs

@ -151,7 +151,7 @@ namespace Avalonia.Automation.Peers
protected override bool HasKeyboardFocusCore() => Owner.IsFocused;
protected override bool IsContentElementCore() => true;
protected override bool IsControlElementCore() => true;
protected override bool IsEnabledCore() => Owner.IsEnabled;
protected override bool IsEnabledCore() => Owner.IsEffectivelyEnabled;
protected override bool IsKeyboardFocusableCore() => Owner.Focusable;
protected override void SetFocusCore() => Owner.Focus();

2
src/Avalonia.Controls/Calendar/Calendar.cs

@ -1567,7 +1567,7 @@ namespace Avalonia.Controls
base.OnPointerReleased(e);
if (!HasFocusInternal && e.InitialPressMouseButton == MouseButton.Left)
{
FocusManager.Instance?.Focus(this);
Focus();
}
}

3
src/Avalonia.Controls/ComboBox.cs

@ -230,8 +230,7 @@ namespace Avalonia.Controls
var firstChild = Presenter?.Panel?.Children.FirstOrDefault(c => CanFocus(c));
if (firstChild != null)
{
FocusManager.Instance?.Focus(firstChild, NavigationMethod.Directional);
e.Handled = true;
e.Handled = firstChild.Focus(NavigationMethod.Directional);
}
}
}

4
src/Avalonia.Controls/ContextMenu.cs

@ -360,7 +360,7 @@ namespace Avalonia.Controls
private void PopupOpened(object? sender, EventArgs e)
{
_previousFocus = FocusManager.Instance?.Current;
_previousFocus = FocusManager.GetFocusManager(this)?.GetFocusedElement();
Focus();
_popupHostChangedHandler?.Invoke(_popup!.Host);
@ -390,7 +390,7 @@ namespace Avalonia.Controls
}
// HACK: Reset the focus when the popup is closed. We need to fix this so it's automatic.
FocusManager.Instance?.Focus(_previousFocus);
_previousFocus?.Focus();
RaiseEvent(new RoutedEventArgs
{

11
src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs

@ -323,10 +323,11 @@ namespace Avalonia.Controls
e.Handled = true;
break;
case Key.Tab:
if (FocusManager.Instance?.Current is IInputElement focus)
var focusManager = FocusManager.GetFocusManager(this);
if (focusManager?.GetFocusedElement() is { } focus)
{
var nextFocus = KeyboardNavigationHandler.GetNext(focus, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
nextFocus?.Focus(NavigationMethod.Tab);
e.Handled = true;
}
break;
@ -449,15 +450,15 @@ namespace Avalonia.Controls
if (monthCol < dayCol && monthCol < yearCol)
{
KeyboardDevice.Instance?.SetFocusedElement(_monthSelector, NavigationMethod.Pointer, KeyModifiers.None);
_monthSelector?.Focus(NavigationMethod.Pointer);
}
else if (dayCol < monthCol && dayCol < yearCol)
{
KeyboardDevice.Instance?.SetFocusedElement(_daySelector, NavigationMethod.Pointer, KeyModifiers.None);
_monthSelector?.Focus(NavigationMethod.Pointer);
}
else if (yearCol < monthCol && yearCol < dayCol)
{
KeyboardDevice.Instance?.SetFocusedElement(_yearSelector, NavigationMethod.Pointer, KeyModifiers.None);
_yearSelector?.Focus(NavigationMethod.Pointer);
}
}

6
src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs

@ -161,10 +161,10 @@ namespace Avalonia.Controls
e.Handled = true;
break;
case Key.Tab:
if (FocusManager.Instance?.Current is IInputElement focus)
if (FocusManager.GetFocusManager(this)?.GetFocusedElement() is { } focus)
{
var nextFocus = KeyboardNavigationHandler.GetNext(focus, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
nextFocus?.Focus(NavigationMethod.Tab);
e.Handled = true;
}
break;
@ -216,7 +216,7 @@ namespace Avalonia.Controls
_periodSelector.SelectedValue = hr >= 12 ? 1 : 0;
SetGrid();
KeyboardDevice.Instance?.SetFocusedElement(_hourSelector, NavigationMethod.Pointer, KeyModifiers.None);
_hourSelector?.Focus(NavigationMethod.Pointer);
}
private void SetGrid()

4
src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs

@ -250,14 +250,14 @@ namespace Avalonia.Controls.Primitives
// Try and focus content inside Flyout
if (Popup.Child.Focusable)
{
FocusManager.Instance?.Focus(Popup.Child);
Popup.Child.Focus();
}
else
{
var nextFocus = KeyboardNavigationHandler.GetNext(Popup.Child, NavigationDirection.Next);
if (nextFocus != null)
{
FocusManager.Instance?.Focus(nextFocus);
nextFocus.Focus();
}
}
}

11
src/Avalonia.Controls/ItemsControl.cs

@ -590,19 +590,20 @@ namespace Avalonia.Controls
{
if (!e.Handled)
{
var focus = FocusManager.Instance;
var focus = FocusManager.GetFocusManager(this);
var direction = e.Key.ToNavigationDirection();
var container = Presenter?.Panel as INavigableContainer;
if (container == null ||
focus?.Current == null ||
if (focus == null ||
container == null ||
focus.GetFocusedElement() == null ||
direction == null ||
direction.Value.IsTab())
{
return;
}
Visual? current = focus.Current as Visual;
Visual? current = focus.GetFocusedElement() as Visual;
while (current != null)
{
@ -612,7 +613,7 @@ namespace Avalonia.Controls
if (next != null)
{
focus.Focus(next, NavigationMethod.Directional, e.KeyModifiers);
next.Focus(NavigationMethod.Directional, e.KeyModifiers);
e.Handled = true;
}

2
src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs

@ -302,7 +302,7 @@ namespace Avalonia.Controls.Presenters
/// <remarks>
/// This method is automatically called when the control is attached to a visual tree.
/// </remarks>
protected internal virtual void AttachToScrollViewer()
internal void AttachToScrollViewer()
{
var owner = this.FindAncestorOfType<ScrollViewer>();

2
src/Avalonia.Controls/Primitives/AccessText.cs

@ -60,7 +60,7 @@ namespace Avalonia.Controls.Primitives
/// Renders the <see cref="AccessText"/> to a drawing context.
/// </summary>
/// <param name="context">The drawing context.</param>
protected internal override void RenderCore(DrawingContext context)
private protected override void RenderCore(DrawingContext context)
{
base.RenderCore(context);
int underscore = Text?.IndexOf('_') ?? -1;

2
src/Avalonia.Controls/Primitives/OverlayPopupHost.cs

@ -51,7 +51,7 @@ namespace Avalonia.Controls.Primitives
}
/// <inheritdoc />
protected internal override Interactive? InteractiveParent => Parent as Interactive;
internal override Interactive? InteractiveParent => Parent as Interactive;
/// <inheritdoc />
public void Dispose() => Hide();

6
src/Avalonia.Controls/Primitives/Popup.cs

@ -727,7 +727,7 @@ namespace Avalonia.Controls.Primitives
Closed?.Invoke(this, EventArgs.Empty);
var focusCheck = FocusManager.Instance?.Current;
var focusCheck = FocusManager.GetFocusManager(this)?.GetFocusedElement();
// Focus is set to null as part of popup closing, so we only want to
// set focus to PlacementTarget if this is the case
@ -744,7 +744,7 @@ namespace Avalonia.Controls.Primitives
if (e is object)
{
FocusManager.Instance?.Focus(e);
e.Focus();
}
}
else
@ -752,7 +752,7 @@ namespace Avalonia.Controls.Primitives
var anc = this.FindLogicalAncestorOfType<Control>();
if (anc != null)
{
FocusManager.Instance?.Focus(anc);
anc.Focus();
}
}
}

2
src/Avalonia.Controls/Primitives/PopupRoot.cs

@ -72,7 +72,7 @@ namespace Avalonia.Controls.Primitives
/// <remarks>
/// Popup events are passed to their parent window. This facilitates this.
/// </remarks>
protected internal override Interactive? InteractiveParent => (Interactive?)Parent;
internal override Interactive? InteractiveParent => (Interactive?)Parent;
/// <summary>
/// Gets the control that is hosting the popup root.

2
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -200,7 +200,7 @@ namespace Avalonia.Controls.Primitives
/// <remarks>
/// This method is automatically called when the control is attached to a visual tree.
/// </remarks>
protected internal virtual void AttachToScrollViewer()
internal void AttachToScrollViewer()
{
var owner = this.FindAncestorOfType<ScrollViewer>();

2
src/Avalonia.Controls/Primitives/TemplatedControl.cs

@ -318,7 +318,7 @@ namespace Avalonia.Controls.Primitives
}
/// <inheritdoc />
protected sealed override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
internal sealed override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
var count = VisualChildren.Count;

2
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@ -104,7 +104,7 @@ namespace Avalonia.Controls.Primitives
}
/// <inheritdoc />
protected override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
internal override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
foreach (var l in _layers)
((ILogical)l).NotifyResourcesChanged(e);

2
src/Avalonia.Controls/TextBlock.cs

@ -555,7 +555,7 @@ namespace Avalonia.Controls
}
// Workaround to seal Render method, we need to make so because AccessText was overriding Render method which is sealed now.
internal protected virtual void RenderCore(DrawingContext context)
private protected virtual void RenderCore(DrawingContext context)
{
var background = Background;

5
src/Avalonia.Controls/TopLevel.cs

@ -452,6 +452,9 @@ namespace Avalonia.Controls
/// </summary>
public IClipboard? Clipboard => PlatformImpl?.TryGetFeature<IClipboard>();
/// <inheritdoc />
public IFocusManager? FocusManager => AvaloniaLocator.Current.GetService<IFocusManager>();
/// <inheritdoc/>
Point IRenderRoot.PointToClient(PixelPoint p)
{
@ -725,7 +728,7 @@ namespace Avalonia.Controls
void PlatformImpl_LostFocus()
{
var focused = (Visual?)FocusManager.Instance?.Current;
var focused = (Visual?)FocusManager?.GetFocusedElement();
if (focused == null)
return;
while (focused.VisualParent != null)

3
src/Avalonia.Controls/TreeView.cs

@ -560,8 +560,7 @@ namespace Avalonia.Controls
if (next != null)
{
FocusManager.Instance?.Focus(next, NavigationMethod.Directional);
e.Handled = true;
e.Handled = next.Focus(NavigationMethod.Directional);
}
}
else

2
src/Avalonia.Controls/TreeViewItem.cs

@ -238,7 +238,7 @@ namespace Avalonia.Controls
}
else
{
FocusManager.Instance?.Focus(treeViewItem, NavigationMethod.Directional);
treeViewItem.Focus(NavigationMethod.Directional);
}
return true;

2
src/Avalonia.Controls/Viewbox.cs

@ -82,7 +82,7 @@ namespace Avalonia.Controls
/// Gets or sets the transform applied to the container visual that
/// hosts the child of the Viewbox
/// </summary>
protected internal ITransform? InternalTransform
internal ITransform? InternalTransform
{
get => _containerVisual.RenderTransform;
set => _containerVisual.RenderTransform = value;

14
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -356,7 +356,7 @@ namespace Avalonia.Controls
{
var items = Items;
if (_isInLayout || index < 0 || index >= items.Count || _realizedElements is null)
if (_isInLayout || index < 0 || index >= items.Count || _realizedElements is null || !IsEffectivelyVisible)
return null;
if (GetRealizedElement(index) is Control element)
@ -682,9 +682,12 @@ namespace Avalonia.Controls
_scrollViewer?.UnregisterAnchorCandidate(element);
var recycleKey = element.GetValue(RecycleKeyProperty);
Debug.Assert(recycleKey is not null);
if (recycleKey == s_itemIsItsOwnContainer)
if (recycleKey is null)
{
RemoveInternalChild(element);
}
else if (recycleKey == s_itemIsItsOwnContainer)
{
element.IsVisible = false;
}
@ -707,9 +710,8 @@ namespace Avalonia.Controls
Debug.Assert(ItemContainerGenerator is not null);
var recycleKey = element.GetValue(RecycleKeyProperty);
Debug.Assert(recycleKey is not null);
if (recycleKey == s_itemIsItsOwnContainer)
if (recycleKey is null || recycleKey == s_itemIsItsOwnContainer)
{
RemoveInternalChild(element);
}

4
src/Avalonia.Controls/WindowBase.cs

@ -234,7 +234,7 @@ namespace Avalonia.Controls
if (this is IFocusScope scope)
{
FocusManager.Instance?.RemoveFocusScope(scope);
((FocusManager?)FocusManager)?.RemoveFocusScope(scope);
}
base.HandleClosed();
@ -326,7 +326,7 @@ namespace Avalonia.Controls
if (scope != null)
{
FocusManager.Instance?.SetFocusScope(scope);
((FocusManager?)FocusManager)?.SetFocusScope(scope);
}
IsActive = true;

8
src/Avalonia.Diagnostics/Diagnostics/DevTools.cs

@ -86,7 +86,7 @@ namespace Avalonia.Diagnostics
private static IDisposable Open(IDevToolsTopLevelGroup topLevelGroup, DevToolsOptions options,
Window? owner, Application? app)
{
var focussedControl = KeyboardDevice.Instance?.FocusedElement as Control;
var focusedControl = owner?.FocusManager?.GetFocusedElement() as Control;
AvaloniaObject root = topLevelGroup switch
{
ClassicDesktopStyleApplicationLifetimeTopLevelGroup gr => new Controls.Application(gr, app ?? Application.Current!),
@ -98,7 +98,7 @@ namespace Avalonia.Diagnostics
if (s_open.TryGetValue(topLevelGroup, out var mainWindow))
{
mainWindow.Activate();
mainWindow.SelectedControl(focussedControl);
mainWindow.SelectedControl(focusedControl);
return Disposable.Empty;
}
if (topLevelGroup.Items.Count == 1 && topLevelGroup.Items is not INotifyCollectionChanged)
@ -110,7 +110,7 @@ namespace Avalonia.Diagnostics
if (group.Key.Items.Contains(singleTopLevel))
{
group.Value.Activate();
group.Value.SelectedControl(focussedControl);
group.Value.SelectedControl(focusedControl);
return Disposable.Empty;
}
}
@ -124,7 +124,7 @@ namespace Avalonia.Diagnostics
Tag = topLevelGroup
};
window.SetOptions(options);
window.SelectedControl(focussedControl);
window.SelectedControl(focusedControl);
window.Closed += DevToolsClosed;
s_open.Add(topLevelGroup, window);
if (options.ShowAsChildWindow && owner is not null)

5
src/Avalonia.Themes.Fluent/Controls/ScrollViewer.xaml

@ -33,11 +33,12 @@
VerticalSnapPointsType="{TemplateBinding VerticalSnapPointsType}"
HorizontalSnapPointsAlignment="{TemplateBinding HorizontalSnapPointsAlignment}"
VerticalSnapPointsAlignment="{TemplateBinding VerticalSnapPointsAlignment}"
Padding="{TemplateBinding Padding}">
Padding="{TemplateBinding Padding}"
ScrollViewer.IsScrollInertiaEnabled="{TemplateBinding IsScrollInertiaEnabled}">
<ScrollContentPresenter.GestureRecognizers>
<ScrollGestureRecognizer CanHorizontallyScroll="{Binding CanHorizontallyScroll, ElementName=PART_ContentPresenter}"
CanVerticallyScroll="{Binding CanVerticallyScroll, ElementName=PART_ContentPresenter}"
IsScrollInertiaEnabled="{Binding IsScrollInertiaEnabled, RelativeSource={RelativeSource TemplatedParent}}" />
IsScrollInertiaEnabled="{Binding (ScrollViewer.IsScrollInertiaEnabled), ElementName=PART_ContentPresenter}"/>
</ScrollContentPresenter.GestureRecognizers>
</ScrollContentPresenter>
<ScrollBar Name="PART_HorizontalScrollBar"

5
src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml

@ -14,11 +14,12 @@
VerticalSnapPointsType="{TemplateBinding VerticalSnapPointsType}"
HorizontalSnapPointsAlignment="{TemplateBinding HorizontalSnapPointsAlignment}"
VerticalSnapPointsAlignment="{TemplateBinding VerticalSnapPointsAlignment}"
Background="{TemplateBinding Background}">
Background="{TemplateBinding Background}"
ScrollViewer.IsScrollInertiaEnabled="{TemplateBinding IsScrollInertiaEnabled}">
<ScrollContentPresenter.GestureRecognizers>
<ScrollGestureRecognizer CanHorizontallyScroll="{Binding CanHorizontallyScroll, ElementName=PART_ContentPresenter}"
CanVerticallyScroll="{Binding CanVerticallyScroll, ElementName=PART_ContentPresenter}"
IsScrollInertiaEnabled="{Binding IsScrollInertiaEnabled, RelativeSource={RelativeSource TemplatedParent}}" />
IsScrollInertiaEnabled="{Binding (ScrollViewer.IsScrollInertiaEnabled), ElementName=PART_ContentPresenter}"/>
</ScrollContentPresenter.GestureRecognizers>
</ScrollContentPresenter>
<ScrollBar Name="PART_HorizontalScrollBar"

4
src/Headless/Avalonia.Headless.Vnc/HeadlessVncFramebufferSource.cs

@ -40,11 +40,11 @@ namespace Avalonia.Headless.Vnc
{
Window?.MouseMove(pt);
foreach (var btn in CheckedButtons)
if (_previousButtons.HasAllFlags(btn) && !buttons.HasAllFlags(btn))
if (_previousButtons.HasFlag(btn) && !buttons.HasFlag(btn))
Window?.MouseUp(pt, TranslateButton(btn), modifiers);
foreach (var btn in CheckedButtons)
if (!_previousButtons.HasAllFlags(btn) && buttons.HasAllFlags(btn))
if (!_previousButtons.HasFlag(btn) && buttons.HasFlag(btn))
Window?.MouseDown(pt, TranslateButton(btn), modifiers);
_previousButtons = buttons;
}, DispatcherPriority.Input);

2
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@ -107,7 +107,7 @@ namespace Avalonia.LinuxFramebuffer
if (_topLevel is IFocusScope scope)
{
FocusManager.Instance?.SetFocusScope(scope);
((FocusManager)_topLevel.FocusManager).SetFocusScope(scope);
}
}

6
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@ -154,7 +154,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
var namespaces = _nsInfo.XmlNamespaces;
if (!namespaces.TryGetValue(ns, out var lst))
throw new ArgumentException("Unable to resolve namespace for type " + qualifiedTypeName);
foreach (var entry in lst)
var resolvable = lst.Where(static e => e.ClrAssemblyName is { Length: > 0 });
foreach (var entry in resolvable)
{
var asm = Assembly.Load(new AssemblyName(entry.ClrAssemblyName));
var resolved = asm.GetType(entry.ClrNamespace + "." + name);
@ -164,7 +165,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
throw new ArgumentException(
$"Unable to resolve type {qualifiedTypeName} from any of the following locations: " +
string.Join(",", lst.Select(e => $"`{e.ClrAssemblyName}:{e.ClrNamespace}.{name}`")));
string.Join(",", resolvable.Select(e => $"`clr-namespace:{e.ClrNamespace};assembly={e.ClrAssemblyName}`")))
{ HelpLink = "https://docs.avaloniaui.net/guides/basics/introduction-to-xaml#valid-xaml-namespaces" };
}
}

33
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -7,7 +7,6 @@ using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering.Utilities;
using Avalonia.Utilities;
using Avalonia.Media.Imaging;
using SkiaSharp;
using ISceneBrush = Avalonia.Media.ISceneBrush;
@ -26,7 +25,7 @@ namespace Avalonia.Skia
private readonly Stack<double> _opacityStack = new();
private readonly Matrix? _postTransform;
private double _currentOpacity = 1.0f;
private readonly bool _canTextUseLcdRendering;
private readonly bool _disableSubpixelTextRendering;
private Matrix _currentTransform;
private bool _disposed;
private GRContext? _grContext;
@ -59,11 +58,11 @@ namespace Avalonia.Skia
/// Dpi of drawings.
/// </summary>
public Vector Dpi;
/// <summary>
/// Render text without Lcd rendering.
/// Render text without subpixel antialiasing.
/// </summary>
public bool DisableTextLcdRendering;
public bool DisableSubpixelTextRendering;
/// <summary>
/// GPU-accelerated context (optional)
@ -135,7 +134,7 @@ namespace Avalonia.Skia
_dpi = createInfo.Dpi;
_disposables = disposables;
_canTextUseLcdRendering = !createInfo.DisableTextLcdRendering;
_disableSubpixelTextRendering = createInfo.DisableSubpixelTextRendering;
_grContext = createInfo.GrContext;
_gpu = createInfo.Gpu;
if (_grContext != null)
@ -519,7 +518,23 @@ namespace Avalonia.Skia
{
var glyphRunImpl = (GlyphRunImpl)glyphRun;
var textBlob = glyphRunImpl.GetTextBlob(RenderOptions);
var textRenderOptions = RenderOptions;
if (_disableSubpixelTextRendering)
{
switch (textRenderOptions.TextRenderingMode)
{
case TextRenderingMode.Unspecified
when textRenderOptions.EdgeMode == EdgeMode.Antialias || textRenderOptions.EdgeMode == EdgeMode.Unspecified:
case TextRenderingMode.SubpixelAntialias:
{
textRenderOptions = textRenderOptions with { TextRenderingMode = TextRenderingMode.Antialias };
break;
}
}
}
var textBlob = glyphRunImpl.GetTextBlob(textRenderOptions);
Canvas.DrawText(textBlob, (float)glyphRun.BaselineOrigin.X,
(float)glyphRun.BaselineOrigin.Y, paintWrapper.Paint);
@ -969,6 +984,7 @@ namespace Avalonia.Skia
using (var ctx = intermediate.CreateDrawingContext())
{
ctx.RenderOptions = RenderOptions;
ctx.Clear(Colors.Transparent);
content.Render(ctx, rect.TopLeft == default ? null : Matrix.CreateTranslation(-rect.X, -rect.Y));
}
@ -997,6 +1013,7 @@ namespace Avalonia.Skia
using var pictureTarget = new PictureRenderTarget(_gpu, _grContext, _dpi);
using (var ctx = pictureTarget.CreateDrawingContext(calc.IntermediateSize))
{
ctx.RenderOptions = RenderOptions;
ctx.PushClip(calc.IntermediateClip);
content.Render(ctx, transform);
ctx.PopClip();
@ -1283,7 +1300,7 @@ namespace Avalonia.Skia
Height = pixelSize.Height,
Dpi = _dpi,
Format = format,
DisableTextLcdRendering = !_canTextUseLcdRendering,
DisableTextLcdRendering = isLayer ? _disableSubpixelTextRendering : true,
GrContext = _grContext,
Gpu = _gpu,
Session = _session,

4
src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs

@ -3,7 +3,6 @@ using System.Diagnostics.CodeAnalysis;
using Avalonia.Reactive;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
using Avalonia.Rendering;
using SkiaSharp;
namespace Avalonia.Skia
@ -54,8 +53,7 @@ namespace Avalonia.Skia
var createInfo = new DrawingContextImpl.CreateInfo
{
Surface = _framebufferSurface,
Dpi = framebuffer.Dpi,
DisableTextLcdRendering = true
Dpi = framebuffer.Dpi
};
return new DrawingContextImpl(createInfo, _preFramebufferCopyHandler, canvas, framebuffer);

1
src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs

@ -30,7 +30,6 @@ namespace Avalonia.Skia
GrContext = session.GrContext,
Surface = session.SkSurface,
Dpi = SkiaPlatform.DefaultDpi * session.ScaleFactor,
DisableTextLcdRendering = true,
Gpu = _skiaGpu,
CurrentSession = session
};

2
src/Skia/Avalonia.Skia/Helpers/DrawingContextHelper.cs

@ -20,7 +20,7 @@ namespace Avalonia.Skia.Helpers
{
Canvas = canvas,
Dpi = dpi,
DisableTextLcdRendering = true,
DisableSubpixelTextRendering = true,
};
return new DrawingContextImpl(createInfo);

4
src/Skia/Avalonia.Skia/PictureRenderTarget.cs

@ -39,7 +39,7 @@ internal class PictureRenderTarget : IDisposable
{
Canvas = canvas,
Dpi = _dpi,
DisableTextLcdRendering = true,
DisableSubpixelTextRendering = true,
GrContext = _grContext,
Gpu = _gpu,
};
@ -52,4 +52,4 @@ internal class PictureRenderTarget : IDisposable
}
public void Dispose() => _picture?.Dispose();
}
}

2
src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs

@ -106,7 +106,7 @@ namespace Avalonia.Skia
{
Surface = _surface.Surface,
Dpi = Dpi,
DisableTextLcdRendering = _disableLcdRendering,
DisableSubpixelTextRendering = _disableLcdRendering,
GrContext = _grContext,
Gpu = _gpu,
};

2
src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs

@ -22,7 +22,7 @@ namespace Avalonia.Win32.Embedding
UnmanagedMethods.SetParent(WindowHandle, Handle);
_root.Prepare();
if (_root.IsFocused)
FocusManager.Instance.Focus(null);
_root.FocusManager.ClearFocus();
_root.GotFocus += RootGotFocus;
FixPosition();

8
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@ -141,13 +141,13 @@ namespace Avalonia.Win32.Interop.Wpf
{
var state = Keyboard.Modifiers;
var rv = default(RawInputModifiers);
if (state.HasAllFlags(ModifierKeys.Windows))
if (state.HasFlag(ModifierKeys.Windows))
rv |= RawInputModifiers.Meta;
if (state.HasAllFlags(ModifierKeys.Alt))
if (state.HasFlag(ModifierKeys.Alt))
rv |= RawInputModifiers.Alt;
if (state.HasAllFlags(ModifierKeys.Control))
if (state.HasFlag(ModifierKeys.Control))
rv |= RawInputModifiers.Control;
if (state.HasAllFlags(ModifierKeys.Shift))
if (state.HasFlag(ModifierKeys.Shift))
rv |= RawInputModifiers.Shift;
if (e != null)
{

2
src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs

@ -5,7 +5,7 @@ using Avalonia.Win32.Interop;
namespace Avalonia.Win32.Input
{
class WindowsKeyboardDevice : KeyboardDevice
internal class WindowsKeyboardDevice : KeyboardDevice
{
private readonly byte[] _keyStates = new byte[256];

58
tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs

@ -23,7 +23,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
Assert.Same(target, FocusManager.Instance.Current);
Assert.Same(target, root.FocusManager.GetFocusedElement());
}
}
@ -39,14 +39,14 @@ namespace Avalonia.Base.UnitTests.Input
Child = target = new Button() { IsVisible = false}
};
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
target.Focus();
Assert.False(target.IsFocused);
Assert.False(target.IsKeyboardFocusWithin);
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -67,14 +67,14 @@ namespace Avalonia.Base.UnitTests.Input
}
};
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
target.Focus();
Assert.False(target.IsFocused);
Assert.False(target.IsKeyboardFocusWithin);
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -100,11 +100,11 @@ namespace Avalonia.Base.UnitTests.Input
first.Focus();
Assert.Same(first, FocusManager.Instance.Current);
Assert.Same(first, root.FocusManager.GetFocusedElement());
second.Focus();
Assert.Same(first, FocusManager.Instance.Current);
Assert.Same(first, root.FocusManager.GetFocusedElement());
}
}
@ -120,14 +120,14 @@ namespace Avalonia.Base.UnitTests.Input
Child = target = new Button() { IsEnabled = false }
};
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
target.Focus();
Assert.False(target.IsFocused);
Assert.False(target.IsKeyboardFocusWithin);
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -148,14 +148,14 @@ namespace Avalonia.Base.UnitTests.Input
}
};
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
target.Focus();
Assert.False(target.IsFocused);
Assert.False(target.IsKeyboardFocusWithin);
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -201,7 +201,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
target.IsVisible = false;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -224,7 +224,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
container.IsVisible = false;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -243,7 +243,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
target.IsEnabled = false;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -266,7 +266,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
container.IsEnabled = false;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -285,7 +285,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
root.Child = null;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -312,13 +312,13 @@ namespace Avalonia.Base.UnitTests.Input
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus"));
Assert.False(target2.IsFocused);
Assert.False(target2.Classes.Contains(":focus"));
FocusManager.Instance?.Focus(target2, NavigationMethod.Tab);
target2.Focus(NavigationMethod.Tab);
Assert.False(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus"));
Assert.True(target2.IsFocused);
@ -348,19 +348,19 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus-visible"));
Assert.False(target2.IsFocused);
Assert.False(target2.Classes.Contains(":focus-visible"));
FocusManager.Instance?.Focus(target2, NavigationMethod.Tab);
target2.Focus(NavigationMethod.Tab);
Assert.False(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus-visible"));
Assert.True(target2.IsFocused);
Assert.True(target2.Classes.Contains(":focus-visible"));
FocusManager.Instance?.Focus(target1, NavigationMethod.Directional);
target1.Focus(NavigationMethod.Directional);
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-visible"));
Assert.False(target2.IsFocused);
@ -390,7 +390,7 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-within"));
Assert.True(target1.IsKeyboardFocusWithin);
@ -425,7 +425,7 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-within"));
Assert.True(target1.IsKeyboardFocusWithin);
@ -436,7 +436,7 @@ namespace Avalonia.Base.UnitTests.Input
Assert.True(root.Classes.Contains(":focus-within"));
Assert.True(root.IsKeyboardFocusWithin);
FocusManager.Instance?.Focus(target2);
target2.Focus();
Assert.False(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus-within"));
@ -478,7 +478,7 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-within"));
Assert.True(target1.IsKeyboardFocusWithin);
@ -534,7 +534,7 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-within"));
Assert.True(target1.IsKeyboardFocusWithin);
@ -545,7 +545,7 @@ namespace Avalonia.Base.UnitTests.Input
Assert.Equal(KeyboardDevice.Instance.FocusedElement, target1);
FocusManager.Instance?.Focus(target2);
target2.Focus();
Assert.False(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus-within"));
@ -578,9 +578,9 @@ namespace Avalonia.Base.UnitTests.Input
};
target.Focus();
FocusManager.Instance.Focus(null);
root.FocusManager.ClearFocus();
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save