diff --git a/.github/pr_labels.yml b/.github/pr_labels.yml index 388e47276f..2b0eb795be 100644 --- a/.github/pr_labels.yml +++ b/.github/pr_labels.yml @@ -1,6 +1,8 @@ version: '1.1.0' invalidStatus: "pending" labelRule: - # Allow any label, while requiring at least some - startsWith: - - "" + values: + - "bug" + - "feature" + - "enhancement" + - "area-infrastructure" diff --git a/Documentation/build.md b/Documentation/build.md index ea91f035f8..065d2ee960 100644 --- a/Documentation/build.md +++ b/Documentation/build.md @@ -100,7 +100,14 @@ On macOS it is necessary to build and manually install the respective native lib # Building Avalonia into a local NuGet cache It is possible to build Avalonia locally and generate NuGet packages that can be used locally to test local changes. -To do so you need to run: + +First, install Nuke's dotnet global tool like so: + +```bash +dotnet tool install Nuke.GlobalTool --global +``` + +Then you need to run: ```bash nuke --target BuildToNuGetCache --configuration Release ``` diff --git a/api/Avalonia.Android.nupkg.xml b/api/Avalonia.Android.nupkg.xml deleted file mode 100644 index 5e68aafc3f..0000000000 --- a/api/Avalonia.Android.nupkg.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - CP0001 - T:Avalonia.Android.Internal.Resource.Animation - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Animator - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Attribute - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Boolean - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Color - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Dimension - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Drawable - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Id - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Integer - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Interpolator - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Layout - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.String - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Style - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0001 - T:Avalonia.Android.Internal.Resource.Styleable - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0007 - T:Avalonia.Android.Internal.Resource - baseline/net6.0-android31.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - \ No newline at end of file diff --git a/api/Avalonia.Browser.nupkg.xml b/api/Avalonia.Browser.nupkg.xml deleted file mode 100644 index 16bdbfe25d..0000000000 --- a/api/Avalonia.Browser.nupkg.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CP0002 - M:Avalonia.Browser.AvaloniaView.get_IsComposing - baseline/net7.0/Avalonia.Browser.dll - target/net8.0-browser1.0/Avalonia.Browser.dll - - - CP0002 - M:Avalonia.Browser.AvaloniaView.OnDragEvent(System.Runtime.InteropServices.JavaScript.JSObject) - baseline/net7.0/Avalonia.Browser.dll - target/net8.0-browser1.0/Avalonia.Browser.dll - - - CP0008 - T:Avalonia.Browser.AvaloniaView - baseline/net7.0/Avalonia.Browser.dll - target/net8.0-browser1.0/Avalonia.Browser.dll - - \ No newline at end of file diff --git a/api/Avalonia.Controls.ColorPicker.nupkg.xml b/api/Avalonia.Controls.ColorPicker.nupkg.xml deleted file mode 100644 index 8fadd656ea..0000000000 --- a/api/Avalonia.Controls.ColorPicker.nupkg.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorPicker.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorPreviewer.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorSlider.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorSpectrum.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorView.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/Fluent.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorPicker.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorPreviewer.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorSlider.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorSpectrum.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorView.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/Simple.xaml - baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll - target/netstandard2.0/Avalonia.Controls.ColorPicker.dll - - \ No newline at end of file diff --git a/api/Avalonia.Controls.DataGrid.nupkg.xml b/api/Avalonia.Controls.DataGrid.nupkg.xml deleted file mode 100644 index 1dc020aa79..0000000000 --- a/api/Avalonia.Controls.DataGrid.nupkg.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent.xaml - baseline/netstandard2.0/Avalonia.Controls.DataGrid.dll - target/netstandard2.0/Avalonia.Controls.DataGrid.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple.xaml - baseline/netstandard2.0/Avalonia.Controls.DataGrid.dll - target/netstandard2.0/Avalonia.Controls.DataGrid.dll - - \ No newline at end of file diff --git a/api/Avalonia.Diagnostics.nupkg.xml b/api/Avalonia.Diagnostics.nupkg.xml deleted file mode 100644 index 5bc2bfa99c..0000000000 --- a/api/Avalonia.Diagnostics.nupkg.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Controls/BrushEditor.axaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Controls/FilterTextBox.axaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Controls/ThicknessEditor.axaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Views/ConsoleView.xaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Views/ControlDetailsView.xaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Views/EventsPageView.xaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Views/LayoutExplorerView.axaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Views/MainView.xaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Views/MainWindow.xaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Diagnostics/Views/TreePageView.xaml - baseline/netstandard2.0/Avalonia.Diagnostics.dll - target/netstandard2.0/Avalonia.Diagnostics.dll - - \ No newline at end of file diff --git a/api/Avalonia.Skia.nupkg.xml b/api/Avalonia.Skia.nupkg.xml deleted file mode 100644 index a88fc8ba0a..0000000000 --- a/api/Avalonia.Skia.nupkg.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - CP0006 - M:Avalonia.Skia.ISkiaSharpApiLease.TryLeasePlatformGraphicsApi - baseline/netstandard2.0/Avalonia.Skia.dll - target/netstandard2.0/Avalonia.Skia.dll - - \ No newline at end of file diff --git a/api/Avalonia.Themes.Fluent.nupkg.xml b/api/Avalonia.Themes.Fluent.nupkg.xml deleted file mode 100644 index 08fb493760..0000000000 --- a/api/Avalonia.Themes.Fluent.nupkg.xml +++ /dev/null @@ -1,448 +0,0 @@ - - - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/BaseColorsPalette.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/BaseResources.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/FluentControlResources.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AdornerLayer.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AutoCompleteBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Button.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ButtonSpinner.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Calendar.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDatePicker.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDayButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CaptionButtons.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Carousel.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CheckBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBoxItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContentControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContextMenu.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DataValidationErrors.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DatePicker.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DateTimePickerShared.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DropDownButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/EmbeddableControlRoot.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Expander.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/FluentControls.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/FlyoutPresenter.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/GridSplitter.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ItemsControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Label.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBoxItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ManagedFileChooser.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Menu.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuFlyoutPresenter.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuScrollViewer.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NativeMenuBar.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NotificationCard.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NumericUpDown.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/OverlayPopupHost.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PathIcon.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PopupRoot.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ProgressBar.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RadioButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshContainer.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshVisualizer.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RepeatButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollBar.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollViewer.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SelectableTextBlock.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Separator.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Slider.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitView.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStrip.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStripItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TextBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ThemeVariantScope.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TimePicker.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TitleBar.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleSwitch.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToolTip.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TransitioningContentControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeView.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeViewItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/UserControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Window.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/WindowNotificationManager.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/DensityStyles/Compact.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/FluentTheme.xaml - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - \ No newline at end of file diff --git a/api/Avalonia.Themes.Simple.nupkg.xml b/api/Avalonia.Themes.Simple.nupkg.xml deleted file mode 100644 index 8f4ac0585a..0000000000 --- a/api/Avalonia.Themes.Simple.nupkg.xml +++ /dev/null @@ -1,424 +0,0 @@ - - - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/Base.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AdornerLayer.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AutoCompleteBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Button.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ButtonSpinner.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Calendar.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDatePicker.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDayButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CaptionButtons.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Carousel.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CheckBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBoxItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContentControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContextMenu.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DataValidationErrors.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DatePicker.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DateTimePickerShared.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DropDownButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/EmbeddableControlRoot.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Expander.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/FlyoutPresenter.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/GridSplitter.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ItemsControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Label.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBoxItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ManagedFileChooser.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Menu.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuFlyoutPresenter.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NativeMenuBar.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NotificationCard.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NumericUpDown.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/OverlayPopupHost.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PathIcon.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PopupRoot.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ProgressBar.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RadioButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshContainer.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshVisualizer.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RepeatButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollBar.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollViewer.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SelectableTextBlock.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Separator.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SimpleControls.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Slider.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitView.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStrip.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStripItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TextBox.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ThemeVariantScope.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TimePicker.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TitleBar.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleButton.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleSwitch.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToolTip.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TransitioningContentControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeView.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeViewItem.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/UserControl.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Window.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/WindowNotificationManager.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/SimpleTheme.xaml - baseline/netstandard2.0/Avalonia.Themes.Simple.dll - target/netstandard2.0/Avalonia.Themes.Simple.dll - - \ No newline at end of file diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml index a47a716d3d..6b79f6f33b 100644 --- a/api/Avalonia.nupkg.xml +++ b/api/Avalonia.nupkg.xml @@ -1,1020 +1,6 @@  - - CP0001 - T:XamlX.Ast.IXamlAstImperativeNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlAstManipulationNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlAstNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlAstNodeNeedsParentStack - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlAstPropertyReference - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlAstTypeReference - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlAstValueNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlAstVisitor - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlILOptimizedEmitablePropertySetter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlLineInfo - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlPropertySetter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.IXamlWrappedMethod - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.PropertySetterBinderParameters - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstClrProperty - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstClrTypeReference - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstCompilerLocalNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstConstructableObjectNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstContextLocalNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstExtensions - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstImperativeValueManipulation - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstLocalInitializationNodeEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstManipulationImperativeNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstNamePropertyReference - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstNeedsParentStackValueNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstNewClrObjectNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstObjectNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstRuntimeCastNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstTextNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstXamlPropertyValueNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstXmlDirective - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlAstXmlTypeReference - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlConstantNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlDeferredContentInitializeIntermediateRootNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlDeferredContentNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlDocument - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlIntermediateRootObjectNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlLoadMethodDelegateNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlManipulationGroupNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlMarkupExtensionNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlMethodCallBaseNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlMethodWithCasts - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlNoReturnMethodCallNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlNullExtensionNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlObjectInitializationNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlPropertyAssignmentNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlPropertyValueManipulationNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlRootObjectNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlStaticExtensionNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlStaticOrTargetedReturnMethodCallNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlToArrayNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlTypeExtensionNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlValueNodeWithBeginInit - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlValueWithManipulationNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlValueWithSideEffectNodeBase - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlWrappedMethod - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Ast.XamlWrappedMethodWithCasts - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Compiler.XamlCompiler`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Compiler.XamlImperativeCompiler`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IHasLocalsPool - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlAstEmitableNode`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlAstLocalsEmitableNode`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlAstLocalsNodeEmitter`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlAstNodeEmitter`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlCustomEmitMethod`1 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlCustomEmitMethodWithContext`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlEmitablePropertySetter`1 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlEmitableWrappedMethod`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlEmitableWrappedMethodWithLocals`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlEmitResult - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlPropertySetterEmitter`1 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlWrappedMethodEmitter`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.IXamlWrappedMethodEmitterWithLocals`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.XamlContextFactoryCallback`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.XamlContextTypeBuilderCallback`1 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.XamlEmitContext`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.XamlEmitContextWithLocals`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.XamlLanguageEmitMappings`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Emit.XamlRuntimeContext`2 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.CheckingILEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.ManipulationGroupEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.MarkupExtensionEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.MethodCallEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.NewObjectEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.ObjectInitializationNodeEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.PropertyAssignmentEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.PropertyValueManipulationEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.TextNodeEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.Emitters.ValueWithManipulationsEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.ILEmitContext - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.ILEmitContextSettings - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.ILEmitHelpers - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.IXamlAstILEmitableNode - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.IXamlILAstNodeEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.IXamlILEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.IXamlILLocal - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.NamespaceInfoProvider - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.RecordingIlEmitter - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.RuntimeContext - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.SreTypeSystem - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.XamlILCompiler - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.XamlILContextDefinition - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.XamlIlEmitterExtensions - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.IL.XamlILNodeEmitResult - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Parsers.CommaSeparatedParenthesesTreeParser - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Parsers.SystemXamlMarkupExtensionParser.SystemXamlMarkupExtensionParser - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Parsers.XamlMarkupExtensionParser - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Parsers.XDocumentXamlParser - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Parsers.XDocumentXamlParserSettings - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.AstTransformationContext - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.GuidIdentifierGenerator - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.IXamlAstTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.IXamlCustomAttributeResolver - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.IXamlIdentifierGenerator - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.NamespaceInfoHelper - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.TransformerConfiguration - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.ApplyWhitespaceNormalization - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.ConstructableObjectTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.ContentConvertTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.ConvertPropertyValuesToAssignmentsTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.DeferredContentTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.FlattenAstTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.KnownDirectivesTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.MarkupExtensionTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.NewObjectTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.PropertyReferenceResolver - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.RemoveWhitespaceBetweenPropertyValuesTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.ResolveContentPropertyTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.ResolvePropertyValueAddersTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.TextNodeMerger - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.TopDownInitializationTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.TypeReferenceResolver - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.XamlIntrinsicsTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.Transformers.XArgumentsTransformer - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.XamlContextBase - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.XamlLanguageTypeMappings - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.XamlTransformHelpers - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.XamlTypeWellKnownTypes - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.Transform.XamlXmlnsMappings - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.FindMethodMethodSignature - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IFileSource - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlAssembly - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlConstructor - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlConstructorBuilder`1 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlCustomAttribute - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlDelegateTypeBuilder - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlEventInfo - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlField - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlLabel - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlLocal - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlMember - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlMethod - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlMethodBuilder`1 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlProperty - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlType - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlTypeBuilder`1 - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.IXamlTypeSystem - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.TypeSystemHelpers - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.XamlGenericParameterConstraint - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.XamlLocalsPool - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.XamlPseudoType - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.TypeSystem.XamlTypeSystemExtensions - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.XamlLoadException - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.XamlNamespaces - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.XamlParseException - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.XamlTransformException - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:XamlX.XamlTypeSystemException - baseline/designer/Avalonia.Designer.HostApp.dll - target/designer/Avalonia.Designer.HostApp.dll - - - CP0001 - T:Avalonia.AvaloniaLocator.RegistrationHelper`1 - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0001 - T:Avalonia.AvaloniaLocator.ResolverDisposable - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - CP0001 T:Avalonia.Diagnostics.AppliedStyle @@ -1027,66 +13,6 @@ baseline/netstandard2.0/Avalonia.Base.dll target/netstandard2.0/Avalonia.Base.dll - - CP0001 - T:Avalonia.Input.FocusManager.<GetFocusScopeAncestors>d__18 - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0001 - T:Avalonia.Layout.LayoutManager.<>c - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0001 - T:Avalonia.Layout.LayoutManager.ArrangeResult - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0001 - T:Avalonia.Layout.LayoutManager.EffectiveViewportChangedListener - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0001 - T:Avalonia.Rendering.DefaultRenderTimer.<>c__DisplayClass13_0 - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0001 - T:Avalonia.Rendering.UiThreadRenderTimer.<>c__DisplayClass3_0 - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0001 - T:Avalonia.Controls.Primitives.PopupPositioning.ManagedPopupPositioner.<>c__DisplayClass5_0 - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll - - - CP0001 - T:Avalonia.Controls.Primitives.PopupPositioning.ManagedPopupPositionerPopupImplHelper.<>c - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll - - - CP0001 - T:Avalonia.Controls.Primitives.PopupPositioning.ManagedPopupPositionerPopupImplHelper.MoveResizeDelegate - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll - - - CP0001 - T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/AboutAvaloniaDialog.xaml - baseline/netstandard2.0/Avalonia.Dialogs.dll - target/netstandard2.0/Avalonia.Dialogs.dll - CP0002 M:Avalonia.Diagnostics.StyledElementExtensions.GetStyleDiagnostics(Avalonia.StyledElement) @@ -1094,34 +20,10 @@ target/netstandard2.0/Avalonia.Base.dll - CP0006 - M:Avalonia.Platform.IAssetLoader.InvalidateAssemblyCache - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0006 - M:Avalonia.Platform.IAssetLoader.InvalidateAssemblyCache(System.String) - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0006 - P:Avalonia.Media.IRadialGradientBrush.RadiusX - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0006 - P:Avalonia.Media.IRadialGradientBrush.RadiusY - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll - - - CP0006 - P:Avalonia.Rendering.Composition.ICompositionGpuImportedObject.ImportCompleted - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + M:Avalonia.Controls.Screens.#ctor(Avalonia.Platform.IScreenImpl) + baseline/netstandard2.0/Avalonia.Controls.dll + target/netstandard2.0/Avalonia.Controls.dll CP0006 @@ -1141,4 +43,10 @@ baseline/netstandard2.0/Avalonia.Controls.dll target/netstandard2.0/Avalonia.Controls.dll + + CP0009 + T:Avalonia.Controls.Screens + baseline/netstandard2.0/Avalonia.Controls.dll + target/netstandard2.0/Avalonia.Controls.dll + \ No newline at end of file diff --git a/build/SharedVersion.props b/build/SharedVersion.props index bca2ef9eec..628f53bf5c 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -3,6 +3,7 @@ Avalonia 11.2.999 + 11.1.0 Avalonia Team Copyright 2013-$([System.DateTime]::Now.ToString(`yyyy`)) © The AvaloniaUI Project https://avaloniaui.net diff --git a/build/SourceLink.props b/build/SourceLink.props index b0f1f2c2cc..fb014e7e21 100644 --- a/build/SourceLink.props +++ b/build/SourceLink.props @@ -20,6 +20,6 @@ - + diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj index 5dd69e7009..9a67ee0161 100644 --- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj +++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj @@ -34,7 +34,7 @@ 1AFD334123E03C4F0042899B /* controlhost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AFD334023E03C4F0042899B /* controlhost.mm */; }; 37155CE4233C00EB0034DCE9 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 37155CE3233C00EB0034DCE9 /* menu.h */; }; 37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; }; - 37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; }; + 37C09D8821580FE4006A6758 /* StorageProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* StorageProvider.mm */; }; 37DDA9B0219330F8002E132B /* AvnString.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37DDA9AF219330F8002E132B /* AvnString.mm */; }; 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; }; 520624B322973F4100C4DCEF /* menu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 520624B222973F4100C4DCEF /* menu.mm */; }; @@ -57,6 +57,7 @@ AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */; }; BC11A5BE2608D58F0017BAD0 /* automation.h in Headers */ = {isa = PBXBuildFile; fileRef = BC11A5BC2608D58F0017BAD0 /* automation.h */; }; BC11A5BF2608D58F0017BAD0 /* automation.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC11A5BD2608D58F0017BAD0 /* automation.mm */; }; + BC7C33822C066DBF00945A48 /* AvnAutomationNode.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7C33812C066DBF00945A48 /* AvnAutomationNode.h */; }; ED3791C42862E1F40080BD62 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED3791C32862E1F40080BD62 /* UniformTypeIdentifiers.framework */; }; ED754D262A97306B0078B4DF /* PlatformRenderTimer.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED754D252A97306B0078B4DF /* PlatformRenderTimer.mm */; }; EDF8CDCD2964CB01001EE34F /* PlatformSettings.mm in Sources */ = {isa = PBXBuildFile; fileRef = EDF8CDCC2964CB01001EE34F /* PlatformSettings.mm */; }; @@ -94,7 +95,7 @@ 379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = ""; }; 37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = ""; }; 37A517B22159597E00FBA241 /* Screens.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Screens.mm; sourceTree = ""; }; - 37C09D8721580FE4006A6758 /* SystemDialogs.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SystemDialogs.mm; sourceTree = ""; }; + 37C09D8721580FE4006A6758 /* StorageProvider.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = StorageProvider.mm; sourceTree = ""; }; 37DDA9AF219330F8002E132B /* AvnString.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AvnString.mm; sourceTree = ""; }; 37DDA9B121933371002E132B /* AvnString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnString.h; sourceTree = ""; }; 37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = ""; }; @@ -122,6 +123,8 @@ AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platformthreading.mm; sourceTree = ""; }; BC11A5BC2608D58F0017BAD0 /* automation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = automation.h; sourceTree = ""; }; BC11A5BD2608D58F0017BAD0 /* automation.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = automation.mm; sourceTree = ""; }; + BC7C33812C066DBF00945A48 /* AvnAutomationNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvnAutomationNode.h; sourceTree = ""; }; + BC7C33832C066F1100945A48 /* AvnAccessibility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnAccessibility.h; sourceTree = ""; }; ED3791C32862E1F40080BD62 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; ED754D252A97306B0078B4DF /* PlatformRenderTimer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformRenderTimer.mm; sourceTree = ""; }; EDF8CDCC2964CB01001EE34F /* PlatformSettings.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformSettings.mm; sourceTree = ""; }; @@ -167,6 +170,8 @@ isa = PBXGroup; children = ( F10084852BFF1FB40024303E /* TopLevelImpl.mm */, + BC7C33832C066F1100945A48 /* AvnAccessibility.h */, + BC7C33812C066DBF00945A48 /* AvnAutomationNode.h */, ED754D252A97306B0078B4DF /* PlatformRenderTimer.mm */, 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */, 8D2F3511292F6AAE007FCF54 /* AvnTextInputMethodDelegate.h */, @@ -197,7 +202,7 @@ 523484CB26EA68AA00EA0C2C /* trayicon.h */, 1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */, 37A517B22159597E00FBA241 /* Screens.mm */, - 37C09D8721580FE4006A6758 /* SystemDialogs.mm */, + 37C09D8721580FE4006A6758 /* StorageProvider.mm */, EDF8CDCC2964CB01001EE34F /* PlatformSettings.mm */, AB7A61F02147C815003C5833 /* Products */, AB661C1C2148230E00291242 /* Frameworks */, @@ -245,6 +250,7 @@ 183916173528EC2737DBE5E1 /* WindowBaseImpl.h in Headers */, 1839171DCC651B0638603AC4 /* INSWindowHolder.h in Headers */, 183919D91DB9AAB5D700C2EA /* WindowImpl.h in Headers */, + BC7C33822C066DBF00945A48 /* AvnAutomationNode.h in Headers */, 18391CF07316F819E76B617C /* IWindowStateChanged.h in Headers */, 8D300D65292D0A6800320C49 /* AvnTextInputMethod.h in Headers */, 8D2F3512292F6AAE007FCF54 /* AvnTextInputMethodDelegate.h in Headers */, @@ -333,7 +339,7 @@ 1AFD334123E03C4F0042899B /* controlhost.mm in Sources */, 1A465D10246AB61600C5858B /* dnd.mm in Sources */, AB00E4F72147CA920032A60A /* main.mm in Sources */, - 37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */, + 37C09D8821580FE4006A6758 /* StorageProvider.mm in Sources */, 1839179A55FC1421BEE83330 /* WindowBaseImpl.mm in Sources */, F10084862BFF1FB40024303E /* TopLevelImpl.mm in Sources */, 1839125F057B0A4EB1760058 /* WindowImpl.mm in Sources */, diff --git a/native/Avalonia.Native/src/OSX/AvnAccessibility.h b/native/Avalonia.Native/src/OSX/AvnAccessibility.h new file mode 100644 index 0000000000..6658d8523e --- /dev/null +++ b/native/Avalonia.Native/src/OSX/AvnAccessibility.h @@ -0,0 +1,13 @@ +#pragma once +#import +#import "avalonia-native.h" + +// Defines the interface between AvnAutomationNode and objects which implement +// NSAccessibility such as AvnAccessibilityElement or AvnWindow. +@protocol AvnAccessibility +@required +- (void) raiseChildrenChanged; +@optional +- (void) raiseFocusChanged; +- (void) raisePropertyChanged:(AvnAutomationProperty)property; +@end diff --git a/native/Avalonia.Native/src/OSX/AvnAutomationNode.h b/native/Avalonia.Native/src/OSX/AvnAutomationNode.h new file mode 100644 index 0000000000..58bea8caf9 --- /dev/null +++ b/native/Avalonia.Native/src/OSX/AvnAutomationNode.h @@ -0,0 +1,18 @@ +#pragma once +#include "avalonia-native.h" +#include "AvnAccessibility.h" + +// Defines a means for managed code to raise accessibility events. +class AvnAutomationNode : public ComSingleObject +{ +public: + FORWARD_IUNKNOWN() + AvnAutomationNode(id owner) { _owner = owner; } + AvnAccessibilityElement* GetOwner() { return _owner; } + virtual void Dispose() override { _owner = nil; } + virtual void ChildrenChanged () override { [_owner raiseChildrenChanged]; } + virtual void PropertyChanged (AvnAutomationProperty property) override { [_owner raisePropertyChanged:property]; } + virtual void FocusChanged () override { [_owner raiseFocusChanged]; } +private: + __strong id _owner; +}; diff --git a/native/Avalonia.Native/src/OSX/AvnView.h b/native/Avalonia.Native/src/OSX/AvnView.h index 4f673fceef..75a5e98ed4 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.h +++ b/native/Avalonia.Native/src/OSX/AvnView.h @@ -22,5 +22,5 @@ -(AvnPlatformResizeReason) getResizeReason; -(void) setResizeReason:(AvnPlatformResizeReason)reason; -(void) setRenderTarget:(NSObject* _Nonnull)target; -+ (AvnPoint)toAvnPoint:(CGPoint)p; +-(void) raiseAccessibilityChildrenChanged; @end diff --git a/native/Avalonia.Native/src/OSX/AvnView.mm b/native/Avalonia.Native/src/OSX/AvnView.mm index ab52bcc4a9..8c38b1cf2d 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.mm +++ b/native/Avalonia.Native/src/OSX/AvnView.mm @@ -19,12 +19,12 @@ AvnPixelSize _lastPixelSize; NSObject* _currentRenderTarget; AvnPlatformResizeReason _resizeReason; - AvnAccessibilityElement* _accessibilityChild; NSRect _cursorRect; NSMutableAttributedString* _text; NSRange _selectedRange; NSRange _markedRange; NSEvent* _lastKeyDownEvent; + NSMutableArray* _accessibilityChildren; } - (void)onClosed @@ -189,16 +189,6 @@ return pt; } -+ (AvnPoint)toAvnPoint:(CGPoint)p -{ - AvnPoint result; - - result.X = p.x; - result.Y = p.y; - - return result; -} - - (void) viewDidChangeBackingProperties { auto fsize = [self convertSizeToBacking: [self frame].size]; @@ -255,9 +245,13 @@ return; } - auto localPoint = [self convertPoint:[event locationInWindow] toView:self]; - auto avnPoint = [AvnView toAvnPoint:localPoint]; - auto point = [self translateLocalPoint:avnPoint]; + NSPoint eventLocation = [event locationInWindow]; + + auto viewLocation = [self convertPoint:NSMakePoint(0, 0) toView:nil]; + + auto localPoint = NSMakePoint(eventLocation.x - viewLocation.x, viewLocation.y - eventLocation.y); + + auto point = ToAvnPoint(localPoint); AvnVector delta = { 0, 0}; if(type == Wheel) @@ -303,7 +297,22 @@ ) ) ) - [self becomeFirstResponder]; + { + WindowBaseImpl* windowBase = dynamic_cast(_parent.getRaw()); + + if(windowBase != nullptr){ + WindowBaseImpl* parent = windowBase->Parent; + + if(parent != nullptr){ + auto parentWindow = parent->Window; + + [parentWindow makeFirstResponder:parent->View]; + } + } else{ + [self becomeFirstResponder]; + } + } + if(_parent != nullptr) { @@ -442,6 +451,7 @@ - (void)mouseEntered:(NSEvent *)event { + [self mouseEvent:event withType:Move]; [super mouseEntered:event]; } @@ -733,7 +743,7 @@ - (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id )info { auto localPoint = [self convertPoint:[info draggingLocation] toView:self]; - auto avnPoint = [AvnView toAvnPoint:localPoint]; + auto avnPoint = ToAvnPoint(localPoint); auto point = [self translateLocalPoint:avnPoint]; auto modifiers = [self getModifiers:[[NSApp currentEvent] modifierFlags]]; NSDragOperation nsop = [info draggingSourceOperationMask]; @@ -801,35 +811,74 @@ _resizeReason = reason; } -- (AvnAccessibilityElement *) accessibilityChild +- (NSArray *)accessibilityChildren { - if (_accessibilityChild == nil) - { - auto peer = _parent->TopLevelEvents->GetAutomationPeer(); + if (_accessibilityChildren == nil) + [self recalculateAccessibiltyChildren]; + return _accessibilityChildren; +} - if (peer == nil) - return nil; +- (id _Nullable) accessibilityHitTest:(NSPoint)point +{ + if (![[self window] isKindOfClass:[AvnWindow class]]) + return self; - _accessibilityChild = [AvnAccessibilityElement acquire:peer]; - } + auto window = (AvnWindow*)[self window]; + auto peer = [window automationPeer]; - return _accessibilityChild; -} + if (!peer->IsRootProvider()) + return nil; -- (NSArray *)accessibilityChildren -{ - auto child = [self accessibilityChild]; - return NSAccessibilityUnignoredChildrenForOnlyChild(child); + auto clientPoint = [window convertPointFromScreen:point]; + auto localPoint = [self translateLocalPoint:ToAvnPoint(clientPoint)]; + auto hit = peer->RootProvider_GetPeerFromPoint(localPoint); + return [AvnAccessibilityElement acquire:hit]; } -- (id)accessibilityHitTest:(NSPoint)point +- (void)raiseAccessibilityChildrenChanged { - return [[self accessibilityChild] accessibilityHitTest:point]; + auto changed = _accessibilityChildren ? [NSMutableSet setWithArray:_accessibilityChildren] : [NSMutableSet set]; + + [self recalculateAccessibiltyChildren]; + + if (_accessibilityChildren) + [changed addObjectsFromArray:_accessibilityChildren]; + + NSAccessibilityPostNotificationWithUserInfo( + self, + NSAccessibilityLayoutChangedNotification, + @{ NSAccessibilityUIElementsKey: [changed allObjects]}); } -- (id)accessibilityFocusedUIElement +- (void)recalculateAccessibiltyChildren { - return [[self accessibilityChild] accessibilityFocusedUIElement]; + _accessibilityChildren = [[NSMutableArray alloc] init]; + + if (![[self window] isKindOfClass:[AvnWindow class]]) + { + return; + } + + // The accessibility children of the Window are exposed as children + // of the AvnView. + auto window = (AvnWindow*)[self window]; + auto peer = [window automationPeer]; + auto childPeers = peer->GetChildren(); + auto childCount = childPeers != nullptr ? childPeers->GetCount() : 0; + + if (childCount > 0) + { + for (int i = 0; i < childCount; ++i) + { + IAvnAutomationPeer* child; + + if (childPeers->Get(i, &child) == S_OK) + { + id element = [AvnAccessibilityElement acquire:child]; + [_accessibilityChildren addObject:element]; + } + } + } } - (void) setText:(NSString *)text{ diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 86d412c76a..9b92dba523 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -24,6 +24,8 @@ #include "WindowImpl.h" #include "AvnView.h" #include "WindowInterfaces.h" +#include "AvnAutomationNode.h" +#include "AvnString.h" @implementation CLASS_NAME { @@ -34,6 +36,13 @@ bool _isExtended; bool _isTransitioningToFullScreen; AvnMenu* _menu; + IAvnAutomationPeer* _automationPeer; + AvnAutomationNode* _automationNode; +} + +-(AvnView* _Nullable) view +{ + return _parent->View; } -(void) setIsExtended:(bool)value; @@ -208,7 +217,7 @@ ComPtr parent = _parent; _parent = NULL; - auto window = dynamic_cast(parent.getRaw()); + auto window = dynamic_cast(parent.getRaw()); if(window != nullptr) { @@ -453,7 +462,7 @@ if (!NSPointInRect(viewPoint, view.bounds)) { - auto avnPoint = [AvnView toAvnPoint:windowPoint]; + auto avnPoint = ToAvnPoint(windowPoint); auto point = [self translateLocalPoint:avnPoint]; AvnVector delta = { 0, 0 }; @@ -489,5 +498,41 @@ _parent = nullptr; } +- (id _Nullable) accessibilityFocusedUIElement +{ + if (![self automationPeer]->IsRootProvider()) + return nil; + auto focusedPeer = [self automationPeer]->RootProvider_GetFocus(); + return [AvnAccessibilityElement acquire:focusedPeer]; +} + +- (NSString * _Nullable) accessibilityIdentifier +{ + return GetNSStringAndRelease([self automationPeer]->GetAutomationId()); +} + +- (IAvnAutomationPeer* _Nonnull) automationPeer +{ + if (_automationPeer == nullptr) + { + _automationPeer = _parent->BaseEvents->GetAutomationPeer(); + _automationNode = new AvnAutomationNode(self); + _automationPeer->SetNode(_automationNode); + } + + return _automationPeer; +} + +- (void)raiseChildrenChanged +{ + [_parent->View raiseAccessibilityChildrenChanged]; +} + +- (void)raiseFocusChanged +{ + id focused = [self accessibilityFocusedUIElement]; + NSAccessibilityPostNotification(focused, NSAccessibilityFocusedUIElementChangedNotification); +} + @end diff --git a/native/Avalonia.Native/src/OSX/Screens.mm b/native/Avalonia.Native/src/OSX/Screens.mm index 85f4b7c50a..2279dae7c8 100644 --- a/native/Avalonia.Native/src/OSX/Screens.mm +++ b/native/Avalonia.Native/src/OSX/Screens.mm @@ -1,36 +1,62 @@ #include "common.h" +#include "AvnString.h" class Screens : public ComSingleObject { - public: - FORWARD_IUNKNOWN() - +private: + ComPtr _events; public: - virtual HRESULT GetScreenCount (int* ret) override + FORWARD_IUNKNOWN() + + Screens(IAvnScreenEvents* events) { + _events = events; + CGDisplayRegisterReconfigurationCallback(CGDisplayReconfigurationCallBack, this); + } + + virtual HRESULT GetScreenIds ( + unsigned int* ptrFirstResult, + int* screenCound) override { START_COM_CALL; @autoreleasepool { - *ret = (int)[NSScreen screens].count; - + auto screens = [NSScreen screens]; + *screenCound = (int)screens.count; + + if (ptrFirstResult == nil) + return S_OK; + + for (int i = 0; i < screens.count; i++) { + ptrFirstResult[i] = [[screens objectAtIndex:i] av_displayId]; + } + return S_OK; } } - - virtual HRESULT GetScreen (int index, AvnScreen* ret) override - { + + virtual HRESULT GetScreen ( + CGDirectDisplayID displayId, + void** localizedName, + AvnScreen* ret + ) override { START_COM_CALL; @autoreleasepool { - if(index < 0 || index >= [NSScreen screens].count) - { - return E_INVALIDARG; + NSScreen* screen; + for (NSScreen *s in NSScreen.screens) { + if (s.av_displayId == displayId) + { + screen = s; + break; + } } - auto screen = [[NSScreen screens] objectAtIndex:index]; - + if (screen == nil) { + return E_INVALIDARG; + } + ret->Bounds.Height = [screen frame].size.height; ret->Bounds.Width = [screen frame].size.width; ret->Bounds.X = [screen frame].origin.x; @@ -43,14 +69,45 @@ public: ret->Scaling = 1; - ret->IsPrimary = index == 0; - + ret->IsPrimary = CGDisplayIsMain(displayId); + + // Compute natural orientation: + auto naturalScreenSize = CGDisplayScreenSize(displayId); + auto isNaturalLandscape = naturalScreenSize.width > naturalScreenSize.height; + // Normalize rotation: + auto rotation = (int)CGDisplayRotation(displayId) % 360; + if (rotation < 0) rotation = 360 - rotation; + // Get current orientation relative to the natural + if (rotation >= 0 && rotation < 90) { + ret->Orientation = isNaturalLandscape ? AvnScreenOrientation::Landscape : AvnScreenOrientation::Portrait; + } else if (rotation >= 90 && rotation < 180) { + ret->Orientation = isNaturalLandscape ? AvnScreenOrientation::Portrait : AvnScreenOrientation::Landscape; + } else if (rotation >= 180 && rotation < 270) { + ret->Orientation = isNaturalLandscape ? AvnScreenOrientation::LandscapeFlipped : AvnScreenOrientation::PortraitFlipped; + } else { + ret->Orientation = isNaturalLandscape ? AvnScreenOrientation::PortraitFlipped : AvnScreenOrientation::LandscapeFlipped; + } + + if (@available(macOS 10.15, *)) { + *localizedName = CreateAvnString([screen localizedName]); + } + return S_OK; } } + +private: + static void CGDisplayReconfigurationCallBack(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *screens) + { + auto object = (Screens *)screens; + auto events = object->_events; + if (events != nil) { + events->OnChanged(); + } + } }; -extern IAvnScreens* CreateScreens() +extern IAvnScreens* CreateScreens(IAvnScreenEvents* events) { - return new Screens(); + return new Screens(events); } diff --git a/native/Avalonia.Native/src/OSX/SystemDialogs.mm b/native/Avalonia.Native/src/OSX/StorageProvider.mm similarity index 84% rename from native/Avalonia.Native/src/OSX/SystemDialogs.mm rename to native/Avalonia.Native/src/OSX/StorageProvider.mm index c09464af4f..0fd77c6789 100644 --- a/native/Avalonia.Native/src/OSX/SystemDialogs.mm +++ b/native/Avalonia.Native/src/OSX/StorageProvider.mm @@ -64,12 +64,91 @@ const int kFileTypePopupTag = 10975; @end -class SystemDialogs : public ComSingleObject +class StorageProvider : public ComSingleObject { ExtensionDropdownHandler* __strong _extension_dropdown_handler; public: FORWARD_IUNKNOWN() + + virtual HRESULT SaveBookmarkToBytes ( + IAvnString* fileUriStr, + void** err, + IAvnString** ppv + ) override + { + @autoreleasepool + { + if(ppv == nullptr) + return E_POINTER; + + NSError* error; + auto fileUri = [NSURL URLWithString: GetNSStringAndRelease(fileUriStr)]; + auto bookmarkData = [fileUri bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error]; + if (bookmarkData) + { + *ppv = CreateByteArray((void*)bookmarkData.bytes, (int)bookmarkData.length); + } + if (error != nil) + { + *err = CreateAvnString([error localizedDescription]); + } + return S_OK; + } + } + + virtual HRESULT ReadBookmarkFromBytes ( + void* ptr, + int len, + IAvnString** ppv + ) override { + @autoreleasepool + { + if(ppv == nullptr) + return E_POINTER; + + auto bookmarkData = [[NSData alloc] initWithBytes:ptr length:len]; + auto fileUri = [NSURL URLByResolvingBookmarkData: bookmarkData + options:NSURLBookmarkResolutionWithSecurityScope|NSURLBookmarkResolutionWithoutUI + relativeToURL:nil + bookmarkDataIsStale:nil + error:nil]; + + if (fileUri) + { + *ppv = CreateAvnString([fileUri absoluteString]); + } + return S_OK; + } + } + + virtual void ReleaseBookmark ( + IAvnString* fileUriStr + ) override { + // no-op + } + + virtual bool OpenSecurityScope ( + IAvnString* fileUriStr + ) override { + @autoreleasepool + { + auto fileUri = [NSURL URLWithString: GetNSStringAndRelease(fileUriStr)]; + auto success = [fileUri startAccessingSecurityScopedResource]; + return success; + } + } + + virtual void CloseSecurityScope ( + IAvnString* fileUriStr + ) override { + @autoreleasepool + { + auto fileUri = [NSURL URLWithString: GetNSStringAndRelease(fileUriStr)]; + [fileUri stopAccessingSecurityScopedResource]; + } + } + virtual void SelectFolderDialog (IAvnWindow* parentWindowHandle, IAvnSystemDialogEvents* events, bool allowMultiple, @@ -94,7 +173,8 @@ public: if(initialDirectory != nullptr) { auto directoryString = [NSString stringWithUTF8String:initialDirectory]; - panel.directoryURL = [NSURL fileURLWithPath:directoryString]; + panel.directoryURL = [NSURL fileURLWithPath:directoryString + isDirectory:true]; } auto handler = ^(NSModalResponse result) { @@ -104,19 +184,9 @@ public: if(urls.count > 0) { - void* strings[urls.count]; - - for(int i = 0; i < urls.count; i++) - { - auto url = [urls objectAtIndex:i]; - - auto string = [url path]; - - strings[i] = (void*)[string UTF8String]; - } - - events->OnCompleted((int)urls.count, &strings[0]); - + auto uriStrings = CreateAvnStringArray(urls); + events->OnCompleted(uriStrings); + [panel orderOut:panel]; if(parentWindowHandle != nullptr) @@ -129,7 +199,7 @@ public: } } - events->OnCompleted(0, nullptr); + events->OnCompleted(nullptr); }; @@ -169,7 +239,8 @@ public: if(initialDirectory != nullptr) { auto directoryString = [NSString stringWithUTF8String:initialDirectory]; - panel.directoryURL = [NSURL fileURLWithPath:directoryString]; + panel.directoryURL = [NSURL fileURLWithPath:directoryString + isDirectory:true]; } if(initialFile != nullptr) @@ -186,19 +257,9 @@ public: if(urls.count > 0) { - void* strings[urls.count]; - - for(int i = 0; i < urls.count; i++) - { - auto url = [urls objectAtIndex:i]; - - auto string = [url path]; - - strings[i] = (void*)[string UTF8String]; - } - - events->OnCompleted((int)urls.count, &strings[0]); - + auto uriStrings = CreateAvnStringArray(urls); + events->OnCompleted(uriStrings); + [panel orderOut:panel]; if(parentWindowHandle != nullptr) @@ -211,7 +272,7 @@ public: } } - events->OnCompleted(0, nullptr); + events->OnCompleted(nullptr); }; @@ -248,7 +309,8 @@ public: if(initialDirectory != nullptr) { auto directoryString = [NSString stringWithUTF8String:initialDirectory]; - panel.directoryURL = [NSURL fileURLWithPath:directoryString]; + panel.directoryURL = [NSURL fileURLWithPath:directoryString + isDirectory:true]; } if(initialFile != nullptr) @@ -261,15 +323,11 @@ public: auto handler = ^(NSModalResponse result) { if(result == NSFileHandlingPanelOKButton) { - void* strings[1]; - auto url = [panel URL]; - - auto string = [url path]; - strings[0] = (void*)[string UTF8String]; - - events->OnCompleted(1, &strings[0]); - + auto urls = [NSArray arrayWithObject:url]; + auto uriStrings = CreateAvnStringArray(urls); + events->OnCompleted(uriStrings); + [panel orderOut:panel]; if(parentWindowHandle != nullptr) @@ -281,7 +339,7 @@ public: return; } - events->OnCompleted(0, nullptr); + events->OnCompleted(nullptr); }; @@ -516,7 +574,7 @@ private: }; }; -extern IAvnSystemDialogs* CreateSystemDialogs() +extern IAvnStorageProvider* CreateStorageProvider() { - return new SystemDialogs(); + return new StorageProvider(); } diff --git a/native/Avalonia.Native/src/OSX/TopLevelImpl.h b/native/Avalonia.Native/src/OSX/TopLevelImpl.h index d6243b6268..dd494ab761 100644 --- a/native/Avalonia.Native/src/OSX/TopLevelImpl.h +++ b/native/Avalonia.Native/src/OSX/TopLevelImpl.h @@ -58,7 +58,8 @@ public: virtual HRESULT PointToScreen(AvnPoint point, AvnPoint *ret) override; virtual HRESULT SetTransparencyMode(AvnWindowTransparencyMode mode) override; - + + virtual HRESULT GetCurrentDisplayId (CGDirectDisplayID* ret) override; protected: NSCursor *cursor; virtual void UpdateAppearance(); diff --git a/native/Avalonia.Native/src/OSX/TopLevelImpl.mm b/native/Avalonia.Native/src/OSX/TopLevelImpl.mm index 0a56b71f82..6200f096d3 100644 --- a/native/Avalonia.Native/src/OSX/TopLevelImpl.mm +++ b/native/Avalonia.Native/src/OSX/TopLevelImpl.mm @@ -192,11 +192,23 @@ HRESULT TopLevelImpl::PointToClient(AvnPoint point, AvnPoint *ret) { return S_OK; } - point = ConvertPointY(point); - NSRect convertRect = [window convertRectFromScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)]; - auto viewPoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y); + auto frame = [View frame]; + + auto viewRect = [View convertRect:frame toView:nil]; + + auto viewScreenRect = [window convertRectToScreen:viewRect]; + + auto primaryDisplayHeight = NSMaxY([[[NSScreen screens] firstObject] frame]); + + //Window coord are bottom to top so we need to adjust by primaryScreenHeight + auto viewScreenLocation = NSMakePoint(viewScreenRect.origin.x, primaryDisplayHeight - viewScreenRect.origin.y - frame.size.height); + + //Substract client point from screen position of the view + auto localPoint = NSMakePoint(point.X - viewScreenLocation.x, point.Y - viewScreenLocation.y); + + point = ToAvnPoint(localPoint); - *ret = [View translateLocalPoint:ToAvnPoint(viewPoint)]; + *ret = point; return S_OK; } @@ -217,11 +229,24 @@ HRESULT TopLevelImpl::PointToScreen(AvnPoint point, AvnPoint *ret) { return S_OK; } + + auto frame = [View frame]; + + //Get rect inside current window + auto viewRect = [View convertRect:frame toView:nil]; + + //Get screen rect of the view + auto viewScreenRect = [window convertRectToScreen:viewRect]; + + auto primaryDisplayHeight = NSMaxY([[[NSScreen screens] firstObject] frame]); + + //Window coord are bottom to top so we need to adjust by primaryScreenHeight + auto viewScreenLocation = NSMakePoint(viewScreenRect.origin.x, primaryDisplayHeight - viewScreenRect.origin.y - frame.size.height); - auto cocoaViewPoint = ToNSPoint([View translateLocalPoint:point]); - NSRect convertRect = [window convertRectToScreen:NSMakeRect(cocoaViewPoint.x, cocoaViewPoint.y, 0.0, 0.0)]; - auto cocoaScreenPoint = NSPointFromCGPoint(NSMakePoint(convertRect.origin.x, convertRect.origin.y)); - *ret = ConvertPointY(ToAvnPoint(cocoaScreenPoint)); + //Add client point to screen position of the view + auto screenPoint = ToAvnPoint(NSMakePoint(viewScreenLocation.x + point.X, viewScreenLocation.y + point.Y)); + + *ret = screenPoint; return S_OK; } @@ -233,6 +258,15 @@ HRESULT TopLevelImpl::SetTransparencyMode(AvnWindowTransparencyMode mode) { return S_OK; } +HRESULT TopLevelImpl::GetCurrentDisplayId (CGDirectDisplayID* ret) { + START_COM_CALL; + + auto window = [View window]; + *ret = [window.screen av_displayId]; + + return S_OK; +} + void TopLevelImpl::UpdateAppearance() { } diff --git a/native/Avalonia.Native/src/OSX/WindowInterfaces.h b/native/Avalonia.Native/src/OSX/WindowInterfaces.h index 6e6d62e85e..d920183435 100644 --- a/native/Avalonia.Native/src/OSX/WindowInterfaces.h +++ b/native/Avalonia.Native/src/OSX/WindowInterfaces.h @@ -7,11 +7,13 @@ #import #include "WindowProtocol.h" #include "WindowBaseImpl.h" +#include "AvnAccessibility.h" -@interface AvnWindow : NSWindow +@interface AvnWindow : NSWindow -(AvnWindow* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask; +-(AvnView* _Nullable) view; @end -@interface AvnPanel : NSPanel +@interface AvnPanel : NSPanel -(AvnPanel* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask; -@end \ No newline at end of file +@end diff --git a/native/Avalonia.Native/src/OSX/WindowProtocol.h b/native/Avalonia.Native/src/OSX/WindowProtocol.h index cb5f86bdb9..5d1df951a6 100644 --- a/native/Avalonia.Native/src/OSX/WindowProtocol.h +++ b/native/Avalonia.Native/src/OSX/WindowProtocol.h @@ -8,6 +8,7 @@ #import @class AvnMenu; +struct IAvnAutomationPeer; @protocol AvnWindowProtocol -(void) pollModalSession: (NSModalSession _Nonnull) session; @@ -16,6 +17,7 @@ -(void) showAppMenuOnly; -(void) showWindowMenuWithAppMenu; -(void) applyMenu:(AvnMenu* _Nullable)menu; +-(IAvnAutomationPeer* _Nonnull) automationPeer; -(double) getExtendedTitleBarHeight; -(void) setIsExtended:(bool)value; diff --git a/native/Avalonia.Native/src/OSX/automation.h b/native/Avalonia.Native/src/OSX/automation.h index 367df3619d..5d96637241 100644 --- a/native/Avalonia.Native/src/OSX/automation.h +++ b/native/Avalonia.Native/src/OSX/automation.h @@ -1,12 +1,13 @@ #pragma once #import +#include "AvnAccessibility.h" NS_ASSUME_NONNULL_BEGIN class IAvnAutomationPeer; -@interface AvnAccessibilityElement : NSAccessibilityElement -+ (AvnAccessibilityElement *) acquire:(IAvnAutomationPeer *) peer; +@interface AvnAccessibilityElement : NSAccessibilityElement ++ (id _Nullable) acquire:(IAvnAutomationPeer *) peer; @end NS_ASSUME_NONNULL_END diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm index 0f5f294329..543aa78cbe 100644 --- a/native/Avalonia.Native/src/OSX/automation.mm +++ b/native/Avalonia.Native/src/OSX/automation.mm @@ -1,66 +1,19 @@ #include "common.h" #include "automation.h" +#include "AvnAutomationNode.h" #include "AvnString.h" #include "INSWindowHolder.h" #include "AvnView.h" - -@interface AvnAccessibilityElement (Events) -- (void) raiseChildrenChanged; -@end - -@interface AvnRootAccessibilityElement : AvnAccessibilityElement -- (AvnView *) ownerView; -- (AvnRootAccessibilityElement *) initWithPeer:(IAvnAutomationPeer *) peer owner:(AvnView*) owner; -- (void) raiseFocusChanged; -@end - -class AutomationNode : public ComSingleObject -{ -public: - FORWARD_IUNKNOWN() - - AutomationNode(AvnAccessibilityElement* owner) - { - _owner = owner; - } - - AvnAccessibilityElement* GetOwner() - { - return _owner; - } - - virtual void Dispose() override - { - _owner = nil; - } - - virtual void ChildrenChanged () override - { - [_owner raiseChildrenChanged]; - } - - virtual void PropertyChanged (AvnAutomationProperty property) override - { - - } - - virtual void FocusChanged () override - { - [(AvnRootAccessibilityElement*)_owner raiseFocusChanged]; - } - -private: - __strong AvnAccessibilityElement* _owner; -}; +#include "WindowInterfaces.h" @implementation AvnAccessibilityElement { IAvnAutomationPeer* _peer; - AutomationNode* _node; + AvnAutomationNode* _node; NSMutableArray* _children; } -+ (AvnAccessibilityElement *)acquire:(IAvnAutomationPeer *)peer ++ (id _Nullable)acquire:(IAvnAutomationPeer *)peer { if (peer == nullptr) return nil; @@ -68,7 +21,7 @@ private: auto instance = peer->GetNode(); if (instance != nullptr) - return dynamic_cast(instance)->GetOwner(); + return dynamic_cast(instance)->GetOwner(); if (peer->IsRootProvider()) { @@ -82,7 +35,7 @@ private: auto holder = dynamic_cast(window); auto view = holder->GetNSView(); - return [[AvnRootAccessibilityElement alloc] initWithPeer:peer owner:view]; + return [view window]; } else { @@ -94,7 +47,7 @@ private: { self = [super init]; _peer = peer; - _node = new AutomationNode(self); + _node = new AvnAutomationNode(self); _peer->SetNode(_node); return self; } @@ -256,25 +209,8 @@ private: - (NSRect)accessibilityFrame { - id topLevel = [self accessibilityTopLevelUIElement]; - auto result = NSZeroRect; - - if ([topLevel isKindOfClass:[AvnRootAccessibilityElement class]]) - { - auto root = (AvnRootAccessibilityElement*)topLevel; - auto view = [root ownerView]; - - if (view) - { - auto window = [view window]; - auto bounds = ToNSRect(_peer->GetBoundingRectangle()); - auto windowBounds = [view convertRect:bounds toView:nil]; - auto screenBounds = [window convertRectToScreen:windowBounds]; - result = screenBounds; - } - } - - return result; + auto bounds = _peer->GetBoundingRectangle(); + return [self rectToScreen:bounds]; } - (id)accessibilityParent @@ -389,6 +325,24 @@ private: return [super isAccessibilitySelectorAllowed:selector]; } +- (NSRect)rectToScreen:(AvnRect)rect +{ + id topLevel = [self accessibilityTopLevelUIElement]; + + if (![topLevel isKindOfClass:[AvnWindow class]]) + return NSZeroRect; + + auto window = (AvnWindow*)topLevel; + auto view = [window view]; + + if (view == nil) + return NSZeroRect; + + auto nsRect = ToNSRect(rect); + auto windowRect = [view convertRect:nsRect toView:nil]; + return [window convertRectToScreen:windowRect]; +} + - (void)raiseChildrenChanged { auto changed = _children ? [NSMutableSet setWithArray:_children] : [NSMutableSet set]; @@ -429,7 +383,7 @@ private: if (childPeers->Get(i, &child) == S_OK) { - auto element = [AvnAccessibilityElement acquire:child]; + id element = [AvnAccessibilityElement acquire:child]; [_children addObject:element]; } } @@ -441,64 +395,3 @@ private: } @end - -@implementation AvnRootAccessibilityElement -{ - AvnView* _owner; -} - -- (AvnRootAccessibilityElement *)initWithPeer:(IAvnAutomationPeer *)peer owner:(AvnView *)owner -{ - self = [super initWithPeer:peer]; - _owner = owner; - - // Seems we need to raise a focus changed notification here if we have focus - auto focusedPeer = [self peer]->RootProvider_GetFocus(); - id focused = [AvnAccessibilityElement acquire:focusedPeer]; - - if (focused) - NSAccessibilityPostNotification(focused, NSAccessibilityFocusedUIElementChangedNotification); - - return self; -} - -- (AvnView *)ownerView -{ - return _owner; -} - -- (id)accessibilityFocusedUIElement -{ - auto focusedPeer = [self peer]->RootProvider_GetFocus(); - return [AvnAccessibilityElement acquire:focusedPeer]; -} - -- (id)accessibilityHitTest:(NSPoint)point -{ - auto clientPoint = [[_owner window] convertPointFromScreen:point]; - auto localPoint = [_owner translateLocalPoint:ToAvnPoint(clientPoint)]; - auto hit = [self peer]->RootProvider_GetPeerFromPoint(localPoint); - return [AvnAccessibilityElement acquire:hit]; -} - -- (id)accessibilityParent -{ - return _owner; -} - -- (void)raiseFocusChanged -{ - id focused = [self accessibilityFocusedUIElement]; - NSAccessibilityPostNotification(focused, NSAccessibilityFocusedUIElementChangedNotification); -} - -// Although this method is marked as deprecated we get runtime warnings if we don't handle it. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" -- (void)accessibilityPerformAction:(NSAccessibilityActionName)action -{ - [_owner accessibilityPerformAction:action]; -} -#pragma clang diagnostic pop - -@end diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h index 38b702d775..36c157704d 100644 --- a/native/Avalonia.Native/src/OSX/common.h +++ b/native/Avalonia.Native/src/OSX/common.h @@ -14,8 +14,8 @@ extern void PostDispatcherCallback(IAvnActionCallback* cb); extern IAvnTopLevel* CreateAvnTopLevel(IAvnTopLevelEvents* events); extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events); extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events); -extern IAvnSystemDialogs* CreateSystemDialogs(); -extern IAvnScreens* CreateScreens(); +extern IAvnStorageProvider* CreateStorageProvider(); +extern IAvnScreens* CreateScreens(IAvnScreenEvents* cb); extern IAvnClipboard* CreateClipboard(NSPasteboard*, NSPasteboardItem*); extern NSPasteboardItem* TryGetPasteboardItem(IAvnClipboard*); extern NSObject* CreateDraggingSource(NSDragOperation op, IAvnDndResultCallback* cb, void* handle); @@ -89,6 +89,13 @@ public: - (void) action; @end +@implementation NSScreen (AvNSScreen) +- (CGDirectDisplayID)av_displayId +{ + return [self.deviceDescription[@"NSScreenNumber"] unsignedIntValue]; +} +@end + class AvnInsidePotentialDeadlock { public: diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm index a36170fddc..d1dbe9d186 100644 --- a/native/Avalonia.Native/src/OSX/main.mm +++ b/native/Avalonia.Native/src/OSX/main.mm @@ -276,24 +276,24 @@ public: } } - virtual HRESULT CreateSystemDialogs(IAvnSystemDialogs** ppv) override + virtual HRESULT CreateStorageProvider(IAvnStorageProvider** ppv) override { START_COM_CALL; @autoreleasepool { - *ppv = ::CreateSystemDialogs(); + *ppv = ::CreateStorageProvider(); return S_OK; } } - virtual HRESULT CreateScreens (IAvnScreens** ppv) override + virtual HRESULT CreateScreens (IAvnScreenEvents* cb, IAvnScreens** ppv) override { START_COM_CALL; @autoreleasepool { - *ppv = ::CreateScreens (); + *ppv = ::CreateScreens (cb); return S_OK; } } diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index 7a7edcb1cb..1235979cb2 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -1,4 +1,5 @@ + #include "common.h" #include "menu.h" #include "KeyTransform.h" diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index 2dfdf52209..863dfd8f5e 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -19,6 +19,7 @@ using static Nuke.Common.Tools.Xunit.XunitTasks; using static Nuke.Common.Tools.VSWhere.VSWhereTasks; using static Serilog.Log; using MicroCom.CodeGenerator; +using NuGet.Configuration; using Nuke.Common.IO; /* @@ -369,6 +370,9 @@ partial class Build : NukeBuild { if (!Parameters.IsPackingToLocalCache) throw new InvalidOperationException(); + + var globalPackagesFolder = SettingsUtility.GetGlobalPackagesFolder( + Settings.LoadDefaultSettings(RootDirectory)); foreach (var path in Parameters.NugetRoot.GlobFiles("*.nupkg")) { @@ -379,11 +383,11 @@ partial class Build : NukeBuild .Elements().First(x => x.Name.LocalName == "metadata") .Elements().First(x => x.Name.LocalName == "id").Value; - var packagePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), - ".nuget", - "packages", + var packagePath = Path.Combine( + globalPackagesFolder, packageId.ToLowerInvariant(), BuildParameters.LocalBuildVersion); + if (Directory.Exists(packagePath)) Directory.Delete(packagePath, true); Directory.CreateDirectory(packagePath); diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs index d664d74d2a..50f4f1c5da 100644 --- a/nukebuild/BuildParameters.cs +++ b/nukebuild/BuildParameters.cs @@ -116,9 +116,10 @@ public partial class Build IsNuGetRelease = IsMainRepo && IsReleasable && IsReleaseBranch; // VERSION - Version = b.ForceNugetVersion ?? GetVersion(); + var (propsVersion, propsApiCompatVersion) = GetVersion(); + Version = b.ForceNugetVersion ?? propsVersion; - ApiValidationBaseline = b.ApiValidationBaseline ?? new Version(new Version(Version.Split('-', StringSplitOptions.None).First()).Major, 0).ToString(); + ApiValidationBaseline = b.ApiValidationBaseline ?? propsApiCompatVersion; UpdateApiValidationSuppression = b.UpdateApiValidationSuppression ?? IsLocalBuild; if (IsRunningOnAzure) @@ -153,10 +154,13 @@ public partial class Build VersionOutputDir = b.VersionOutputDir; } - string GetVersion() + (string Version, string ApiCompatVersion) GetVersion() { var xdoc = XDocument.Load(RootDirectory / "build/SharedVersion.props"); - return xdoc.Descendants().First(x => x.Name.LocalName == "Version").Value; + return ( + xdoc.Descendants().First(x => x.Name.LocalName == "Version").Value, + xdoc.Descendants().First(x => x.Name.LocalName == "ApiCompatVersion").Value + ); } } diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets index 05984271b2..9d68af031f 100644 --- a/packages/Avalonia/AvaloniaBuildTasks.targets +++ b/packages/Avalonia/AvaloniaBuildTasks.targets @@ -135,6 +135,14 @@ Outputs="@(CompileAvaloniaXamlOutputs)" Condition="'@(AvaloniaResource)@(AvaloniaXaml)' != '' AND $(DesignTimeBuild) != true AND $(EnableAvaloniaXamlCompilation) != false"> + + + - - - - - $(IntermediateOutputPath)/Avalonia/references - - - diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs index dcc2066149..c54b616b17 100644 --- a/samples/ControlCatalog.Android/MainActivity.cs +++ b/samples/ControlCatalog.Android/MainActivity.cs @@ -1,5 +1,6 @@ using Android.App; using Android.Content.PM; +using Android.OS; using Avalonia; using Avalonia.Android; using static Android.Content.Intent; @@ -10,10 +11,9 @@ using static Android.Content.Intent; namespace ControlCatalog.Android { - [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, Exported = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] - // CategoryBrowsable and DataScheme are required for Protocol activation. + [Activity(Name = "com.Avalonia.ControlCatalog.MainActivity", Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, Exported = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] // CategoryLeanbackLauncher is required for Android TV. - [IntentFilter(new [] { ActionView }, Categories = new [] { CategoryDefault, CategoryBrowsable, CategoryLeanbackLauncher }, DataScheme = "avln" )] + [IntentFilter(new [] { ActionView }, Categories = new [] { CategoryDefault, CategoryLeanbackLauncher })] public class MainActivity : AvaloniaMainActivity { protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) @@ -25,4 +25,19 @@ namespace ControlCatalog.Android }); } } + + /// + /// Special activity to handle OpenUri activation. + /// `AvaloniaActivity` internally will redirect parameters to the Avalonia Application. + /// + [Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true, Theme = "@android:style/Theme.NoDisplay")] + [IntentFilter(new[] {ActionView}, Categories = new[] {CategoryDefault, CategoryBrowsable}, DataScheme = "avln")] + public class DataSchemeActivity : AvaloniaActivity + { + protected override void OnCreate(Bundle? savedInstanceState) + { + base.OnCreate(savedInstanceState); + Finish(); + } + } } diff --git a/samples/ControlCatalog.Browser/wwwroot/Logo.svg b/samples/ControlCatalog.Browser/wwwroot/Logo.svg deleted file mode 100644 index 3e18ea1958..0000000000 --- a/samples/ControlCatalog.Browser/wwwroot/Logo.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/samples/ControlCatalog.Browser/wwwroot/app.css b/samples/ControlCatalog.Browser/wwwroot/app.css index 77f2051221..f27738d8ea 100644 --- a/samples/ControlCatalog.Browser/wwwroot/app.css +++ b/samples/ControlCatalog.Browser/wwwroot/app.css @@ -3,8 +3,8 @@ position: absolute; height: 100%; width: 100%; - background: #1b2a4e; - font-family: 'Nunito', sans-serif; + background: white; + font-family: 'Outfit', sans-serif; justify-content: center; align-items: center; display: flex; @@ -12,23 +12,14 @@ } .avalonia-splash h2 { + font-weight: 400; font-size: 1.5rem; - color: #8b44ac; } .avalonia-splash a { - color: white; text-decoration: none; font-size: 2.5rem; - display: block; -} - -.avalonia-splash img { - opacity: 0.05; - height: 35%; - position: absolute; - right: 3%; - bottom: 3%; + display: block; } .avalonia-splash.splash-close { @@ -36,3 +27,32 @@ display: none; opacity: 0; } + +/* Light theme styles */ +@media (prefers-color-scheme: light) { + .avalonia-splash { + background: white; + } + + .avalonia-splash h2 { + color: #1b2a4e; + } + + .avalonia-splash a { + color: #0D6EFD; + } +} + +@media (prefers-color-scheme: dark) { + .avalonia-splash { + background: #1b2a4e; + } + + .avalonia-splash h2 { + color: white; + } + + .avalonia-splash a { + color: white; + } +} diff --git a/samples/ControlCatalog.Browser/wwwroot/index.html b/samples/ControlCatalog.Browser/wwwroot/index.html index d8bf05fe3c..4a1e12bbc1 100644 --- a/samples/ControlCatalog.Browser/wwwroot/index.html +++ b/samples/ControlCatalog.Browser/wwwroot/index.html @@ -15,9 +15,21 @@ diff --git a/samples/ControlCatalog.Browser/wwwroot/main.js b/samples/ControlCatalog.Browser/wwwroot/main.js index 35c8245b01..ebc62e74d7 100644 --- a/samples/ControlCatalog.Browser/wwwroot/main.js +++ b/samples/ControlCatalog.Browser/wwwroot/main.js @@ -1,15 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - import { dotnet } from './_framework/dotnet.js' const is_browser = typeof window != "undefined"; if (!is_browser) throw new Error(`Expected to be running in a browser`); const dotnetRuntime = await dotnet + .withDiagnosticTracing(false) .withApplicationArgumentsFromQuery() .create(); -const config = dotnetRuntime.getConfig(); - -await dotnetRuntime.runMain(config.mainAssemblyName, [globalThis.location.href]); +await dotnet.run(); diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 5e47f36c0b..6246c73ce2 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -196,6 +196,9 @@ + + + diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs index 31fa54a23a..89bccb4475 100644 --- a/samples/ControlCatalog/MainView.xaml.cs +++ b/samples/ControlCatalog/MainView.xaml.cs @@ -25,16 +25,6 @@ namespace ControlCatalog var sideBar = this.Get("Sidebar"); - if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime) - { - var tabItems = (sideBar.Items as IList); - tabItems?.Add(new TabItem() - { - Header = "Screens", - Content = new ScreenPage() - }); - } - var themes = this.Get("Themes"); themes.SelectedItem = App.CurrentTheme; themes.SelectionChanged += (sender, e) => diff --git a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml index fc3ad9b895..7a1bfaa824 100644 --- a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml +++ b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml @@ -77,6 +77,23 @@ + A TimePicker with seconds enabled. + + + + + + + + + <TimePicker UseSeconds="True" /> + + + + + + @@ -85,8 +102,8 @@ - - A TimePicker with minute increments specified. + + A TimePicker with minute increment specified. @@ -96,7 +113,24 @@ - <TimePicker MinuteIncrement="15" /> + <TimePicker MinuteIncrement="15" SecondIncrement="30" /> + + + + + + + A TimePicker with seconds enabled and minute & second increments specified. + + + + + + + + + <TimePicker UseSeconds="True" MinuteIncrement="15" SecondIncrement="30" /> @@ -137,6 +171,40 @@ + A TimePicker using a 12-hour clock and seconds. + + + + + + + + + <TimePicker ClockIdentifier="12HourClock" UseSeconds="True" /> + + + + + + + A TimePicker using a 24-hour clock and seconds. + + + + + + + + + <TimePicker ClockIdentifier="24HourClock" UseSeconds="True" /> + + + + + + diff --git a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs index 7520dabf37..5c7ccc151b 100644 --- a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs @@ -15,7 +15,7 @@ namespace ControlCatalog.Pages "Order of month, day, and year is dynamically set based on user date settings"; this.Get("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " + - "to set a reminder. The TimePicker displays three controls for hour, minute, and AM / PM(if necessary).These controls " + + "to set a reminder. The TimePicker displays four controls for hour, minute, seconds(optional), and AM / PM(if necessary).These controls " + "are easy to use with touch or mouse, and they can be styled and configured in several different ways. " + "12 - hour or 24 - hour clock and visibility of AM / PM is dynamically set based on user time settings, or can be overridden."; diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index fc66f533c6..5b7814fb5d 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -254,17 +254,24 @@ namespace ControlCatalog.Pages if (file is not null) { - // Sync disposal of StreamWriter is not supported on WASM + try + { + // Sync disposal of StreamWriter is not supported on WASM #if NET6_0_OR_GREATER - await using var stream = await file.OpenWriteAsync(); - await using var writer = new System.IO.StreamWriter(stream); + await using var stream = await file.OpenWriteAsync(); + await using var writer = new System.IO.StreamWriter(stream); #else - using var stream = await file.OpenWriteAsync(); - using var writer = new System.IO.StreamWriter(stream); + using var stream = await file.OpenWriteAsync(); + using var writer = new System.IO.StreamWriter(stream); #endif - await writer.WriteLineAsync(openedFileContent.Text); + await writer.WriteLineAsync(openedFileContent.Text); - SetFolder(await file.GetParentAsync()); + SetFolder(await file.GetParentAsync()); + } + catch (Exception ex) + { + openedFileContent.Text = ex.ToString(); + } } await SetPickerResult(file is null ? null : new[] { file }); @@ -280,8 +287,6 @@ namespace ControlCatalog.Pages }); await SetPickerResult(folders); - - SetFolder(folders.FirstOrDefault()); }; this.Get + + + + + + Tray Icon Clicked + Tray Icon Menu Clicked + + @@ -177,7 +213,20 @@ - + + + + + + + + + + + diff --git a/samples/IntegrationTestApp/TopmostWindowTest.axaml.cs b/samples/IntegrationTestApp/TopmostWindowTest.axaml.cs new file mode 100644 index 0000000000..4bdfe0a65c --- /dev/null +++ b/samples/IntegrationTestApp/TopmostWindowTest.axaml.cs @@ -0,0 +1,21 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; + +namespace IntegrationTestApp; + +public partial class TopmostWindowTest : Window +{ + public TopmostWindowTest(string name) + { + Name = name; + InitializeComponent(); + PositionChanged += (s, e) => CurrentPosition.Text = $"{Position}"; + } + + private void Button_OnClick(object? sender, RoutedEventArgs e) + { + Position += new PixelPoint(100, 100); + } +} diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs index 4e7917494b..7117595787 100644 --- a/src/Android/Avalonia.Android/AvaloniaActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs @@ -8,6 +8,8 @@ using Android.OS; using Android.Runtime; using Android.Views; using AndroidX.AppCompat.App; +using Avalonia.Platform; +using Avalonia.Android.Platform; using Avalonia.Android.Platform.Storage; using Avalonia.Controls.ApplicationLifetimes; @@ -22,6 +24,7 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity private EventHandler? _onActivated, _onDeactivated; private GlobalLayoutListener? _listener; private object? _content; + private bool _contentViewSet; internal AvaloniaView? _view; public Action? ActivityResult { get; set; } @@ -39,6 +42,17 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity _content = value; if (_view is not null) { + if (!_contentViewSet) + { + _contentViewSet = true; + + SetContentView(_view); + + _listener = new GlobalLayoutListener(_view); + + _view.ViewTreeObserver?.AddOnGlobalLayoutListener(_listener); + } + _view.Content = _content; } } @@ -76,14 +90,13 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity base.OnCreate(savedInstanceState); - SetContentView(_view); - - _listener = new GlobalLayoutListener(_view); - - _view.ViewTreeObserver?.AddOnGlobalLayoutListener(_listener); + if (Avalonia.Application.Current?.TryGetFeature() + is AndroidActivatableLifetime activatableLifetime) + { + activatableLifetime.CurrentIntendActivity = this; + } - // TODO: we probably don't need to create AvaloniaView, if it's just a protocol activation, and main activity is already created. - if (Intent?.Data is {} androidUri + if (Intent?.Data is { } androidUri && androidUri.IsAbsolute && Uri.TryCreate(androidUri.ToString(), UriKind.Absolute, out var uri)) { @@ -131,8 +144,11 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity { if (_view is not null) { + if (_listener is not null) + { + _view.ViewTreeObserver?.RemoveOnGlobalLayoutListener(_listener); + } _view.Content = null; - _view.ViewTreeObserver?.RemoveOnGlobalLayoutListener(_listener); _view.Dispose(); _view = null; } diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs index 5ecbee0414..639082ed02 100644 --- a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs @@ -10,18 +10,6 @@ public class AvaloniaMainActivity : AvaloniaActivity { private protected static SingleViewLifetime? Lifetime; - public override void OnCreate(Bundle? savedInstanceState, PersistableBundle? persistentState) - { - // Global IActivatableLifetime expects a main activity, so we need to replace it on each OnCreate. - if (Avalonia.Application.Current?.TryGetFeature() - is AndroidActivatableLifetime activatableLifetime) - { - activatableLifetime.Activity = this; - } - - base.OnCreate(savedInstanceState, persistentState); - } - private protected override void InitializeAvaloniaView(object? initialContent) { // Android can run OnCreate + InitializeAvaloniaView multiple times per process lifetime. @@ -55,6 +43,12 @@ public class AvaloniaMainActivity : AvaloniaActivity if (_view is null) throw new InvalidOperationException("Unknown error: AvaloniaView initialization has failed."); } + + if (Avalonia.Application.Current?.TryGetFeature() + is AndroidActivatableLifetime activatableLifetime) + { + activatableLifetime.CurrentMainActivity = this; + } } protected virtual AppBuilder CreateAppBuilder() => AppBuilder.Configure().UseAndroid(); diff --git a/src/Android/Avalonia.Android/Platform/AndroidActivatableLifetime.cs b/src/Android/Avalonia.Android/Platform/AndroidActivatableLifetime.cs index a09c0ea88a..9679d39d5e 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidActivatableLifetime.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidActivatableLifetime.cs @@ -5,32 +5,71 @@ namespace Avalonia.Android.Platform; internal class AndroidActivatableLifetime : ActivatableLifetimeBase { - private IAvaloniaActivity? _activity; + private IAvaloniaActivity? _mainActivity, _intendActivity; - public IAvaloniaActivity? Activity + /// + /// While we primarily handle main activity lifecycle events. + /// Any secondary activity might send protocol or file activation. + /// + public IAvaloniaActivity? CurrentIntendActivity { - get => _activity; + get => _intendActivity; set { - if (_activity is not null) + if (_intendActivity is not null) { - _activity.Activated -= ActivityOnActivated; - _activity.Deactivated -= ActivityOnDeactivated; + _intendActivity.Activated -= IntendActivityOnActivated; } - _activity = value; + _intendActivity = value; - if (_activity is not null) + if (_intendActivity is not null) { - _activity.Activated += ActivityOnActivated; - _activity.Deactivated += ActivityOnDeactivated; + _intendActivity.Activated += IntendActivityOnActivated; + } + } + } + + public IAvaloniaActivity? CurrentMainActivity + { + get => _mainActivity; + set + { + if (_mainActivity is not null) + { + _mainActivity.Activated -= MainActivityOnActivated; + _mainActivity.Deactivated -= MainActivityOnDeactivated; + } + + _mainActivity = value; + + if (_mainActivity is not null) + { + _mainActivity.Activated += MainActivityOnActivated; + _mainActivity.Deactivated += MainActivityOnDeactivated; } } } - public override bool TryEnterBackground() => (_activity as Activity)?.MoveTaskToBack(true) == true; + public override bool TryEnterBackground() => (_mainActivity as Activity)?.MoveTaskToBack(true) == true; - private void ActivityOnDeactivated(object? sender, ActivatedEventArgs e) => OnDeactivated(e); + private void MainActivityOnDeactivated(object? sender, ActivatedEventArgs e) => OnDeactivated(e); + + private void MainActivityOnActivated(object? sender, ActivatedEventArgs e) + { + if (!IsIntendActivation(e.Kind)) + { + OnActivated(e); + } + } + + private void IntendActivityOnActivated(object? sender, ActivatedEventArgs e) + { + if (IsIntendActivation(e.Kind)) + { + OnActivated(e); + } + } - private void ActivityOnActivated(object? sender, ActivatedEventArgs e) => OnActivated(e); + private static bool IsIntendActivation(ActivationKind kind) => kind is ActivationKind.File or ActivationKind.OpenUri; } diff --git a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs index 18cad0aebf..992d37ed18 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs @@ -4,6 +4,7 @@ using Android.App; using Android.OS; using Android.Views; using Android.Views.Animations; +using AndroidX.Core.Graphics; using AndroidX.Core.View; using Avalonia.Android.Platform.SkiaPlatform; using Avalonia.Animation.Easings; @@ -25,6 +26,7 @@ namespace Avalonia.Android.Platform private Color? _systemBarColor; private InputPaneState _state; private Rect _previousRect; + private Insets? _previousImeInset; private readonly bool _usesLegacyLayouts; private AndroidWindow Window => _activity.Window ?? throw new InvalidOperationException("Activity.Window must be set."); @@ -148,6 +150,19 @@ namespace Avalonia.Android.Platform State = insets.IsVisible(WindowInsetsCompat.Type.Ime()) ? InputPaneState.Open : InputPaneState.Closed; + // Workaround for weird inset values for android 11 + if(Build.VERSION.SdkInt == BuildVersionCodes.R) + { + var imeInset = insets.GetInsets(WindowInsetsCompat.Type.Ime()); + if(_previousImeInset == default) + _previousImeInset = imeInset; + if(imeInset.Bottom != _previousImeInset.Bottom) + { + NotifyStateChanged(State, _previousRect, OccludedRect, TimeSpan.Zero, null); + } + _previousImeInset = imeInset; + } + return insets; } @@ -191,11 +206,6 @@ namespace Avalonia.Android.Platform { _statusBarTheme = value; - if (!_topLevel.View.IsShown) - { - return; - } - var compat = new WindowInsetsControllerCompat(Window, _topLevel.View); if (_isDefaultSystemBarLightTheme == null) @@ -229,11 +239,6 @@ namespace Avalonia.Android.Platform { _systemUiVisibility = value; - if (!_topLevel.View.IsShown) - { - return; - } - var compat = WindowCompat.GetInsetsController(Window, _topLevel.View); if (value == null || value.Value) diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 83a43d883f..79052bf9bd 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -101,7 +101,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform internal InvalidationAwareSurfaceView InternalView => _view; public double DesktopScaling => RenderScaling; - public IScreenImpl? Screen { get; } public IPlatformHandle Handle => _view; public IEnumerable Surfaces { get; } diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs index 952717729f..bb27379a70 100644 --- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs +++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs @@ -10,6 +10,7 @@ using Android.Provider; using Android.Webkit; using Avalonia.Logging; using Avalonia.Platform.Storage; +using Avalonia.Platform.Storage.FileIO; using Java.Lang; using AndroidUri = Android.Net.Uri; using Exception = System.Exception; @@ -53,7 +54,8 @@ internal abstract class AndroidStorageItem : IStorageBookmarkItem } Activity.ContentResolver?.TakePersistableUriPermission(Uri, ActivityFlags.GrantWriteUriPermission | ActivityFlags.GrantReadUriPermission); - return Uri.ToString(); + + return StorageBookmarkHelper.EncodeBookmark(AndroidStorageProvider.AndroidKey, Uri.ToString()!); } public async Task ReleaseBookmarkAsync() diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs index 64c9c3a3cb..54d6afad43 100644 --- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs +++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading.Tasks; using Android; using Android.App; using Android.Content; using Android.Provider; using Avalonia.Platform.Storage; +using Avalonia.Platform.Storage.FileIO; using AndroidUri = Android.Net.Uri; using Exception = System.Exception; using JavaFile = Java.IO.File; @@ -15,6 +17,7 @@ namespace Avalonia.Android.Platform.Storage; internal class AndroidStorageProvider : IStorageProvider { + public static ReadOnlySpan AndroidKey => "android"u8; private readonly Activity _activity; public AndroidStorageProvider(Activity activity) @@ -30,8 +33,8 @@ internal class AndroidStorageProvider : IStorageProvider public Task OpenFolderBookmarkAsync(string bookmark) { - var uri = AndroidUri.Parse(bookmark) ?? throw new ArgumentException("Couldn't parse Bookmark value", nameof(bookmark)); - return Task.FromResult(new AndroidStorageFolder(_activity, uri, false)); + var uri = DecodeUriFromBookmark(bookmark); + return Task.FromResult(uri is null ? null : new AndroidStorageFolder(_activity, uri, false)); } public async Task TryGetFileFromPathAsync(Uri filePath) @@ -129,8 +132,19 @@ internal class AndroidStorageProvider : IStorageProvider public Task OpenFileBookmarkAsync(string bookmark) { - var uri = AndroidUri.Parse(bookmark) ?? throw new ArgumentException("Couldn't parse Bookmark value", nameof(bookmark)); - return Task.FromResult(new AndroidStorageFile(_activity, uri)); + var uri = DecodeUriFromBookmark(bookmark); + return Task.FromResult(uri is null ? null : new AndroidStorageFile(_activity, uri)); + } + + private static AndroidUri? DecodeUriFromBookmark(string bookmark) + { + return StorageBookmarkHelper.TryDecodeBookmark(AndroidKey, bookmark, out var bytes) switch + { + StorageBookmarkHelper.DecodeResult.Success => AndroidUri.Parse(Encoding.UTF8.GetString(bytes!)), + // Attempt to decode 11.0 android bookmarks + StorageBookmarkHelper.DecodeResult.InvalidFormat => AndroidUri.Parse(bookmark), + _ => null + }; } public async Task> OpenFilePickerAsync(FilePickerOpenOptions options) diff --git a/src/Android/Avalonia.Android/SingleViewLifetime.cs b/src/Android/Avalonia.Android/SingleViewLifetime.cs index e71f4e0333..b5dbf38c64 100644 --- a/src/Android/Avalonia.Android/SingleViewLifetime.cs +++ b/src/Android/Avalonia.Android/SingleViewLifetime.cs @@ -10,7 +10,7 @@ internal class SingleViewLifetime : ISingleViewApplicationLifetime, ISingleTopLe private AvaloniaMainActivity? _activity; /// - /// Since Main Activity can be swapped, we should adjust litetime as well. + /// Since Main Activity can be swapped, we should adjust lifetime as well. /// public AvaloniaMainActivity Activity { diff --git a/src/Avalonia.Base/ApiCompatBaseline.txt b/src/Avalonia.Base/ApiCompatBaseline.txt deleted file mode 100644 index 7f378d2f65..0000000000 --- a/src/Avalonia.Base/ApiCompatBaseline.txt +++ /dev/null @@ -1,4 +0,0 @@ -Compat issues with assembly Avalonia.Base: -MembersMustExist : Member 'public System.Int32 System.Int32 Avalonia.Threading.DispatcherPriority.value__' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Threading.IDispatcher.Post(System.Action, T, Avalonia.Threading.DispatcherPriority)' is present in the implementation but not in the contract. -Total Issues: 2 diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index 37457ad7c3..853d585232 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -818,11 +818,9 @@ namespace Avalonia var fallback = value.HasValue ? value : value.WithValue(property.GetUnsetValue(this)); property.InvokeSetter(this, fallback); break; - case BindingValueType.DataValidationError: - property.InvokeSetter(this, value); - break; case BindingValueType.Value: case BindingValueType.BindingErrorWithFallback: + case BindingValueType.DataValidationError: case BindingValueType.DataValidationErrorWithFallback: property.InvokeSetter(this, value); break; diff --git a/src/Avalonia.Base/Data/BindingNotification.cs b/src/Avalonia.Base/Data/BindingNotification.cs index a3a2e0c2b0..39ef4374aa 100644 --- a/src/Avalonia.Base/Data/BindingNotification.cs +++ b/src/Avalonia.Base/Data/BindingNotification.cs @@ -178,7 +178,7 @@ namespace Avalonia.Data /// to . If is a /// then the value will first be extracted. /// - public static object? UpdateValue(object o, object value) + public static object? UpdateValue(object? o, object value) { if (o is BindingNotification n) { diff --git a/src/Avalonia.Base/Data/BindingOperations.cs b/src/Avalonia.Base/Data/BindingOperations.cs index 9170fbfaa0..b0a97e5c00 100644 --- a/src/Avalonia.Base/Data/BindingOperations.cs +++ b/src/Avalonia.Base/Data/BindingOperations.cs @@ -101,6 +101,25 @@ namespace Avalonia.Data return Apply(target, property, binding); } + /// + /// Retrieves the that is currently active on the + /// specified property. + /// + /// + /// The from which to retrieve the binding expression. + /// + /// + /// The binding target property from which to retrieve the binding expression. + /// + /// + /// The object that is active on the given property or + /// null if no binding expression is active on the given property. + /// + public static BindingExpressionBase? GetBindingExpressionBase(AvaloniaObject target, AvaloniaProperty property) + { + return target.GetValueStore().GetExpression(property); + } + private sealed class TwoWayBindingDisposable : IDisposable { private readonly IDisposable _toTargetSubscription; diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index 6d2872fc82..1765cd5d78 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -459,7 +459,7 @@ namespace Avalonia.Data { if (value is UnsetValueType) { - throw new InvalidOperationException("AvaloniaValue.UnsetValue is not a valid value for BindingValue<>."); + throw new InvalidOperationException("AvaloniaProperty.UnsetValue is not a valid value for BindingValue<>."); } if (value is DoNothingType) diff --git a/src/Avalonia.Base/Data/Core/BindingExpression.cs b/src/Avalonia.Base/Data/Core/BindingExpression.cs index c98650fa8e..ba0ce7bb9e 100644 --- a/src/Avalonia.Base/Data/Core/BindingExpression.cs +++ b/src/Avalonia.Base/Data/Core/BindingExpression.cs @@ -160,7 +160,7 @@ internal partial class BindingExpression : UntypedBindingExpressionBase, IDescri var source = _nodes[0].Source; for (var i = 0; i < _nodes.Count; ++i) - _nodes[i].SetSource(null, null); + _nodes[i].SetSource(AvaloniaProperty.UnsetValue, null); _nodes[0].SetSource(source, null); } @@ -253,10 +253,6 @@ internal partial class BindingExpression : UntypedBindingExpressionBase, IDescri _nodes[nodeIndex + 1].SetSource(value, dataValidationError); WriteTargetValueToSource(); } - else if (value is null) - { - OnNodeError(nodeIndex, "Value is null."); - } else { _nodes[nodeIndex + 1].SetSource(value, dataValidationError); @@ -273,11 +269,11 @@ internal partial class BindingExpression : UntypedBindingExpressionBase, IDescri /// The error message. internal void OnNodeError(int nodeIndex, string error) { - // Set the source of all nodes after the one that errored to null. This needs to be done - // for each node individually because setting the source to null will not result in + // Set the source of all nodes after the one that errored to unset. This needs to be done + // for each node individually because setting the source to unset will not result in // OnNodeValueChanged or OnNodeError being called. for (var i = nodeIndex + 1; i < _nodes.Count; ++i) - _nodes[i].SetSource(null, null); + _nodes[i].SetSource(AvaloniaProperty.UnsetValue, null); if (_mode == BindingMode.OneWayToSource) return; @@ -394,7 +390,7 @@ internal partial class BindingExpression : UntypedBindingExpressionBase, IDescri protected override void StopCore() { foreach (var node in _nodes) - node.Reset(); + node.SetSource(AvaloniaProperty.UnsetValue, null); if (_mode is BindingMode.TwoWay or BindingMode.OneWayToSource && TryGetTarget(out var target)) diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/ArrayIndexerNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/ArrayIndexerNode.cs index a347a1ab72..514cf235ff 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/ArrayIndexerNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/ArrayIndexerNode.cs @@ -44,8 +44,11 @@ internal sealed class ArrayIndexerNode : ExpressionNode, ISettableNode return false; } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + if (source is Array array) SetValue(array.GetValue(_indexes)); else diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/AvaloniaPropertyAccessorNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/AvaloniaPropertyAccessorNode.cs index 09f4c9be26..266fbb884a 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/AvaloniaPropertyAccessorNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/AvaloniaPropertyAccessorNode.cs @@ -38,6 +38,9 @@ internal sealed class AvaloniaPropertyAccessorNode : protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + if (source is AvaloniaObject newObject) { WeakEvents.AvaloniaPropertyChanged.Subscribe(newObject, this); diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/CollectionNodeBase.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/CollectionNodeBase.cs index db8a8e8080..1c9c7d0294 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/CollectionNodeBase.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/CollectionNodeBase.cs @@ -22,8 +22,11 @@ internal abstract class CollectionNodeBase : ExpressionNode, UpdateValueOrSetError(sender); } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + Subscribe(source); UpdateValue(source); } diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/DataContextNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/DataContextNode.cs index 14e21d4192..2aa14f12a2 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/DataContextNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/DataContextNode.cs @@ -4,8 +4,11 @@ namespace Avalonia.Data.Core.ExpressionNodes; internal sealed class DataContextNode : DataContextNodeBase { - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + if (source is IDataContextProvider && source is AvaloniaObject ao) { ao.PropertyChanged += OnPropertyChanged; diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs index 8b53190f86..7a8ab69e6b 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text; @@ -60,16 +61,6 @@ internal abstract class ExpressionNode BuildString(builder); } - /// - /// Resets the node to its uninitialized state when the is unsubscribed. - /// - public void Reset() - { - SetSource(null, null); - _source = null; - _value = AvaloniaProperty.UnsetValue; - } - /// /// Sets the owner binding. /// @@ -101,28 +92,26 @@ internal abstract class ExpressionNode /// public void SetSource(object? source, Exception? dataValidationError) { - var oldSource = Source; - - if (source == AvaloniaProperty.UnsetValue) - source = null; + if (_source?.TryGetTarget(out var oldSource) != true) + oldSource = AvaloniaProperty.UnsetValue; if (source == oldSource) return; - if (oldSource is not null) + if (oldSource is not null && oldSource != AvaloniaProperty.UnsetValue) Unsubscribe(oldSource); - _source = new(source); - - if (source is null) + if (source == AvaloniaProperty.UnsetValue) { - // If the source is null then the value is null. We explicitly do not want to call + // If the source is unset then the value is unset. We explicitly do not want to call // OnSourceChanged as we don't want to raise errors for subsequent nodes in the // binding change. + _source = null; _value = AvaloniaProperty.UnsetValue; } else { + _source = new(source); try { OnSourceChanged(source, dataValidationError); } catch (Exception e) { SetError(e); } } @@ -222,24 +211,28 @@ internal abstract class ExpressionNode protected void SetValue(object? value, Exception? dataValidationError = null) { Debug.Assert(value is not BindingNotification); + _value = value; + Owner?.OnNodeValueChanged(Index, value, dataValidationError); + } - if (Owner is null) - return; - - // We raise a change notification if: - // - // - This is the initial value (_value is null) - // - There is a data validation error - // - There is no data validation error, but the owner has one - // - The new value is different to the old value - if (_value is null || - dataValidationError is not null || - (dataValidationError is null && Owner.ErrorType == BindingErrorType.DataValidationError) || - !Equals(value, _value)) + /// + /// Called from to validate that the source + /// is non-null and raise a node error if it is not. + /// + /// The expression node source. + /// + /// True if the source is non-null; otherwise, false. + /// + protected bool ValidateNonNullSource([NotNullWhen(true)] object? source) + { + if (source is null) { - _value = value; - Owner.OnNodeValueChanged(Index, value, dataValidationError); + Owner?.OnNodeError(Index - 1, "Value is null."); + _value = null; + return false; } + + return true; } /// @@ -250,7 +243,7 @@ internal abstract class ExpressionNode /// /// Any data validation error reported by the previous expression node. /// - protected abstract void OnSourceChanged(object source, Exception? dataValidationError); + protected abstract void OnSourceChanged(object? source, Exception? dataValidationError); /// /// When implemented in a derived class, unsubscribes from the previous source. diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/FuncTransformNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/FuncTransformNode.cs index 7ad0b7ee97..1eb15d2469 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/FuncTransformNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/FuncTransformNode.cs @@ -21,8 +21,11 @@ internal sealed class FuncTransformNode : ExpressionNode // We don't have enough information to add anything here. } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + SetValue(_transform(source)); } } diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/LogicalAncestorElementNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/LogicalAncestorElementNode.cs index ccf6c76f90..b15f285867 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/LogicalAncestorElementNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/LogicalAncestorElementNode.cs @@ -56,8 +56,11 @@ internal sealed class LogicalAncestorElementNode : SourceNode return target is ILogical logical && logical.IsAttachedToLogicalTree; } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + if (source is ILogical logical) { var locator = ControlLocator.Track(logical, _ancestorLevel, _ancestorType); diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/LogicalNotNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/LogicalNotNode.cs index bb65ac16dd..8b1102b463 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/LogicalNotNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/LogicalNotNode.cs @@ -28,14 +28,12 @@ internal sealed class LogicalNotNode : ExpressionNode, ISettableNode return false; } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { var v = BindingNotification.ExtractValue(source); if (TryConvert(v, out var value)) - { SetValue(BindingNotification.UpdateValue(source, !value), dataValidationError); - } else SetError($"Unable to convert '{source}' to bool."); } diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/MethodCommandNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/MethodCommandNode.cs index 76ea564320..e0641f1461 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/MethodCommandNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/MethodCommandNode.cs @@ -39,8 +39,11 @@ internal sealed class MethodCommandNode : ExpressionNode, IWeakEventSubscriber

(source); if (_plugin.Start(reference, PropertyName) is { } accessor) diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginPropertyAccessorNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginPropertyAccessorNode.cs index d1ecc13208..533520d35c 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginPropertyAccessorNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginPropertyAccessorNode.cs @@ -42,8 +42,11 @@ internal sealed class DynamicPluginPropertyAccessorNode : ExpressionNode, IPrope return _accessor?.SetValue(value, BindingPriority.LocalValue) ?? false; } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + var reference = new WeakReference(source); if (GetPlugin(source) is { } plugin && diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs index 70b0f710a2..f6c692e685 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs @@ -16,8 +16,11 @@ internal sealed class DynamicPluginStreamNode : ExpressionNode builder.Append('^'); } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + var reference = new WeakReference(source); if (GetPlugin(reference) is { } plugin && diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ReflectionIndexerNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ReflectionIndexerNode.cs index 52526431dc..abc7d80744 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ReflectionIndexerNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ReflectionIndexerNode.cs @@ -52,8 +52,11 @@ internal sealed class ReflectionIndexerNode : CollectionNodeBase, ISettableNode return true; } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + _indexes = null; if (GetIndexer(source.GetType(), out _getter, out _setter)) diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ReflectionTypeCastNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ReflectionTypeCastNode.cs index c973d9d236..8b356603a6 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ReflectionTypeCastNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ReflectionTypeCastNode.cs @@ -19,8 +19,11 @@ internal sealed class ReflectionTypeCastNode : ExpressionNode builder.Append(')'); } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + if (_targetType.IsInstanceOfType(source)) SetValue(source); else diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/StreamNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/StreamNode.cs index 19e5a58828..32ccc9e214 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/StreamNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/StreamNode.cs @@ -23,8 +23,11 @@ internal sealed class StreamNode : ExpressionNode, IObserver void IObserver.OnError(Exception error) { } void IObserver.OnNext(object? value) => SetValue(value); - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + if (_plugin.Start(new(source)) is { } accessor) { _subscription = accessor.Subscribe(this); diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/TemplatedParentNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/TemplatedParentNode.cs index 6e81a01cee..3dca520fa7 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/TemplatedParentNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/TemplatedParentNode.cs @@ -22,8 +22,11 @@ internal sealed class TemplatedParentNode : SourceNode throw new InvalidOperationException("Cannot find a StyledElement to get a TemplatedParent."); } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + if (source is StyledElement newElement) { newElement.PropertyChanged += OnPropertyChanged; diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/VisualAncestorElementNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/VisualAncestorElementNode.cs index 4bca2c8cb4..4cf27d8968 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/VisualAncestorElementNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/VisualAncestorElementNode.cs @@ -56,8 +56,11 @@ internal sealed class VisualAncestorElementNode : SourceNode return target is Visual visual && visual.IsAttachedToVisualTree; } - protected override void OnSourceChanged(object source, Exception? dataValidationError) + protected override void OnSourceChanged(object? source, Exception? dataValidationError) { + if (!ValidateNonNullSource(source)) + return; + if (source is Visual visual) { var locator = VisualLocator.Track(visual, _ancestorLevel, _ancestorType); diff --git a/src/Avalonia.Base/Data/Core/UntypedObservableBindingExpression.cs b/src/Avalonia.Base/Data/Core/UntypedObservableBindingExpression.cs index 1e26caa051..df529d8675 100644 --- a/src/Avalonia.Base/Data/Core/UntypedObservableBindingExpression.cs +++ b/src/Avalonia.Base/Data/Core/UntypedObservableBindingExpression.cs @@ -30,5 +30,18 @@ internal class UntypedObservableBindingExpression : UntypedBindingExpressionBase void IObserver.OnCompleted() { } void IObserver.OnError(Exception error) { } - void IObserver.OnNext(object? value) => PublishValue(value); + + void IObserver.OnNext(object? value) + { + if (value is BindingNotification n) + { + var v = n.Value; + var e = n.Error is not null ? new BindingError(n.Error, n.ErrorType) : null; + PublishValue(v, e); + } + else + { + PublishValue(value); + } + } } diff --git a/src/Avalonia.Base/Data/TemplateBinding.cs b/src/Avalonia.Base/Data/TemplateBinding.cs index db878620b4..fd3c0f5b62 100644 --- a/src/Avalonia.Base/Data/TemplateBinding.cs +++ b/src/Avalonia.Base/Data/TemplateBinding.cs @@ -5,6 +5,7 @@ using System.Globalization; using Avalonia.Data.Converters; using Avalonia.Data.Core; using Avalonia.Logging; +using Avalonia.Metadata; using Avalonia.Styling; namespace Avalonia.Data @@ -26,7 +27,7 @@ namespace Avalonia.Data { } - public TemplateBinding(AvaloniaProperty property) + public TemplateBinding([InheritDataTypeFrom(InheritDataTypeFromScopeKind.ControlTemplate)] AvaloniaProperty property) : base(BindingPriority.Template) { Property = property; @@ -64,6 +65,7 @@ namespace Avalonia.Data ///

/// Gets or sets the name of the source property on the templated parent. /// + [InheritDataTypeFrom(InheritDataTypeFromScopeKind.ControlTemplate)] public AvaloniaProperty? Property { get; set; } /// diff --git a/src/Avalonia.Base/Input/MouseDevice.cs b/src/Avalonia.Base/Input/MouseDevice.cs index 9624bd2ef6..fc60551606 100644 --- a/src/Avalonia.Base/Input/MouseDevice.cs +++ b/src/Avalonia.Base/Input/MouseDevice.cs @@ -305,5 +305,10 @@ namespace Avalonia.Input { return _pointer; } + + internal void PlatformCaptureLost() + { + _pointer.Capture(null); + } } } diff --git a/src/Avalonia.Base/Input/TouchDevice.cs b/src/Avalonia.Base/Input/TouchDevice.cs index cc80457226..8e662ea1b9 100644 --- a/src/Avalonia.Base/Input/TouchDevice.cs +++ b/src/Avalonia.Base/Input/TouchDevice.cs @@ -160,5 +160,11 @@ namespace Avalonia.Input ? pointer : null; } + + internal void PlatformCaptureLost() + { + foreach (var pointer in _pointers.Values) + pointer.Capture(null); + } } } diff --git a/src/Avalonia.Base/Media/Fonts/Tables/HorizontalHeadTable.cs b/src/Avalonia.Base/Media/Fonts/Tables/HorizontalHeadTable.cs index 10b831dd1e..0942296536 100644 --- a/src/Avalonia.Base/Media/Fonts/Tables/HorizontalHeadTable.cs +++ b/src/Avalonia.Base/Media/Fonts/Tables/HorizontalHeadTable.cs @@ -59,11 +59,11 @@ namespace Avalonia.Media.Fonts.Tables public short XMaxExtent { get; } - public static HorizontalHeadTable Load(IGlyphTypeface glyphTypeface) + public static HorizontalHeadTable? Load(IGlyphTypeface glyphTypeface) { if (!glyphTypeface.TryGetTable(Tag, out var table)) { - throw new MissingFontTableException("Could not load table", "name"); + return null; } using var stream = new MemoryStream(table); diff --git a/src/Avalonia.Base/Media/Fonts/Tables/Name/NameTable.cs b/src/Avalonia.Base/Media/Fonts/Tables/Name/NameTable.cs index f94482222c..e2a5cbb681 100644 --- a/src/Avalonia.Base/Media/Fonts/Tables/Name/NameTable.cs +++ b/src/Avalonia.Base/Media/Fonts/Tables/Name/NameTable.cs @@ -3,26 +3,24 @@ // Ported from: https://github.com/SixLabors/Fonts/blob/034a440aece357341fcc6b02db58ffbe153e54ef/src/SixLabors.Fonts using System.Collections.Generic; -using System.Globalization; using System.IO; -using System.Linq; namespace Avalonia.Media.Fonts.Tables.Name { internal class NameTable { internal const string TableName = "name"; - internal static OpenTypeTag Tag = OpenTypeTag.Parse(TableName); + internal static readonly OpenTypeTag Tag = OpenTypeTag.Parse(TableName); private readonly NameRecord[] _names; - internal NameTable(NameRecord[] names, IReadOnlyList languages) + internal NameTable(NameRecord[] names, IReadOnlyList languages) { _names = names; Languages = languages; } - public IReadOnlyList Languages { get; } + public IReadOnlyList Languages { get; } /// /// Gets the name of the font. @@ -30,7 +28,7 @@ namespace Avalonia.Media.Fonts.Tables.Name /// /// The name of the font. /// - public string Id(CultureInfo culture) + public string Id(ushort culture) => GetNameById(culture, KnownNameIds.UniqueFontID); /// @@ -39,7 +37,7 @@ namespace Avalonia.Media.Fonts.Tables.Name /// /// The name of the font. /// - public string FontName(CultureInfo culture) + public string FontName(ushort culture) => GetNameById(culture, KnownNameIds.FullFontName); /// @@ -48,7 +46,7 @@ namespace Avalonia.Media.Fonts.Tables.Name /// /// The name of the font. /// - public string FontFamilyName(CultureInfo culture) + public string FontFamilyName(ushort culture) => GetNameById(culture, KnownNameIds.FontFamilyName); /// @@ -57,12 +55,12 @@ namespace Avalonia.Media.Fonts.Tables.Name /// /// The name of the font. /// - public string FontSubFamilyName(CultureInfo culture) + public string FontSubFamilyName(ushort culture) => GetNameById(culture, KnownNameIds.FontSubfamilyName); - public string GetNameById(CultureInfo culture, KnownNameIds nameId) + public string GetNameById(ushort culture, KnownNameIds nameId) { - var languageId = culture.LCID; + var languageId = culture; NameRecord? usaVersion = null; NameRecord? firstWindows = null; NameRecord? first = null; @@ -97,7 +95,7 @@ namespace Avalonia.Media.Fonts.Tables.Name string.Empty; } - public string GetNameById(CultureInfo culture, ushort nameId) + public string GetNameById(ushort culture, ushort nameId) => GetNameById(culture, (KnownNameIds)nameId); public static NameTable Load(IGlyphTypeface glyphTypeface) @@ -160,7 +158,7 @@ namespace Avalonia.Media.Fonts.Tables.Name readable.LoadValue(reader); } - var cultures = new List(); + var cultures = new List(); foreach (var nameRecord in names) { @@ -169,16 +167,12 @@ namespace Avalonia.Media.Fonts.Tables.Name continue; } - var culture = new CultureInfo(nameRecord.LanguageID); - - if (!cultures.Contains(culture)) + if (!cultures.Contains(nameRecord.LanguageID)) { - cultures.Add(culture); + cultures.Add(nameRecord.LanguageID); } } - //var languages = languageNames.Select(x => x.Value).ToArray(); - return new NameTable(names, cultures); } } diff --git a/src/Avalonia.Base/Media/GlyphRun.cs b/src/Avalonia.Base/Media/GlyphRun.cs index 350f3ec028..a81dbdb3f0 100644 --- a/src/Avalonia.Base/Media/GlyphRun.cs +++ b/src/Avalonia.Base/Media/GlyphRun.cs @@ -574,7 +574,10 @@ namespace Avalonia.Media } } - nextCluster = _glyphInfos[currentIndex].GlyphCluster; + if (_glyphInfos.Count > 0 && currentIndex <= _glyphInfos.Count) + { + nextCluster = _glyphInfos[currentIndex].GlyphCluster; + } } var clusterLength = Math.Max(0, nextCluster - cluster); @@ -639,7 +642,7 @@ namespace Avalonia.Media { int firstCluster, lastCluster; - if (Characters.IsEmpty) + if (Characters.IsEmpty || _glyphInfos.Count == 0) { firstCluster = 0; lastCluster = 0; diff --git a/src/Avalonia.Base/Media/IGlyphTypeface2.cs b/src/Avalonia.Base/Media/IGlyphTypeface2.cs index d2e0e4d2dd..2c7ea58bcb 100644 --- a/src/Avalonia.Base/Media/IGlyphTypeface2.cs +++ b/src/Avalonia.Base/Media/IGlyphTypeface2.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Globalization; using System.IO; using Avalonia.Media.Fonts; @@ -17,8 +16,9 @@ namespace Avalonia.Media /// /// Gets the localized family names. + /// Keys are culture identifiers. /// - IReadOnlyDictionary FamilyNames { get; } + IReadOnlyDictionary FamilyNames { get; } /// /// Gets supported font features. diff --git a/src/Avalonia.Base/Media/TextDecoration.cs b/src/Avalonia.Base/Media/TextDecoration.cs index 8661959aa6..beac28da4a 100644 --- a/src/Avalonia.Base/Media/TextDecoration.cs +++ b/src/Avalonia.Base/Media/TextDecoration.cs @@ -182,18 +182,18 @@ namespace Avalonia.Media break; } - var origin = new Point(); + var origin = baselineOrigin; switch (Location) { - case TextDecorationLocation.Baseline: - origin += glyphRun.BaselineOrigin; + case TextDecorationLocation.Overline: + origin += new Point(0, textMetrics.Ascent); break; case TextDecorationLocation.Strikethrough: - origin += new Point(baselineOrigin.X, baselineOrigin.Y + textMetrics.StrikethroughPosition); + origin += new Point(0, textMetrics.StrikethroughPosition); break; case TextDecorationLocation.Underline: - origin += new Point(baselineOrigin.X, baselineOrigin.Y + textMetrics.UnderlinePosition); + origin += new Point(0, textMetrics.UnderlinePosition); break; } @@ -255,7 +255,10 @@ namespace Avalonia.Media } } - drawingContext.DrawLine(pen, origin, origin + new Point(glyphRun.Metrics.Width, 0)); + var p1 = origin; + var p2 = p1 + new Point(glyphRun.Metrics.Width, 0); + + drawingContext.DrawLine(pen, p1, p2); } } } diff --git a/src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs b/src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs index a1dc0827e8..5bb8ad5b95 100644 --- a/src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs +++ b/src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs @@ -64,7 +64,7 @@ namespace Avalonia.Media.TextFormatting if (Properties.BackgroundBrush != null) { - drawingContext.DrawRectangle(Properties.BackgroundBrush, null, GlyphRun.Bounds); + drawingContext.DrawRectangle(Properties.BackgroundBrush, null, GlyphRun.Bounds.Translate(new Vector(0, -Baseline))); } drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun); @@ -204,7 +204,8 @@ namespace Avalonia.Media.TextFormatting ShapedBuffer.FontRenderingEmSize, Text, ShapedBuffer, - biDiLevel: BidiLevel); + biDiLevel: BidiLevel, + baselineOrigin: new Point()); } public void Dispose() diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index 954a9b2deb..154c98ae54 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -115,18 +115,19 @@ namespace Avalonia.Media.TextFormatting switch (baselineAlignment) { + case BaselineAlignment.Baseline: + return textLine.Baseline; case BaselineAlignment.Top: - return 0; + case BaselineAlignment.TextTop: + return textLine.Baseline - textLine.Extent + textRun.Size.Height / 2; case BaselineAlignment.Center: - return textLine.Height / 2 - textRun.Size.Height / 2; + return textLine.Height / 2 + baseline - textRun.Size.Height / 2; + case BaselineAlignment.Subscript: case BaselineAlignment.Bottom: - return textLine.Height - textRun.Size.Height; - case BaselineAlignment.Baseline: - case BaselineAlignment.TextTop: case BaselineAlignment.TextBottom: - case BaselineAlignment.Subscript: + return textLine.Height - textRun.Size.Height + baseline; case BaselineAlignment.Superscript: - return textLine.Baseline - baseline; + return baseline; default: throw new ArgumentOutOfRangeException(nameof(baselineAlignment), baselineAlignment, null); } @@ -731,23 +732,26 @@ namespace Avalonia.Media.TextFormatting } } - if (coveredLength > 0) + if (coveredLength == 0) { - if (lastBounds != null && TryMergeWithLastBounds(currentBounds, lastBounds)) - { - currentBounds = lastBounds; - - result[result.Count - 1] = currentBounds; - } - else - { - result.Add(currentBounds); - } + //This should never happen + break; + } - lastBounds = currentBounds; + if (lastBounds != null && TryMergeWithLastBounds(currentBounds, lastBounds)) + { + currentBounds = lastBounds; - remainingLength -= coveredLength; + result[result.Count - 1] = currentBounds; + } + else + { + result.Add(currentBounds); } + + lastBounds = currentBounds; + + remainingLength -= coveredLength; } result.Sort(TextBoundsComparer); @@ -1017,10 +1021,23 @@ namespace Avalonia.Media.TextFormatting var characterLength = Math.Abs(startHit.FirstCharacterIndex + startHit.TrailingLength - endHit.FirstCharacterIndex - endHit.TrailingLength); - //Make sure we properly deal with zero width space runs - if (characterLength == 0 && currentRun.Length > 0 && currentRun.GlyphRun.Metrics.WidthIncludingTrailingWhitespace == 0) + if (characterLength == 0 && currentRun.Text.Length > 0 && startIndex < currentRun.Text.Length) { - characterLength = currentRun.Length; + //Make sure we are properly dealing with zero width space runs + var codepointEnumerator = new CodepointEnumerator(currentRun.Text.Span.Slice(startIndex)); + + while (remainingLength > 0 && codepointEnumerator.MoveNext(out var codepoint)) + { + if (codepoint.IsWhiteSpace) + { + characterLength++; + remainingLength--; + } + else + { + break; + } + } } if (endX < startX) @@ -1073,13 +1090,26 @@ namespace Avalonia.Media.TextFormatting var characterLength = Math.Abs(startHit.FirstCharacterIndex + startHit.TrailingLength - endHit.FirstCharacterIndex - endHit.TrailingLength); - //Make sure we properly deal with zero width space runs - if (characterLength == 0 && currentRun.Length > 0 && currentRun.GlyphRun.Metrics.WidthIncludingTrailingWhitespace == 0) + if (characterLength == 0 && currentRun.Text.Length > 0 && startIndex < currentRun.Text.Length) { - characterLength = currentRun.Length; + //Make sure we are properly dealing with zero width space runs + var codepointEnumerator = new CodepointEnumerator(currentRun.Text.Span.Slice(startIndex)); + + while (remainingLength > 0 && codepointEnumerator.MoveNext(out var codepoint)) + { + if (codepoint.IsWhiteSpace) + { + characterLength++; + remainingLength--; + } + else + { + break; + } + } } - if(startHit.FirstCharacterIndex > endHit.FirstCharacterIndex) + if (startHit.FirstCharacterIndex > endHit.FirstCharacterIndex) { startHit = endHit; } @@ -1143,7 +1173,6 @@ namespace Avalonia.Media.TextFormatting } TextRun? currentRun = null; - TextRun? previousRun = null; while (runIndex < _indexedTextRuns.Count) { @@ -1182,7 +1211,7 @@ namespace Avalonia.Media.TextFormatting break; } - case TextRun: + case not null: { if(direction == LogicalDirection.Forward) { @@ -1212,8 +1241,6 @@ namespace Avalonia.Media.TextFormatting } runIndex++; - - previousRun = currentRun; } return currentRun; @@ -1242,61 +1269,57 @@ namespace Avalonia.Media.TextFormatting switch (_textRuns[index]) { case ShapedTextRun textRun: - { - var textMetrics = textRun.TextMetrics; - var glyphRun = textRun.GlyphRun; - var runBounds = glyphRun.InkBounds.WithX(widthIncludingWhitespace + glyphRun.InkBounds.X); + { + var textMetrics = textRun.TextMetrics; + var glyphRun = textRun.GlyphRun; + var runBounds = glyphRun.InkBounds.WithX(widthIncludingWhitespace + glyphRun.InkBounds.X); - bounds = bounds.Union(runBounds); + bounds = bounds.Union(runBounds); - if (fontRenderingEmSize < textMetrics.FontRenderingEmSize) - { - fontRenderingEmSize = textMetrics.FontRenderingEmSize; + if (ascent > textMetrics.Ascent) + { + ascent = textMetrics.Ascent; + } - if (ascent > textMetrics.Ascent) - { - ascent = textMetrics.Ascent; - } + if (descent < textMetrics.Descent) + { + descent = textMetrics.Descent; + } - if (descent < textMetrics.Descent) - { - descent = textMetrics.Descent; - } + if (lineGap < textMetrics.LineGap) + { + lineGap = textMetrics.LineGap; + } - if (lineGap < textMetrics.LineGap) - { - lineGap = textMetrics.LineGap; - } + if (descent - ascent + lineGap > height) + { + height = descent - ascent + lineGap; + } - if (descent - ascent + lineGap > height) - { - height = descent - ascent + lineGap; - } - } - widthIncludingWhitespace += textRun.Size.Width; + widthIncludingWhitespace += textRun.Size.Width; - break; - } + break; + } case DrawableTextRun drawableTextRun: + { + widthIncludingWhitespace += drawableTextRun.Size.Width; + + if (drawableTextRun.Size.Height > height) { - widthIncludingWhitespace += drawableTextRun.Size.Width; + height = drawableTextRun.Size.Height; + } - if (drawableTextRun.Size.Height > height) - { - height = drawableTextRun.Size.Height; - } - - //Adjust current ascent so drawables and text align at the bottom edge of the line. - var offset = Math.Max(0, drawableTextRun.Baseline + ascent - descent); + //Adjust current ascent so drawables and text align at the bottom edge of the line. + var offset = Math.Max(0, drawableTextRun.Baseline + ascent - descent); - ascent -= offset; + ascent -= offset; - bounds = bounds.Union(new Rect(new Point(bounds.Right, 0), drawableTextRun.Size)); + bounds = bounds.Union(new Rect(new Point(bounds.Right, 0), drawableTextRun.Size)); - break; - } + break; + } } } diff --git a/src/Avalonia.Base/Media/Typeface.cs b/src/Avalonia.Base/Media/Typeface.cs index 8363b82400..d9bd158886 100644 --- a/src/Avalonia.Base/Media/Typeface.cs +++ b/src/Avalonia.Base/Media/Typeface.cs @@ -31,7 +31,7 @@ namespace Avalonia.Media throw new ArgumentException("Font stretch must be > 1."); } - FontFamily = fontFamily; + FontFamily = fontFamily ?? FontFamily.Default; Style = style; Weight = weight; Stretch = stretch; diff --git a/src/Avalonia.Base/Metadata/InheritDataTypeFromAttribute.cs b/src/Avalonia.Base/Metadata/InheritDataTypeFromAttribute.cs new file mode 100644 index 0000000000..4a57667f82 --- /dev/null +++ b/src/Avalonia.Base/Metadata/InheritDataTypeFromAttribute.cs @@ -0,0 +1,44 @@ +using System; + +namespace Avalonia.Metadata; + +/// +/// Represents the kind of scope from which a data type can be inherited. Used in resolving target for AvaloniaProperty. +/// +public enum InheritDataTypeFromScopeKind +{ + /// + /// Indicates that the data type should be inherited from a style. + /// + Style = 1, + + /// + /// Indicates that the data type should be inherited from a control template. + /// + ControlTemplate, +} + +/// +/// Attribute that instructs the compiler to resolve the data type using specific scope hints, such as Style or ControlTemplate. +/// +/// +/// This attribute is used to configure markup extensions like TemplateBinding to properly parse AvaloniaProperty values, +/// targeting a specific scope data type. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] +public sealed class InheritDataTypeFromAttribute : Attribute +{ + /// + /// Initializes a new instance of the class with the specified scope kind. + /// + /// The kind of scope from which to inherit the data type. + public InheritDataTypeFromAttribute(InheritDataTypeFromScopeKind scopeKind) + { + ScopeKind = scopeKind; + } + + /// + /// Gets the kind of scope from which the data type should be inherited. + /// + public InheritDataTypeFromScopeKind ScopeKind { get; } +} diff --git a/src/Avalonia.Base/Platform/PlatformHandle.cs b/src/Avalonia.Base/Platform/PlatformHandle.cs index 9cc2741a12..79dd4f54dc 100644 --- a/src/Avalonia.Base/Platform/PlatformHandle.cs +++ b/src/Avalonia.Base/Platform/PlatformHandle.cs @@ -5,7 +5,7 @@ namespace Avalonia.Platform /// /// Represents a platform-specific handle. /// - public class PlatformHandle : IPlatformHandle + public class PlatformHandle : IPlatformHandle, IEquatable { /// /// Initializes a new instance of the class. @@ -29,5 +29,44 @@ namespace Avalonia.Platform /// Gets an optional string that describes what represents. /// public string? HandleDescriptor { get; } + + /// + public override string ToString() + { + return $"PlatformHandle {{ {HandleDescriptor} = {Handle} }}"; + } + + /// + public bool Equals(PlatformHandle? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return Handle == other.Handle && HandleDescriptor == other.HandleDescriptor; + } + + /// + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((PlatformHandle)obj); + } + + /// + public override int GetHashCode() + { + return (Handle, HandleDescriptor).GetHashCode(); + } + + public static bool operator ==(PlatformHandle? left, PlatformHandle? right) + { + return Equals(left, right); + } + + public static bool operator !=(PlatformHandle? left, PlatformHandle? right) + { + return !Equals(left, right); + } } } diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs index 715fc182d6..c465dddb84 100644 --- a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs +++ b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs @@ -1,115 +1,10 @@ -using System; -using System.IO; -using System.Security; +using System.IO; using System.Threading.Tasks; namespace Avalonia.Platform.Storage.FileIO; -internal class BclStorageFile : IStorageBookmarkFile +internal sealed class BclStorageFile(FileInfo fileInfo) : BclStorageItem(fileInfo), IStorageBookmarkFile { - public BclStorageFile(FileInfo fileInfo) - { - FileInfo = fileInfo ?? throw new ArgumentNullException(nameof(fileInfo)); - } - - public FileInfo FileInfo { get; } - - public string Name => FileInfo.Name; - - public virtual bool CanBookmark => true; - - public Uri Path - { - get - { - try - { - if (FileInfo.Directory is not null) - { - return StorageProviderHelpers.FilePathToUri(FileInfo.FullName); - } - } - catch (SecurityException) - { - } - return new Uri(FileInfo.Name, UriKind.Relative); - } - } - - public Task GetBasicPropertiesAsync() - { - if (FileInfo.Exists) - { - return Task.FromResult(new StorageItemProperties( - (ulong)FileInfo.Length, - FileInfo.CreationTimeUtc, - FileInfo.LastAccessTimeUtc)); - } - return Task.FromResult(new StorageItemProperties()); - } - - public Task GetParentAsync() - { - if (FileInfo.Directory is { } directory) - { - return Task.FromResult(new BclStorageFolder(directory)); - } - return Task.FromResult(null); - } - - public Task OpenReadAsync() - { - return Task.FromResult(FileInfo.OpenRead()); - } - - public Task OpenWriteAsync() - { - var stream = new FileStream(FileInfo.FullName, FileMode.Create, FileAccess.Write, FileShare.Write); - return Task.FromResult(stream); - } - - public virtual Task SaveBookmarkAsync() - { - return Task.FromResult(FileInfo.FullName); - } - - public Task ReleaseBookmarkAsync() - { - // No-op - return Task.CompletedTask; - } - - protected virtual void Dispose(bool disposing) - { - } - - ~BclStorageFile() - { - Dispose(disposing: false); - } - - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - - public Task DeleteAsync() - { - FileInfo.Delete(); - return Task.CompletedTask; - } - - public Task MoveAsync(IStorageFolder destination) - { - if (destination is BclStorageFolder storageFolder) - { - var newPath = System.IO.Path.Combine(storageFolder.DirectoryInfo.FullName, FileInfo.Name); - FileInfo.MoveTo(newPath); - - return Task.FromResult(new BclStorageFile(new FileInfo(newPath))); - } - - return Task.FromResult(null); - } + public Task OpenReadAsync() => Task.FromResult(OpenReadCore(fileInfo)); + public Task OpenWriteAsync() => Task.FromResult(OpenWriteCore(fileInfo)); } diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs index a5727dc3cd..05572d6058 100644 --- a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs +++ b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs @@ -1,128 +1,22 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Security; using System.Threading.Tasks; using Avalonia.Utilities; namespace Avalonia.Platform.Storage.FileIO; -internal class BclStorageFolder : IStorageBookmarkFolder +internal sealed class BclStorageFolder(DirectoryInfo directoryInfo) + : BclStorageItem(directoryInfo), IStorageBookmarkFolder { - public BclStorageFolder(DirectoryInfo directoryInfo) - { - DirectoryInfo = directoryInfo ?? throw new ArgumentNullException(nameof(directoryInfo)); - if (!DirectoryInfo.Exists) - { - throw new ArgumentException("Directory must exist", nameof(directoryInfo)); - } - } + public IAsyncEnumerable GetItemsAsync() => GetItemsCore(directoryInfo) + .Select(WrapFileSystemInfo) + .Where(f => f is not null) + .AsAsyncEnumerable()!; - public string Name => DirectoryInfo.Name; + public Task CreateFileAsync(string name) => Task.FromResult( + (IStorageFile?)WrapFileSystemInfo(CreateFileCore(directoryInfo, name))); - public DirectoryInfo DirectoryInfo { get; } - - public bool CanBookmark => true; - - public Uri Path - { - get - { - try - { - return StorageProviderHelpers.FilePathToUri(DirectoryInfo.FullName); - } - catch (SecurityException) - { - return new Uri(DirectoryInfo.Name, UriKind.Relative); - } - } - } - - public Task GetBasicPropertiesAsync() - { - var props = new StorageItemProperties( - null, - DirectoryInfo.CreationTimeUtc, - DirectoryInfo.LastAccessTimeUtc); - return Task.FromResult(props); - } - - public Task GetParentAsync() - { - if (DirectoryInfo.Parent is { } directory) - { - return Task.FromResult(new BclStorageFolder(directory)); - } - return Task.FromResult(null); - } - - public IAsyncEnumerable GetItemsAsync() - => DirectoryInfo.EnumerateDirectories() - .Select(d => (IStorageItem)new BclStorageFolder(d)) - .Concat(DirectoryInfo.EnumerateFiles().Select(f => new BclStorageFile(f))) - .AsAsyncEnumerable(); - - public virtual Task SaveBookmarkAsync() - { - return Task.FromResult(DirectoryInfo.FullName); - } - - public Task ReleaseBookmarkAsync() - { - // No-op - return Task.CompletedTask; - } - - protected virtual void Dispose(bool disposing) - { - } - - ~BclStorageFolder() - { - Dispose(disposing: false); - } - - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - - public Task DeleteAsync() - { - DirectoryInfo.Delete(true); - return Task.CompletedTask; - } - - public Task MoveAsync(IStorageFolder destination) - { - if (destination is BclStorageFolder storageFolder) - { - var newPath = System.IO.Path.Combine(storageFolder.DirectoryInfo.FullName, DirectoryInfo.Name); - DirectoryInfo.MoveTo(newPath); - - return Task.FromResult(new BclStorageFolder(new DirectoryInfo(newPath))); - } - - return Task.FromResult(null); - } - - public Task CreateFileAsync(string name) - { - var fileName = System.IO.Path.Combine(DirectoryInfo.FullName, name); - var newFile = new FileInfo(fileName); - - using var stream = newFile.Create(); - - return Task.FromResult(new BclStorageFile(newFile)); - } - - public Task CreateFolderAsync(string name) - { - var newFolder = DirectoryInfo.CreateSubdirectory(name); - - return Task.FromResult(new BclStorageFolder(newFolder)); - } + public Task CreateFolderAsync(string name) => Task.FromResult( + (IStorageFolder?)WrapFileSystemInfo(CreateFolderCore(directoryInfo, name))); } diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageItem.cs b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageItem.cs new file mode 100644 index 0000000000..123d0e9283 --- /dev/null +++ b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageItem.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Security; +using System.Threading.Tasks; + +namespace Avalonia.Platform.Storage.FileIO; + +internal abstract class BclStorageItem(FileSystemInfo fileSystemInfo) : IStorageBookmarkItem, IStorageItemWithFileSystemInfo +{ + public FileSystemInfo FileSystemInfo { get; } = fileSystemInfo switch + { + null => throw new ArgumentNullException(nameof(fileSystemInfo)), + DirectoryInfo { Exists: false } => throw new ArgumentException("Directory must exist", nameof(fileSystemInfo)), + _ => fileSystemInfo + }; + + public string Name => FileSystemInfo.Name; + + public bool CanBookmark => true; + + public Uri Path => GetPathCore(FileSystemInfo); + + public Task GetBasicPropertiesAsync() + { + return Task.FromResult(GetBasicPropertiesAsyncCore(FileSystemInfo)); + } + + public Task GetParentAsync() => Task.FromResult( + (IStorageFolder?)WrapFileSystemInfo(GetParentCore(FileSystemInfo))); + + public Task DeleteAsync() + { + DeleteCore(FileSystemInfo); + return Task.CompletedTask; + } + + public Task MoveAsync(IStorageFolder destination) => Task.FromResult( + WrapFileSystemInfo(MoveCore(FileSystemInfo, destination))); + + public Task SaveBookmarkAsync() + { + var path = FileSystemInfo.FullName; + return Task.FromResult(StorageBookmarkHelper.EncodeBclBookmark(path)); + } + + public Task ReleaseBookmarkAsync() => Task.CompletedTask; + + public void Dispose() { } + + [return: NotNullIfNotNull(nameof(fileSystemInfo))] + protected IStorageItem? WrapFileSystemInfo(FileSystemInfo? fileSystemInfo) => fileSystemInfo switch + { + DirectoryInfo directoryInfo => new BclStorageFolder(directoryInfo), + FileInfo fileInfo => new BclStorageFile(fileInfo), + _ => null + }; + + internal static void DeleteCore(FileSystemInfo fileSystemInfo) => fileSystemInfo.Delete(); + + internal static Uri GetPathCore(FileSystemInfo fileSystemInfo) + { + try + { + if (fileSystemInfo is DirectoryInfo { Parent: not null } or FileInfo { Directory: not null }) + { + return StorageProviderHelpers.UriFromFilePath(fileSystemInfo.FullName, fileSystemInfo is DirectoryInfo); + } + } + catch (SecurityException) + { + } + + return new Uri(fileSystemInfo.Name, UriKind.Relative); + } + + internal static StorageItemProperties GetBasicPropertiesAsyncCore(FileSystemInfo fileSystemInfo) + { + if (fileSystemInfo.Exists) + { + return new StorageItemProperties( + fileSystemInfo is FileInfo fileInfo ? (ulong)fileInfo.Length : 0, + fileSystemInfo.CreationTimeUtc, + fileSystemInfo.LastAccessTimeUtc); + } + + return new StorageItemProperties(); + } + + internal static DirectoryInfo? GetParentCore(FileSystemInfo fileSystemInfo) => fileSystemInfo switch + { + FileInfo { Directory: { } directory } => directory, + DirectoryInfo { Parent: { } parent } => parent, + _ => null + }; + + internal static FileSystemInfo? MoveCore(FileSystemInfo fileSystemInfo, IStorageFolder destination) + { + if (destination?.TryGetLocalPath() is { } destinationPath) + { + var newPath = System.IO.Path.Combine(destinationPath, fileSystemInfo.Name); + if (fileSystemInfo is DirectoryInfo directoryInfo) + { + directoryInfo.MoveTo(newPath); + return new DirectoryInfo(newPath); + } + + if (fileSystemInfo is FileInfo fileInfo) + { + fileInfo.MoveTo(newPath); + return new FileInfo(newPath); + } + } + + return null; + } + + internal static FileStream OpenReadCore(FileInfo fileInfo) => fileInfo.OpenRead(); + + internal static FileStream OpenWriteCore(FileInfo fileInfo) => + new(fileInfo.FullName, FileMode.Create, FileAccess.Write, FileShare.Write); + + internal static IEnumerable GetItemsCore(DirectoryInfo directoryInfo) => directoryInfo + .EnumerateDirectories() + .OfType() + .Concat(directoryInfo.EnumerateFiles()); + + internal static FileInfo CreateFileCore(DirectoryInfo directoryInfo, string name) + { + var fileName = System.IO.Path.Combine(directoryInfo.FullName, name); + var newFile = new FileInfo(fileName); + + using var stream = newFile.Create(); + return newFile; + } + + internal static DirectoryInfo CreateFolderCore(DirectoryInfo directoryInfo, string name) => + directoryInfo.CreateSubdirectory(name); +} diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageProvider.cs b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageProvider.cs index 34409f5fda..fd2f499d06 100644 --- a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageProvider.cs +++ b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageProvider.cs @@ -4,6 +4,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; using Avalonia.Compatibility; +using Avalonia.Logging; namespace Avalonia.Platform.Storage.FileIO; @@ -20,18 +21,12 @@ internal abstract class BclStorageProvider : IStorageProvider public virtual Task OpenFileBookmarkAsync(string bookmark) { - var file = new FileInfo(bookmark); - return file.Exists - ? Task.FromResult(new BclStorageFile(file)) - : Task.FromResult(null); + return Task.FromResult(OpenBookmark(bookmark) as IStorageBookmarkFile); } public virtual Task OpenFolderBookmarkAsync(string bookmark) { - var folder = new DirectoryInfo(bookmark); - return folder.Exists - ? Task.FromResult(new BclStorageFolder(folder)) - : Task.FromResult(null); + return Task.FromResult(OpenBookmark(bookmark) as IStorageBookmarkFolder); } public virtual Task TryGetFileFromPathAsync(Uri filePath) @@ -63,6 +58,16 @@ internal abstract class BclStorageProvider : IStorageProvider } public virtual Task TryGetWellKnownFolderAsync(WellKnownFolder wellKnownFolder) + { + if (TryGetWellKnownFolderCore(wellKnownFolder) is { } directoryInfo) + { + return Task.FromResult(new BclStorageFolder(directoryInfo)); + } + + return Task.FromResult(null); + } + + internal static DirectoryInfo? TryGetWellKnownFolderCore(WellKnownFolder wellKnownFolder) { // Note, this BCL API returns different values depending on the .NET version. // We should also document it. @@ -82,16 +87,16 @@ internal abstract class BclStorageProvider : IStorageProvider if (folderPath is null) { - return Task.FromResult(null); + return null; } var directory = new DirectoryInfo(folderPath); if (!directory.Exists) { - return Task.FromResult(null); + return null; } - - return Task.FromResult(new BclStorageFolder(directory)); + + return directory; string GetFromSpecialFolder(Environment.SpecialFolder folder) => Environment.GetFolderPath(folder, Environment.SpecialFolderOption.Create); @@ -104,7 +109,7 @@ internal abstract class BclStorageProvider : IStorageProvider if (OperatingSystemEx.IsWindows()) { return Environment.OSVersion.Version.Major < 6 ? null : - SHGetKnownFolderPath(s_folderDownloads, 0, IntPtr.Zero); + Marshal.PtrToStringUni(SHGetKnownFolderPath(s_folderDownloads, 0, IntPtr.Zero)); } if (OperatingSystemEx.IsLinux()) @@ -123,8 +128,27 @@ internal abstract class BclStorageProvider : IStorageProvider return null; } - + + private IStorageBookmarkItem? OpenBookmark(string bookmark) + { + try + { + if (StorageBookmarkHelper.TryDecodeBclBookmark(bookmark, out var localPath)) + { + return StorageProviderHelpers.TryCreateBclStorageItem(localPath); + } + + return null; + } + catch (Exception ex) + { + Logger.TryGet(LogEventLevel.Information, LogArea.Platform)? + .Log(this, "Unable to read file bookmark: {Exception}", ex); + return null; + } + } + private static readonly Guid s_folderDownloads = new Guid("374DE290-123F-4565-9164-39C4925E467B"); - [DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)] - private static extern string SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid id, int flags, IntPtr token); + [DllImport("shell32.dll")] + private static extern IntPtr SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid id, int flags, IntPtr token); } diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/SecurityScopedStream.cs b/src/Avalonia.Base/Platform/Storage/FileIO/SecurityScopedStream.cs new file mode 100644 index 0000000000..0e0ffa3b1b --- /dev/null +++ b/src/Avalonia.Base/Platform/Storage/FileIO/SecurityScopedStream.cs @@ -0,0 +1,116 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Avalonia.Platform.Storage.FileIO; + +/// +/// Stream wrapper currently used by Apple platforms, +/// where in sandboxed scenario it's advised to call [NSUri startAccessingSecurityScopedResource]. +/// +internal sealed class SecurityScopedStream(FileStream _stream, IDisposable _securityScope) : Stream +{ + public override bool CanRead => _stream.CanRead; + + public override bool CanSeek => _stream.CanSeek; + + public override bool CanWrite => _stream.CanWrite; + + public override long Length => _stream.Length; + + public override long Position + { + get => _stream.Position; + set => _stream.Position = value; + } + + public override void Flush() => + _stream.Flush(); + + public override Task FlushAsync(CancellationToken cancellationToken) => + _stream.FlushAsync(cancellationToken); + + public override int ReadByte() => + _stream.ReadByte(); + + public override int Read(byte[] buffer, int offset, int count) => + _stream.Read(buffer, offset, count); + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + _stream.ReadAsync(buffer, offset, count, cancellationToken); + +#if NET6_0_OR_GREATER + public override int Read(Span buffer) => _stream.Read(buffer); + + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) => + _stream.ReadAsync(buffer, cancellationToken); +#endif + + public override void Write(byte[] buffer, int offset, int count) => + _stream.Write(buffer, offset, count); + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + _stream.WriteAsync(buffer, offset, count, cancellationToken); + +#if NET6_0_OR_GREATER + public override void Write(ReadOnlySpan buffer) => _stream.Write(buffer); + + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) => + _stream.WriteAsync(buffer, cancellationToken); +#endif + + public override void WriteByte(byte value) => _stream.WriteByte(value); + + public override long Seek(long offset, SeekOrigin origin) => + _stream.Seek(offset, origin); + + public override void SetLength(long value) => + _stream.SetLength(value); + +#if NET6_0_OR_GREATER + public override void CopyTo(Stream destination, int bufferSize) => _stream.CopyTo(destination, bufferSize); +#endif + + public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) => + _stream.CopyToAsync(destination, bufferSize, cancellationToken); + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => + _stream.BeginRead(buffer, offset, count, callback, state); + + public override int EndRead(IAsyncResult asyncResult) => _stream.EndRead(asyncResult); + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => + _stream.BeginWrite(buffer, offset, count, callback, state); + + public override void EndWrite(IAsyncResult asyncResult) => _stream.EndWrite(asyncResult); + + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + _stream.Dispose(); + } + } + finally + { + _securityScope.Dispose(); + } + } + +#if NET6_0_OR_GREATER + public override async ValueTask DisposeAsync() + { + try + { + await _stream.DisposeAsync(); + } + finally + { + _securityScope.Dispose(); + } + } +#endif +} diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/StorageBookmarkHelper.cs b/src/Avalonia.Base/Platform/Storage/FileIO/StorageBookmarkHelper.cs new file mode 100644 index 0000000000..a71dd6f3e6 --- /dev/null +++ b/src/Avalonia.Base/Platform/Storage/FileIO/StorageBookmarkHelper.cs @@ -0,0 +1,153 @@ +using System; +using System.Buffers; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Text; + +namespace Avalonia.Platform.Storage.FileIO; + +/// +/// In order to have unique bookmarks across platforms, we prepend a platform specific suffix before native bookmark. +/// And always encoding them in base64 before returning to the user. +/// +/// +/// Bookmarks are encoded as: +/// 0-6 - avalonia prefix with version number +/// 7-15 - platform key +/// 16+ - native bookmark value +/// Which is then encoded in Base64. +/// +internal static class StorageBookmarkHelper +{ + private const int HeaderLength = 16; + private static ReadOnlySpan AvaHeaderPrefix => "ava.v1."u8; + private static ReadOnlySpan FakeBclBookmarkPlatform => "bcl"u8; + + [return: NotNullIfNotNull(nameof(nativeBookmark))] + public static string? EncodeBookmark(ReadOnlySpan platform, string? nativeBookmark) => + nativeBookmark is null ? null : EncodeBookmark(platform, Encoding.UTF8.GetBytes(nativeBookmark)); + + public static string? EncodeBookmark(ReadOnlySpan platform, ReadOnlySpan nativeBookmarkBytes) + { + if (nativeBookmarkBytes.Length == 0) + { + return null; + } + + if (platform.Length > HeaderLength) + { + throw new ArgumentException($"Platform name should not be longer than {HeaderLength} bytes", nameof(platform)); + } + + var arrayLength = HeaderLength + nativeBookmarkBytes.Length; + var arrayPool = ArrayPool.Shared.Rent(arrayLength); + try + { + // Write platform into first 16 bytes. + var arraySpan = arrayPool.AsSpan(0, arrayLength); + AvaHeaderPrefix.CopyTo(arraySpan); + platform.CopyTo(arraySpan.Slice(AvaHeaderPrefix.Length)); + + // Write bookmark bytes. + nativeBookmarkBytes.CopyTo(arraySpan.Slice(HeaderLength)); + + // We must use span overload because ArrayPool might return way too big array. +#if NET6_0_OR_GREATER + return Convert.ToBase64String(arraySpan); +#else + return Convert.ToBase64String(arraySpan.ToArray(), Base64FormattingOptions.None); +#endif + } + finally + { + ArrayPool.Shared.Return(arrayPool); + } + } + + public enum DecodeResult + { + Success = 0, + InvalidFormat, + InvalidPlatform + } + + public static DecodeResult TryDecodeBookmark(ReadOnlySpan platform, string? base64bookmark, out byte[]? nativeBookmark) + { + if (platform.Length > HeaderLength + || platform.Length == 0 + || base64bookmark is null + || base64bookmark.Length % 4 != 0) + { + nativeBookmark = null; + return DecodeResult.InvalidFormat; + } + + Span decodedBookmark; +#if NET6_0_OR_GREATER + // Each base64 character represents 6 bits, but to be safe, + var arrayPool = ArrayPool.Shared.Rent(HeaderLength + base64bookmark.Length * 6); + if (Convert.TryFromBase64Chars(base64bookmark, arrayPool, out int bytesWritten)) + { + decodedBookmark = arrayPool.AsSpan().Slice(0, bytesWritten); + } + else + { + nativeBookmark = null; + return DecodeResult.InvalidFormat; + } +#else + decodedBookmark = Convert.FromBase64String(base64bookmark).AsSpan(); +#endif + try + { + if (decodedBookmark.Length < HeaderLength + // Check if decoded string starts with the correct prefix, checking v1 at the same time. + && !AvaHeaderPrefix.SequenceEqual(decodedBookmark.Slice(0, AvaHeaderPrefix.Length))) + { + nativeBookmark = null; + return DecodeResult.InvalidFormat; + } + + var actualPlatform = decodedBookmark.Slice(AvaHeaderPrefix.Length, platform.Length); + if (!actualPlatform.SequenceEqual(platform)) + { + nativeBookmark = null; + return DecodeResult.InvalidPlatform; + } + + nativeBookmark = decodedBookmark.Slice(HeaderLength).ToArray(); + return DecodeResult.Success; + } + finally + { +#if NET6_0_OR_GREATER + ArrayPool.Shared.Return(arrayPool); +#endif + } + } + + public static string EncodeBclBookmark(string localPath) => EncodeBookmark(FakeBclBookmarkPlatform, localPath); + + public static bool TryDecodeBclBookmark(string nativeBookmark, [NotNullWhen(true)] out string? localPath) + { + var decodeResult = TryDecodeBookmark(FakeBclBookmarkPlatform, nativeBookmark, out var bytes); + if (decodeResult == DecodeResult.Success) + { + localPath = Encoding.UTF8.GetString(bytes!); + return true; + } + if (decodeResult == DecodeResult.InvalidFormat + && nativeBookmark.IndexOfAny(Path.GetInvalidPathChars()) < 0 + && !string.IsNullOrEmpty(Path.GetDirectoryName(nativeBookmark))) + { + // Attempt to restore old BCL bookmarks. + // Don't check for File.Exists here, as it will be done at later point in TryGetStorageItem. + // Just validate if it looks like a valid file path. + localPath = nativeBookmark; + return true; + } + + localPath = null; + return false; + } +} diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/StorageProviderHelpers.cs b/src/Avalonia.Base/Platform/Storage/FileIO/StorageProviderHelpers.cs index 76323eb900..48cc79672b 100644 --- a/src/Avalonia.Base/Platform/Storage/FileIO/StorageProviderHelpers.cs +++ b/src/Avalonia.Base/Platform/Storage/FileIO/StorageProviderHelpers.cs @@ -8,7 +8,7 @@ namespace Avalonia.Platform.Storage.FileIO; internal static class StorageProviderHelpers { - public static IStorageItem? TryCreateBclStorageItem(string path) + public static BclStorageItem? TryCreateBclStorageItem(string path) { if (!string.IsNullOrWhiteSpace(path)) { @@ -28,28 +28,36 @@ internal static class StorageProviderHelpers return null; } - public static Uri FilePathToUri(string path) + public static string? TryGetPathFromFileUri(Uri? uri) + { + // android "content:", browser and ios relative links are ignored. + return uri is { IsAbsoluteUri: true, Scheme: "file" } ? uri.LocalPath : null; + } + + public static Uri UriFromFilePath(string path, bool isDirectory) { var uriPath = new StringBuilder(path) .Replace("%", $"%{(int)'%':X2}") .Replace("[", $"%{(int)'[':X2}") - .Replace("]", $"%{(int)']':X2}") - .ToString(); + .Replace("]", $"%{(int)']':X2}"); + + if (!path.EndsWith('/') && isDirectory) + { + uriPath.Append('/'); + } - return new UriBuilder("file", string.Empty) { Path = uriPath }.Uri; + return new UriBuilder("file", string.Empty) { Path = uriPath.ToString() }.Uri; } - - public static bool TryFilePathToUri(string path, [NotNullWhen(true)] out Uri? uri) + + public static Uri? TryGetUriFromFilePath(string path, bool isDirectory) { try { - uri = FilePathToUri(path); - return true; + return UriFromFilePath(path, isDirectory); } catch { - uri = null; - return false; + return null; } } diff --git a/src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs b/src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs index 40f2720ee8..70c4f4bb0b 100644 --- a/src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs +++ b/src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs @@ -1,8 +1,14 @@ -using System.Threading.Tasks; +using System.IO; +using System.Threading.Tasks; using Avalonia.Metadata; namespace Avalonia.Platform.Storage; +internal interface IStorageItemWithFileSystemInfo : IStorageItem +{ + FileSystemInfo FileSystemInfo { get; } +} + [NotClientImplementable] public interface IStorageBookmarkItem : IStorageItem { diff --git a/src/Avalonia.Base/Platform/Storage/StorageProviderExtensions.cs b/src/Avalonia.Base/Platform/Storage/StorageProviderExtensions.cs index 3933d23e4f..8f0c890ed1 100644 --- a/src/Avalonia.Base/Platform/Storage/StorageProviderExtensions.cs +++ b/src/Avalonia.Base/Platform/Storage/StorageProviderExtensions.cs @@ -17,7 +17,7 @@ public static class StorageProviderExtensions return Task.FromResult(StorageProviderHelpers.TryCreateBclStorageItem(filePath) as IStorageFile); } - if (StorageProviderHelpers.TryFilePathToUri(filePath, out var uri)) + if (StorageProviderHelpers.TryGetUriFromFilePath(filePath, false) is { } uri) { return provider.TryGetFileFromPathAsync(uri); } @@ -34,7 +34,7 @@ public static class StorageProviderExtensions return Task.FromResult(StorageProviderHelpers.TryCreateBclStorageItem(folderPath) as IStorageFolder); } - if (StorageProviderHelpers.TryFilePathToUri(folderPath, out var uri)) + if (StorageProviderHelpers.TryGetUriFromFilePath(folderPath, true) is { } uri) { return provider.TryGetFolderFromPathAsync(uri); } @@ -56,21 +56,11 @@ public static class StorageProviderExtensions { // We can avoid double escaping of the path by checking for BclStorageFolder. // Ideally, `folder.Path.LocalPath` should also work, as that's only available way for the users. - if (item is BclStorageFolder storageFolder) + if (item is IStorageItemWithFileSystemInfo storageItem) { - return storageFolder.DirectoryInfo.FullName; - } - if (item is BclStorageFile storageFile) - { - return storageFile.FileInfo.FullName; - } - - if (item.Path is { IsAbsoluteUri: true, Scheme: "file" } absolutePath) - { - return absolutePath.LocalPath; + return storageItem.FileSystemInfo.FullName; } - // android "content:", browser and ios relative links go here. - return null; + return StorageProviderHelpers.TryGetPathFromFileUri(item.Path); } } diff --git a/src/Avalonia.Base/PropertyStore/ValueStore.cs b/src/Avalonia.Base/PropertyStore/ValueStore.cs index 67d176ecea..789383b860 100644 --- a/src/Avalonia.Base/PropertyStore/ValueStore.cs +++ b/src/Avalonia.Base/PropertyStore/ValueStore.cs @@ -292,6 +292,42 @@ namespace Avalonia.PropertyStore return property.GetDefaultValue(Owner); } + public BindingExpressionBase? GetExpression(AvaloniaProperty property) + { + var evaluatedLocalValue = false; + + bool TryGetLocalValue(out BindingExpressionBase? result) + { + if (!evaluatedLocalValue) + { + evaluatedLocalValue = true; + + if (_localValueBindings?.TryGetValue(property.Id, out var o) == true) + { + result = o as BindingExpressionBase; + return true; + } + } + + result = null; + return false; + } + + for (var i = _frames.Count - 1; i >= 0; --i) + { + var frame = _frames[i]; + + if (frame.Priority > BindingPriority.LocalValue && TryGetLocalValue(out var localExpression)) + return localExpression; + + if (frame.TryGetEntryIfActive(property, out var entry, out _)) + return entry as BindingExpressionBase; + } + + TryGetLocalValue(out var e); + return e; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static EffectiveValue CastEffectiveValue(EffectiveValue value) { diff --git a/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt deleted file mode 100644 index bfcec2960a..0000000000 --- a/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt +++ /dev/null @@ -1,4 +0,0 @@ -Compat issues with assembly Avalonia.Controls.DataGrid: -MembersMustExist : Member 'protected void Avalonia.Controls.DataGridCheckBoxColumn.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.DataGridTextColumn.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -Total Issues: 2 diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index c3f428450b..63f47c3e4d 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -2140,7 +2140,7 @@ namespace Avalonia.Controls if (DataConnection.DataSource != null && !DataConnection.EventsWired) { DataConnection.WireEvents(DataConnection.DataSource); - InitializeElements(false /*recycleRows*/); + InitializeElements(true /*recycleRows*/); } } diff --git a/src/Avalonia.Controls.DataGrid/Utils/ReflectionHelper.cs b/src/Avalonia.Controls.DataGrid/Utils/ReflectionHelper.cs index 38e18b57de..a33ae0e80b 100644 --- a/src/Avalonia.Controls.DataGrid/Utils/ReflectionHelper.cs +++ b/src/Avalonia.Controls.DataGrid/Utils/ReflectionHelper.cs @@ -19,6 +19,8 @@ namespace Avalonia.Controls.Utils internal const char LeftIndexerToken = '['; internal const char PropertyNameSeparator = '.'; internal const char RightIndexerToken = ']'; + internal const char LeftParenthesisToken = '('; + internal const char RightParenthesisToken = ')'; private static Type FindGenericType(Type definition, Type type) { @@ -482,12 +484,35 @@ namespace Avalonia.Controls.Utils List propertyPaths = new List(); if (!string.IsNullOrEmpty(propertyPath)) { + bool parenthesisOn = false; int startIndex = 0; for (int index = 0; index < propertyPath.Length; index++) { - if (propertyPath[index] == PropertyNameSeparator) + if (parenthesisOn) { - propertyPaths.Add(propertyPath.Substring(startIndex, index - startIndex)); + if (propertyPath[index] == RightParenthesisToken) + { + parenthesisOn = false; + startIndex = index + 1; + } + continue; + } + + if (propertyPath[index] == LeftParenthesisToken) + { + parenthesisOn = true; + if (startIndex != index) + { + propertyPaths.Add(propertyPath.Substring(startIndex, index - startIndex)); + startIndex = index + 1; + } + } + else if (propertyPath[index] == PropertyNameSeparator) + { + if (startIndex != index) + { + propertyPaths.Add(propertyPath.Substring(startIndex, index - startIndex)); + } startIndex = index + 1; } else if (startIndex != index && propertyPath[index] == LeftIndexerToken) diff --git a/src/Avalonia.Controls/ApiCompatBaseline.txt b/src/Avalonia.Controls/ApiCompatBaseline.txt deleted file mode 100644 index 33e5efbc15..0000000000 --- a/src/Avalonia.Controls/ApiCompatBaseline.txt +++ /dev/null @@ -1,112 +0,0 @@ -Compat issues with assembly Avalonia.Controls: -MembersMustExist : Member 'protected void Avalonia.Controls.Button.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.ButtonSpinner.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.CalendarDatePicker.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.ContextMenu.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Avalonia.Controls.DropDown' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Avalonia.Controls.DropDownItem' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.Expander.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Controls.IMenuItem.StaysOpenOnClick' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Controls.IMenuItem.StaysOpenOnClick.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.IMenuItem.StaysOpenOnClick.set(System.Boolean)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseClosed()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseOpening()' is present in the implementation but not in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.ItemsRepeater.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.DirectProperty Avalonia.DirectProperty Avalonia.Controls.NumericUpDown.ValueProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.NumericUpDown.IncrementProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.NumericUpDown.MaximumProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.NumericUpDown.MinimumProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Double Avalonia.Controls.NumericUpDown.Increment.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.NumericUpDown.Increment.set(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Double Avalonia.Controls.NumericUpDown.Maximum.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.NumericUpDown.Maximum.set(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Double Avalonia.Controls.NumericUpDown.Minimum.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.NumericUpDown.Minimum.set(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected System.Double Avalonia.Controls.NumericUpDown.OnCoerceIncrement(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected System.Double Avalonia.Controls.NumericUpDown.OnCoerceMaximum(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected System.Double Avalonia.Controls.NumericUpDown.OnCoerceMinimum(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected System.Double Avalonia.Controls.NumericUpDown.OnCoerceValue(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.NumericUpDown.OnIncrementChanged(System.Double, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.NumericUpDown.OnMaximumChanged(System.Double, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.NumericUpDown.OnMinimumChanged(System.Double, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.NumericUpDown.OnValueChanged(System.Double, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.NumericUpDown.RaiseValueChangedEvent(System.Double, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Double Avalonia.Controls.NumericUpDown.Value.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.NumericUpDown.Value.set(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.NumericUpDownValueChangedEventArgs..ctor(Avalonia.Interactivity.RoutedEvent, System.Double, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Double Avalonia.Controls.NumericUpDownValueChangedEventArgs.NewValue.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Double Avalonia.Controls.NumericUpDownValueChangedEventArgs.OldValue.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.ProgressBar.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.ScrollViewer.AllowAutoHideProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.Slider.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.AttachedProperty Avalonia.AttachedProperty Avalonia.Controls.TextBlock.FontFamilyProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.AttachedProperty Avalonia.AttachedProperty Avalonia.Controls.TextBlock.FontStyleProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.AttachedProperty Avalonia.AttachedProperty Avalonia.Controls.TextBlock.FontWeightProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.AttachedProperty Avalonia.AttachedProperty Avalonia.Controls.TextBlock.ForegroundProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.AttachedProperty Avalonia.AttachedProperty Avalonia.Controls.TextBlock.FontSizeProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.TextBlock.TextAlignmentProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.TextBlock.TextTrimmingProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.TextBlock.TextWrappingProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.TextBlock.LineHeightProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.TextBlock.MaxLinesProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.Media.FontFamily Avalonia.Controls.TextBlock.GetFontFamily(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Double Avalonia.Controls.TextBlock.GetFontSize(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.Media.FontStyle Avalonia.Controls.TextBlock.GetFontStyle(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.Media.FontWeight Avalonia.Controls.TextBlock.GetFontWeight(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.Media.IBrush Avalonia.Controls.TextBlock.GetForeground(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetFontFamily(Avalonia.Controls.Control, Avalonia.Media.FontFamily)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetFontSize(Avalonia.Controls.Control, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetFontStyle(Avalonia.Controls.Control, Avalonia.Media.FontStyle)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetFontWeight(Avalonia.Controls.Control, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetForeground(Avalonia.Controls.Control, Avalonia.Media.IBrush)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.TextBox.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.TopLevel' does not implement interface 'Avalonia.Utilities.IWeakSubscriber' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.Viewbox' does not inherit from base type 'Avalonia.Controls.Decorator' in the implementation but it does in the contract. -MembersMustExist : Member 'public Avalonia.AvaloniaProperty Avalonia.AvaloniaProperty Avalonia.Controls.Viewbox.StretchProperty' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.Window' does not implement interface 'Avalonia.Utilities.IWeakSubscriber' in the implementation but it does in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.Window.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.WindowBase' does not implement interface 'Avalonia.Utilities.IWeakSubscriber' in the implementation but it does in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.EventHandler Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.ShutdownRequested' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.add_ShutdownRequested(System.EventHandler)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.remove_ShutdownRequested(System.EventHandler)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.TryShutdown(System.Int32)' is present in the implementation but not in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.Embedding.EmbeddableControlRoot' does not implement interface 'Avalonia.Utilities.IWeakSubscriber' in the implementation but it does in the contract. -MembersMustExist : Member 'public System.Action Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.Resized.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.Resized.set(System.Action)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.AvaloniaProperty Avalonia.AvaloniaProperty Avalonia.Controls.Notifications.NotificationCard.CloseOnClickProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.Notifications.WindowNotificationManager.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.Platform.ITopLevelNativeMenuExporter.SetNativeMenu(Avalonia.Controls.NativeMenu)' is present in the contract but not in the implementation. -MembersMustExist : Member 'protected void Avalonia.Controls.Presenters.ScrollContentPresenter.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected Avalonia.Media.FormattedText Avalonia.Controls.Presenters.TextPresenter.CreateFormattedText()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.Media.FormattedText Avalonia.Controls.Presenters.TextPresenter.FormattedText.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Int32 Avalonia.Controls.Presenters.TextPresenter.GetCaretIndex(Avalonia.Point)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.Presenters.TextPresenter.InvalidateFormattedText()' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.Primitives.PopupRoot' does not implement interface 'Avalonia.Utilities.IWeakSubscriber' in the implementation but it does in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.ScrollBar.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.SelectingItemsControl.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.Track.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Avalonia.Platform.ExportWindowingSubsystemAttribute' does not exist in the implementation but it does exist in the contract. -EnumValuesMustMatch : Enum value 'Avalonia.Platform.ExtendClientAreaChromeHints Avalonia.Platform.ExtendClientAreaChromeHints.Default' is (System.Int32)2 in the implementation but (System.Int32)1 in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.Screen Avalonia.Platform.IScreenImpl.ScreenFromPoint(Avalonia.PixelPoint)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.Screen Avalonia.Platform.IScreenImpl.ScreenFromRect(Avalonia.PixelRect)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.Screen Avalonia.Platform.IScreenImpl.ScreenFromWindow(Avalonia.Platform.IWindowBaseImpl)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Nullable Avalonia.Platform.ITopLevelImpl.FrameSize' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Nullable Avalonia.Platform.ITopLevelImpl.FrameSize.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Action Avalonia.Platform.ITopLevelImpl.Resized.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Action Avalonia.Platform.ITopLevelImpl.Resized.get()' is present in the contract but not in the implementation. -MembersMustExist : Member 'public System.Action Avalonia.Platform.ITopLevelImpl.Resized.get()' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.Resized.set(System.Action)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.Resized.set(System.Action)' is present in the contract but not in the implementation. -MembersMustExist : Member 'public void Avalonia.Platform.ITopLevelImpl.Resized.set(System.Action)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.ICursorImpl)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' is present in the contract but not in the implementation. -MembersMustExist : Member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowBaseImpl.Show(System.Boolean)' is present in the contract but not in the implementation. -MembersMustExist : Member 'public void Avalonia.Platform.IWindowBaseImpl.Show(System.Boolean)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowBaseImpl.Show(System.Boolean, System.Boolean)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size)' is present in the contract but not in the implementation. -MembersMustExist : Member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size, Avalonia.Platform.PlatformResizeReason)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.ITrayIconImpl Avalonia.Platform.IWindowingPlatform.CreateTrayIcon()' is present in the implementation but not in the contract. -Total Issues: 110 diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs index 43c140a05f..2957214308 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs @@ -117,16 +117,30 @@ namespace Avalonia.Controls.ApplicationLifetimes } public int Start(string[] args) + { + return StartCore(args); + } + + /// + /// Since the lifetime must be set up/prepared with 'args' before executing Start(), an overload with no parameters seems more suitable for integrating with some lifetime manager providers, such as MS HostApplicationBuilder. + /// + /// exit code + public int Start() + { + return StartCore(Args ?? Array.Empty()); + } + + internal int StartCore(string[] args) { SetupCore(args); - + _cts = new CancellationTokenSource(); // Note due to a bug in the JIT we wrap this in a method, otherwise MainWindow // gets stuffed into a local var and can not be GCed until after the program stops. // this method never exits until program end. - ShowMainWindow(); - + ShowMainWindow(); + Dispatcher.UIThread.MainLoop(_cts.Token); Environment.ExitCode = _exitCode; return _exitCode; diff --git a/src/Avalonia.Controls/Automation/Peers/TitleBarAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/TitleBarAutomationPeer.cs new file mode 100644 index 0000000000..e6920c1e02 --- /dev/null +++ b/src/Avalonia.Controls/Automation/Peers/TitleBarAutomationPeer.cs @@ -0,0 +1,26 @@ +using Avalonia.Automation; +using Avalonia.Automation.Peers; +using Avalonia.Controls.Chrome; + +namespace Avalonia.Controls.Automation.Peers; + +internal class TitleBarAutomationPeer : ControlAutomationPeer +{ + public TitleBarAutomationPeer(TitleBar owner) : base(owner) + { + } + + protected override bool IsContentElementCore() => true; + + protected override string GetClassNameCore() + { + return "TitleBar"; + } + + protected override string? GetAutomationIdCore() => base.GetAutomationIdCore() ?? "AvaloniaTitleBar"; + + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.TitleBar; + } +} diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index 498f9cdf7f..d796fabb05 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -1,4 +1,6 @@ using System; +using Avalonia.Automation.Peers; +using Avalonia.Controls.Automation.Peers; using Avalonia.Reactive; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; @@ -94,5 +96,8 @@ namespace Avalonia.Controls.Chrome _captionButtons?.Detach(); _captionButtons = null; } + + /// + protected override AutomationPeer OnCreateAutomationPeer() => new TitleBarAutomationPeer(this); } } diff --git a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs index cbe2eddf53..e9cdd3039a 100644 --- a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs +++ b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs @@ -18,6 +18,7 @@ namespace Avalonia.Controls.Primitives Day, Hour, Minute, + Second, TimePeriod //AM or PM } @@ -516,6 +517,8 @@ namespace Avalonia.Controls.Primitives return new TimeSpan(value, 0, 0).ToString(ItemFormat); case DateTimePickerPanelType.Minute: return new TimeSpan(0, value, 0).ToString(ItemFormat); + case DateTimePickerPanelType.Second: + return new TimeSpan(0, 0, value).ToString(ItemFormat); case DateTimePickerPanelType.TimePeriod: return value == MinimumValue ? TimeUtils.GetAMDesignator() : TimeUtils.GetPMDesignator(); default: diff --git a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs index 62ac76e71c..111c9ff623 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs @@ -18,12 +18,15 @@ namespace Avalonia.Controls [TemplatePart("PART_FlyoutButtonContentGrid", typeof(Grid))] [TemplatePart("PART_HourTextBlock", typeof(TextBlock))] [TemplatePart("PART_MinuteTextBlock", typeof(TextBlock))] + [TemplatePart("PART_SecondTextBlock", typeof(TextBlock))] [TemplatePart("PART_PeriodTextBlock", typeof(TextBlock))] [TemplatePart("PART_PickerPresenter", typeof(TimePickerPresenter))] [TemplatePart("PART_Popup", typeof(Popup))] [TemplatePart("PART_SecondColumnDivider", typeof(Rectangle))] [TemplatePart("PART_SecondPickerHost", typeof(Border))] - [TemplatePart("PART_ThirdPickerHost", typeof(Border))] + [TemplatePart("PART_ThirdColumnDivider", typeof(Rectangle))] + [TemplatePart("PART_ThirdPickerHost", typeof(Border))] + [TemplatePart("PART_FourthPickerHost", typeof(Border))] [PseudoClasses(":hasnotime")] public class TimePicker : TemplatedControl { @@ -32,12 +35,24 @@ namespace Avalonia.Controls /// public static readonly StyledProperty MinuteIncrementProperty = AvaloniaProperty.Register(nameof(MinuteIncrement), 1, coerce: CoerceMinuteIncrement); + + /// + /// Defines the property + /// + public static readonly StyledProperty SecondIncrementProperty = + AvaloniaProperty.Register(nameof(SecondIncrement), 1, coerce: CoerceSecondIncrement); /// /// Defines the property /// public static readonly StyledProperty ClockIdentifierProperty = AvaloniaProperty.Register(nameof(ClockIdentifier), "12HourClock", coerce: CoerceClockIdentifier); + + /// + /// Defines the property + /// + public static readonly StyledProperty UseSecondsProperty = + AvaloniaProperty.Register(nameof(UseSeconds), false, coerce: CoerceUseSeconds); /// /// Defines the property @@ -52,11 +67,14 @@ namespace Avalonia.Controls private Border? _firstPickerHost; private Border? _secondPickerHost; private Border? _thirdPickerHost; + private Border? _fourthPickerHost; private TextBlock? _hourText; private TextBlock? _minuteText; + private TextBlock? _secondText; private TextBlock? _periodText; private Rectangle? _firstSplitter; private Rectangle? _secondSplitter; + private Rectangle? _thirdSplitter; private Grid? _contentGrid; private Popup? _popup; @@ -85,6 +103,23 @@ namespace Avalonia.Controls return value; } + + /// + /// Gets or sets the second increment in the picker + /// + public int SecondIncrement + { + get => GetValue(SecondIncrementProperty); + set => SetValue(SecondIncrementProperty, value); + } + + private static int CoerceSecondIncrement(AvaloniaObject sender, int value) + { + if (value < 1 || value > 59) + throw new ArgumentOutOfRangeException(null, "1 >= SecondIncrement <= 59"); + + return value; + } /// /// Gets or sets the clock identifier, either 12HourClock or 24HourClock @@ -103,6 +138,24 @@ namespace Avalonia.Controls return value; } + + /// + /// Gets or sets the use seconds switch, either true or false + /// + public bool UseSeconds + { + + get => GetValue(UseSecondsProperty); + set => SetValue(UseSecondsProperty, value); + } + + private static bool CoerceUseSeconds(AvaloniaObject sender, bool value) + { + if (!(value == true || value == false)) + throw new ArgumentException("Invalid UseSeconds", default(bool).ToString()); + + return value; + } /// /// Gets or sets the selected time. Can be null. @@ -135,13 +188,16 @@ namespace Avalonia.Controls _firstPickerHost = e.NameScope.Find("PART_FirstPickerHost"); _secondPickerHost = e.NameScope.Find("PART_SecondPickerHost"); _thirdPickerHost = e.NameScope.Find("PART_ThirdPickerHost"); + _fourthPickerHost = e.NameScope.Find("PART_FourthPickerHost"); _hourText = e.NameScope.Find("PART_HourTextBlock"); _minuteText = e.NameScope.Find("PART_MinuteTextBlock"); + _secondText = e.NameScope.Find("PART_SecondTextBlock"); _periodText = e.NameScope.Find("PART_PeriodTextBlock"); _firstSplitter = e.NameScope.Find("PART_FirstColumnDivider"); _secondSplitter = e.NameScope.Find("PART_SecondColumnDivider"); + _thirdSplitter = e.NameScope.Find("PART_ThirdColumnDivider"); _contentGrid = e.NameScope.Find("PART_FlyoutButtonContentGrid"); @@ -160,7 +216,9 @@ namespace Avalonia.Controls _presenter.Dismissed += OnDismissPicker; _presenter[!TimePickerPresenter.MinuteIncrementProperty] = this[!MinuteIncrementProperty]; + _presenter[!TimePickerPresenter.SecondIncrementProperty] = this[!SecondIncrementProperty]; _presenter[!TimePickerPresenter.ClockIdentifierProperty] = this[!ClockIdentifierProperty]; + _presenter[!TimePickerPresenter.UseSecondsProperty] = this[!UseSecondsProperty]; } } @@ -172,11 +230,20 @@ namespace Avalonia.Controls { SetSelectedTimeText(); } + else if (change.Property == SecondIncrementProperty) + { + SetSelectedTimeText(); + } else if (change.Property == ClockIdentifierProperty) { SetGrid(); SetSelectedTimeText(); } + else if (change.Property == UseSecondsProperty) + { + SetGrid(); + SetSelectedTimeText(); + } else if (change.Property == SelectedTimeProperty) { var (oldValue, newValue) = change.GetOldAndNewValue(); @@ -196,29 +263,40 @@ namespace Avalonia.Controls columnsD.Add(new ColumnDefinition(GridLength.Star)); columnsD.Add(new ColumnDefinition(GridLength.Auto)); columnsD.Add(new ColumnDefinition(GridLength.Star)); + if (UseSeconds) + { + columnsD.Add(new ColumnDefinition(GridLength.Auto)); + columnsD.Add(new ColumnDefinition(GridLength.Star)); + } if (!use24HourClock) { columnsD.Add(new ColumnDefinition(GridLength.Auto)); columnsD.Add(new ColumnDefinition(GridLength.Star)); } - + _contentGrid.ColumnDefinitions = columnsD; + + _thirdPickerHost!.IsVisible = UseSeconds; + _secondSplitter!.IsVisible = UseSeconds; - _thirdPickerHost!.IsVisible = !use24HourClock; - _secondSplitter!.IsVisible = !use24HourClock; + _fourthPickerHost!.IsVisible = !use24HourClock; + _thirdSplitter!.IsVisible = !use24HourClock; + + var amPmColumn = (UseSeconds) ? 6 : 4; Grid.SetColumn(_firstPickerHost!, 0); Grid.SetColumn(_secondPickerHost!, 2); - - Grid.SetColumn(_thirdPickerHost, use24HourClock ? 0 : 4); + Grid.SetColumn(_thirdPickerHost!, UseSeconds ? 4 : 0); + Grid.SetColumn(_fourthPickerHost, use24HourClock ? 0 : amPmColumn); Grid.SetColumn(_firstSplitter!, 1); - Grid.SetColumn(_secondSplitter, use24HourClock ? 0 : 3); + Grid.SetColumn(_secondSplitter!, UseSeconds ? 3 : 0); + Grid.SetColumn(_thirdSplitter, use24HourClock ? 0 : amPmColumn-1); } private void SetSelectedTimeText() { - if (_hourText == null || _minuteText == null || _periodText == null) + if (_hourText == null || _minuteText == null || _secondText == null || _periodText == null) return; var time = SelectedTime; @@ -230,11 +308,12 @@ namespace Avalonia.Controls { var hr = newTime.Hours; hr = hr > 12 ? hr - 12 : hr == 0 ? 12 : hr; - newTime = new TimeSpan(hr, newTime.Minutes, 0); + newTime = new TimeSpan(hr, newTime.Minutes, newTime.Seconds); } _hourText.Text = newTime.ToString("%h"); _minuteText.Text = newTime.ToString("mm"); + _secondText.Text = newTime.ToString("ss"); PseudoClasses.Set(":hasnotime", false); _periodText.Text = time.Value.Hours >= 12 ? TimeUtils.GetPMDesignator() : TimeUtils.GetAMDesignator(); @@ -244,6 +323,7 @@ namespace Avalonia.Controls // By clearing local value, we reset text property to the value from the template. _hourText.ClearValue(TextBlock.TextProperty); _minuteText.ClearValue(TextBlock.TextProperty); + _secondText.ClearValue(TextBlock.TextProperty); PseudoClasses.Set(":hasnotime", true); _periodText.Text = DateTime.Now.Hour >= 12 ? TimeUtils.GetPMDesignator() : TimeUtils.GetAMDesignator(); diff --git a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs index 7f19d0545e..be5c2db6fa 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs @@ -19,12 +19,16 @@ namespace Avalonia.Controls [TemplatePart("PART_MinuteDownButton", typeof(RepeatButton))] [TemplatePart("PART_MinuteSelector", typeof(DateTimePickerPanel), IsRequired = true)] [TemplatePart("PART_MinuteUpButton", typeof(RepeatButton))] + [TemplatePart("PART_SecondDownButton", typeof(RepeatButton))] + [TemplatePart("PART_SecondHost", typeof(Panel), IsRequired = true)] + [TemplatePart("PART_SecondSelector", typeof(DateTimePickerPanel), IsRequired = true)] + [TemplatePart("PART_SecondUpButton", typeof(RepeatButton))] [TemplatePart("PART_PeriodDownButton", typeof(RepeatButton))] [TemplatePart("PART_PeriodHost", typeof(Panel), IsRequired = true)] [TemplatePart("PART_PeriodSelector", typeof(DateTimePickerPanel), IsRequired = true)] [TemplatePart("PART_PeriodUpButton", typeof(RepeatButton))] [TemplatePart("PART_PickerContainer", typeof(Grid), IsRequired = true)] - [TemplatePart("PART_SecondSpacer", typeof(Rectangle), IsRequired = true)] + [TemplatePart("PART_ThirdSpacer", typeof(Rectangle), IsRequired = true)] public class TimePickerPresenter : PickerPresenterBase { /// @@ -32,12 +36,24 @@ namespace Avalonia.Controls /// public static readonly StyledProperty MinuteIncrementProperty = TimePicker.MinuteIncrementProperty.AddOwner(); + + /// + /// Defines the property + /// + public static readonly StyledProperty SecondIncrementProperty = + TimePicker.SecondIncrementProperty.AddOwner(); /// /// Defines the property /// public static readonly StyledProperty ClockIdentifierProperty = TimePicker.ClockIdentifierProperty.AddOwner(); + + /// + /// Defines the property + /// + public static readonly StyledProperty UseSecondsProperty = + TimePicker.UseSecondsProperty.AddOwner(); /// /// Defines the property @@ -60,15 +76,20 @@ namespace Avalonia.Controls private Button? _acceptButton; private Button? _dismissButton; private Rectangle? _spacer2; + private Rectangle? _spacer3; + private Panel? _secondHost; private Panel? _periodHost; private DateTimePickerPanel? _hourSelector; private DateTimePickerPanel? _minuteSelector; + private DateTimePickerPanel? _secondSelector; private DateTimePickerPanel? _periodSelector; private Button? _hourUpButton; private Button? _minuteUpButton; + private Button? _secondUpButton; private Button? _periodUpButton; private Button? _hourDownButton; private Button? _minuteDownButton; + private Button? _secondDownButton; private Button? _periodDownButton; /// @@ -79,6 +100,15 @@ namespace Avalonia.Controls get => GetValue(MinuteIncrementProperty); set => SetValue(MinuteIncrementProperty, value); } + + /// + /// Gets or sets the second increment in the selector + /// + public int SecondIncrement + { + get => GetValue(SecondIncrementProperty); + set => SetValue(SecondIncrementProperty, value); + } /// /// Gets or sets the current clock identifier, either 12HourClock or 24HourClock @@ -88,6 +118,15 @@ namespace Avalonia.Controls get => GetValue(ClockIdentifierProperty); set => SetValue(ClockIdentifierProperty, value); } + + /// + /// Gets or sets the current clock identifier, either 12HourClock or 24HourClock + /// + public bool UseSeconds + { + get => GetValue(UseSecondsProperty); + set => SetValue(UseSecondsProperty, value); + } /// /// Gets or sets the current time @@ -104,12 +143,15 @@ namespace Avalonia.Controls _pickerContainer = e.NameScope.Get("PART_PickerContainer"); _periodHost = e.NameScope.Get("PART_PeriodHost"); + _secondHost = e.NameScope.Get("PART_SecondHost"); _hourSelector = e.NameScope.Get("PART_HourSelector"); _minuteSelector = e.NameScope.Get("PART_MinuteSelector"); + _secondSelector = e.NameScope.Get("PART_SecondSelector"); _periodSelector = e.NameScope.Get("PART_PeriodSelector"); - + _spacer2 = e.NameScope.Get("PART_SecondSpacer"); + _spacer3 = e.NameScope.Get("PART_ThirdSpacer"); _acceptButton = e.NameScope.Get