diff --git a/api/Avalonia.Skia.nupkg.xml b/api/Avalonia.Skia.nupkg.xml new file mode 100644 index 0000000000..eda59fc334 --- /dev/null +++ b/api/Avalonia.Skia.nupkg.xml @@ -0,0 +1,28 @@ + + + + + CP0008 + T:Avalonia.Skia.ISkiaGpu + baseline/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll + current/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll + + + CP0008 + T:Avalonia.Skia.ISkiaGpuWithPlatformGraphicsContext + baseline/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll + current/Avalonia.Skia/lib/net10.0/Avalonia.Skia.dll + + + CP0008 + T:Avalonia.Skia.ISkiaGpu + baseline/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll + current/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll + + + CP0008 + T:Avalonia.Skia.ISkiaGpuWithPlatformGraphicsContext + baseline/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll + current/Avalonia.Skia/lib/net8.0/Avalonia.Skia.dll + + diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml index 3858eaa6ff..5a424cb8ee 100644 --- a/api/Avalonia.nupkg.xml +++ b/api/Avalonia.nupkg.xml @@ -19,24 +19,54 @@ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Platform.IOptionalFeatureProvider + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0001 T:Avalonia.Platform.IReadableBitmapWithAlphaImpl baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Platform.OptionalFeatureProviderExtensions + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0001 T:Avalonia.Utilities.StringTokenizer baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Controls.AutoCompleteBox.BindingEvaluator`1 + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0001 + T:Avalonia.Controls.NativeMenuItemToggleType + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + CP0001 T:Avalonia.Controls.Primitives.IScrollable baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + CP0001 + T:Avalonia.Markup.Xaml.ConstructorArgumentAttribute + baseline/Avalonia/lib/net10.0/Avalonia.Markup.Xaml.dll + current/Avalonia/lib/net10.0/Avalonia.Markup.Xaml.dll + CP0001 T:Avalonia.Media.Fonts.FontFamilyLoader @@ -61,30 +91,66 @@ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Platform.IOptionalFeatureProvider + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0001 T:Avalonia.Platform.IReadableBitmapWithAlphaImpl baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Platform.OptionalFeatureProviderExtensions + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0001 T:Avalonia.Utilities.StringTokenizer baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Controls.AutoCompleteBox.BindingEvaluator`1 + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0001 + T:Avalonia.Controls.NativeMenuItemToggleType + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0001 T:Avalonia.Controls.Primitives.IScrollable baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + CP0001 + T:Avalonia.Markup.Xaml.ConstructorArgumentAttribute + baseline/Avalonia/lib/net8.0/Avalonia.Markup.Xaml.dll + current/Avalonia/lib/net8.0/Avalonia.Markup.Xaml.dll + CP0001 T:Avalonia.Media.Fonts.FontFamilyLoader baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + CP0002 + F:Avalonia.Controls.ResourcesChangedEventArgs.Empty + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0002 F:Avalonia.Media.DrawingImage.ViewboxProperty @@ -97,6 +163,18 @@ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0002 + M:Avalonia.Controls.ResourcesChangedEventArgs.#ctor + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Data.ReflectionBinding.#ctor(System.String,Avalonia.Data.BindingMode) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0002 M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers) @@ -283,6 +361,18 @@ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + CP0002 + F:Avalonia.Controls.NativeMenuBar.EnableMenuItemClickForwardingProperty + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + F:Avalonia.Controls.NativeMenuItem.ToggleTypeProperty + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + CP0002 F:Avalonia.Controls.TextBlock.LetterSpacingProperty @@ -367,6 +457,36 @@ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Controls.NativeMenuBar.SetEnableMenuItemClickForwarding(Avalonia.Controls.MenuItem,System.Boolean) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.NativeMenuItem.get_ToggleType + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.OverlayPopupHost.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect}) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.OverlayPopupHost.CreatePopupHost(Avalonia.Visual,Avalonia.IAvaloniaDependencyResolver) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.PopupRoot.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect}) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + CP0002 M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Controls.Control) @@ -421,6 +541,18 @@ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Data.Binding.#ctor(System.String,Avalonia.Data.BindingMode) + baseline/Avalonia/lib/net10.0/Avalonia.Markup.dll + current/Avalonia/lib/net10.0/Avalonia.Markup.dll + + + CP0002 + M:Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension.#ctor(System.String,Avalonia.Data.BindingMode) + baseline/Avalonia/lib/net10.0/Avalonia.Markup.Xaml.dll + current/Avalonia/lib/net10.0/Avalonia.Markup.Xaml.dll + CP0002 F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache @@ -451,6 +583,12 @@ baseline/Avalonia/lib/net6.0/Avalonia.Dialogs.dll current/Avalonia/lib/net6.0/Avalonia.Dialogs.dll + + CP0002 + F:Avalonia.Controls.ResourcesChangedEventArgs.Empty + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0002 F:Avalonia.Media.DrawingImage.ViewboxProperty @@ -463,6 +601,18 @@ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0002 + M:Avalonia.Controls.ResourcesChangedEventArgs.#ctor + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Data.ReflectionBinding.#ctor(System.String,Avalonia.Data.BindingMode) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0002 M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers) @@ -649,6 +799,18 @@ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + CP0002 + F:Avalonia.Controls.NativeMenuBar.EnableMenuItemClickForwardingProperty + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + F:Avalonia.Controls.NativeMenuItem.ToggleTypeProperty + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0002 F:Avalonia.Controls.TextBlock.LetterSpacingProperty @@ -733,6 +895,36 @@ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Controls.NativeMenuBar.SetEnableMenuItemClickForwarding(Avalonia.Controls.MenuItem,System.Boolean) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.NativeMenuItem.get_ToggleType + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.OverlayPopupHost.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect}) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.OverlayPopupHost.CreatePopupHost(Avalonia.Visual,Avalonia.IAvaloniaDependencyResolver) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.PopupRoot.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect}) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0002 M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Controls.Control) @@ -793,6 +985,18 @@ baseline/Avalonia/lib/net8.0/Avalonia.Dialogs.dll current/Avalonia/lib/net8.0/Avalonia.Dialogs.dll + + CP0002 + M:Avalonia.Data.Binding.#ctor(System.String,Avalonia.Data.BindingMode) + baseline/Avalonia/lib/net8.0/Avalonia.Markup.dll + current/Avalonia/lib/net8.0/Avalonia.Markup.dll + + + CP0002 + M:Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension.#ctor(System.String,Avalonia.Data.BindingMode) + baseline/Avalonia/lib/net8.0/Avalonia.Markup.Xaml.dll + current/Avalonia/lib/net8.0/Avalonia.Markup.Xaml.dll + CP0002 F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache @@ -1141,36 +1345,252 @@ baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll + + CP0007 + T:Avalonia.Controls.ResourcesChangedEventArgs + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0007 + T:Avalonia.Controls.ResourcesChangedEventArgs + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0008 + T:Avalonia.Media.ImmediateDrawingContext + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0008 T:Avalonia.Media.StreamGeometryContext baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0008 + T:Avalonia.Platform.IPlatformGraphicsContext + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0008 + T:Avalonia.Platform.IPlatformGraphicsWithFeatures + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0008 + T:Avalonia.Platform.IPlatformRenderInterfaceContext + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0008 T:Avalonia.Platform.IWriteableBitmapImpl baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0008 + T:Avalonia.Application + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Controls.Platform.IWin32OptionsTopLevelImpl + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Platform.IPopupImpl + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Platform.ITopLevelImpl + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Platform.IWindowBaseImpl + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Platform.IWindowImpl + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Metal.IMetalDevice + baseline/Avalonia/lib/net10.0/Avalonia.Metal.dll + current/Avalonia/lib/net10.0/Avalonia.Metal.dll + + + CP0008 + T:Avalonia.OpenGL.Egl.EglContext + baseline/Avalonia/lib/net10.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net10.0/Avalonia.OpenGL.dll + + + CP0008 + T:Avalonia.OpenGL.IGlContext + baseline/Avalonia/lib/net10.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net10.0/Avalonia.OpenGL.dll + + + CP0008 + T:Avalonia.Vulkan.IVulkanDevice + baseline/Avalonia/lib/net10.0/Avalonia.Vulkan.dll + current/Avalonia/lib/net10.0/Avalonia.Vulkan.dll + + + CP0008 + T:Avalonia.Vulkan.IVulkanPlatformGraphicsContext + baseline/Avalonia/lib/net10.0/Avalonia.Vulkan.dll + current/Avalonia/lib/net10.0/Avalonia.Vulkan.dll + + + CP0008 + T:Avalonia.Media.ImmediateDrawingContext + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0008 T:Avalonia.Media.StreamGeometryContext baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0008 + T:Avalonia.Platform.IPlatformGraphicsContext + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0008 + T:Avalonia.Platform.IPlatformGraphicsWithFeatures + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0008 + T:Avalonia.Platform.IPlatformRenderInterfaceContext + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0008 T:Avalonia.Platform.IWriteableBitmapImpl baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0008 + T:Avalonia.Application + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Controls.Platform.IWin32OptionsTopLevelImpl + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Platform.IPopupImpl + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Platform.ITopLevelImpl + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Platform.IWindowBaseImpl + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Platform.IWindowImpl + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0008 + T:Avalonia.Metal.IMetalDevice + baseline/Avalonia/lib/net8.0/Avalonia.Metal.dll + current/Avalonia/lib/net8.0/Avalonia.Metal.dll + + + CP0008 + T:Avalonia.OpenGL.Egl.EglContext + baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + + + CP0008 + T:Avalonia.OpenGL.IGlContext + baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + + + CP0008 + T:Avalonia.Vulkan.IVulkanDevice + baseline/Avalonia/lib/net8.0/Avalonia.Vulkan.dll + current/Avalonia/lib/net8.0/Avalonia.Vulkan.dll + + + CP0008 + T:Avalonia.Vulkan.IVulkanPlatformGraphicsContext + baseline/Avalonia/lib/net8.0/Avalonia.Vulkan.dll + current/Avalonia/lib/net8.0/Avalonia.Vulkan.dll + + + CP0009 + T:Avalonia.Controls.ResourcesChangedEventArgs + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0009 T:Avalonia.Platform.Screen baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + CP0009 + T:Avalonia.Controls.ResourcesChangedEventArgs + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0009 T:Avalonia.Platform.Screen diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index c4c42a7311..819072db18 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -8,8 +8,10 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Headless; +using Avalonia.LinuxFramebuffer; using Avalonia.LinuxFramebuffer.Output; using Avalonia.LogicalTree; +using Avalonia.Platform; using Avalonia.Rendering.Composition; using Avalonia.Threading; using Avalonia.Vulkan; @@ -19,16 +21,9 @@ namespace ControlCatalog.Desktop { static class Program { - private static bool s_useFramebuffer; - [STAThread] static int Main(string[] args) { - if (args.Contains("--fbdev")) - { - s_useFramebuffer = true; - } - if (args.Contains("--wait-for-attach")) { Console.WriteLine("Attach debugger and use 'Set next statement'"); @@ -45,12 +40,27 @@ namespace ControlCatalog.Desktop double GetScaling() { var idx = Array.IndexOf(args, "--scaling"); - if (idx != 0 && args.Length > idx + 1 && + if (idx >= 0 && args.Length > idx + 1 && double.TryParse(args[idx + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out var scaling)) return scaling; return 1; } - if (s_useFramebuffer) + SurfaceOrientation GetOrientation() + { + var idx = Array.IndexOf(args, "--orientation"); + if (idx >= 0 && args.Length > idx + 1 && + Enum.TryParse(args[idx + 1], true, out var orientation)) + return orientation; + return SurfaceOrientation.Rotation0; + } + string? GetCard() + { + var idx = Array.IndexOf(args, "--card"); + if (idx >= 0 && args.Length > idx + 1) + return args[idx + 1]; + return null; + } + if (args.Contains("--fbdev")) { SilenceConsole(); return builder.StartLinuxFbDev(args, new FbDevOutputOptions() @@ -108,13 +118,17 @@ namespace ControlCatalog.Desktop else if (args.Contains("--drm")) { SilenceConsole(); - return builder.StartLinuxDrm(args, scaling: GetScaling()); + return builder.StartLinuxDrm(args, card: GetCard(), options: new DrmOutputOptions() + { + Scaling = GetScaling(), + Orientation = GetOrientation(), + }); } else if (args.Contains("--dxgi")) { builder.With(new Win32PlatformOptions() { - CompositionMode = new [] { Win32CompositionMode.LowLatencyDxgiSwapChain } + CompositionMode = [Win32CompositionMode.LowLatencyDxgiSwapChain] }); return builder.StartWithClassicDesktopLifetime(args); } @@ -151,14 +165,14 @@ namespace ControlCatalog.Desktop .WithDeveloperTools() .AfterSetup(builder => { - EmbedSample.Implementation = OperatingSystem.IsWindows() ? (INativeDemoControl)new EmbedSampleWin() + EmbedSample.Implementation = OperatingSystem.IsWindows() ? new EmbedSampleWin() : OperatingSystem.IsMacOS() ? new EmbedSampleMac() : OperatingSystem.IsLinux() ? new EmbedSampleGtk() : null; }) .LogToTrace(); - static void SilenceConsole() + private static void SilenceConsole() { new Thread(() => { diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs index d9e64ecee0..47b6eb7f4a 100644 --- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs +++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs @@ -7,30 +7,12 @@ using Avalonia.Controls; using Avalonia.Data; using Avalonia.Data.Converters; using Avalonia.LogicalTree; +using ControlCatalog.Models; namespace ControlCatalog.Pages { public partial class AutoCompleteBoxPage : UserControl { - public class StateData - { - public string Name { get; private set; } - public string Abbreviation { get; private set; } - public string Capital { get; private set; } - - public StateData(string name, string abbreviatoin, string capital) - { - Name = name; - Abbreviation = abbreviatoin; - Capital = capital; - } - - public override string ToString() - { - return Name; - } - } - private static StateData[] BuildAllStates() { return new StateData[] diff --git a/samples/IntegrationTestApp/MainWindow.axaml.cs b/samples/IntegrationTestApp/MainWindow.axaml.cs index be552201c0..894c052d6c 100644 --- a/samples/IntegrationTestApp/MainWindow.axaml.cs +++ b/samples/IntegrationTestApp/MainWindow.axaml.cs @@ -37,7 +37,7 @@ namespace IntegrationTestApp { Header = (string?)page.Name, ToolTip = $"Tip:{(string?)page.Name}", - ToggleType = NativeMenuItemToggleType.Radio, + ToggleType = MenuItemToggleType.Radio }; menuItem.Click += (_, _) => diff --git a/samples/IntegrationTestApp/Pages/EmbeddingPage.axaml b/samples/IntegrationTestApp/Pages/EmbeddingPage.axaml index 632893bcd0..4d6bc24b47 100644 --- a/samples/IntegrationTestApp/Pages/EmbeddingPage.axaml +++ b/samples/IntegrationTestApp/Pages/EmbeddingPage.axaml @@ -16,5 +16,7 @@ + + diff --git a/samples/IntegrationTestApp/Pages/EmbeddingPage.axaml.cs b/samples/IntegrationTestApp/Pages/EmbeddingPage.axaml.cs index 93855cd13d..465743afbf 100644 --- a/samples/IntegrationTestApp/Pages/EmbeddingPage.axaml.cs +++ b/samples/IntegrationTestApp/Pages/EmbeddingPage.axaml.cs @@ -1,10 +1,19 @@ +using System; +using Avalonia.Automation; using Avalonia.Controls; +using Avalonia.Controls.Embedding; using Avalonia.Interactivity; +using IntegrationTestApp.Embedding; +using MonoMac.AppKit; +using MonoMac.CoreGraphics; +using MonoMac.ObjCRuntime; namespace IntegrationTestApp; public partial class EmbeddingPage : UserControl { + private const long NSModalResponseContinue = -1002; + public EmbeddingPage() { InitializeComponent(); @@ -19,5 +28,65 @@ public partial class EmbeddingPage : UserControl private void Reset_Click(object? sender, RoutedEventArgs e) { ResetText(); + ModalResultTextBox.Text = ""; + } + + private void RunNativeModalSession_OnClick(object? sender, RoutedEventArgs e) + { + MacHelper.EnsureInitialized(); + + var app = NSApplication.SharedApplication; + var modalWindow = CreateNativeWindow(); + var session = app.BeginModalSession(modalWindow); + + while (true) + { + if (app.RunModalSession(session) != NSModalResponseContinue) + break; + } + + app.EndModalSession(session); + } + + private NSWindow CreateNativeWindow() + { + var button = new Button + { + Name = "ButtonInModal", + Content = "Button" + }; + + AutomationProperties.SetAutomationId(button, "ButtonInModal"); + + var root = new EmbeddableControlRoot + { + Width = 200, + Height = 200, + Content = button + }; + root.Prepare(); + + var window = new NSWindow( + new CGRect(0, 0, root.Width, root.Height), + NSWindowStyle.Titled | NSWindowStyle.Closable, + NSBackingStore.Buffered, + false); + + window.Identifier = "ModalNativeWindow"; + window.WillClose += (_, _) => NSApplication.SharedApplication.StopModal(); + + button.Click += (_, _) => + { + ModalResultTextBox.Text = "Clicked"; + window.Close(); + }; + + if (root.TryGetPlatformHandle() is not { } handle) + throw new InvalidOperationException("Could not get platform handle"); + + window.ContentView = (NSView)Runtime.GetNSObject(handle.Handle)!; + root.StartRendering(); + + return window; } } diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs index 6841f5ba92..60345e0a50 100644 --- a/src/Android/Avalonia.Android/AvaloniaActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs @@ -119,22 +119,14 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity activatableLifetime.CurrentIntendActivity = this; } - if (Intent?.Data is { } androidUri - && androidUri.IsAbsolute - && Uri.TryCreate(androidUri.ToString(), UriKind.Absolute, out var uri)) - { - if (uri.Scheme == Uri.UriSchemeFile) - { - if (AndroidStorageItem.CreateItem(this, androidUri) is { } item) - { - _onActivated?.Invoke(this, new FileActivatedEventArgs(new [] { item })); - } - } - else - { - _onActivated?.Invoke(this, new ProtocolActivatedEventArgs(uri)); - } - } + HandleIntent(Intent); + } + + protected override void OnNewIntent(Intent? intent) + { + base.OnNewIntent(intent); + + HandleIntent(intent); } protected override void OnStop() @@ -218,6 +210,26 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity _view = new AvaloniaView(this) { Content = initialContent }; } + private void HandleIntent(Intent? intent) + { + if (intent?.Data is { } androidUri + && androidUri.IsAbsolute + && Uri.TryCreate(androidUri.ToString(), UriKind.Absolute, out var uri)) + { + if (uri.Scheme == Uri.UriSchemeFile || uri.Scheme == "content") + { + if (AndroidStorageItem.CreateItem(this, androidUri) is { } item) + { + _onActivated?.Invoke(this, new FileActivatedEventArgs(new[] { item })); + } + } + else + { + _onActivated?.Invoke(this, new ProtocolActivatedEventArgs(uri)); + } + } + } + public void OnBackInvoked() { var eventArgs = new AndroidBackRequestedEventArgs(); diff --git a/src/Android/Avalonia.Android/Platform/AndroidScreens.cs b/src/Android/Avalonia.Android/Platform/AndroidScreens.cs index 3f1f9bf44e..9b0f1bee38 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidScreens.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidScreens.cs @@ -10,6 +10,7 @@ using AndroidX.Window.Layout; using Avalonia.Android.Platform.SkiaPlatform; using Avalonia.Platform; using AndroidOrientation = global::Android.Content.Res.Orientation; +using AndroidRotation = global::Android.Views.SurfaceOrientation; namespace Avalonia.Android.Platform; @@ -53,7 +54,7 @@ internal class AndroidScreen(Display display) : PlatformScreen(new PlatformHandl var orientation = displayContext.Resources?.Configuration?.Orientation; if (orientation == AndroidOrientation.Square) naturalOrientation = ScreenOrientation.None; - else if (rotation is SurfaceOrientation.Rotation0 or SurfaceOrientation.Rotation180) + else if (rotation is AndroidRotation.Rotation0 or AndroidRotation.Rotation180) naturalOrientation = orientation == AndroidOrientation.Landscape ? ScreenOrientation.Landscape : ScreenOrientation.Portrait; @@ -73,14 +74,14 @@ internal class AndroidScreen(Display display) : PlatformScreen(new PlatformHandl CurrentOrientation = (display.Rotation, naturalOrientation) switch { (_, ScreenOrientation.None) => ScreenOrientation.None, - (SurfaceOrientation.Rotation0, ScreenOrientation.Landscape) => ScreenOrientation.Landscape, - (SurfaceOrientation.Rotation90, ScreenOrientation.Landscape) => ScreenOrientation.Portrait, - (SurfaceOrientation.Rotation180, ScreenOrientation.Landscape) => ScreenOrientation.LandscapeFlipped, - (SurfaceOrientation.Rotation270, ScreenOrientation.Landscape) => ScreenOrientation.PortraitFlipped, - (SurfaceOrientation.Rotation0, _) => ScreenOrientation.Portrait, - (SurfaceOrientation.Rotation90, _) => ScreenOrientation.Landscape, - (SurfaceOrientation.Rotation180, _) => ScreenOrientation.PortraitFlipped, - (SurfaceOrientation.Rotation270, _) => ScreenOrientation.LandscapeFlipped, + (AndroidRotation.Rotation0, ScreenOrientation.Landscape) => ScreenOrientation.Landscape, + (AndroidRotation.Rotation90, ScreenOrientation.Landscape) => ScreenOrientation.Portrait, + (AndroidRotation.Rotation180, ScreenOrientation.Landscape) => ScreenOrientation.LandscapeFlipped, + (AndroidRotation.Rotation270, ScreenOrientation.Landscape) => ScreenOrientation.PortraitFlipped, + (AndroidRotation.Rotation0, _) => ScreenOrientation.Portrait, + (AndroidRotation.Rotation90, _) => ScreenOrientation.Landscape, + (AndroidRotation.Rotation180, _) => ScreenOrientation.PortraitFlipped, + (AndroidRotation.Rotation270, _) => ScreenOrientation.LandscapeFlipped, _ => ScreenOrientation.Portrait }; } diff --git a/src/Avalonia.Base/Controls/IResourceHost.cs b/src/Avalonia.Base/Controls/IResourceHost.cs index 361e3562ec..286f0e36ef 100644 --- a/src/Avalonia.Base/Controls/IResourceHost.cs +++ b/src/Avalonia.Base/Controls/IResourceHost.cs @@ -29,12 +29,4 @@ namespace Avalonia.Controls /// void NotifyHostedResourcesChanged(ResourcesChangedEventArgs e); } - - // TODO12: merge with IResourceHost - internal interface IResourceHost2 : IResourceHost - { - event EventHandler ResourcesChanged2; - - void NotifyHostedResourcesChanged(ResourcesChangedToken token); - } } diff --git a/src/Avalonia.Base/Controls/ResourceDictionary.cs b/src/Avalonia.Base/Controls/ResourceDictionary.cs index e0944a5708..f8f6267e7b 100644 --- a/src/Avalonia.Base/Controls/ResourceDictionary.cs +++ b/src/Avalonia.Base/Controls/ResourceDictionary.cs @@ -358,7 +358,7 @@ namespace Avalonia.Controls if (hasResources) { - owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create()); + owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create()); } } @@ -385,7 +385,7 @@ namespace Avalonia.Controls if (hasResources) { - owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create()); + owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create()); } } diff --git a/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs b/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs index 36cc00d245..07c1c8d654 100644 --- a/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs +++ b/src/Avalonia.Base/Controls/ResourceNodeExtensions.cs @@ -158,7 +158,7 @@ namespace Avalonia.Controls protected override void Initialize() { - _target.SubscribeToResourcesChanged(ResourcesChanged, ResourcesChanged2); + _target.ResourcesChanged += ResourcesChanged; if (_target is IThemeVariantHost themeVariantHost) { @@ -168,7 +168,7 @@ namespace Avalonia.Controls protected override void Deinitialize() { - _target.UnsubscribeFromResourcesChanged(ResourcesChanged, ResourcesChanged2); + _target.ResourcesChanged -= ResourcesChanged; if (_target is IThemeVariantHost themeVariantHost) { @@ -186,11 +186,6 @@ namespace Avalonia.Controls PublishNext(GetValue()); } - private void ResourcesChanged2(object? sender, ResourcesChangedToken token) - { - PublishNext(GetValue()); - } - private void ActualThemeVariantChanged(object? sender, EventArgs e) { PublishNext(GetValue()); @@ -230,7 +225,7 @@ namespace Avalonia.Controls _target.OwnerChanged += OwnerChanged; _owner = _target.Owner; - _owner?.SubscribeToResourcesChanged(ResourcesChanged, ResourcesChanged2); + _owner?.ResourcesChanged += ResourcesChanged; if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost) { @@ -242,7 +237,7 @@ namespace Avalonia.Controls { _target.OwnerChanged -= OwnerChanged; - _owner?.UnsubscribeFromResourcesChanged(ResourcesChanged, ResourcesChanged2); + _owner?.ResourcesChanged -= ResourcesChanged; if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost) { @@ -270,7 +265,7 @@ namespace Avalonia.Controls private void OwnerChanged(object? sender, EventArgs e) { - _owner?.UnsubscribeFromResourcesChanged(ResourcesChanged, ResourcesChanged2); + _owner?.ResourcesChanged -= ResourcesChanged; if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost) { @@ -279,7 +274,7 @@ namespace Avalonia.Controls _owner = _target.Owner; - _owner?.SubscribeToResourcesChanged(ResourcesChanged, ResourcesChanged2); + _owner?.ResourcesChanged += ResourcesChanged; if (_overrideThemeVariant is null && _owner is IThemeVariantHost themeVariantHost2) { @@ -299,11 +294,6 @@ namespace Avalonia.Controls PublishNext(); } - private void ResourcesChanged2(object? sender, ResourcesChangedToken token) - { - PublishNext(); - } - private object? GetValue() { var theme = _overrideThemeVariant ?? (_target.Owner as IThemeVariantHost)?.ActualThemeVariant; diff --git a/src/Avalonia.Base/Controls/ResourceProvider.cs b/src/Avalonia.Base/Controls/ResourceProvider.cs index f0ab42a4a8..f73f11e713 100644 --- a/src/Avalonia.Base/Controls/ResourceProvider.cs +++ b/src/Avalonia.Base/Controls/ResourceProvider.cs @@ -45,7 +45,7 @@ public abstract class ResourceProvider : AvaloniaObject, IResourceProvider protected void RaiseResourcesChanged() { - Owner?.NotifyHostedResourcesChanged(ResourcesChangedToken.Create()); + Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create()); } /// @@ -57,7 +57,7 @@ public abstract class ResourceProvider : AvaloniaObject, IResourceProvider { if (HasResources) { - owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create()); + owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create()); } } @@ -70,7 +70,7 @@ public abstract class ResourceProvider : AvaloniaObject, IResourceProvider { if (HasResources) { - owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create()); + owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create()); } } diff --git a/src/Avalonia.Base/Controls/ResourcesChangedEventArgs.cs b/src/Avalonia.Base/Controls/ResourcesChangedEventArgs.cs index a60c95a2e0..f78910b003 100644 --- a/src/Avalonia.Base/Controls/ResourcesChangedEventArgs.cs +++ b/src/Avalonia.Base/Controls/ResourcesChangedEventArgs.cs @@ -1,10 +1,24 @@ -using System; +using System.Threading; -namespace Avalonia.Controls +namespace Avalonia.Controls; + +/// +/// Represents the event arguments of . +/// The identifies the changes. +/// +/// The sequence number used to identify the changes. +/// +/// For performance reasons, this type is a struct. +/// Avoid using a default instance of this type or its default constructor, call instead. +/// +public readonly record struct ResourcesChangedEventArgs(int SequenceNumber) { - // TODO12: change this to be a struct, remove ResourcesChangedToken - public class ResourcesChangedEventArgs : EventArgs - { - public static new readonly ResourcesChangedEventArgs Empty = new ResourcesChangedEventArgs(); - } + private static int s_lastSequenceNumber; + + /// + /// Creates a new instance of with an auto-incremented sequence number. + /// + /// + public static ResourcesChangedEventArgs Create() + => new(Interlocked.Increment(ref s_lastSequenceNumber)); } diff --git a/src/Avalonia.Base/Controls/ResourcesChangedHelper.cs b/src/Avalonia.Base/Controls/ResourcesChangedHelper.cs deleted file mode 100644 index 8ad121ad3a..0000000000 --- a/src/Avalonia.Base/Controls/ResourcesChangedHelper.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using Avalonia.LogicalTree; - -namespace Avalonia.Controls; - -internal static class ResourcesChangedHelper -{ - internal static void NotifyHostedResourcesChanged(this IResourceHost host, ResourcesChangedToken token) - { - if (host is IResourceHost2 host2) - host2.NotifyHostedResourcesChanged(token); - else - host.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty); - } - - internal static void NotifyResourcesChanged(this ILogical logical, ResourcesChangedToken token) - { - if (logical is StyledElement styledElement) - styledElement.NotifyResourcesChanged(token); - else - logical.NotifyResourcesChanged(ResourcesChangedEventArgs.Empty); - } - - internal static void SubscribeToResourcesChanged( - this IResourceHost host, - EventHandler handler, - EventHandler handler2) - { - if (host is IResourceHost2 host2) - host2.ResourcesChanged2 += handler2; - else - host.ResourcesChanged += handler; - } - - internal static void UnsubscribeFromResourcesChanged( - this IResourceHost host, - EventHandler handler, - EventHandler handler2) - { - if (host is IResourceHost2 host2) - host2.ResourcesChanged2 -= handler2; - else - host.ResourcesChanged -= handler; - } -} diff --git a/src/Avalonia.Base/Controls/ResourcesChangedToken.cs b/src/Avalonia.Base/Controls/ResourcesChangedToken.cs deleted file mode 100644 index 8de692e729..0000000000 --- a/src/Avalonia.Base/Controls/ResourcesChangedToken.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading; - -namespace Avalonia.Controls; - -internal record struct ResourcesChangedToken(int SequenceNumber) -{ - private static int s_lastSequenceNumber; - - public static ResourcesChangedToken Create() - => new(Interlocked.Increment(ref s_lastSequenceNumber)); -} diff --git a/src/Avalonia.Base/Data/CompiledBinding.cs b/src/Avalonia.Base/Data/CompiledBinding.cs index 764b04957e..952a5cddc4 100644 --- a/src/Avalonia.Base/Data/CompiledBinding.cs +++ b/src/Avalonia.Base/Data/CompiledBinding.cs @@ -7,6 +7,7 @@ using Avalonia.Data.Converters; using Avalonia.Data.Core; using Avalonia.Data.Core.ExpressionNodes; using Avalonia.Data.Core.Parsers; +using Avalonia.Metadata; namespace Avalonia.Data; @@ -70,6 +71,7 @@ public class CompiledBinding : BindingBase /// /// Gets or sets the binding path. /// + [ConstructorArgument("path")] public CompiledBindingPath? Path { get; set; } /// diff --git a/src/Avalonia.Base/Data/ReflectionBinding.cs b/src/Avalonia.Base/Data/ReflectionBinding.cs index 1209d47a2e..299f6317b4 100644 --- a/src/Avalonia.Base/Data/ReflectionBinding.cs +++ b/src/Avalonia.Base/Data/ReflectionBinding.cs @@ -8,6 +8,7 @@ using Avalonia.Data.Converters; using Avalonia.Data.Core; using Avalonia.Data.Core.ExpressionNodes; using Avalonia.Data.Core.Parsers; +using Avalonia.Metadata; using Avalonia.Utilities; namespace Avalonia.Data @@ -34,17 +35,6 @@ namespace Avalonia.Data { Path = path; } - - /// - /// Initializes a new instance of the class. - /// - /// The binding path. - /// The binding mode. - public ReflectionBinding(string path, BindingMode mode) - { - Path = path; - Mode = mode; - } /// /// Gets or sets the amount of time, in milliseconds, to wait before updating the binding @@ -95,6 +85,7 @@ namespace Avalonia.Data /// /// Gets or sets the binding path. /// + [ConstructorArgument("path")] public string Path { get; set; } = ""; /// diff --git a/src/Avalonia.Base/Data/TemplateBinding.cs b/src/Avalonia.Base/Data/TemplateBinding.cs index 428f9c4a11..55b3e74ce5 100644 --- a/src/Avalonia.Base/Data/TemplateBinding.cs +++ b/src/Avalonia.Base/Data/TemplateBinding.cs @@ -48,6 +48,7 @@ namespace Avalonia.Data /// /// Gets or sets the name of the source property on the templated parent. /// + [ConstructorArgument("property")] [InheritDataTypeFrom(InheritDataTypeFromScopeKind.ControlTemplate)] public AvaloniaProperty? Property { get; set; } diff --git a/src/Avalonia.Base/Diagnostics/ObsoletionMessages.cs b/src/Avalonia.Base/Diagnostics/ObsoletionMessages.cs deleted file mode 100644 index bfada91abe..0000000000 --- a/src/Avalonia.Base/Diagnostics/ObsoletionMessages.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Avalonia.Diagnostics; - -internal static class ObsoletionMessages -{ - public const string MayBeRemovedInAvalonia12 = "This API may be removed in Avalonia 12. If you depend on this API, please open an issue with details of your use-case."; -} diff --git a/src/Avalonia.Base/Platform/IOptionalFeatureProvider.cs b/src/Avalonia.Base/IOptionalFeatureProvider.cs similarity index 92% rename from src/Avalonia.Base/Platform/IOptionalFeatureProvider.cs rename to src/Avalonia.Base/IOptionalFeatureProvider.cs index 27c2243791..55c3ef7984 100644 --- a/src/Avalonia.Base/Platform/IOptionalFeatureProvider.cs +++ b/src/Avalonia.Base/IOptionalFeatureProvider.cs @@ -1,8 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; -// TODO12: move to Avalonia namespace. -namespace Avalonia.Platform; +namespace Avalonia; public interface IOptionalFeatureProvider { diff --git a/src/Avalonia.Base/Input/MouseDevice.cs b/src/Avalonia.Base/Input/MouseDevice.cs index 5a0cdad755..62105c7deb 100644 --- a/src/Avalonia.Base/Input/MouseDevice.cs +++ b/src/Avalonia.Base/Input/MouseDevice.cs @@ -34,6 +34,8 @@ namespace Avalonia.Input _pointer = pointer ?? new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true); } + internal Pointer Pointer => _pointer; + internal static TMouseDevice GetOrCreatePrimary() where TMouseDevice : MouseDevice, new() { if (_primary is TMouseDevice device) diff --git a/src/Avalonia.Base/Input/Pointer.cs b/src/Avalonia.Base/Input/Pointer.cs index f243a2e382..94643fa91e 100644 --- a/src/Avalonia.Base/Input/Pointer.cs +++ b/src/Avalonia.Base/Input/Pointer.cs @@ -77,6 +77,7 @@ namespace Avalonia.Input if (oldVisual != null) oldVisual.DetachedFromVisualTree -= OnCaptureDetached; Captured = control; + CaptureSource = source; if (source != CaptureSource.Platform) PlatformCapture(control); @@ -115,6 +116,7 @@ namespace Avalonia.Input public IInputElement? Captured { get; private set; } public PointerType Type { get; } + public bool IsPrimary { get; } /// @@ -124,6 +126,8 @@ namespace Avalonia.Input public bool IsGestureRecognitionSkipped { get; set; } + internal CaptureSource CaptureSource { get; private set; } = CaptureSource.Platform; + public void Dispose() { if (Captured != null) diff --git a/src/Avalonia.Base/Media/Imaging/Bitmap.cs b/src/Avalonia.Base/Media/Imaging/Bitmap.cs index 9c0c20d170..63ec02737f 100644 --- a/src/Avalonia.Base/Media/Imaging/Bitmap.cs +++ b/src/Avalonia.Base/Media/Imaging/Bitmap.cs @@ -291,9 +291,7 @@ namespace Avalonia.Media.Imaging { get { - // TODO12: We should probably make PlatformImpl to be nullable or make it possible to check - // and fix IRef in general (right now Item is not nullable while it internally is) - if (PlatformImpl.Item == null!) + if (!PlatformImpl.IsAlive) return null; return PlatformImpl; } diff --git a/src/Avalonia.Base/Metadata/ConstructorArgumentAttribute.cs b/src/Avalonia.Base/Metadata/ConstructorArgumentAttribute.cs new file mode 100644 index 0000000000..5c0021655b --- /dev/null +++ b/src/Avalonia.Base/Metadata/ConstructorArgumentAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace Avalonia.Metadata; + +/// +/// Indicates that a property corresponds to a named parameter in the constructor. +/// +/// The name of the parameter in the constructor. +/// This attribute is used for XAML. +[AttributeUsage(AttributeTargets.Property)] +public sealed class ConstructorArgumentAttribute(string name) : Attribute +{ + /// + /// Gets the name of the parameter in the constructor. + /// + public string Name { get; } = name; +} diff --git a/src/Avalonia.Base/Platform/ISurfaceOrientation.cs b/src/Avalonia.Base/Platform/ISurfaceOrientation.cs new file mode 100644 index 0000000000..2f4f2d3241 --- /dev/null +++ b/src/Avalonia.Base/Platform/ISurfaceOrientation.cs @@ -0,0 +1,6 @@ +namespace Avalonia.Platform; + +internal interface ISurfaceOrientation +{ + SurfaceOrientation Orientation { get; } +} diff --git a/src/Avalonia.Base/Platform/SurfaceOrientation.cs b/src/Avalonia.Base/Platform/SurfaceOrientation.cs new file mode 100644 index 0000000000..71835fb6ff --- /dev/null +++ b/src/Avalonia.Base/Platform/SurfaceOrientation.cs @@ -0,0 +1,9 @@ +namespace Avalonia.Platform; + +public enum SurfaceOrientation +{ + Rotation0, + Rotation90, + Rotation180, + Rotation270, +} diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs index b7f6262d9f..711d17d014 100644 --- a/src/Avalonia.Base/StyledElement.cs +++ b/src/Avalonia.Base/StyledElement.cs @@ -29,7 +29,7 @@ namespace Avalonia IDataContextProvider, ILogical, IThemeVariantHost, - IResourceHost2, + IResourceHost, IStyleHost, ISetLogicalParent, ISetInheritanceParent, @@ -94,8 +94,7 @@ namespace Avalonia private AvaloniaObject? _templatedParent; private bool _dataContextUpdating; private ControlTheme? _implicitTheme; - private EventHandler? _resourcesChanged2; - private ResourcesChangedToken _lastResourcesChangedToken; + private ResourcesChangedEventArgs _lastResourcesChangedEventArgs; /// /// Initializes static members of the class. @@ -150,12 +149,6 @@ namespace Avalonia /// public event EventHandler? ResourcesChanged; - event EventHandler? IResourceHost2.ResourcesChanged2 - { - add => _resourcesChanged2 += value; - remove => _resourcesChanged2 -= value; - } - /// public event EventHandler? ActualThemeVariantChanged; @@ -437,14 +430,11 @@ namespace Avalonia /// void ILogical.NotifyResourcesChanged(ResourcesChangedEventArgs e) - => NotifyResourcesChanged(ResourcesChangedToken.Create()); + => NotifyResourcesChanged(e); /// void IResourceHost.NotifyHostedResourcesChanged(ResourcesChangedEventArgs e) - => NotifyResourcesChanged(ResourcesChangedToken.Create()); - - void IResourceHost2.NotifyHostedResourcesChanged(ResourcesChangedToken token) - => NotifyResourcesChanged(token); + => NotifyResourcesChanged(e); /// public bool TryGetResource(object key, ThemeVariant? theme, out object? value) @@ -499,7 +489,7 @@ namespace Avalonia // non-rooted control beacuse it's unlikely that dynamic resources need to be // correct until the control is added to the tree, and it causes a *lot* of // notifications. - NotifyResourcesChanged(ResourcesChangedToken.Create()); + NotifyResourcesChanged(ResourcesChangedEventArgs.Create()); } RaisePropertyChanged(ParentProperty, old, Parent); @@ -552,8 +542,8 @@ namespace Avalonia /// /// Notifies child controls that a change has been made to resources that apply to them. /// - /// The change token. - internal virtual void NotifyChildResourcesChanged(ResourcesChangedToken token) + /// The change token. + internal virtual void NotifyChildResourcesChanged(ResourcesChangedEventArgs e) { if (_logicalChildren is object) { @@ -563,7 +553,7 @@ namespace Avalonia { for (var i = 0; i < count; ++i) { - _logicalChildren[i].NotifyResourcesChanged(token); + _logicalChildren[i].NotifyResourcesChanged(e); } } } @@ -895,7 +885,7 @@ namespace Avalonia ReevaluateImplicitTheme(); ApplyStyling(); - NotifyResourcesChanged(ResourcesChangedToken.Create(), propagate: false); + NotifyResourcesChanged(ResourcesChangedEventArgs.Create(), propagate: false); OnAttachedToLogicalTree(e); AttachedToLogicalTree?.Invoke(this, e); @@ -999,23 +989,22 @@ namespace Avalonia } internal void NotifyResourcesChanged( - ResourcesChangedToken token, + ResourcesChangedEventArgs e, bool propagate = true) { // We already got a notification for this element, ignore. - if (token.Equals(_lastResourcesChangedToken)) + if (e.Equals(_lastResourcesChangedEventArgs)) { return; } - _lastResourcesChangedToken = token; + _lastResourcesChangedEventArgs = e; - _resourcesChanged2?.Invoke(this, token); - ResourcesChanged?.Invoke(this, ResourcesChangedEventArgs.Empty); + ResourcesChanged?.Invoke(this, e); if (propagate) { - NotifyChildResourcesChanged(token); + NotifyChildResourcesChanged(e); } } diff --git a/src/Avalonia.Base/Styling/StyleBase.cs b/src/Avalonia.Base/Styling/StyleBase.cs index 038fc7c5c3..7dbdb22e9c 100644 --- a/src/Avalonia.Base/Styling/StyleBase.cs +++ b/src/Avalonia.Base/Styling/StyleBase.cs @@ -54,7 +54,7 @@ namespace Avalonia.Styling if (hadResources || _resources.HasResources) { - Owner.NotifyHostedResourcesChanged(ResourcesChangedToken.Create()); + Owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create()); } } } diff --git a/src/Avalonia.Base/Utilities/Ref.cs b/src/Avalonia.Base/Utilities/Ref.cs index 0b6abe5189..49a7a42710 100644 --- a/src/Avalonia.Base/Utilities/Ref.cs +++ b/src/Avalonia.Base/Utilities/Ref.cs @@ -28,6 +28,10 @@ namespace Avalonia.Utilities /// A reference to the value as the new type but sharing the refcount. IRef CloneAs() where TResult : class; + /// + /// Gets whether the reference still tracks a valid item. + /// + bool IsAlive { get; } /// /// The current refcount of the object tracked in this reference. For debugging/unit test use only. @@ -172,6 +176,8 @@ namespace Avalonia.Utilities return new Ref(item, counter); } + public bool IsAlive => _item is not null; + public int RefCount => _counter?.RefCount ?? throw new ObjectDisposedException("Ref<" + typeof(T) + ">"); } } diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs index 0bad04bb23..ff04499c42 100644 --- a/src/Avalonia.Controls/Application.cs +++ b/src/Avalonia.Controls/Application.cs @@ -30,7 +30,7 @@ namespace Avalonia /// method. /// - Tracks the lifetime of the application. /// - public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IThemeVariantHost, IResourceHost2, IApplicationPlatformEvents, IOptionalFeatureProvider + public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IThemeVariantHost, IResourceHost, IApplicationPlatformEvents, IOptionalFeatureProvider { /// /// The application-global data templates. @@ -43,7 +43,6 @@ namespace Avalonia private Action>? _stylesRemoved; private IApplicationLifetime? _applicationLifetime; private bool _setupCompleted; - private EventHandler? _resourcesChanged2; /// /// Defines the property. @@ -62,12 +61,6 @@ namespace Avalonia /// public event EventHandler? ResourcesChanged; - event EventHandler? IResourceHost2.ResourcesChanged2 - { - add => _resourcesChanged2 += value; - remove => _resourcesChanged2 -= value; - } - [Obsolete("Use Application.Current.TryGetFeature() instead.")] public event EventHandler? UrlsOpened; @@ -239,16 +232,9 @@ namespace Avalonia void IResourceHost.NotifyHostedResourcesChanged(ResourcesChangedEventArgs e) { - _resourcesChanged2?.Invoke(this, ResourcesChangedToken.Create()); ResourcesChanged?.Invoke(this, e); } - void IResourceHost2.NotifyHostedResourcesChanged(ResourcesChangedToken token) - { - _resourcesChanged2?.Invoke(this, token); - ResourcesChanged?.Invoke(this, ResourcesChangedEventArgs.Empty); - } - void IStyleHost.StylesAdded(IReadOnlyList styles) { _stylesAdded?.Invoke(styles); diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs index 90cedbce8c..ae009636af 100644 --- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs +++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs @@ -212,6 +212,12 @@ namespace Avalonia.Controls public static readonly StyledProperty InnerRightContentProperty = TextBox.InnerRightContentProperty.AddOwner(); + /// + /// Defines the property. + /// + public static readonly StyledProperty ValueMemberBindingProperty = + AvaloniaProperty.Register(nameof(ValueMemberBinding)); + /// /// Gets or sets the caret index /// @@ -332,26 +338,16 @@ namespace Avalonia.Controls } /// - /// Gets or sets the that - /// is used to get the values for display in the text portion of - /// the - /// control. + /// Gets or sets the that is used to get the values for display in the text portion + /// of the control. /// - /// The object used - /// when binding to a collection property. + /// The object used when binding to a collection property. [AssignBinding] [InheritDataTypeFromItems(nameof(ItemsSource))] public BindingBase? ValueMemberBinding { - get => _valueBindingEvaluator?.ValueBinding; - set - { - if (ValueMemberBinding != value) - { - _valueBindingEvaluator = new BindingEvaluator(value); - OnValueMemberBindingChanged(value); - } - } + get => GetValue(ValueMemberBindingProperty); + set => SetValue(ValueMemberBindingProperty, value); } /// diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs index ffa95285e5..880fd0ac8a 100644 --- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs @@ -189,7 +189,7 @@ namespace Avalonia.Controls /// /// A control that can provide updated string values from a binding. /// - private BindingEvaluator? _valueBindingEvaluator; + private BindingEvaluator? _valueMemberBindingEvaluator; /// /// A weak subscription for the collection changed event. @@ -439,6 +439,7 @@ namespace Avalonia.Controls if (!_settingItemTemplateFromValueMemberBinding) _itemTemplateIsFromValueMemberBinding = false; } + private void OnValueMemberBindingChanged(BindingBase? value) { if (_itemTemplateIsFromValueMemberBinding) @@ -460,6 +461,16 @@ namespace Avalonia.Controls } } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == ValueMemberBindingProperty) + { + OnValueMemberBindingChanged(change.GetNewValue()); + } + } + static AutoCompleteBox() { FocusableProperty.OverrideDefaultValue(true); @@ -1181,25 +1192,6 @@ namespace Avalonia.Controls } } - /// - /// Formats an Item for text comparisons based on Converter - /// and ConverterCulture properties. - /// - /// The object to format. - /// A value indicating whether to clear - /// the data context after the lookup is performed. - /// Formatted Value. - private string? FormatValue(object? value, bool clearDataContext) - { - string? result = FormatValue(value); - if (clearDataContext && _valueBindingEvaluator != null) - { - _valueBindingEvaluator.ClearDataContext(); - } - - return result; - } - /// /// Converts the specified object to a string by using the /// and @@ -1215,9 +1207,13 @@ namespace Avalonia.Controls /// protected virtual string? FormatValue(object? value) { - if (_valueBindingEvaluator != null) + if (ValueMemberBinding is { } valueMemberBinding) { - return _valueBindingEvaluator.GetDynamicValue(value) ?? String.Empty; + _valueMemberBindingEvaluator ??= new(); + _valueMemberBindingEvaluator.UpdateBinding(valueMemberBinding); + var result = _valueMemberBindingEvaluator.Evaluate(value) ?? string.Empty; + _valueMemberBindingEvaluator.ClearDataContext(); + return result; } return value == null ? String.Empty : value.ToString(); @@ -1451,9 +1447,6 @@ namespace Avalonia.Controls _view?.Clear(); _view?.AddRange(_newViewItems); - - // Clear the evaluator to discard a reference to the last item - _valueBindingEvaluator?.ClearDataContext(); } finally { @@ -1638,7 +1631,7 @@ namespace Avalonia.Controls if (top != null) { newSelectedItem = top; - string? topString = FormatValue(top, true); + string? topString = FormatValue(top); // Only replace partially when the two words being the same int minLength = Math.Min(topString?.Length ?? 0, Text?.Length ?? 0); @@ -1744,7 +1737,7 @@ namespace Avalonia.Controls } else if (TextSelector != null) { - text = TextSelector(SearchText, FormatValue(newItem, true)); + text = TextSelector(SearchText, FormatValue(newItem)); } else if (ItemSelector != null) { @@ -1752,7 +1745,7 @@ namespace Avalonia.Controls } else { - text = FormatValue(newItem, true); + text = FormatValue(newItem); } // Update the Text property and the TextBox values @@ -2020,109 +2013,5 @@ namespace Avalonia.Controls return string.Equals(value, text, StringComparison.Ordinal); } } - - // TODO12: Remove, this shouldn't be part of the public API. Use our internal BindingEvaluator instead. - /// - /// A framework element that permits a binding to be evaluated in a new data - /// context leaf node. - /// - /// The type of dynamic binding to return. - public class BindingEvaluator : Control - { - /// - /// Gets or sets the string value binding used by the control. - /// - private BindingBase? _binding; - - /// - /// Identifies the Value dependency property. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1002:AvaloniaProperty objects should not be owned by a generic type", - Justification = "This property is not supposed to be used from XAML.")] - public static readonly StyledProperty ValueProperty = - AvaloniaProperty.Register, T>(nameof(Value)); - - /// - /// Gets or sets the data item value. - /// - public T Value - { - get => GetValue(ValueProperty); - set => SetValue(ValueProperty, value); - } - - /// - /// Gets or sets the value binding. - /// - public BindingBase? ValueBinding - { - get => _binding; - set - { - _binding = value; - if (value is not null) - Bind(ValueProperty, value); - } - } - - /// - /// Initializes a new instance of the BindingEvaluator class. - /// - public BindingEvaluator() - { } - - /// - /// Initializes a new instance of the BindingEvaluator class, - /// setting the initial binding to the provided parameter. - /// - /// The initial string value binding. - public BindingEvaluator(BindingBase? binding) - : this() - { - ValueBinding = binding; - } - - /// - /// Clears the data context so that the control does not keep a - /// reference to the last-looked up item. - /// - public void ClearDataContext() - { - DataContext = null; - } - - /// - /// Updates the data context of the framework element and returns the - /// updated binding value. - /// - /// The object to use as the data context. - /// If set to true, this parameter will - /// clear the data context immediately after retrieving the value. - /// Returns the evaluated T value of the bound dependency - /// property. - public T GetDynamicValue(object o, bool clearDataContext) - { - DataContext = o; - T value = Value; - if (clearDataContext) - { - DataContext = null; - } - return value; - } - - /// - /// Updates the data context of the framework element and returns the - /// updated binding value. - /// - /// The object to use as the data context. - /// Returns the evaluated T value of the bound dependency - /// property. - public T GetDynamicValue(object? o) - { - DataContext = o; - return Value; - } - } } } diff --git a/src/Avalonia.Controls/NativeMenuBar.cs b/src/Avalonia.Controls/NativeMenuBar.cs index 118c2291cc..2f271ef34c 100644 --- a/src/Avalonia.Controls/NativeMenuBar.cs +++ b/src/Avalonia.Controls/NativeMenuBar.cs @@ -3,8 +3,6 @@ using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Data; -using Avalonia.Interactivity; -using Avalonia.Metadata; using Avalonia.Reactive; using Avalonia.VisualTree; @@ -13,25 +11,11 @@ namespace Avalonia.Controls [TemplatePart("PART_NativeMenuPresenter", typeof(MenuBase))] public class NativeMenuBar : TemplatedControl { - [Unstable("To be removed in 12.0, NativeMenuBar now has a default template")] // TODO12 - public static readonly AttachedProperty EnableMenuItemClickForwardingProperty = - AvaloniaProperty.RegisterAttached( - "EnableMenuItemClickForwarding"); - private MenuBase? _menu; private IDisposable? _subscriptions; static NativeMenuBar() { - EnableMenuItemClickForwardingProperty.Changed.Subscribe(args => - { - var item = (MenuItem)args.Sender; - if (args.NewValue.GetValueOrDefault()) - item.Click += OnMenuItemClick; - else - item.Click -= OnMenuItemClick; - }); - // TODO12 Ideally we should make NativeMenuBar inherit MenuBase directly, but it would be a breaking change for 11.x. // Changing default template while keeping old StyleKeyOverride => Menu isn't a breaking change. TemplateProperty.OverrideDefaultValue(new FuncControlTemplate((_, ns) => new NativeMenuBarPresenter @@ -77,17 +61,6 @@ namespace Avalonia.Controls _subscriptions = null; } - [Unstable("To be removed in 12.0, NativeMenuBar now has a default template.")] // TODO12 - public static void SetEnableMenuItemClickForwarding(MenuItem menuItem, bool enable) - { - menuItem.SetValue(EnableMenuItemClickForwardingProperty, enable); - } - - private static void OnMenuItemClick(object? sender, RoutedEventArgs e) - { - (((MenuItem)sender!).DataContext as INativeMenuItemExporterEventsImplBridge)?.RaiseClicked(); - } - private void SubscribeToToplevel(TopLevel topLevel, MenuBase menu) { _subscriptions?.Dispose(); diff --git a/src/Avalonia.Controls/NativeMenuBarPresenter.cs b/src/Avalonia.Controls/NativeMenuBarPresenter.cs index 286f80d699..c0e790c466 100644 --- a/src/Avalonia.Controls/NativeMenuBarPresenter.cs +++ b/src/Avalonia.Controls/NativeMenuBarPresenter.cs @@ -32,9 +32,7 @@ internal class NativeMenuBarPresenter : Menu [!MenuItem.CommandParameterProperty] = nativeItem.GetObservable(NativeMenuItem.CommandParameterProperty).ToBinding(), [!MenuItem.InputGestureProperty] = nativeItem.GetObservable(NativeMenuItem.GestureProperty).ToBinding(), - [!MenuItem.ToggleTypeProperty] = nativeItem.GetObservable(NativeMenuItem.ToggleTypeProperty) - // TODO12 remove NativeMenuItemToggleType - .Select(v => (MenuItemToggleType)v).ToBinding(), + [!MenuItem.ToggleTypeProperty] = nativeItem.GetObservable(NativeMenuItem.ToggleTypeProperty).ToBinding(), [!ToolTip.TipProperty] = nativeItem.GetObservable(NativeMenuItem.ToolTipProperty).ToBinding(), }; diff --git a/src/Avalonia.Controls/NativeMenuItem.cs b/src/Avalonia.Controls/NativeMenuItem.cs index 6c093ff1f6..b0b6bb611f 100644 --- a/src/Avalonia.Controls/NativeMenuItem.cs +++ b/src/Avalonia.Controls/NativeMenuItem.cs @@ -119,11 +119,11 @@ namespace Avalonia.Controls } /// - public static readonly StyledProperty ToggleTypeProperty = - AvaloniaProperty.Register(nameof(ToggleType)); + public static readonly StyledProperty ToggleTypeProperty = + AvaloniaProperty.Register(nameof(ToggleType)); /// - public NativeMenuItemToggleType ToggleType + public MenuItemToggleType ToggleType { get => GetValue(ToggleTypeProperty); set => SetValue(ToggleTypeProperty, value); @@ -232,12 +232,4 @@ namespace Avalonia.Controls } } } - - // TODO12: remove this enum and use MenuItemToggleType only - public enum NativeMenuItemToggleType - { - None = MenuItemToggleType.None, - CheckBox = MenuItemToggleType.CheckBox, - Radio = MenuItemToggleType.Radio - } } diff --git a/src/Avalonia.Controls/Primitives/IPopupHost.cs b/src/Avalonia.Controls/Primitives/IPopupHost.cs index c4f992363e..7ed87682a6 100644 --- a/src/Avalonia.Controls/Primitives/IPopupHost.cs +++ b/src/Avalonia.Controls/Primitives/IPopupHost.cs @@ -1,11 +1,9 @@ using System; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives.PopupPositioning; -using Avalonia.Diagnostics; using Avalonia.Input; using Avalonia.Media; using Avalonia.Metadata; -using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives { @@ -17,8 +15,7 @@ namespace Avalonia.Controls.Primitives /// () or an which is created /// on an . /// - [NotClientImplementable] - [Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)] + [PrivateApi] public interface IPopupHost : IDisposable, IFocusScope { /// diff --git a/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs b/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs index 3e4fee20b7..d52e0e4d98 100644 --- a/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs +++ b/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs @@ -121,16 +121,6 @@ namespace Avalonia.Controls.Primitives // Nothing to do here: overlay popups are implemented inside the window. } - [Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)] - public void ConfigurePosition(Visual target, PlacementMode placement, Point offset, - PopupAnchor anchor = PopupAnchor.None, PopupGravity gravity = PopupGravity.None, - PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All, - Rect? rect = null) - { - ((IPopupHost)this).ConfigurePosition(new PopupPositionRequest(target, placement, offset, anchor, gravity, - constraintAdjustment, rect, null)); - } - /// void IPopupHost.ConfigurePosition(PopupPositionRequest positionRequest) { @@ -191,12 +181,8 @@ namespace Avalonia.Controls.Primitives double IManagedPopupPositionerPopup.Scaling => 1; - // TODO12: mark PrivateAPI or internal. - [Unstable("PopupHost is considered an internal API. Use Popup or any Popup-based controls (Flyout, Tooltip) instead.")] - public static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver) - => CreatePopupHost(target, dependencyResolver, false); - - internal static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver, bool shouldUseOverlayLayer) + [PrivateApi] + public static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver, bool shouldUseOverlayLayer) { if (!shouldUseOverlayLayer) { diff --git a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs index a0b853f2dc..82dead1ed5 100644 --- a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs +++ b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs @@ -66,7 +66,6 @@ namespace Avalonia.Controls.Primitives.PopupPositioning /// requirement that a popup must intersect with or be at least partially adjacent to its parent /// surface. /// - [Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)] public record struct PopupPositionerParameters { private PopupGravity _gravity; diff --git a/src/Avalonia.Controls/Primitives/PopupPositioning/PopupPositionRequest.cs b/src/Avalonia.Controls/Primitives/PopupPositioning/PopupPositionRequest.cs index 35e15e3057..ab1002cb9b 100644 --- a/src/Avalonia.Controls/Primitives/PopupPositioning/PopupPositionRequest.cs +++ b/src/Avalonia.Controls/Primitives/PopupPositioning/PopupPositionRequest.cs @@ -4,7 +4,6 @@ using Avalonia.Metadata; namespace Avalonia.Controls.Primitives.PopupPositioning; [PrivateApi] -[Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)] public class PopupPositionRequest { internal PopupPositionRequest(Visual target, PlacementMode placement) diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs index f88ed0b93b..6dc4627f0c 100644 --- a/src/Avalonia.Controls/Primitives/PopupRoot.cs +++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs @@ -136,17 +136,6 @@ namespace Avalonia.Controls.Primitives } } - [Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)] - public void ConfigurePosition(Visual target, PlacementMode placement, Point offset, - PopupAnchor anchor = PopupAnchor.None, - PopupGravity gravity = PopupGravity.None, - PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All, - Rect? rect = null) - { - ((IPopupHost)this).ConfigurePosition(new PopupPositionRequest(target, placement, offset, anchor, gravity, - constraintAdjustment, rect, null)); - } - void IPopupHost.ConfigurePosition(PopupPositionRequest request) { _popupPositionRequest = request; diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index 7444e187be..d8ecfa99e8 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -362,7 +362,7 @@ namespace Avalonia.Controls.Primitives } /// - internal sealed override void NotifyChildResourcesChanged(ResourcesChangedToken token) + internal sealed override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e) { var count = VisualChildren.Count; @@ -370,11 +370,11 @@ namespace Avalonia.Controls.Primitives { if (VisualChildren[i] is ILogical logical) { - logical.NotifyResourcesChanged(token); + logical.NotifyResourcesChanged(e); } } - base.NotifyChildResourcesChanged(token); + base.NotifyChildResourcesChanged(e); } /// diff --git a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs index 2e1b9a59fb..91aa6b9bd0 100644 --- a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs +++ b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs @@ -118,12 +118,12 @@ namespace Avalonia.Controls.Primitives } /// - internal override void NotifyChildResourcesChanged(ResourcesChangedToken token) + internal override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e) { foreach (var l in _layers) - l.NotifyResourcesChanged(token); + l.NotifyResourcesChanged(e); - base.NotifyChildResourcesChanged(token); + base.NotifyChildResourcesChanged(e); } /// diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 78c2868b88..8a631fe075 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -121,12 +121,6 @@ namespace Avalonia.Controls (s, h) => s.ResourcesChanged -= h ); - private static readonly WeakEvent - ResourcesChanged2WeakEvent = WeakEvent.Register( - (s, h) => s.ResourcesChanged2 += h, - (s, h) => s.ResourcesChanged2 -= h - ); - private readonly IInputManager? _inputManager; private readonly IToolTipService? _tooltipService; private readonly IAccessKeyHandler? _accessKeyHandler; @@ -144,7 +138,6 @@ namespace Avalonia.Controls private ILayoutManager? _layoutManager; private Border? _transparencyFallbackBorder; private TargetWeakEventSubscriber? _resourcesChangesSubscriber; - private TargetWeakEventSubscriber? _resourcesChangesSubscriber2; private IStorageProvider? _storageProvider; private Screens? _screens; private LayoutDiagnosticBridge? _layoutDiagnosticBridge; @@ -270,25 +263,15 @@ namespace Avalonia.Controls var stylingParent = ((IStyleHost)this).StylingParent; - if (stylingParent is IResourceHost2 applicationResources2) + if (stylingParent is IResourceHost applicationResources2) { - _resourcesChangesSubscriber2 = new TargetWeakEventSubscriber( + _resourcesChangesSubscriber = new TargetWeakEventSubscriber( this, static (target, _, _, token) => { target.NotifyResourcesChanged(token); }); - ResourcesChanged2WeakEvent.Subscribe(applicationResources2, _resourcesChangesSubscriber2); - } - else if (stylingParent is IResourceHost applicationResources) - { - _resourcesChangesSubscriber = new TargetWeakEventSubscriber( - this, static (target, _, _, _) => - { - target.NotifyResourcesChanged(ResourcesChangedToken.Create()); - }); - - ResourcesChangedWeakEvent.Subscribe(applicationResources, _resourcesChangesSubscriber); + ResourcesChangedWeakEvent.Subscribe(applicationResources2, _resourcesChangesSubscriber); } impl.LostFocus += PlatformImpl_LostFocus; diff --git a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs index b020aaec34..78595d7bb0 100644 --- a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs +++ b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs @@ -260,13 +260,13 @@ namespace Avalonia.FreeDesktop if (name == "toggle-type") { - if (item.ToggleType == NativeMenuItemToggleType.CheckBox) + if (item.ToggleType == MenuItemToggleType.CheckBox) return VariantValue.String("checkmark"); - if (item.ToggleType == NativeMenuItemToggleType.Radio) + if (item.ToggleType == MenuItemToggleType.Radio) return VariantValue.String("radio"); } - if (name == "toggle-state" && item.ToggleType != NativeMenuItemToggleType.None) + if (name == "toggle-state" && item.ToggleType != MenuItemToggleType.None) return VariantValue.Int32(item.IsChecked ? 1 : 0); if (name == "icon-data") diff --git a/src/Avalonia.Native/IAvnMenuItem.cs b/src/Avalonia.Native/IAvnMenuItem.cs index fd851122f2..f9b3e2d2d6 100644 --- a/src/Avalonia.Native/IAvnMenuItem.cs +++ b/src/Avalonia.Native/IAvnMenuItem.cs @@ -43,7 +43,7 @@ namespace Avalonia.Native.Interop.Impl private void UpdateIsVisible(bool isVisible) => SetIsVisible(isVisible.AsComBool()); private void UpdateIsChecked(bool isChecked) => SetIsChecked(isChecked.AsComBool()); - private void UpdateToggleType(NativeMenuItemToggleType toggleType) + private void UpdateToggleType(MenuItemToggleType toggleType) { SetToggleType((AvnMenuItemToggleType)toggleType); } diff --git a/src/Avalonia.Native/TopLevelImpl.cs b/src/Avalonia.Native/TopLevelImpl.cs index d45e50d5c6..c707da379f 100644 --- a/src/Avalonia.Native/TopLevelImpl.cs +++ b/src/Avalonia.Native/TopLevelImpl.cs @@ -65,8 +65,8 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface private NativeControlHostImpl? _nativeControlHost; private PlatformBehaviorInhibition? _platformBehaviorInhibition; - private readonly MouseDevice? _mouse; - private readonly PenDevice? _pen; + private readonly MouseDevice _mouse; + private readonly PenDevice _pen; private readonly IKeyboardDevice? _keyboard; private readonly ICursorFactory? _cursorFactory; @@ -480,6 +480,18 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface void IAvnTopLevelEvents.LostFocus() { _parent.LostFocus?.Invoke(); + + // macOS doesn't have the concept of mouse capture. If we're losing the focus during an implicit capture + // (standard mouse down), we should release it to avoid mouse events going to an old window. + var mouse = _parent._mouse; + var captured = mouse.Pointer.Captured; + + if (captured is not null && + mouse.Pointer.CaptureSource == CaptureSource.Implicit && + TopLevel.GetTopLevel(captured as Visual)?.PlatformImpl == _parent) + { + mouse.PlatformCaptureLost(); + } } AvnDragDropEffects IAvnTopLevelEvents.DragEvent(AvnDragEventType type, AvnPoint position, diff --git a/src/Avalonia.OpenGL/GlConsts.cs b/src/Avalonia.OpenGL/GlConsts.cs index 55be3da5f0..c1e1df0639 100644 --- a/src/Avalonia.OpenGL/GlConsts.cs +++ b/src/Avalonia.OpenGL/GlConsts.cs @@ -20,7 +20,7 @@ namespace Avalonia.OpenGL // public const int GL_LINE_STRIP = 0x0003; public const int GL_TRIANGLES = 0x0004; // public const int GL_TRIANGLE_STRIP = 0x0005; -// public const int GL_TRIANGLE_FAN = 0x0006; + public const int GL_TRIANGLE_FAN = 0x0006; // public const int GL_QUADS = 0x0007; // public const int GL_QUAD_STRIP = 0x0008; // public const int GL_POLYGON = 0x0009; diff --git a/src/Avalonia.OpenGL/GlInterface.cs b/src/Avalonia.OpenGL/GlInterface.cs index 12a5ef733e..63d265c41e 100644 --- a/src/Avalonia.OpenGL/GlInterface.cs +++ b/src/Avalonia.OpenGL/GlInterface.cs @@ -343,6 +343,8 @@ namespace Avalonia.OpenGL [GetProcAddress("glUniform1f")] public partial void Uniform1f(int location, float falue); + [GetProcAddress("glUniform1i")] + public partial void Uniform1i(int location, int value); [GetProcAddress("glUniformMatrix4fv")] public partial void UniformMatrix4fv(int location, int count, bool transpose, void* value); diff --git a/src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs b/src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs index 95f135a40a..920c66ed1a 100644 --- a/src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs +++ b/src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs @@ -154,6 +154,6 @@ internal sealed class SystemAccentColors : ResourceProvider private void PlatformSettingsOnColorValuesChanged(object? sender, PlatformColorValues e) { _invalidateColors = true; - Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty); + Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create()); } } diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs b/src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs index 53cd36215c..fc03021743 100644 --- a/src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs +++ b/src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs @@ -63,7 +63,7 @@ namespace Avalonia.Themes.Fluent if (change.Property == DensityStyleProperty) { - Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty); + Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Create()); } } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs b/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs index f733fe4d72..42a8ed4f0d 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs @@ -1,4 +1,5 @@ using Avalonia.Media; +using Avalonia.Platform; namespace Avalonia.LinuxFramebuffer { @@ -12,7 +13,13 @@ namespace Avalonia.LinuxFramebuffer /// Default: 1.0 /// public double Scaling { get; set; } = 1.0; - + + /// + /// The orientation of the screen relative to the frame buffer memory orientation + /// Default: Normal + /// + public SurfaceOrientation Orientation { get; set; } = SurfaceOrientation.Rotation0; + /// /// If true an two cycle buffer swapping is processed at init. /// Default: True diff --git a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs index 2a086b353b..edd0b1ef72 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs @@ -11,7 +11,7 @@ using Avalonia.Rendering.Composition; namespace Avalonia.LinuxFramebuffer { - class FramebufferToplevelImpl : ITopLevelImpl, IScreenInfoProvider + class FramebufferToplevelImpl : ITopLevelImpl, IScreenInfoProvider, ISurfaceOrientation { private readonly IOutputBackend _outputBackend; private readonly IInputBackend _inputBackend; @@ -81,5 +81,7 @@ using Avalonia.Rendering.Composition; public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1); public object? TryGetFeature(Type featureType) => null; + + SurfaceOrientation ISurfaceOrientation.Orientation => _outputBackend is ISurfaceOrientation surfaceOrientation ? surfaceOrientation.Orientation : SurfaceOrientation.Rotation0; } } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index abff7f0936..671508a943 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -1,8 +1,10 @@ using System; using System.IO; +using System.Linq; using System.Threading; using Avalonia.Input; using Avalonia.Input.Raw; +using Avalonia.Platform; using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; namespace Avalonia.LinuxFramebuffer.Input.LibInput { @@ -30,9 +32,22 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput private unsafe void InputThread(IntPtr ctx, LibInputBackendOptions options) { var fd = libinput_get_fd(ctx); + IntPtr[] devices = [.. options.Events!.Select(f => libinput_path_add_device(ctx, f)).Where(d => d != IntPtr.Zero)]; + var screenOrientation = _screen is ISurfaceOrientation surfaceOrientation ? surfaceOrientation.Orientation : SurfaceOrientation.Rotation0; + + float[] matrix = screenOrientation switch + { + SurfaceOrientation.Rotation90 => [0, 1, 0, -1, 0, 1], + SurfaceOrientation.Rotation180 => [-1, 0, 1, 0, -1, 1], + SurfaceOrientation.Rotation270 => [0, -1, 1, 1, 0, 0], + _ => [1, 0, 0, 0, 1, 0], // Normal + }; + + foreach (var device in devices) + { + libinput_device_config_calibration_set_matrix(device, matrix); + } - foreach (var f in options.Events!) - libinput_path_add_device(ctx, f); while (true) { IntPtr ev; diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs index c027440708..fbb11905f9 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs @@ -55,6 +55,9 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput [DllImport(LibInput)] public extern static IntPtr libinput_path_remove_device(IntPtr device); + [DllImport(LibInput)] + public extern static int libinput_device_config_calibration_set_matrix(IntPtr device, float[] matrix); + [DllImport(LibInput)] public extern static int libinput_get_fd(IntPtr ctx); diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index 92ec8b475d..0d7d74e01c 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -142,7 +142,10 @@ namespace Avalonia.LinuxFramebuffer { get { - EnsureTopLevel(); + if (_topLevel == null) + { + EnsureTopLevel(); + } return _topLevel; } } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs index 12ab5ad821..ddd3b6e49f 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs @@ -13,11 +13,13 @@ using static Avalonia.LinuxFramebuffer.Output.LibDrm; namespace Avalonia.LinuxFramebuffer.Output { - public unsafe class DrmOutput : IGlOutputBackend, IGlPlatformSurface + public unsafe class DrmOutput : IGlOutputBackend, IGlPlatformSurface, ISurfaceOrientation { private DrmOutputOptions _outputOptions = new(); private DrmCard _card; - public PixelSize PixelSize => _mode.Resolution; + public PixelSize PixelSize => Orientation == SurfaceOrientation.Rotation0 || Orientation == SurfaceOrientation.Rotation180 + ? new PixelSize(_mode.Resolution.Width, _mode.Resolution.Height) + : new PixelSize(_mode.Resolution.Height, _mode.Resolution.Width); public double Scaling { @@ -25,6 +27,12 @@ namespace Avalonia.LinuxFramebuffer.Output set => _outputOptions.Scaling = value; } + public SurfaceOrientation Orientation + { + get => _outputOptions.Orientation; + set => _outputOptions.Orientation = value; + } + class SharedContextGraphics : IPlatformGraphics { private readonly IPlatformGraphicsContext _context; @@ -113,6 +121,12 @@ namespace Avalonia.LinuxFramebuffer.Output private IntPtr _currentBo; private IntPtr _gbmTargetSurface; private uint _crtcId; + private int _rotationFbo; + private int _rotationTexture; + private PixelSize _rotatedSize; + private int _rotationProgram; + private int _rotationVbo; + private int _rotationVao; void FbDestroyCallback(IntPtr bo, IntPtr userData) { @@ -157,7 +171,6 @@ namespace Avalonia.LinuxFramebuffer.Output return fbHandle; } - [MemberNotNull(nameof(_card))] [MemberNotNull(nameof(PlatformGraphics))] [MemberNotNull(nameof(FbDestroyDelegate))] @@ -236,6 +249,129 @@ namespace Avalonia.LinuxFramebuffer.Output _mode = mode; _currentBo = bo; + + // Initialize FBO for rotation if needed + var needsRotation = _outputOptions.Orientation != SurfaceOrientation.Rotation0; + if (needsRotation) + { + // For 90/270 rotation, swap width and height + _rotatedSize = (_outputOptions.Orientation == SurfaceOrientation.Rotation90 || + _outputOptions.Orientation == SurfaceOrientation.Rotation270) + ? new PixelSize(modeInfo.Resolution.Height, modeInfo.Resolution.Width) + : modeInfo.Resolution; + + using (_deferredContext.MakeCurrent(_eglSurface)) + { + var gl = _deferredContext.GlInterface; + _rotationFbo = gl.GenFramebuffer(); + _rotationTexture = gl.GenTexture(); + + gl.BindTexture(GlConsts.GL_TEXTURE_2D, _rotationTexture); + gl.TexImage2D(GlConsts.GL_TEXTURE_2D, 0, GlConsts.GL_RGBA, _rotatedSize.Width, _rotatedSize.Height, 0, + GlConsts.GL_RGBA, GlConsts.GL_UNSIGNED_BYTE, IntPtr.Zero); + gl.TexParameteri(GlConsts.GL_TEXTURE_2D, GlConsts.GL_TEXTURE_MIN_FILTER, GlConsts.GL_LINEAR); + gl.TexParameteri(GlConsts.GL_TEXTURE_2D, GlConsts.GL_TEXTURE_MAG_FILTER, GlConsts.GL_LINEAR); + + gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, _rotationFbo); + gl.FramebufferTexture2D(GlConsts.GL_FRAMEBUFFER, GlConsts.GL_COLOR_ATTACHMENT0, + GlConsts.GL_TEXTURE_2D, _rotationTexture, 0); + gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0); + + // Create shader program for textured quad + const string vertexShader = @" + attribute vec2 aPos; + attribute vec2 aTexCoord; + varying vec2 vTexCoord; + void main() { + gl_Position = vec4(aPos, 0.0, 1.0); + vTexCoord = aTexCoord; + }"; + + const string fragmentShader = @" + precision mediump float; + varying vec2 vTexCoord; + uniform sampler2D uTexture; + void main() { + gl_FragColor = texture2D(uTexture, vTexCoord); + }"; + + var vs = gl.CreateShader(GlConsts.GL_VERTEX_SHADER); + gl.ShaderSourceString(vs, vertexShader); + gl.CompileShader(vs); + + var fs = gl.CreateShader(GlConsts.GL_FRAGMENT_SHADER); + gl.ShaderSourceString(fs, fragmentShader); + gl.CompileShader(fs); + + _rotationProgram = gl.CreateProgram(); + gl.AttachShader(_rotationProgram, vs); + gl.AttachShader(_rotationProgram, fs); + gl.LinkProgram(_rotationProgram); + gl.DeleteShader(vs); + gl.DeleteShader(fs); + + // Create VBO with quad vertices - texture coords depend on rotation + // Format: x, y, u, v + float[] vertices = _outputOptions.Orientation switch + { + SurfaceOrientation.Rotation90 => new float[] { + // 90° clockwise rotation + -1.0f, -1.0f, 1.0f, 0.0f, // Bottom-left -> Bottom-right of texture + 1.0f, -1.0f, 1.0f, 1.0f, // Bottom-right -> Top-right of texture + 1.0f, 1.0f, 0.0f, 1.0f, // Top-right -> Top-left of texture + -1.0f, 1.0f, 0.0f, 0.0f // Top-left -> Bottom-left of texture + }, + SurfaceOrientation.Rotation180 => new float[] { + // 180° rotation + -1.0f, -1.0f, 1.0f, 1.0f, // Bottom-left -> Top-right of texture + 1.0f, -1.0f, 0.0f, 1.0f, // Bottom-right -> Top-left of texture + 1.0f, 1.0f, 0.0f, 0.0f, // Top-right -> Bottom-left of texture + -1.0f, 1.0f, 1.0f, 0.0f // Top-left -> Bottom-right of texture + }, + SurfaceOrientation.Rotation270 => new float[] { + // 270° clockwise (90° counter-clockwise) rotation + -1.0f, -1.0f, 0.0f, 1.0f, // Bottom-left -> Top-left of texture + 1.0f, -1.0f, 0.0f, 0.0f, // Bottom-right -> Bottom-left of texture + 1.0f, 1.0f, 1.0f, 0.0f, // Top-right -> Bottom-right of texture + -1.0f, 1.0f, 1.0f, 1.0f // Top-left -> Top-right of texture + }, + _ => new float[] { + // No rotation (shouldn't reach here but fallback) + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 1.0f + } + }; + + _rotationVbo = gl.GenBuffer(); + _rotationVao = gl.GenVertexArray(); + + gl.BindVertexArray(_rotationVao); + gl.BindBuffer(GlConsts.GL_ARRAY_BUFFER, _rotationVbo); + + fixed (float* ptr = vertices) + { + gl.BufferData(GlConsts.GL_ARRAY_BUFFER, new IntPtr(vertices.Length * sizeof(float)), + new IntPtr(ptr), GlConsts.GL_STATIC_DRAW); + } + + var posAttrib = gl.GetAttribLocationString(_rotationProgram, "aPos"); + gl.EnableVertexAttribArray(posAttrib); + gl.VertexAttribPointer(posAttrib, 2, GlConsts.GL_FLOAT, 0, 4 * sizeof(float), IntPtr.Zero); + + var texAttrib = gl.GetAttribLocationString(_rotationProgram, "aTexCoord"); + gl.EnableVertexAttribArray(texAttrib); + gl.VertexAttribPointer(texAttrib, 2, GlConsts.GL_FLOAT, 0, 4 * sizeof(float), new IntPtr(2 * sizeof(float))); + + gl.BindVertexArray(0); + } + } + else + { + // No rotation needed + _rotatedSize = modeInfo.Resolution; + } if (_outputOptions.EnableInitialBufferSwapping) { @@ -288,7 +424,39 @@ namespace Avalonia.LinuxFramebuffer.Output public void Dispose() { - _parent._deferredContext.GlInterface.Flush(); + var gl = _parent._deferredContext.GlInterface; + + if (_parent._outputOptions.Orientation != SurfaceOrientation.Rotation0) + { + // Rotation enabled - blit from FBO to screen + // Unbind FBO to render to default framebuffer + gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0); + gl.Viewport(0, 0, _parent._mode.Resolution.Width, _parent._mode.Resolution.Height); + + // Clear the screen + gl.ClearColor(0, 0, 0, 1); + gl.Clear(GlConsts.GL_COLOR_BUFFER_BIT); + + // Use the shader program + gl.UseProgram(_parent._rotationProgram); + + // Bind the FBO texture + gl.ActiveTexture(GlConsts.GL_TEXTURE0); + gl.BindTexture(GlConsts.GL_TEXTURE_2D, _parent._rotationTexture); + + // Set texture uniform (texture unit 0) + var texLoc = gl.GetUniformLocationString(_parent._rotationProgram, "uTexture"); + gl.Uniform1i(texLoc, 0); + + // Draw the rotated quad + gl.BindVertexArray(_parent._rotationVao); + gl.DrawArrays(GlConsts.GL_TRIANGLE_FAN, 0, 4); + gl.BindVertexArray(0); + + gl.UseProgram(0); + } + + gl.Flush(); _parent._eglSurface.SwapBuffers(); var nextBo = gbm_surface_lock_front_buffer(_parent._gbmTargetSurface); @@ -333,7 +501,7 @@ namespace Avalonia.LinuxFramebuffer.Output public IGlContext Context => _parent._deferredContext; - public PixelSize Size => _parent._mode.Resolution; + public PixelSize Size => _parent._rotatedSize; public double Scaling => _parent.Scaling; @@ -342,7 +510,23 @@ namespace Avalonia.LinuxFramebuffer.Output public IGlPlatformSurfaceRenderingSession BeginDraw() { - return new RenderSession(_parent, _parent._deferredContext.MakeCurrent(_parent._eglSurface)); + var clearContext = _parent._deferredContext.MakeCurrent(_parent._eglSurface); + var gl = _parent._deferredContext.GlInterface; + + if (_parent._outputOptions.Orientation != SurfaceOrientation.Rotation0) + { + // Bind FBO for rendering when rotation is enabled + gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, _parent._rotationFbo); + gl.Viewport(0, 0, _parent._rotatedSize.Width, _parent._rotatedSize.Height); + } + else + { + // Render directly to screen when no rotation + gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0); + gl.Viewport(0, 0, _parent._mode.Resolution.Width, _parent._mode.Resolution.Height); + } + + return new RenderSession(_parent, clearContext); } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/DynamicResourceExpression.cs b/src/Markup/Avalonia.Markup.Xaml/Data/DynamicResourceExpression.cs index e65282b36b..fbe09fa0de 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Data/DynamicResourceExpression.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Data/DynamicResourceExpression.cs @@ -84,8 +84,6 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e) => PublishValue(); - private void ResourcesChanged2(object? sender, ResourcesChangedToken token) => PublishValue(); - private void ActualThemeVariantChanged(object? sender, EventArgs e) { if (!IsRunning) @@ -134,7 +132,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions { if (host is not null) { - host.SubscribeToResourcesChanged(ResourcesChanged, ResourcesChanged2); + host.ResourcesChanged += ResourcesChanged; if (!_overrideThemeVariant && _host is IThemeVariantHost themeVariantHost) { @@ -148,7 +146,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions { if (host is not null) { - host.UnsubscribeFromResourcesChanged(ResourcesChanged, ResourcesChanged2); + host.ResourcesChanged -= ResourcesChanged; if (!_overrideThemeVariant && _host is IThemeVariantHost themeVariantHost) themeVariantHost.ActualThemeVariantChanged -= ActualThemeVariantChanged; diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs index f602b1a82d..8737367fb1 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs @@ -3,6 +3,7 @@ using Avalonia.Controls; using Avalonia.Data; using Avalonia.Data.Core; using Avalonia.Markup.Xaml.XamlIl.Runtime; +using Avalonia.Metadata; using Avalonia.Styling; namespace Avalonia.Markup.Xaml.MarkupExtensions @@ -22,6 +23,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions ResourceKey = resourceKey; } + [ConstructorArgument("resourceKey")] public object? ResourceKey { get; set; } public BindingBase ProvideValue(IServiceProvider serviceProvider) diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs index 311d151ddb..f4b7864185 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs @@ -22,13 +22,6 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions /// The binding path. public ReflectionBindingExtension(string path) : base(path) { } - /// - /// Initializes a new instance of the class. - /// - /// The binding path. - /// The binding mode. - public ReflectionBindingExtension(string path, BindingMode mode) : base(path, mode) { } - public ReflectionBinding ProvideValue(IServiceProvider serviceProvider) { return new ReflectionBinding diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs index fce026bb1c..c59d038223 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Data; +using Avalonia.Metadata; namespace Avalonia.Markup.Xaml.MarkupExtensions { diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs b/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs index 513b18c7a7..cf3c82fdb9 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs @@ -32,14 +32,4 @@ namespace Avalonia.Markup.Xaml [RequiresUnreferencedCode(TrimmingMessages.XamlTypeResolvedRequiresUnreferenceCodeMessage)] Type Resolve (string qualifiedTypeName); } - - // TODO12: Move to Avalonia.Base - [AttributeUsage(AttributeTargets.Property)] - public sealed class ConstructorArgumentAttribute : Attribute - { - public ConstructorArgumentAttribute(string name) - { - - } - } } diff --git a/src/Markup/Avalonia.Markup/Data/Binding.cs b/src/Markup/Avalonia.Markup/Data/Binding.cs index 3a0f8a482e..4e624b6479 100644 --- a/src/Markup/Avalonia.Markup/Data/Binding.cs +++ b/src/Markup/Avalonia.Markup/Data/Binding.cs @@ -16,6 +16,4 @@ public class Binding : ReflectionBinding public Binding() { } public Binding(string path) : base(path) { } - - public Binding(string path, BindingMode mode) : base(path, mode) { } } diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs index 46be609ec0..7473563d13 100644 --- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs @@ -125,6 +125,14 @@ namespace Avalonia.Skia _currentFramebufferAddress = framebuffer.Address; + // A surface with a width/height of 0 is invalid and can't be created + if (desiredImageInfo.Width <= 0 || desiredImageInfo.Height <= 0) + { + throw new ArgumentException( + $"Unable to create a surface with size {desiredImageInfo.Width}x{desiredImageInfo.Height}", + nameof(desiredImageInfo)); + } + var surface = SKSurface.Create(desiredImageInfo, _currentFramebufferAddress, framebuffer.RowBytes, new SKSurfaceProperties(SKPixelGeometry.RgbHorizontal)); diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs index 19ede2bbb3..e47dca2391 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs @@ -1091,7 +1091,11 @@ namespace Avalonia.Base.UnitTests var target = new Class1(); var source = new TestTwoWayBindingViewModel(); - target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source }); + target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value)) + { + Mode = BindingMode.TwoWay, + Source = source + }); target.DoubleValue = 123.4; @@ -1105,7 +1109,11 @@ namespace Avalonia.Base.UnitTests var target = new Class1(); var source = new TestTwoWayBindingViewModel(); - target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source }); + target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value)) + { + Mode = BindingMode.TwoWay, + Source = source + }); Assert.False(source.SetterCalled); } @@ -1116,7 +1124,11 @@ namespace Avalonia.Base.UnitTests var target = new Class1(); var source = new TestTwoWayBindingViewModel(); - target.Bind(Class1.DoubleValueProperty, new Binding("[0]", BindingMode.TwoWay) { Source = source }); + target.Bind(Class1.DoubleValueProperty, new Binding("[0]") + { + Mode = BindingMode.TwoWay, + Source = source + }); Assert.False(source.SetterCalled); } @@ -1127,7 +1139,7 @@ namespace Avalonia.Base.UnitTests var target = new TextBlock(); target.DataContext = null; - target.Bind(TextBlock.TextProperty, new Binding("Missing", BindingMode.TwoWay)); + target.Bind(TextBlock.TextProperty, new Binding("Missing") { Mode = BindingMode.TwoWay }); } [Fact] @@ -1136,7 +1148,7 @@ namespace Avalonia.Base.UnitTests var target = new TextBlock(); target.DataContext = null; - target.Bind(TextBlock.TextProperty, new Binding("[0]", BindingMode.TwoWay)); + target.Bind(TextBlock.TextProperty, new Binding("[0]") { Mode = BindingMode.TwoWay }); } [Theory(Skip = "Will need changes to binding internals in order to pass")] @@ -1147,7 +1159,11 @@ namespace Avalonia.Base.UnitTests { var target = new Class1(); var source = new TestTwoWayBindingViewModel(); - var binding = new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source }; + var binding = new Binding(nameof(source.Value)) + { + Mode = BindingMode.TwoWay, + Source = source + }; target.Bind(Class1.DoubleValueProperty, binding, priority); target.SetValue(Class1.DoubleValueProperty, 123.4, priority - 1); @@ -1165,7 +1181,11 @@ namespace Avalonia.Base.UnitTests { var target = new Class1(); var source = new TestTwoWayBindingViewModel(); - var binding1 = new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source }; + var binding1 = new Binding(nameof(source.Value)) + { + Mode = BindingMode.TwoWay, + Source = source + }; var binding2 = new BehaviorSubject(123.4); target.Bind(Class1.DoubleValueProperty, binding1, priority); @@ -1182,7 +1202,11 @@ namespace Avalonia.Base.UnitTests var target = new Class1(); var source = new TestTwoWayBindingViewModel(); - target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source }); + target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value)) + { + Mode = BindingMode.TwoWay, + Source = source + }); target.SetValue(Class1.DoubleValueProperty, 123.4, BindingPriority.Animation); // Setter should not be called because the TwoWay binding with Style priority @@ -1197,7 +1221,11 @@ namespace Avalonia.Base.UnitTests var source1 = new TestTwoWayBindingViewModel(); var source2 = new BehaviorSubject(123.4); - target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source1.Value), BindingMode.TwoWay) { Source = source1 }); + target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source1.Value)) + { + Mode = BindingMode.TwoWay, + Source = source1 + }); target.Bind(Class1.DoubleValueProperty, source2, BindingPriority.Animation); // Setter should not be called because the TwoWay binding with Style priority diff --git a/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs b/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs index 0551fa5bc4..7eb2550e52 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs @@ -143,8 +143,9 @@ namespace Avalonia.Base.UnitTests.Styling Classes = { "foo" }, }; - var binding = new Binding("Name", BindingMode.OneWay) + var binding = new Binding("Name") { + Mode = BindingMode.OneWay, Converter = new TestConverter(), RelativeSource = new RelativeSource(RelativeSourceMode.Self), }; diff --git a/tests/Avalonia.Benchmarks/Data/Binding_Setup.cs b/tests/Avalonia.Benchmarks/Data/Binding_Setup.cs index 84f5bec10f..e26e636580 100644 --- a/tests/Avalonia.Benchmarks/Data/Binding_Setup.cs +++ b/tests/Avalonia.Benchmarks/Data/Binding_Setup.cs @@ -31,7 +31,7 @@ public class Binding_Setup public void Setup_DataContext_Property_Binding_TwoWay() { var target = _target; - var binding = new Binding(nameof(_data.IntValue), mode: BindingMode.TwoWay); + var binding = new Binding(nameof(_data.IntValue)) { Mode = BindingMode.TwoWay }; for (var i = 0; i < 100; ++i) { diff --git a/tests/Avalonia.Benchmarks/Data/Binding_Values.cs b/tests/Avalonia.Benchmarks/Data/Binding_Values.cs index 7cf30eee4d..fa62292e90 100644 --- a/tests/Avalonia.Benchmarks/Data/Binding_Values.cs +++ b/tests/Avalonia.Benchmarks/Data/Binding_Values.cs @@ -36,7 +36,7 @@ public class Binding_Values _data.IntValue = -1; var target = _target; - var binding = new Binding(nameof(_data.IntValue), mode: BindingMode.TwoWay); + var binding = new Binding(nameof(_data.IntValue)) { Mode = BindingMode.TwoWay }; using var d = target.Bind(TestControl.IntValueProperty, binding); for (var i = 0; i < 100; ++i) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs index 77dad85e03..8c9a845050 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs @@ -29,7 +29,7 @@ namespace Avalonia.Controls.UnitTests var target = new TextBox { DataContext = new ExceptionTest(), - [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay), + [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10)) { Mode = BindingMode.TwoWay }, Template = CreateTemplate(), }; @@ -51,7 +51,7 @@ namespace Avalonia.Controls.UnitTests var target = new TextBox { DataContext = new ExceptionTest(), - [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay), + [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10)) { Mode = BindingMode.TwoWay }, Template = CreateTemplate(), }; @@ -77,7 +77,7 @@ namespace Avalonia.Controls.UnitTests var target = new TextBox { DataContext = new ExceptionTest(), - [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay), + [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10)) { Mode = BindingMode.TwoWay }, Template = CreateTemplate() }; DataValidationErrors.SetErrorConverter(target, err => "Error: " + err); @@ -101,7 +101,7 @@ namespace Avalonia.Controls.UnitTests var target = new TextBox { DataContext = new ExceptionTest(), - [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay), + [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10)) { Mode = BindingMode.TwoWay }, Template = CreateTemplate(), }; diff --git a/tests/Avalonia.Headless.NUnit.PerAssembly.UnitTests/Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj b/tests/Avalonia.Headless.NUnit.PerAssembly.UnitTests/Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj index a701fcefe8..2a2ad17626 100644 --- a/tests/Avalonia.Headless.NUnit.PerAssembly.UnitTests/Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj +++ b/tests/Avalonia.Headless.NUnit.PerAssembly.UnitTests/Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj @@ -15,7 +15,8 @@ - + + diff --git a/tests/Avalonia.Headless.NUnit.PerTest.UnitTests/Avalonia.Headless.NUnit.PerTest.UnitTests.csproj b/tests/Avalonia.Headless.NUnit.PerTest.UnitTests/Avalonia.Headless.NUnit.PerTest.UnitTests.csproj index a701fcefe8..2a2ad17626 100644 --- a/tests/Avalonia.Headless.NUnit.PerTest.UnitTests/Avalonia.Headless.NUnit.PerTest.UnitTests.csproj +++ b/tests/Avalonia.Headless.NUnit.PerTest.UnitTests/Avalonia.Headless.NUnit.PerTest.UnitTests.csproj @@ -15,7 +15,8 @@ - + + diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs index 42dc681f7c..345c4c3b6d 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests.cs @@ -544,8 +544,8 @@ namespace Avalonia.Markup.UnitTests.Data var root = new Panel { Children = { target1, target2 } }; var source = new Source { Foo = "foo" }; - using (target1.Bind(TextBlock.TextProperty, new Binding("Foo", BindingMode.OneTime))) - using (target2.Bind(TextBlock.TextProperty, new Binding("Foo", BindingMode.OneWayToSource))) + using (target1.Bind(TextBlock.TextProperty, new Binding("Foo") { Mode = BindingMode.OneTime })) + using (target2.Bind(TextBlock.TextProperty, new Binding("Foo") { Mode = BindingMode.OneWayToSource })) { root.DataContext = source; } @@ -643,8 +643,8 @@ namespace Avalonia.Markup.UnitTests.Data Children = { target1, target2 } }; - target1.Bind(TextBlock.TextProperty, new Binding("Foo", BindingMode.TwoWay)); - target2.Bind(TextBlock.TextProperty, new Binding("Foo", BindingMode.OneWayToSource)); + target1.Bind(TextBlock.TextProperty, new Binding("Foo") { Mode = BindingMode.TwoWay }); + target2.Bind(TextBlock.TextProperty, new Binding("Foo") { Mode = BindingMode.OneWayToSource }); Assert.Equal("OneWayToSource", source.Foo); diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Delay.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Delay.cs index a73fbd7bb4..da649bc184 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Delay.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Delay.cs @@ -29,7 +29,11 @@ public class BindingTests_Delay : ScopedTestBase, IDisposable _source = new BindingTests.Source { Foo = InitialFooValue }; _target = new TextBox { DataContext = _source }; - _binding = new Binding(nameof(_source.Foo), BindingMode.TwoWay) { Delay = DelayMilliseconds }; + _binding = new Binding(nameof(_source.Foo)) + { + Mode = BindingMode.TwoWay, + Delay = DelayMilliseconds + }; _bindingExpr = _target.Bind(TextBox.TextProperty, _binding); @@ -120,7 +124,12 @@ public class BindingTests_Delay : ScopedTestBase, IDisposable new TestRoot() { Child = new Panel() { Children = { _target, secondBox } } }; - _target.Bind(TextBox.TextProperty, new Binding(nameof(_source.Foo), BindingMode.TwoWay) { Delay = DelayMilliseconds, UpdateSourceTrigger = UpdateSourceTrigger.LostFocus }); + _target.Bind(TextBox.TextProperty, new Binding(nameof(_source.Foo)) + { + Mode = BindingMode.TwoWay, + Delay = DelayMilliseconds, + UpdateSourceTrigger = UpdateSourceTrigger.LostFocus + }); Assert.True(_target.Focus()); _target.Text = "bar"; @@ -134,7 +143,11 @@ public class BindingTests_Delay : ScopedTestBase, IDisposable [Fact] public void Delayed_Binding_OneWayToSource_DataContext_Change_Should_Update_Source_Immediately() { - _target.Bind(TextBlock.TextProperty, new Binding(nameof(_source.Foo), BindingMode.OneWayToSource) { Delay = DelayMilliseconds }); + _target.Bind(TextBlock.TextProperty, new Binding(nameof(_source.Foo)) + { + Mode = BindingMode.OneWayToSource, + Delay = DelayMilliseconds + }); _target.Text = "bar"; diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Self.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Self.cs index cd1e0cd0a2..5281993f1e 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Self.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Self.cs @@ -34,8 +34,9 @@ namespace Avalonia.Markup.UnitTests.Data var target = new TextBlock { Tag = "Hello World!", - [!TextBlock.TextProperty] = new Binding("Tag", BindingMode.TwoWay) + [!TextBlock.TextProperty] = new Binding("Tag") { + Mode = BindingMode.TwoWay, RelativeSource = new RelativeSource(RelativeSourceMode.Self) }, };