diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index d2f2ee36d5..b802589fc7 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -6,17 +6,18 @@ "build": { "type": "object", "properties": { - "Configuration": { - "type": "string", - "description": "configuration" + "api-baseline": { + "type": "string" + }, + "configuration": { + "type": "string" }, "Continue": { "type": "boolean", "description": "Indicates to continue a previously failed build attempt" }, - "ForceNugetVersion": { - "type": "string", - "description": "force-nuget-version" + "force-nuget-version": { + "type": "string" }, "Help": { "type": "boolean", @@ -89,17 +90,16 @@ "RunRenderTests", "RunTests", "RunToolsTests", + "ValidateApiDiff", "ZipFiles" ] } }, - "SkipPreviewer": { - "type": "boolean", - "description": "skip-previewer" + "skip-previewer": { + "type": "boolean" }, - "SkipTests": { - "type": "boolean", - "description": "skip-tests" + "skip-tests": { + "type": "boolean" }, "Target": { "type": "array", @@ -124,10 +124,14 @@ "RunRenderTests", "RunTests", "RunToolsTests", + "ValidateApiDiff", "ZipFiles" ] } }, + "update-api-suppression": { + "type": "boolean" + }, "Verbosity": { "type": "string", "description": "Logging verbosity during build execution. Default is 'Normal'", diff --git a/api/Avalonia.Controls.ColorPicker.nupkg.xml b/api/Avalonia.Controls.ColorPicker.nupkg.xml new file mode 100644 index 0000000000..90271d6e98 --- /dev/null +++ b/api/Avalonia.Controls.ColorPicker.nupkg.xml @@ -0,0 +1,64 @@ + + + + + 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/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 + + \ No newline at end of file diff --git a/api/Avalonia.Themes.Fluent.nupkg.xml b/api/Avalonia.Themes.Fluent.nupkg.xml new file mode 100644 index 0000000000..f35bf5a629 --- /dev/null +++ b/api/Avalonia.Themes.Fluent.nupkg.xml @@ -0,0 +1,418 @@ + + + + + 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/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/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 + + \ No newline at end of file diff --git a/api/Avalonia.Themes.Simple.nupkg.xml b/api/Avalonia.Themes.Simple.nupkg.xml new file mode 100644 index 0000000000..78d8c4b332 --- /dev/null +++ b/api/Avalonia.Themes.Simple.nupkg.xml @@ -0,0 +1,406 @@ + + + + + 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/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/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 + + \ No newline at end of file diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml new file mode 100644 index 0000000000..6a7d53544e --- /dev/null +++ b/api/Avalonia.nupkg.xml @@ -0,0 +1,10 @@ + + + + + CP0006 + P:Avalonia.Rendering.Composition.ICompositionGpuImportedObject.ImportCompleted + baseline/netstandard2.0/Avalonia.Base.dll + target/netstandard2.0/Avalonia.Base.dll + + \ No newline at end of file diff --git a/build/SourceLink.props b/build/SourceLink.props index dd7ecc8d2a..b0f1f2c2cc 100644 --- a/build/SourceLink.props +++ b/build/SourceLink.props @@ -1,9 +1,9 @@ true - false + true + snupkg true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb @@ -14,10 +14,6 @@ true - - embedded - - diff --git a/nukebuild/ApiDiffValidation.cs b/nukebuild/ApiDiffValidation.cs new file mode 100644 index 0000000000..483bfd336a --- /dev/null +++ b/nukebuild/ApiDiffValidation.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net.Http; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Nuke.Common.Tooling; + +public static class ApiDiffValidation +{ + private static readonly HttpClient s_httpClient = new(); + + public static async Task ValidatePackage( + Tool apiCompatTool, string packagePath, string baselineVersion, + string suppressionFilesFolder, bool updateSuppressionFile) + { + if (baselineVersion is null) + { + throw new InvalidOperationException( + "Build \"api-baseline\" parameter must be set when running Nuke CreatePackages"); + } + + if (!Directory.Exists(suppressionFilesFolder)) + { + Directory.CreateDirectory(suppressionFilesFolder!); + } + + await using (var baselineStream = await DownloadBaselinePackage(packagePath, baselineVersion)) + using (var target = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.Read), ZipArchiveMode.Read)) + using (var baseline = new ZipArchive(baselineStream, ZipArchiveMode.Read)) + using (Helpers.UseTempDir(out var tempFolder)) + { + var targetDlls = GetDlls(target); + var baselineDlls = GetDlls(baseline); + + var left = new List(); + var right = new List(); + + var packageId = GetPackageId(packagePath); + var suppressionFile = Path.Combine(suppressionFilesFolder, packageId + ".nupkg.xml"); + + // Don't use Path.Combine with these left and right tool parameters. + // Microsoft.DotNet.ApiCompat.Tool is stupid and treats '/' and '\' as different assemblies in suppression files. + // So, always use Unix '/' + foreach (var baselineDll in baselineDlls) + { + var baselineDllPath = $"baseline/{baselineDll.target}/{baselineDll.entry.Name}"; + var baselineDllRealPath = Path.Combine(tempFolder, baselineDllPath); + Directory.CreateDirectory(Path.GetDirectoryName(baselineDllRealPath)!); + await using (var baselineDllFile = File.Create(baselineDllRealPath)) + { + await baselineDll.entry.Open().CopyToAsync(baselineDllFile); + } + + var targetDll = targetDlls.FirstOrDefault(e => + e.target == baselineDll.target && e.entry.Name == baselineDll.entry.Name); + if (targetDll.entry is null) + { + throw new InvalidOperationException($"Some assemblies are missing in the new package {packageId}: {baselineDll.entry.Name} for {baselineDll.target}"); + } + + var targetDllPath = $"target/{targetDll.target}/{targetDll.entry.Name}"; + var targetDllRealPath = Path.Combine(tempFolder, targetDllPath); + Directory.CreateDirectory(Path.GetDirectoryName(targetDllRealPath)!); + await using (var targetDllFile = File.Create(targetDllRealPath)) + { + await targetDll.entry.Open().CopyToAsync(targetDllFile); + } + + left.Add(baselineDllPath); + right.Add(targetDllPath); + } + + if (left.Any()) + { + var args = $""" -l={string.Join(',', left)} -r="{string.Join(',', right)}" """; + if (File.Exists(suppressionFile)) + { + args += $""" --suppression-file="{suppressionFile}" """; + } + + if (updateSuppressionFile) + { + args += $""" --suppression-output-file="{suppressionFile}" --generate-suppression-file=true """; + } + + var result = apiCompatTool(args, tempFolder) + .Where(t => t.Type == OutputType.Err).ToArray(); + if (result.Any()) + { + throw new AggregateException( + $"ApiDiffValidation task has failed for \"{Path.GetFileName(packagePath)}\" package", + result.Select(r => new Exception(r.Text))); + } + } + } + } + + private static IReadOnlyCollection<(string target, ZipArchiveEntry entry)> GetDlls(ZipArchive archive) + { + return archive.Entries + .Where(e => Path.GetExtension(e.FullName) == ".dll" + // Exclude analyzers and build task, as we don't care about breaking changes there + && !e.FullName.Contains("analyzers/") && !e.FullName.Contains("analyzers\\") + && !e.Name.Contains("Avalonia.Build.Tasks")) + .Select(e => ( + entry: e, + isRef: e.FullName.Contains("ref/") || e.FullName.Contains("ref\\"), + target: Path.GetDirectoryName(e.FullName)!.Split(new [] { '/', '\\' }).Last()) + ) + .GroupBy(e => (e.target, e.entry.Name)) + .Select(g => g.MaxBy(e => e.isRef)) + .Select(e => (e.target, e.entry)) + .ToArray(); + } + + static async Task DownloadBaselinePackage(string packagePath, string baselineVersion) + { + /* + Gets package name from versions like: + Avalonia.0.10.0-preview1 + Avalonia.11.0.999-cibuild0037534-beta + Avalonia.11.0.0 + */ + var packageId = GetPackageId(packagePath); + Build.Information("Downloading {0} {1} baseline package", packageId, baselineVersion); + + try + { + using var response = await s_httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, + $"https://www.nuget.org/api/v2/package/{packageId}/{baselineVersion}"), HttpCompletionOption.ResponseHeadersRead); + response.EnsureSuccessStatusCode(); + + await using var stream = await response.Content.ReadAsStreamAsync(); + var memoryStream = new MemoryStream(); + await stream.CopyToAsync(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + return memoryStream; + } + catch (Exception ex) + { + throw new InvalidOperationException($"Downloading baseline package for {packageId} {baselineVersion} failed.\r" + ex.Message, ex); + } + } + + static string GetPackageId(string packagePath) + { + return Regex.Replace( + Path.GetFileNameWithoutExtension(packagePath), + """(\.\d+\.\d+\.\d+(?:-.+)?)$""", ""); + } +} diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index 524c9fa4e4..bbfc28aa9f 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -36,6 +36,10 @@ using MicroCom.CodeGenerator; partial class Build : NukeBuild { BuildParameters Parameters { get; set; } + + [PackageExecutable("Microsoft.DotNet.ApiCompat.Tool", "Microsoft.DotNet.ApiCompat.Tool.dll", Framework = "net6.0")] + Tool ApiCompatTool; + protected override void OnBuildInitialized() { Parameters = new BuildParameters(this); @@ -278,7 +282,17 @@ partial class Build : NukeBuild RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." + Parameters.Version + ".nupkg"); }); - + + Target ValidateApiDiff => _ => _ + .DependsOn(CreateNugetPackages) + .Executes(async () => + { + await Task.WhenAll( + Directory.GetFiles(Parameters.NugetRoot, "*.nupkg").Select(nugetPackage => ApiDiffValidation.ValidatePackage( + ApiCompatTool, nugetPackage, Parameters.ApiValidationBaseline, + Parameters.ApiValidationSuppressionFiles, Parameters.UpdateApiValidationSuppression))); + }); + Target RunTests => _ => _ .DependsOn(RunCoreLibsTests) .DependsOn(RunRenderTests) @@ -288,7 +302,8 @@ partial class Build : NukeBuild Target Package => _ => _ .DependsOn(RunTests) - .DependsOn(CreateNugetPackages); + .DependsOn(CreateNugetPackages) + .DependsOn(ValidateApiDiff); Target CiAzureLinux => _ => _ .DependsOn(RunTests); diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs index dfa914d1db..897fdc84f1 100644 --- a/nukebuild/BuildParameters.cs +++ b/nukebuild/BuildParameters.cs @@ -10,18 +10,24 @@ using static Nuke.Common.IO.PathConstruction; public partial class Build { - [Parameter("configuration")] + [Parameter(Name = "configuration")] public string Configuration { get; set; } - [Parameter("skip-tests")] + [Parameter(Name = "skip-tests")] public bool SkipTests { get; set; } - [Parameter("force-nuget-version")] + [Parameter(Name = "force-nuget-version")] public string ForceNugetVersion { get; set; } - [Parameter("skip-previewer")] + [Parameter(Name = "skip-previewer")] public bool SkipPreviewer { get; set; } + [Parameter(Name = "api-baseline")] + public string ApiValidationBaseline { get; set; } + + [Parameter(Name = "update-api-suppression")] + public bool? UpdateApiValidationSuppression { get; set; } + public class BuildParameters { public string Configuration { get; } @@ -57,7 +63,9 @@ public partial class Build public string FileZipSuffix { get; } public AbsolutePath ZipCoreArtifacts { get; } public AbsolutePath ZipNuGetArtifacts { get; } - + public string ApiValidationBaseline { get; } + public bool UpdateApiValidationSuppression { get; } + public AbsolutePath ApiValidationSuppressionFiles { get; } public BuildParameters(Build b) { @@ -103,6 +111,9 @@ public partial class Build // VERSION Version = b.ForceNugetVersion ?? GetVersion(); + ApiValidationBaseline = b.ApiValidationBaseline ?? new Version(new Version(Version).Major, 0).ToString(); + UpdateApiValidationSuppression = b.UpdateApiValidationSuppression ?? IsLocalBuild; + if (IsRunningOnAzure) { if (!IsNuGetRelease) @@ -125,6 +136,7 @@ public partial class Build FileZipSuffix = Version + ".zip"; ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix); ZipNuGetArtifacts = ZipRoot / ("Avalonia-NuGet-" + FileZipSuffix); + ApiValidationSuppressionFiles = RootDirectory / "api"; } string GetVersion() diff --git a/nukebuild/Numerge b/nukebuild/Numerge index aef10ae67d..9738c6121f 160000 --- a/nukebuild/Numerge +++ b/nukebuild/Numerge @@ -1 +1 @@ -Subproject commit aef10ae67dc55c95f49b52a505a0be33bfa297a5 +Subproject commit 9738c6121fdd143c78d3e25686a7e4e13c00f586 diff --git a/nukebuild/Shims.cs b/nukebuild/Shims.cs index 6f79972ad6..eecfcf6da1 100644 --- a/nukebuild/Shims.cs +++ b/nukebuild/Shims.cs @@ -9,12 +9,12 @@ using Numerge; public partial class Build { - static void Information(string info) + internal static void Information(string info) { Logger.Info(info); } - static void Information(string info, params object[] args) + internal static void Information(string info, params object[] args) { Logger.Info(info, args); } diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index 30e1200220..64eccbbb3f 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -8,8 +8,8 @@ 1 net7.0 - - + + @@ -22,6 +22,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + @@ -30,9 +32,9 @@ - - - + + + @@ -41,7 +43,5 @@ dirs.proj - - diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets index 33f22f4d02..6af35ff0d2 100644 --- a/packages/Avalonia/AvaloniaBuildTasks.targets +++ b/packages/Avalonia/AvaloniaBuildTasks.targets @@ -144,4 +144,30 @@ + + + Build + + + + + http://127.0.0.1:6001 + $(OutputPath)/$(AssemblyName).dll + MainWindow.axaml + $(APreviewExecutable) + $([System.IO.Path]::ChangeExtension('$(APreviewExecutable)', '.deps.json')) + $([System.IO.Path]::ChangeExtension('$(APreviewExecutable)', '.runtimeconfig.json')) + $([System.IO.Path]::GetFullPath('$(APreviewFile)')) + + + + + + + + + + + + diff --git a/readme.md b/readme.md index c9539e1eb9..fc5e218a92 100644 --- a/readme.md +++ b/readme.md @@ -10,12 +10,12 @@ [Avalonia](https://avaloniaui.net) is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of platforms such as Windows, macOS, Linux, iOS, Android and WebAssembly. Avalonia is mature and production ready and is used by companies, including [Schneider Electric](https://avaloniaui.net/showcase#se), [Unity](https://avaloniaui.net/showcase#unity), [JetBrains](https://avaloniaui.net/showcase#rider) and [Github](https://avaloniaui.net/showcase#github). -Considered by many to be the spiritual successor to WPF, Avalonia UI provides a familiar, modern development experience for XAML developers creating cross-platform applications. While Avalonia UI is [similar to WPF](https://docs.avaloniaui.net/misc/wpf), it isn't a 1:1 copy, and you'll find plenty of improvements. +Considered by many to be the spiritual successor to WPF, Avalonia UI provides a familiar, modern development experience for XAML developers creating cross-platform applications. While Avalonia UI is [similar to WPF](https://docs.avaloniaui.net/docs/next/get-started/wpf/), it isn't a 1:1 copy, and you'll find plenty of improvements. For those seeking a cross-platform WPF, we have created [Avalonia XPF](https://avaloniaui.net/xpf), enabling WPF applications to run on macOS and Linux with little to no code changes. Avalonia XPF is a commercial product and is licensed per-app, per-platform. #### Roadmap -To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). +To see the status of some of our features, look at our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). #### Breaking Changes You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml index fb097da71b..356834832d 100644 --- a/samples/ControlCatalog/Pages/DataGridPage.xaml +++ b/samples/ControlCatalog/Pages/DataGridPage.xaml @@ -34,7 +34,7 @@ RowBackground="#1000"> - + @@ -68,7 +68,7 @@ - + diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index ddc2b7effb..16eb09de65 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -43,21 +43,15 @@ - - - - - - diff --git a/src/Avalonia.Base/Interactivity/EventRoute.cs b/src/Avalonia.Base/Interactivity/EventRoute.cs index 37539a7153..d0d82b4884 100644 --- a/src/Avalonia.Base/Interactivity/EventRoute.cs +++ b/src/Avalonia.Base/Interactivity/EventRoute.cs @@ -120,11 +120,6 @@ namespace Avalonia.Interactivity return; } - if (e.Source is null) - { - throw new ArgumentException("Event source may not be null", nameof(e)); - } - Interactive? lastTarget = null; var start = 0; var end = _route.Count; diff --git a/src/Avalonia.Base/Platform/Storage/PickerOptions.cs b/src/Avalonia.Base/Platform/Storage/PickerOptions.cs index ed061aa2d5..07f99f32c8 100644 --- a/src/Avalonia.Base/Platform/Storage/PickerOptions.cs +++ b/src/Avalonia.Base/Platform/Storage/PickerOptions.cs @@ -6,7 +6,7 @@ public class PickerOptions { /// - /// Gets or sets the text that appears in the title bar of a folder dialog. + /// Gets or sets the text that appears in the title bar of a picker. /// public string? Title { get; set; } diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs b/src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs index 1021bc58b4..31cbaf2a29 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Threading.Tasks; using Avalonia.Metadata; using Avalonia.Platform; namespace Avalonia.Rendering.Composition; + +[NotClientImplementable] public interface ICompositionGpuInterop { /// @@ -84,15 +87,22 @@ public enum CompositionGpuImportedImageSynchronizationCapabilities /// /// An imported GPU object that's usable by composition APIs /// +[NotClientImplementable] public interface ICompositionGpuImportedObject : IAsyncDisposable { /// /// Tracks the import status of the object. Once the task is completed, /// the user code is allowed to free the resource owner in case when a non-owning - /// sharing handle was used + /// sharing handle was used. /// Task ImportCompleted { get; } - + + /// + /// ImportCompleted (recommended replacement) + [Obsolete("Please use ICompositionGpuImportedObject.ImportCompleted instead")] + [EditorBrowsable(EditorBrowsableState.Never)] + Task ImportCompeted { get; } + /// /// Indicates if the device context this instance is associated with is no longer available /// diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs b/src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs index 9eea228e84..12a252ed96 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs @@ -74,6 +74,8 @@ abstract class CompositionGpuImportedObjectBase : ICompositionGpuImportedObject public abstract void Dispose(); public Task ImportCompleted { get; } + + public Task ImportCompeted => ImportCompleted; public bool IsLost => Context.IsLost; public ValueTask DisposeAsync() => new(Compositor.InvokeServerJobAsync(() => diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs index cb5e21be00..97083ccaf5 100644 --- a/src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs +++ b/src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs @@ -42,22 +42,31 @@ class ServerCompositionRenderData : SimpleServerRenderResource _items.Add(reader.ReadObject()); var collector = s_resourceHashSetPool.Get(); - foreach(var item in _items) - if (item is IRenderDataItemWithServerResources resourceItem) - resourceItem.Collect(collector); - + CollectResources(_items, collector); + foreach (var r in collector.Resources) { _referencedResources.Add(r); r.AddObserver(this); } - + collector.Resources.Clear(); s_resourceHashSetPool.ReturnAndSetNull(ref collector); base.DeserializeChangesCore(reader, committedAt); } + private static void CollectResources(PooledInlineList items, IRenderDataServerResourcesCollector collector) + { + foreach (var item in items) + { + if (item is IRenderDataItemWithServerResources resourceItem) + resourceItem.Collect(collector); + else if (item is RenderDataPushNode pushNode) + CollectResources(pushNode.Children, collector); + } + } + public Rect? Bounds { get @@ -133,4 +142,4 @@ class ServerCompositionRenderData : SimpleServerRenderResource Reset(); base.Dispose(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs b/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs index 7d586e1cbd..5995a03758 100644 --- a/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs +++ b/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs @@ -90,7 +90,7 @@ public partial class Dispatcher { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } DispatcherPriority.Validate(priority, "priority"); @@ -98,7 +98,7 @@ public partial class Dispatcher if (timeout.TotalMilliseconds < 0 && timeout != TimeSpan.FromMilliseconds(-1)) { - throw new ArgumentOutOfRangeException("timeout"); + throw new ArgumentOutOfRangeException(nameof(timeout)); } // Fast-Path: if on the same thread, and invoking at Send priority, @@ -212,7 +212,7 @@ public partial class Dispatcher { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } DispatcherPriority.Validate(priority, "priority"); @@ -220,7 +220,7 @@ public partial class Dispatcher if (timeout.TotalMilliseconds < 0 && timeout != TimeSpan.FromMilliseconds(-1)) { - throw new ArgumentOutOfRangeException("timeout"); + throw new ArgumentOutOfRangeException(nameof(timeout)); } // Fast-Path: if on the same thread, and invoking at Send priority, @@ -304,7 +304,7 @@ public partial class Dispatcher { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } DispatcherPriority.Validate(priority, "priority"); @@ -379,7 +379,7 @@ public partial class Dispatcher { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } DispatcherPriority.Validate(priority, "priority"); diff --git a/src/Avalonia.Base/Threading/Dispatcher.Queue.cs b/src/Avalonia.Base/Threading/Dispatcher.Queue.cs index 829ab4cf87..1644332aea 100644 --- a/src/Avalonia.Base/Threading/Dispatcher.Queue.cs +++ b/src/Avalonia.Base/Threading/Dispatcher.Queue.cs @@ -9,7 +9,9 @@ public partial class Dispatcher private readonly DispatcherPriorityQueue _queue = new(); private bool _signaled; private bool _explicitBackgroundProcessingRequested; - private const int MaximumTimeProcessingBackgroundJobs = 50; + private const int MaximumInputStarvationTimeInFallbackMode = 50; + private const int MaximumInputStarvationTimeInExplicitProcessingExplicitMode = 50; + private int _maximumInputStarvationTime; void RequestBackgroundProcessing() { @@ -35,8 +37,8 @@ public partial class Dispatcher lock (InstanceLock) { _explicitBackgroundProcessingRequested = false; - ExecuteJobsCore(); } + ExecuteJobsCore(true); } /// @@ -130,10 +132,10 @@ public partial class Dispatcher lock (InstanceLock) _signaled = false; - ExecuteJobsCore(); + ExecuteJobsCore(false); } - void ExecuteJobsCore() + void ExecuteJobsCore(bool fromExplicitBackgroundProcessingCallback) { long? backgroundJobExecutionStartedAt = null; while (true) @@ -151,7 +153,6 @@ public partial class Dispatcher if (job.Priority > DispatcherPriority.Input) { ExecuteJob(job); - backgroundJobExecutionStartedAt = null; } // If platform supports pending input query, ask the platform if we can continue running low priority jobs else if (_pendingInputImpl?.CanQueryPendingInput == true) @@ -164,6 +165,13 @@ public partial class Dispatcher return; } } + // We can't ask if the implementation has pending input, so we should let it to call us back + // Once it thinks that input is handled + else if (_backgroundProcessingImpl != null && !fromExplicitBackgroundProcessingCallback) + { + RequestBackgroundProcessing(); + return; + } // We can't check if there is pending input, but still need to enforce interactivity // so we stop processing background jobs after some timeout and start a timer to continue later else @@ -171,7 +179,7 @@ public partial class Dispatcher if (backgroundJobExecutionStartedAt == null) backgroundJobExecutionStartedAt = Now; - if (Now - backgroundJobExecutionStartedAt.Value > MaximumTimeProcessingBackgroundJobs) + if (Now - backgroundJobExecutionStartedAt.Value > _maximumInputStarvationTime) { _signaled = true; RequestBackgroundProcessing(); diff --git a/src/Avalonia.Base/Threading/Dispatcher.Timers.cs b/src/Avalonia.Base/Threading/Dispatcher.Timers.cs index bb252b7f55..51408daad1 100644 --- a/src/Avalonia.Base/Threading/Dispatcher.Timers.cs +++ b/src/Avalonia.Base/Threading/Dispatcher.Timers.cs @@ -127,7 +127,7 @@ public partial class Dispatcher if (needToPromoteTimers) PromoteTimers(); if (needToProcessQueue) - ExecuteJobsCore(); + ExecuteJobsCore(false); UpdateOSTimer(); } diff --git a/src/Avalonia.Base/Threading/Dispatcher.cs b/src/Avalonia.Base/Threading/Dispatcher.cs index f257072dc8..46c6699b5a 100644 --- a/src/Avalonia.Base/Threading/Dispatcher.cs +++ b/src/Avalonia.Base/Threading/Dispatcher.cs @@ -34,6 +34,9 @@ public partial class Dispatcher : IDispatcher _controlledImpl = _impl as IControlledDispatcherImpl; _pendingInputImpl = _impl as IDispatcherImplWithPendingInput; _backgroundProcessingImpl = _impl as IDispatcherImplWithExplicitBackgroundProcessing; + _maximumInputStarvationTime = _backgroundProcessingImpl == null ? + MaximumInputStarvationTimeInFallbackMode : + MaximumInputStarvationTimeInExplicitProcessingExplicitMode; if (_backgroundProcessingImpl != null) _backgroundProcessingImpl.ReadyForBackgroundProcessing += OnReadyForExplicitBackgroundProcessing; } diff --git a/src/Avalonia.Base/Threading/DispatcherFrame.cs b/src/Avalonia.Base/Threading/DispatcherFrame.cs index e826432475..1a80740420 100644 --- a/src/Avalonia.Base/Threading/DispatcherFrame.cs +++ b/src/Avalonia.Base/Threading/DispatcherFrame.cs @@ -38,10 +38,14 @@ public class DispatcherFrame /// for their important criteria to be met. These frames /// should have a timeout associated with them. /// - public DispatcherFrame(bool exitWhenRequested) + public DispatcherFrame(bool exitWhenRequested) : this(Dispatcher.UIThread, exitWhenRequested) { - Dispatcher = Dispatcher.UIThread; Dispatcher.VerifyAccess(); + } + + internal DispatcherFrame(Dispatcher dispatcher, bool exitWhenRequested) + { + Dispatcher = dispatcher; _exitWhenRequested = exitWhenRequested; _continue = true; } diff --git a/src/Avalonia.Base/Threading/DispatcherTimer.cs b/src/Avalonia.Base/Threading/DispatcherTimer.cs index 879d9d8a5f..fbdeed4edc 100644 --- a/src/Avalonia.Base/Threading/DispatcherTimer.cs +++ b/src/Avalonia.Base/Threading/DispatcherTimer.cs @@ -62,7 +62,7 @@ public partial class DispatcherTimer { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } Tick += callback; @@ -112,11 +112,11 @@ public partial class DispatcherTimer bool updateOSTimer = false; if (value.TotalMilliseconds < 0) - throw new ArgumentOutOfRangeException("value", + throw new ArgumentOutOfRangeException(nameof(value), "TimeSpan period must be greater than or equal to zero."); if (value.TotalMilliseconds > Int32.MaxValue) - throw new ArgumentOutOfRangeException("value", + throw new ArgumentOutOfRangeException(nameof(value), "TimeSpan period must be less than or equal to Int32.MaxValue."); lock (_instanceLock) @@ -253,20 +253,20 @@ public partial class DispatcherTimer { if (dispatcher == null) { - throw new ArgumentNullException("dispatcher"); + throw new ArgumentNullException(nameof(dispatcher)); } DispatcherPriority.Validate(priority, "priority"); if (priority == DispatcherPriority.Inactive) { - throw new ArgumentException("Specified priority is not valid.", "priority"); + throw new ArgumentException("Specified priority is not valid.", nameof(priority)); } if (interval.TotalMilliseconds < 0) - throw new ArgumentOutOfRangeException("interval", "TimeSpan period must be greater than or equal to zero."); + throw new ArgumentOutOfRangeException(nameof(interval), "TimeSpan period must be greater than or equal to zero."); if (interval.TotalMilliseconds > Int32.MaxValue) - throw new ArgumentOutOfRangeException("interval", + throw new ArgumentOutOfRangeException(nameof(interval), "TimeSpan period must be less than or equal to Int32.MaxValue."); @@ -349,4 +349,4 @@ public partial class DispatcherTimer // used by Dispatcher internal long DueTimeInMs { get; private set; } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Utilities/SmallDictionary.cs b/src/Avalonia.Base/Utilities/SmallDictionary.cs index b6e62411da..1e63d554b4 100644 --- a/src/Avalonia.Base/Utilities/SmallDictionary.cs +++ b/src/Avalonia.Base/Utilities/SmallDictionary.cs @@ -51,7 +51,7 @@ internal struct InlineDictionary : IEnumerable : IEnumerable() @@ -353,10 +353,16 @@ namespace Avalonia.Build.Tasks ((List)parsedXamlDocuments).Add(new XamlDocumentResource( parsed, res.Uri, res, classType, classModifierPublic.Value, - populateBuilder, - compiler.DefinePopulateMethod(populateBuilder, parsed, populateName, - classTypeDefinition == null && classModifierPublic.Value), - buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value))); + () => new XamlDocumentTypeBuilderProvider( + populateBuilder, + compiler.DefinePopulateMethod( + populateBuilder, + parsed, + populateName, + classTypeDefinition == null && classModifierPublic.Value), + buildName == null ? + null : + compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value)))); } catch (Exception e) { @@ -387,10 +393,17 @@ namespace Avalonia.Build.Tasks foreach (var document in parsedXamlDocuments) { + var res = (IResource)document.FileSource!; + + if (document.Usage == XamlDocumentUsage.Merged && !document.IsPublic) + { + res.Remove(); + continue; + } + var parsed = document.XamlDocument; - var res = (IResource)document.FileSource; var classType = document.ClassType; - var populateBuilder = document.TypeBuilder; + var populateBuilder = document.TypeBuilderProvider.TypeBuilder; try { @@ -399,8 +412,8 @@ namespace Avalonia.Build.Tasks compiler.Compile(parsed, contextClass, - document.PopulateMethod, - document.BuildMethod, + document.TypeBuilderProvider.PopulateMethod, + document.TypeBuilderProvider.BuildMethod, builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name, true), (closureName, closureBaseType) => populateBuilder.DefineSubType(closureBaseType, closureName, false), @@ -412,7 +425,7 @@ namespace Avalonia.Build.Tasks if (classTypeDefinition != null) { var compiledPopulateMethod = typeSystem.GetTypeReference(populateBuilder).Resolve() - .Methods.First(m => m.Name == document.PopulateMethod.Name); + .Methods.First(m => m.Name == document.TypeBuilderProvider.PopulateMethod.Name); var designLoaderFieldType = typeSystem .GetType("System.Action`1") @@ -536,12 +549,12 @@ namespace Avalonia.Build.Tasks } if (document.IsPublic - && (document.BuildMethod != null || classTypeDefinition != null)) + && (document.TypeBuilderProvider.BuildMethod != null || classTypeDefinition != null)) { - var compiledBuildMethod = document.BuildMethod == null ? + var compiledBuildMethod = document.TypeBuilderProvider.BuildMethod is not { } buildMethod ? null : typeSystem.GetTypeReference(builder).Resolve() - .Methods.First(m => m.Name == document.BuildMethod?.Name); + .Methods.First(m => m.Name == buildMethod.Name); var parameterlessConstructor = compiledBuildMethod != null ? null : classTypeDefinition.GetConstructors().FirstOrDefault(c => diff --git a/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs b/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs index 30517f4b00..0026c9e074 100644 --- a/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs +++ b/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs @@ -807,7 +807,7 @@ namespace Avalonia.Collections { if (value < 0) { - throw new ArgumentOutOfRangeException("PageSize cannot have a negative value."); + throw new ArgumentOutOfRangeException(nameof(value), "PageSize cannot have a negative value."); } // if the Refresh is currently deferred, cache the desired PageSize @@ -1954,7 +1954,7 @@ namespace Avalonia.Collections // for indices larger than the count if (index >= Count || index < 0) { - throw new ArgumentOutOfRangeException("index"); + throw new ArgumentOutOfRangeException(nameof(index)); } if (IsGrouping) diff --git a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs index 5d080f5ef6..b2deb1c26e 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs @@ -222,7 +222,7 @@ namespace Avalonia.Controls { if (element == null) { - throw new ArgumentNullException("element"); + throw new ArgumentNullException(nameof(element)); } if (element is CheckBox checkBox) { diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs index e7f9a9a6c4..798228c84c 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs @@ -191,7 +191,7 @@ namespace Avalonia.Controls } if (dataGridColumn == null) { - throw new ArgumentNullException("dataGridColumn"); + throw new ArgumentNullException(nameof(dataGridColumn)); } int columnIndexWithFiller = columnIndex; diff --git a/src/Avalonia.Controls.DataGrid/DataGridLength.cs b/src/Avalonia.Controls.DataGrid/DataGridLength.cs index 4841ddd494..a193352f52 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridLength.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridLength.cs @@ -499,7 +499,7 @@ namespace Avalonia.Controls { if (destinationType == null) { - throw new ArgumentNullException("destinationType"); + throw new ArgumentNullException(nameof(destinationType)); } if (destinationType != typeof(string)) { diff --git a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs index 756951667b..c19d887230 100644 --- a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs @@ -18,7 +18,7 @@ namespace Avalonia.Automation.Peers public ControlAutomationPeer(Control owner) { - Owner = owner ?? throw new ArgumentNullException("owner"); + Owner = owner ?? throw new ArgumentNullException(nameof(owner)); Initialize(); } diff --git a/src/Avalonia.Controls/Automation/Peers/ScrollViewerAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ScrollViewerAutomationPeer.cs index 835ed1c4af..674eb9a241 100644 --- a/src/Avalonia.Controls/Automation/Peers/ScrollViewerAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/ScrollViewerAutomationPeer.cs @@ -146,12 +146,12 @@ namespace Avalonia.Automation.Peers if (scrollHorizontally && (horizontalPercent < 0.0) || (horizontalPercent > 100.0)) { - throw new ArgumentOutOfRangeException("horizontalPercent"); + throw new ArgumentOutOfRangeException(nameof(horizontalPercent)); } if (scrollVertically && (verticalPercent < 0.0) || (verticalPercent > 100.0)) { - throw new ArgumentOutOfRangeException("verticalPercent"); + throw new ArgumentOutOfRangeException(nameof(verticalPercent)); } var offset = Owner.Offset; diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index bce1a3685f..bd05d4947c 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -270,6 +270,7 @@ namespace Avalonia.Controls { if (_popup?.IsInsidePopup(source) == true) { + e.Handled = true; return; } } @@ -516,5 +517,14 @@ namespace Avalonia.Controls } } } + + /// + /// Clears the selection + /// + public void Clear() + { + SelectedItem = null; + SelectedIndex = -1; + } } } diff --git a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs index 69b0ffe9a6..5a5c3fdf1d 100644 --- a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs +++ b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs @@ -165,7 +165,7 @@ namespace Avalonia.Controls.Primitives set { if (value > MaximumValue || value < MinimumValue) - throw new ArgumentOutOfRangeException("SelectedValue"); + throw new ArgumentOutOfRangeException(nameof(value)); var sel = CoerceSelected(value); _selectedValue = sel; @@ -195,7 +195,7 @@ namespace Avalonia.Controls.Primitives set { if (value <= 0 || value > _range) - throw new ArgumentOutOfRangeException("Increment"); + throw new ArgumentOutOfRangeException(nameof(value)); _increment = value; UpdateHelperInfo(); var sel = CoerceSelected(SelectedValue); diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs index b5be12fa54..30f9d8f380 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs @@ -1113,11 +1113,11 @@ namespace Avalonia.Controls } if (value < Minimum) { - throw new ArgumentOutOfRangeException(nameof(value), string.Format("Value must be greater than Minimum value of {0}", Minimum)); + throw new ArgumentOutOfRangeException(nameof(value), $"Value must be greater than Minimum value of {Minimum}"); } else if (value > Maximum) { - throw new ArgumentOutOfRangeException(nameof(value), string.Format("Value must be less than Maximum value of {0}", Maximum)); + throw new ArgumentOutOfRangeException(nameof(value), $"Value must be less than Maximum value of {Maximum}"); } } diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index e22d03273a..66ed1a27e2 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -1395,10 +1395,8 @@ namespace Avalonia.Controls.Primitives public object Evaluate(object? dataContext) { - dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext)); - // Only update the DataContext if necessary - if (!dataContext.Equals(DataContext)) + if (!Equals(dataContext, DataContext)) DataContext = dataContext; return GetValue(ValueProperty); diff --git a/src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs b/src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs index 4c1e0c2565..7ff02711d6 100644 --- a/src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs +++ b/src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs @@ -98,14 +98,14 @@ namespace Avalonia.Controls.PullToRefresh if (_scrollViewer.Content == null) { - throw new ArgumentException(nameof(adaptee), "Adaptee's content property cannot be null."); + throw new ArgumentException("Adaptee's content property cannot be null.", nameof(adaptee)); } var content = adaptee.Content as Visual; if (content == null) { - throw new ArgumentException(nameof(adaptee), "Adaptee's content property must be a Visual"); + throw new ArgumentException("Adaptee's content property must be a Visual", nameof(adaptee)); } if (content.GetVisualParent() == null) @@ -118,7 +118,7 @@ namespace Avalonia.Controls.PullToRefresh if (content.Parent is not InputElement) { - throw new ArgumentException(nameof(adaptee), "Adaptee's content's parent must be a InputElement"); + throw new ArgumentException("Adaptee's content's parent must be a InputElement", nameof(adaptee)); } } @@ -194,12 +194,12 @@ namespace Avalonia.Controls.PullToRefresh var content = _scrollViewer?.Content as Visual; if (content == null) { - throw new ArgumentException(nameof(_scrollViewer), "Adaptee's content property must be a Visual"); + throw new ArgumentException("Adaptee's content property must be a Visual", nameof(_scrollViewer)); } if (content.Parent is not InputElement parent) { - throw new ArgumentException(nameof(_scrollViewer), "Adaptee's content parent must be an InputElement"); + throw new ArgumentException("Adaptee's content parent must be an InputElement", nameof(_scrollViewer)); } MakeInteractionSource(parent); diff --git a/src/Avalonia.Controls/Utils/StringUtils.cs b/src/Avalonia.Controls/Utils/StringUtils.cs index 2ea47b442a..0ae1ef0b97 100644 --- a/src/Avalonia.Controls/Utils/StringUtils.cs +++ b/src/Avalonia.Controls/Utils/StringUtils.cs @@ -76,7 +76,7 @@ namespace Avalonia.Controls.Utils } var codepoint = new Codepoint(text[index]); - + if (!codepoint.IsWhiteSpace) { return false; @@ -85,12 +85,20 @@ namespace Avalonia.Controls.Utils // preceeded by lwsp. if (index > 0) { - var nextCodePoint = new Codepoint(text[index + 1]); + if (index + 1 < text.Length) + { + var nextCodePoint = new Codepoint(text[index + 1]); - if (nextCodePoint.IsBreakChar) + if (nextCodePoint.IsBreakChar) + { + return true; + } + } + else { return true; } + } switch (codepoint.GeneralCategory) @@ -125,7 +133,7 @@ namespace Avalonia.Controls.Utils } cursor = Math.Min(cursor, text.Length); - + int begin; int i; int cr; @@ -181,7 +189,7 @@ namespace Avalonia.Controls.Utils { return cursor; } - + if (cr < text.Length && text[cr] == '\r' && cr + 1 < text.Length && text[cr + 1] == '\n') { lf = cr + 1; @@ -214,9 +222,9 @@ namespace Avalonia.Controls.Utils { return i; } - + var cc = GetCharClass(text[i]); - + // skip over the word, punctuation, or run of whitespace while (i < cr && GetCharClass(text[i]) == cc) { diff --git a/src/Avalonia.Controls/Utils/VirtualizingSnapPointsList.cs b/src/Avalonia.Controls/Utils/VirtualizingSnapPointsList.cs index f92756c59b..eaf501b45f 100644 --- a/src/Avalonia.Controls/Utils/VirtualizingSnapPointsList.cs +++ b/src/Avalonia.Controls/Utils/VirtualizingSnapPointsList.cs @@ -39,7 +39,7 @@ namespace Avalonia.Controls.Utils get { if(index < 0 || index >= Count) - throw new ArgumentOutOfRangeException("index"); + throw new ArgumentOutOfRangeException(nameof(index)); index += _start; diff --git a/src/Avalonia.Native/NativePlatformSettings.cs b/src/Avalonia.Native/NativePlatformSettings.cs index 53d3da0378..42d05d831c 100644 --- a/src/Avalonia.Native/NativePlatformSettings.cs +++ b/src/Avalonia.Native/NativePlatformSettings.cs @@ -23,7 +23,7 @@ internal class NativePlatformSettings : DefaultPlatformSettings AvnPlatformThemeVariant.Dark => (PlatformThemeVariant.Dark, ColorContrastPreference.NoPreference), AvnPlatformThemeVariant.Light => (PlatformThemeVariant.Light, ColorContrastPreference.NoPreference), AvnPlatformThemeVariant.HighContrastDark => (PlatformThemeVariant.Dark, ColorContrastPreference.High), - AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Dark, ColorContrastPreference.High), + AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Light, ColorContrastPreference.High), _ => throw new ArgumentOutOfRangeException() }; var color = _platformSettings.AccentColor; diff --git a/src/Avalonia.Remote.Protocol/MetsysBson.cs b/src/Avalonia.Remote.Protocol/MetsysBson.cs index 8966dd4206..9c5f92b6ac 100644 --- a/src/Avalonia.Remote.Protocol/MetsysBson.cs +++ b/src/Avalonia.Remote.Protocol/MetsysBson.cs @@ -752,7 +752,7 @@ namespace Metsys.Bson if (memberExpression.Expression.NodeType != ExpressionType.Parameter && memberExpression.Expression.NodeType != ExpressionType.Convert) { - throw new ArgumentException(string.Format("Expression '{0}' must resolve to top-level member.", lambdaExpression), nameof(lambdaExpression)); + throw new ArgumentException($"Expression '{lambdaExpression}' must resolve to top-level member.", nameof(lambdaExpression)); } return memberExpression.Member.Name; default: @@ -942,7 +942,7 @@ namespace Metsys.Bson return new ListWrapper(); } } - throw new BsonException(string.Format("Collection of type {0} cannot be deserialized", type.FullName)); + throw new BsonException($"Collection of type {type.FullName} cannot be deserialized"); } public abstract void Add(object value); @@ -1514,7 +1514,7 @@ namespace Metsys.Bson.Configuration result = Visit((MemberExpression)expression.Left); } var index = Expression.Lambda(expression.Right).Compile().DynamicInvoke(); - return result + string.Format("[{0}]", index); + return result + $"[{index}]"; } private string Visit(MemberExpression expression) @@ -1540,7 +1540,7 @@ namespace Metsys.Bson.Configuration if (expression.Method.Name == "get_Item" && expression.Arguments.Count == 1) { var index = Expression.Lambda(expression.Arguments[0]).Compile().DynamicInvoke(); - name += string.Format("[{0}]", index); + name += $"[{index}]"; } return name; } diff --git a/src/Avalonia.X11/X11Clipboard.cs b/src/Avalonia.X11/X11Clipboard.cs index 6e18151fae..637d44d617 100644 --- a/src/Avalonia.X11/X11Clipboard.cs +++ b/src/Avalonia.X11/X11Clipboard.cs @@ -14,6 +14,7 @@ namespace Avalonia.X11 private readonly X11Info _x11; private IDataObject _storedDataObject; private IntPtr _handle; + private TaskCompletionSource _storeAtomTcs; private TaskCompletionSource _requestedFormatsTcs; private TaskCompletionSource _requestedDataTcs; private readonly IntPtr[] _textAtoms; @@ -52,6 +53,12 @@ namespace Avalonia.X11 private unsafe void OnEvent(ref XEvent ev) { + if (ev.type == XEventName.SelectionClear) + { + _storeAtomTcs?.TrySetResult(true); + return; + } + if (ev.type == XEventName.SelectionRequest) { var sel = ev.SelectionRequestEvent; @@ -82,18 +89,9 @@ namespace Avalonia.X11 Encoding textEnc; if (target == _x11.Atoms.TARGETS) { - var atoms = new HashSet { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE }; - foreach (var fmt in _storedDataObject.GetDataFormats()) - { - if (fmt == DataFormats.Text) - foreach (var ta in _textAtoms) - atoms.Add(ta); - else - atoms.Add(_x11.Atoms.GetAtom(fmt)); - } - + var atoms = ConvertDataObject(_storedDataObject); XChangeProperty(_x11.Display, window, property, - _x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms.ToArray(), atoms.Count); + _x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms, atoms.Length); return property; } else if(target == _x11.Atoms.SAVE_TARGETS && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero) @@ -252,20 +250,41 @@ namespace Avalonia.X11 return (string)await SendDataRequest(target); } - private void StoreAtomsInClipboardManager(IntPtr[] atoms) + + private IntPtr[] ConvertDataObject(IDataObject data) + { + var atoms = new HashSet { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE }; + foreach (var fmt in data.GetDataFormats()) + { + if (fmt == DataFormats.Text) + foreach (var ta in _textAtoms) + atoms.Add(ta); + else + atoms.Add(_x11.Atoms.GetAtom(fmt)); + } + return atoms.ToArray(); + } + + private Task StoreAtomsInClipboardManager(IDataObject data) { if (_x11.Atoms.CLIPBOARD_MANAGER != IntPtr.Zero && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero) { var clipboardManager = XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER); if (clipboardManager != IntPtr.Zero) - { + { + if (_storeAtomTcs == null || _storeAtomTcs.Task.IsCompleted) + _storeAtomTcs = new TaskCompletionSource(); + + var atoms = ConvertDataObject(data); XChangeProperty(_x11.Display, _handle, _avaloniaSaveTargetsAtom, _x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms, atoms.Length); XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER, _x11.Atoms.SAVE_TARGETS, _avaloniaSaveTargetsAtom, _handle, IntPtr.Zero); + return _storeAtomTcs.Task; } } + return Task.CompletedTask; } public Task SetTextAsync(string text) @@ -283,9 +302,8 @@ namespace Avalonia.X11 public Task SetDataObjectAsync(IDataObject data) { _storedDataObject = data; - XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero); - StoreAtomsInClipboardManager(_textAtoms); - return Task.CompletedTask; + XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero); + return StoreAtomsInClipboardManager(data); } public async Task GetFormatsAsync() diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs index 18f860a1a8..86ef7879a5 100644 --- a/src/Avalonia.X11/X11Structs.cs +++ b/src/Avalonia.X11/X11Structs.cs @@ -1109,7 +1109,7 @@ namespace Avalonia.X11 { public override string ToString () { - return string.Format("MotifWmHints new XamlDocumentTypeBuilderProvider( + builder, + compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true), + document.RootInstance is null ? + compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true) : + null))); originalDocuments.Add(document); } @@ -242,9 +252,8 @@ namespace Avalonia.Markup.Xaml.XamlIl var createdTypes = parsedDocuments.Select(document => { - compiler.Compile(document.XamlDocument, document.TypeBuilder, document.PopulateMethod, - document.BuildMethod, document.Uri, document.FileSource); - return _sreTypeSystem.GetType(document.TypeBuilder.CreateType()); + compiler.Compile(document.XamlDocument, document.TypeBuilderProvider, document.Uri, document.FileSource); + return _sreTypeSystem.GetType(document.TypeBuilderProvider.TypeBuilder.CreateType()); }).ToArray(); clrPropertyBuilder.CreateTypeInfo(); diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs index 23c67df810..af34d55a3d 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -179,9 +179,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return parsed; } - public void Compile(XamlDocument document, IXamlTypeBuilder tb, IXamlMethodBuilder populateMethod, IXamlMethodBuilder buildMethod, string baseUri, IFileSource fileSource) + public void Compile(XamlDocument document, XamlDocumentTypeBuilderProvider typeBuilderProvider, string baseUri, IFileSource fileSource) { - Compile(document, _contextType, populateMethod, buildMethod, + var tb = typeBuilderProvider.TypeBuilder; + + Compile(document, _contextType, typeBuilderProvider.PopulateMethod, typeBuilderProvider.BuildMethod, _configuration.TypeMappings.XmlNamespaceInfoProvider == null ? null : tb.DefineSubType(_configuration.WellKnownTypes.Object, diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs index 8e04a7d467..f135ed5ffb 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using System.Linq; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; using XamlX.Ast; -using XamlX.IL.Emitters; -using XamlX.Transform.Transformers; using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers; @@ -24,7 +22,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer var mergeResourceIncludeType = context.GetAvaloniaTypes().MergeResourceInclude; var mergeSourceNodes = new List(); - var mergedResourceWasAdded = false; foreach (var manipulationNode in resourceDictionaryManipulation.Children.ToArray()) { void ProcessXamlPropertyAssignmentNode(XamlManipulationGroupNode parent, XamlPropertyAssignmentNode assignmentNode) @@ -39,7 +36,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer { parent.Children.Remove(assignmentNode); mergeSourceNodes.Add(sourceAssignmentNode); - mergedResourceWasAdded = true; } else { @@ -85,25 +81,29 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer return context.ParseError( $"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node); } - + var targetDocument = context.Documents.FirstOrDefault(d => - string.Equals(d.Uri, originalAssetPath, StringComparison.InvariantCultureIgnoreCase)) - ?.XamlDocument.Root as XamlValueWithManipulationNode; - if (targetDocument is null) + string.Equals(d.Uri, originalAssetPath, StringComparison.InvariantCultureIgnoreCase)); + if (targetDocument?.XamlDocument.Root is not XamlValueWithManipulationNode targetDocumentRoot) { return context.ParseError( $"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node); } - var singleRootObject = ((XamlManipulationGroupNode)targetDocument.Manipulation) + var singleRootObject = ((XamlManipulationGroupNode)targetDocumentRoot.Manipulation) .Children.OfType().Single(); if (singleRootObject.Type != resourceDictionaryType) { return context.ParseError( - $"MergeResourceInclude can only include another ResourceDictionary", propertyNode, node); + "MergeResourceInclude can only include another ResourceDictionary", propertyNode, node); } manipulationGroup.Add(singleRootObject.Manipulation); + + if (targetDocument.Usage == XamlDocumentUsage.Unknown) + { + targetDocument.Usage = XamlDocumentUsage.Merged; + } } // Order of resources is defined by ResourceDictionary.TryGetResource. diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs index b859b3ed59..9b5c59682f 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs @@ -1,5 +1,4 @@ -using System; -using XamlX.Ast; +using XamlX.Ast; using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; @@ -14,4 +13,5 @@ internal interface IXamlDocumentResource IXamlMethod PopulateMethod { get; } IFileSource? FileSource { get; } XamlDocument XamlDocument { get; } + XamlDocumentUsage Usage { get; set; } } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs index 932fe067af..0dab80d743 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs @@ -1,6 +1,5 @@ using System; using XamlX.Ast; -using XamlX.IL; using XamlX.TypeSystem; #nullable enable @@ -8,24 +7,23 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; internal class XamlDocumentResource : IXamlDocumentResource { + private readonly Func _createTypeBuilderProvider; + private XamlDocumentTypeBuilderProvider? _typeBuilderProvider; + public XamlDocumentResource( XamlDocument xamlDocument, string? uri, IFileSource? fileSource, IXamlType? classType, bool isPublic, - IXamlTypeBuilder typeBuilder, - IXamlMethodBuilder populateMethod, - IXamlMethodBuilder? buildMethod) + Func createTypeBuilderProvider) { + _createTypeBuilderProvider = createTypeBuilderProvider; XamlDocument = xamlDocument; Uri = uri; FileSource = fileSource; ClassType = classType; IsPublic = isPublic; - TypeBuilder = typeBuilder; - PopulateMethod = populateMethod; - BuildMethod = buildMethod; } public XamlDocument XamlDocument { get; } @@ -34,10 +32,22 @@ internal class XamlDocumentResource : IXamlDocumentResource public IXamlType? ClassType { get; } public bool IsPublic { get; } - public IXamlTypeBuilder TypeBuilder { get; } - public IXamlMethodBuilder PopulateMethod { get; } - public IXamlMethodBuilder? BuildMethod { get; } + public XamlDocumentUsage Usage { get; set; } + + public XamlDocumentTypeBuilderProvider TypeBuilderProvider + { + get + { + if (_typeBuilderProvider is null) + { + _typeBuilderProvider = _createTypeBuilderProvider(); + Usage = XamlDocumentUsage.Used; + } + + return _typeBuilderProvider; + } + } - IXamlMethod? IXamlDocumentResource.BuildMethod => BuildMethod; - IXamlMethod IXamlDocumentResource.PopulateMethod => PopulateMethod; + IXamlMethod? IXamlDocumentResource.BuildMethod => TypeBuilderProvider.BuildMethod; + IXamlMethod IXamlDocumentResource.PopulateMethod => TypeBuilderProvider.PopulateMethod; } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs new file mode 100644 index 0000000000..4701403fb9 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs @@ -0,0 +1,23 @@ +#nullable enable + +using XamlX.IL; +using XamlX.TypeSystem; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; + +internal sealed class XamlDocumentTypeBuilderProvider +{ + public XamlDocumentTypeBuilderProvider( + IXamlTypeBuilder typeBuilder, + IXamlMethodBuilder populateMethod, + IXamlMethodBuilder? buildMethod) + { + TypeBuilder = typeBuilder; + PopulateMethod = populateMethod; + BuildMethod = buildMethod; + } + + public IXamlTypeBuilder TypeBuilder { get; } + public IXamlMethodBuilder PopulateMethod { get; } + public IXamlMethodBuilder? BuildMethod { get; } +} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs new file mode 100644 index 0000000000..ec5b931548 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs @@ -0,0 +1,8 @@ +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; + +internal enum XamlDocumentUsage +{ + Unknown, + Merged, + Used +} diff --git a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs b/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs index ff8ff69d5e..739f0ac251 100644 --- a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs +++ b/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs @@ -33,8 +33,7 @@ namespace Avalonia.Win32.Automation return null; var p = WindowImpl.PointToClient(new PixelPoint((int)x, (int)y)); - var peer = (WindowBaseAutomationPeer)Peer; - var found = InvokeSync(() => peer.GetPeerFromPoint(p)); + var found = InvokeSync(() => Peer.GetPeerFromPoint(p)); var result = GetOrCreate(found) as IRawElementProviderFragment; return result; } diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs index e207bc23ab..85cab1d18e 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs @@ -38,12 +38,10 @@ namespace Avalonia.Win32.OpenGl [MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))] [MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))] - [MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))] private static bool Initialize() => _initialized ??= InitializeCore(); [MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))] [MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))] - [MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))] private static bool InitializeCore() { Dispatcher.UIThread.VerifyAccess(); @@ -74,9 +72,9 @@ namespace Avalonia.Win32.OpenGl Marshal.GetDelegateForFunctionPointer( wglGetProcAddress("wglChoosePixelFormatARB")); - s_glDebugMessageCallback = - Marshal.GetDelegateForFunctionPointer( - wglGetProcAddress("glDebugMessageCallback")); + s_glDebugMessageCallback = wglGetProcAddress("glDebugMessageCallback") is { } setDebugCallback && setDebugCallback != default ? + Marshal.GetDelegateForFunctionPointer(setDebugCallback) : + null; var formats = new int[1]; @@ -144,8 +142,12 @@ namespace Avalonia.Win32.OpenGl }); } - using(new WglRestoreContext(dc, context, null)) - s_glDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero); + if (s_glDebugMessageCallback is not null) + { + using (new WglRestoreContext(dc, context, null)) + s_glDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero); + } + if (context != IntPtr.Zero) return new WglContext(shareContext, version, context, window, dc, _defaultPixelFormat, _defaultPfd); diff --git a/src/Windows/Avalonia.Win32/Win32GlManager.cs b/src/Windows/Avalonia.Win32/Win32GlManager.cs index b3760a37e1..ebb708f4c5 100644 --- a/src/Windows/Avalonia.Win32/Win32GlManager.cs +++ b/src/Windows/Avalonia.Win32/Win32GlManager.cs @@ -20,6 +20,10 @@ static class Win32GlManager { AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl); } + if (gl is IPlatformGraphicsOpenGlContextFactory openGlFactory) + { + AvaloniaLocator.CurrentMutable.Bind().ToConstant(openGlFactory); + } return gl; } diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs index bef5a55b06..98e1077885 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs @@ -28,6 +28,9 @@ namespace Avalonia.Win32.WinRT.Composition public static readonly Guid CLSID_D2D1Border = new Guid(0x2A2D49C0, 0x4ACF, 0x43C7, 0x8C, 0x6A, 0x7C, 0x4A, 0x27, 0x87, 0x4D, 0x27); + public static readonly Guid CLSID_D2D1Opacity = + new Guid("811d79a4-de28-4454-8094-c64685f8bd4c"); + public static readonly Guid CLSID_D2D1Brightness = new Guid(0x8CEA8D1E, 0x77B0, 0x4986, 0xB3, 0xB9, 0x2F, 0x0C, 0x0E, 0xAE, 0x78, 0x87); diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs index 1a922b4acd..10dbcfcc6b 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs @@ -52,6 +52,110 @@ namespace Avalonia.Win32.WinRT.Composition _sources = null; } } + + class BorderEffect : WinUIEffectBase + { + private readonly int _x; + private readonly int _y; + public override Guid EffectId => D2DEffects.CLSID_D2D1Border; + public override uint PropertyCount => 2; + + public BorderEffect(int x, int y, params IGraphicsEffectSource[] _sources):base(_sources) + { + _x = x; + _y = y; + } + + public override IPropertyValue? GetProperty(uint index) + { + if (index == 0) + return new WinRTPropertyValue((uint)_x); + if (index == 1) + return new WinRTPropertyValue((uint)_y); + return null; + } + } + + class BlendEffect : WinUIEffectBase + { + private readonly int _mode; + + public BlendEffect(int mode, params IGraphicsEffectSource[] _sources) : base(_sources) + { + _mode = mode; + } + + public override Guid EffectId => D2DEffects.CLSID_D2D1Blend; + public override uint PropertyCount => 1; + + public override IPropertyValue? GetProperty(uint index) + { + if (index == 0) + return new WinRTPropertyValue((uint)_mode); + return null; + } + } + + class CompositeStepEffect : WinUIEffectBase + { + private readonly float _mode; + + public CompositeStepEffect(int mode, params IGraphicsEffectSource[] _sources) : base(_sources) + { + _mode = mode; + } + + public override Guid EffectId => D2DEffects.CLSID_D2D1Composite; + public override uint PropertyCount => 1; + + public override IPropertyValue? GetProperty(uint index) + { + if (index == 0) + return new WinRTPropertyValue((uint)_mode); + return null; + } + } + + class OpacityEffect : WinUIEffectBase + { + private readonly float _opacity; + + public OpacityEffect(float opacity, params IGraphicsEffectSource[] _sources) : base(_sources) + { + _opacity = opacity; + } + + public override Guid EffectId => D2DEffects.CLSID_D2D1Opacity; + public override uint PropertyCount => 1; + + public override IPropertyValue? GetProperty(uint index) + { + if (index == 0) + return new WinRTPropertyValue(_opacity); + return null; + } + } + + class ColorSourceEffect : WinUIEffectBase + { + private readonly float[] _color; + + public ColorSourceEffect(float[] color) + { + _color = color; + } + + public override Guid EffectId => D2DEffects.CLSID_D2D1Flood; + public override uint PropertyCount => 1; + + public override IPropertyValue? GetProperty(uint index) + { + if (index == 0) + return new WinRTPropertyValue(_color); + return null; + } + } + internal class WinUIGaussianBlurEffect : WinUIEffectBase { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs index 2f22ba99f9..d720e525d3 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs @@ -12,7 +12,8 @@ internal class WinUiCompositedWindow : IDisposable public EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo WindowInfo { get; } private readonly WinUiCompositionShared _shared; private readonly ICompositionRoundedRectangleGeometry? _compositionRoundedRectangleGeometry; - private readonly IVisual? _mica; + private readonly IVisual? _micaLight; + private readonly IVisual? _micaDark; private readonly IVisual _blur; private readonly IVisual _visual; private PixelSize _size; @@ -25,7 +26,8 @@ internal class WinUiCompositedWindow : IDisposable { _compositionRoundedRectangleGeometry?.Dispose(); _blur.Dispose(); - _mica?.Dispose(); + _micaLight?.Dispose(); + _micaDark?.Dispose(); _visual.Dispose(); _surfaceBrush.Dispose(); _target.Dispose(); @@ -50,14 +52,20 @@ internal class WinUiCompositedWindow : IDisposable _target.SetRoot(containerVisual); _blur = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.BlurBrush); - if (shared.MicaBrush != null) + if (shared.MicaBrushLight != null) { - _mica = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrush); - containerChildren.InsertAtTop(_mica); + _micaLight = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrushLight); + containerChildren.InsertAtTop(_micaLight); + } + + if (shared.MicaBrushDark != null) + { + _micaDark = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrushDark); + containerChildren.InsertAtTop(_micaDark); } _compositionRoundedRectangleGeometry = - WinUiCompositionUtils.ClipVisual(shared.Compositor, backdropCornerRadius, _blur, _mica); + WinUiCompositionUtils.ClipVisual(shared.Compositor, backdropCornerRadius, _blur, _micaLight, _micaDark); containerChildren.InsertAtTop(_blur); using var spriteVisual = shared.Compositor.CreateSpriteVisual(); @@ -68,9 +76,6 @@ internal class WinUiCompositedWindow : IDisposable using var compositionBrush = _surfaceBrush.QueryInterface(); spriteVisual.SetBrush(compositionBrush); _target.SetRoot(containerVisual); - - - } public void SetSurface(ICompositionSurface surface) => _surfaceBrush.SetSurface(surface); @@ -79,12 +84,13 @@ internal class WinUiCompositedWindow : IDisposable { lock (_shared.SyncRoot) { - _blur.SetIsVisible(blurEffect == BlurEffect.Acrylic - || blurEffect == BlurEffect.Mica && _mica == null ? + || (blurEffect == BlurEffect.MicaLight && _micaLight == null) || + (blurEffect == BlurEffect.MicaDark && _micaDark == null) ? 1 : 0); - _mica?.SetIsVisible(blurEffect == BlurEffect.Mica ? 1 : 0); + _micaLight?.SetIsVisible(blurEffect == BlurEffect.MicaLight ? 1 : 0); + _micaDark?.SetIsVisible(blurEffect == BlurEffect.MicaDark ? 1 : 0); } } diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs index b3a328d097..7a775afb3a 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs @@ -9,7 +9,8 @@ internal class WinUiCompositionShared : IDisposable public ICompositor5 Compositor5 { get; } public ICompositorDesktopInterop DesktopInterop { get; } public ICompositionBrush BlurBrush { get; } - public ICompositionBrush? MicaBrush { get; } + public ICompositionBrush? MicaBrushLight { get; } + public ICompositionBrush? MicaBrushDark { get; } public object SyncRoot { get; } = new(); public static readonly Version MinWinCompositionVersion = new(10, 0, 17134); @@ -21,14 +22,16 @@ internal class WinUiCompositionShared : IDisposable Compositor = compositor.CloneReference(); Compositor5 = compositor.QueryInterface(); BlurBrush = WinUiCompositionUtils.CreateAcrylicBlurBackdropBrush(compositor); - MicaBrush = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor); + MicaBrushLight = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor, 242, 0.6f); + MicaBrushDark = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor, 32, 0.8f); DesktopInterop = compositor.QueryInterface(); } public void Dispose() { BlurBrush.Dispose(); - MicaBrush?.Dispose(); + MicaBrushLight?.Dispose(); + MicaBrushDark?.Dispose(); DesktopInterop.Dispose(); Compositor.Dispose(); Compositor5.Dispose(); diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs index 7b970868df..29c1e1fe27 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; using MicroCom.Runtime; @@ -5,16 +6,72 @@ namespace Avalonia.Win32.WinRT.Composition; internal static class WinUiCompositionUtils { - public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor) + public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor, float color, float opacity) { if (Win32Platform.WindowsVersion.Build < 22000) return null; + using var backDropParameterFactory = + NativeWinRTMethods.CreateActivationFactory( + "Windows.UI.Composition.CompositionEffectSourceParameter"); + + + var tint = new[] { color / 255f, color / 255f, color / 255f, 255f / 255f }; + + using var tintColorEffect = new ColorSourceEffect(tint); + + + using var tintOpacityEffect = new OpacityEffect(1.0f, tintColorEffect); + using var tintOpacityEffectFactory = compositor.CreateEffectFactory(tintOpacityEffect); + using var tintOpacityEffectBrushEffect = tintOpacityEffectFactory.CreateBrush(); + using var tintOpacityEffectBrush = tintOpacityEffectBrushEffect.QueryInterface(); + + using var luminosityColorEffect = new ColorSourceEffect(tint); + + using var luminosityOpacityEffect = new OpacityEffect(opacity, luminosityColorEffect); + using var luminosityOpacityEffectFactory = compositor.CreateEffectFactory(luminosityOpacityEffect); + using var luminosityOpacityEffectBrushEffect = luminosityOpacityEffectFactory.CreateBrush(); + using var luminosityOpacityEffectBrush = + luminosityOpacityEffectBrushEffect.QueryInterface(); + using var compositorWithBlurredWallpaperBackdropBrush = compositor.QueryInterface(); using var blurredWallpaperBackdropBrush = compositorWithBlurredWallpaperBackdropBrush?.TryCreateBlurredWallpaperBackdropBrush(); - return blurredWallpaperBackdropBrush?.QueryInterface(); + using var micaBackdropBrush = blurredWallpaperBackdropBrush?.QueryInterface(); + + + using var backgroundParameterAsSource = + GetParameterSource("Background", backDropParameterFactory, out var backgroundHandle); + using var foregroundParameterAsSource = + GetParameterSource("Foreground", backDropParameterFactory, out var foregroundHandle); + + using var luminosityBlendEffect = + new BlendEffect(23, backgroundParameterAsSource, foregroundParameterAsSource); + using var luminosityBlendEffectFactory = compositor.CreateEffectFactory(luminosityBlendEffect); + using var luminosityBlendEffectBrush = luminosityBlendEffectFactory.CreateBrush(); + using var luminosityBlendEffectBrush1 = luminosityBlendEffectBrush.QueryInterface(); + luminosityBlendEffectBrush.SetSourceParameter(backgroundHandle, micaBackdropBrush); + luminosityBlendEffectBrush.SetSourceParameter(foregroundHandle, luminosityOpacityEffectBrush); + + + using var backgroundParameterAsSource1 = + GetParameterSource("Background", backDropParameterFactory, out var backgroundHandle1); + using var foregroundParameterAsSource1 = + GetParameterSource("Foreground", backDropParameterFactory, out var foregroundHandle1); + + using var colorBlendEffect = + new BlendEffect(22, backgroundParameterAsSource1, foregroundParameterAsSource1); + using var colorBlendEffectFactory = compositor.CreateEffectFactory(colorBlendEffect); + using var colorBlendEffectBrush = colorBlendEffectFactory.CreateBrush(); + colorBlendEffectBrush.SetSourceParameter(backgroundHandle1, luminosityBlendEffectBrush1); + colorBlendEffectBrush.SetSourceParameter(foregroundHandle1, tintOpacityEffectBrush); + + + // colorBlendEffectBrush.SetSourceParameter(backgroundHandle, micaBackdropBrush); + + using var micaBackdropBrush1 = colorBlendEffectBrush.QueryInterface(); + return micaBackdropBrush1.CloneReference(); } public static ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor) @@ -97,4 +154,15 @@ internal static class WinUiCompositionUtils brush?.Dispose(); } } + + private static IGraphicsEffectSource GetParameterSource(string name, + ICompositionEffectSourceParameterFactory backDropParameterFactory, out IntPtr handle) + { + var backdropString = new HStringInterop(name); + var backDropParameter = + backDropParameterFactory.Create(backdropString.Handle); + var backDropParameterAsSource = backDropParameter.QueryInterface(); + handle = backdropString.Handle; + return backDropParameterAsSource; + } } diff --git a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs index a3918d9ae6..5f2e752af8 100644 --- a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs +++ b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs @@ -4,7 +4,8 @@ { None, Acrylic, - Mica + MicaLight, + MicaDark } internal interface IBlurHost diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs index 684e7ff7b5..8874902d4e 100644 --- a/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs +++ b/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Avalonia.Win32.WinRT @@ -16,7 +17,15 @@ namespace Avalonia.Win32.WinRT UInt32 = u; Type = PropertyType.UInt32; } - + + public WinRTPropertyValue(float[] uiColor) + { + Type = PropertyType.SingleArray; + _singleArray = uiColor; + } + + private readonly float[]? _singleArray; + public PropertyType Type { get; } public int IsNumericScalar { get; } public byte UInt8 { get; } @@ -62,7 +71,17 @@ namespace Avalonia.Win32.WinRT public unsafe ulong* GetUInt64Array(uint* __valueSize) => throw NotImplemented; - public unsafe float* GetSingleArray(uint* __valueSize) => throw NotImplemented; + public unsafe float* GetSingleArray(uint* __valueSize) + { + if (_singleArray == null) + throw NotImplemented; + *__valueSize = (uint)_singleArray.Length; + var allocCoTaskMem = Marshal.AllocCoTaskMem(_singleArray.Length * Unsafe.SizeOf()); + Marshal.Copy(_singleArray, 0, allocCoTaskMem, _singleArray.Length); + float* s = (float*)allocCoTaskMem; + + return s; + } public unsafe double* GetDoubleArray(uint* __valueSize) => throw NotImplemented; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 057cdb2db0..044c2cad67 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -106,6 +106,7 @@ namespace Avalonia.Win32 private static POINTER_PEN_INFO[]? s_historyPenInfos; private static POINTER_INFO[]? s_historyInfos; private static MOUSEMOVEPOINT[]? s_mouseHistoryInfos; + private PlatformThemeVariant _currentThemeVariant; public WindowImpl() { @@ -474,7 +475,12 @@ namespace Avalonia.Win32 return; SetUseHostBackdropBrush(false); - _blurHost?.SetBlur(BlurEffect.Mica); + _blurHost?.SetBlur(_currentThemeVariant switch + { + PlatformThemeVariant.Light => BlurEffect.MicaLight, + PlatformThemeVariant.Dark => BlurEffect.MicaDark, + _ => throw new ArgumentOutOfRangeException() + }); } private void SetAccentState(AccentState state) @@ -778,6 +784,7 @@ namespace Avalonia.Win32 public unsafe void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { + _currentThemeVariant = themeVariant; if (Win32Platform.WindowsVersion.Build >= 22000) { var pvUseBackdropBrush = themeVariant == PlatformThemeVariant.Dark ? 1 : 0; @@ -786,6 +793,10 @@ namespace Avalonia.Win32 (int)DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE, &pvUseBackdropBrush, sizeof(int)); + if (TransparencyLevel == WindowTransparencyLevel.Mica) + { + SetTransparencyMica(Win32Platform.WindowsVersion); + } } } diff --git a/src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj b/src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj index c27801db61..05d72618a9 100644 --- a/src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj +++ b/src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj @@ -5,6 +5,7 @@ Avalonia.Analyzers true true + false true diff --git a/src/tools/Avalonia.Generators/Avalonia.Generators.csproj b/src/tools/Avalonia.Generators/Avalonia.Generators.csproj index cd1e2fcaba..c6992f9438 100644 --- a/src/tools/Avalonia.Generators/Avalonia.Generators.csproj +++ b/src/tools/Avalonia.Generators/Avalonia.Generators.csproj @@ -5,6 +5,7 @@ Avalonia.Generators $(DefineConstants);XAMLX_INTERNAL true + false true true diff --git a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs index 8d45afafa7..fa20be721c 100644 --- a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs +++ b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using Avalonia.Generators.Common.Domain; using Microsoft.CodeAnalysis; @@ -31,7 +32,7 @@ internal class AvaloniaNameGenerator : INameGenerator _code = code; } - public IReadOnlyList GenerateNameReferences(IEnumerable additionalFiles) + public IEnumerable GenerateNameReferences(IEnumerable additionalFiles, CancellationToken cancellationToken) { var resolveViews = from file in additionalFiles @@ -39,7 +40,8 @@ internal class AvaloniaNameGenerator : INameGenerator file.Path.EndsWith(".paml") || file.Path.EndsWith(".axaml")) && _pathPattern.Matches(file.Path) - let xaml = file.GetText()!.ToString() + let xaml = file.GetText(cancellationToken)?.ToString() + where xaml != null let view = _classes.ResolveView(xaml) where view != null && _namespacePattern.Matches(view.Namespace) select view; @@ -51,7 +53,7 @@ internal class AvaloniaNameGenerator : INameGenerator let fileName = ResolveViewFileName(view, _naming) select new GeneratedPartialClass(fileName, code); - return query.ToList(); + return query; } private static string ResolveViewFileName(ResolvedView view, ViewFileNamingStrategy strategy) => strategy switch diff --git a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs index fa1dcde064..407cf4f35f 100644 --- a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs +++ b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs @@ -22,8 +22,19 @@ public class AvaloniaNameSourceGenerator : ISourceGenerator return; } - var partials = generator.GenerateNameReferences(context.AdditionalFiles); - foreach (var (fileName, content) in partials) context.AddSource(fileName, content); + var partials = generator.GenerateNameReferences(context.AdditionalFiles, context.CancellationToken); + foreach (var (fileName, content) in partials) + { + if(context.CancellationToken.IsCancellationRequested) + { + break; + } + + context.AddSource(fileName, content); + } + } + catch (OperationCanceledException) + { } catch (Exception exception) { diff --git a/src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs b/src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs index 922d800332..5b44de43c1 100644 --- a/src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs +++ b/src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; +using System.Threading; using Microsoft.CodeAnalysis; namespace Avalonia.Generators.NameGenerator; internal interface INameGenerator { - IReadOnlyList GenerateNameReferences(IEnumerable additionalFiles); + IEnumerable GenerateNameReferences(IEnumerable additionalFiles, CancellationToken cancellationToken); } internal record GeneratedPartialClass(string FileName, string Content); diff --git a/tests/Avalonia.Base.UnitTests/Utilities/InlineDictionaryTests.cs b/tests/Avalonia.Base.UnitTests/Utilities/InlineDictionaryTests.cs new file mode 100644 index 0000000000..af47d2726a --- /dev/null +++ b/tests/Avalonia.Base.UnitTests/Utilities/InlineDictionaryTests.cs @@ -0,0 +1,53 @@ +#nullable enable + +using System.Collections.Generic; +using Avalonia.Utilities; +using Xunit; + +namespace Avalonia.Base.UnitTests.Utilities; + +public class InlineDictionaryTests +{ + [Fact] + public void Enumeration_After_Add_With_Internal_Array_Works() + { + var dic = new InlineDictionary(); + dic.Add("foo", 1); + dic.Add("bar", 2); + dic.Add("baz", 3); + + Assert.Equal( + new[] { + new KeyValuePair("foo", 1), + new KeyValuePair("bar", 2), + new KeyValuePair("baz", 3) + }, + dic); + } + + [Fact] + public void Enumeration_After_Remove_With_Internal_Array_Works() + { + var dic = new InlineDictionary(); + dic.Add("foo", 1); + dic.Add("bar", 2); + dic.Add("baz", 3); + + Assert.Equal( + new[] { + new KeyValuePair("foo", 1), + new KeyValuePair("bar", 2), + new KeyValuePair("baz", 3) + }, + dic); + + dic.Remove("bar"); + + Assert.Equal( + new[] { + new KeyValuePair("foo", 1), + new KeyValuePair("baz", 3) + }, + dic); + } +} diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs index e9b8895174..9ea12c62fb 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs @@ -268,6 +268,22 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.True(called); } + [Fact] + public void Handles_Null_SelectedItem_When_SelectedValueBinding_Assigned() + { + // Issue #11220 + var items = new object[] { null }; + var sic = new SelectingItemsControl + { + ItemsSource = items, + SelectedIndex = 0, + SelectedValueBinding = new Binding("Name"), + Template = Template() + }; + + Assert.Null(sic.SelectedValue); + } + private static FuncControlTemplate Template() { return new FuncControlTemplate((control, scope) => diff --git a/tests/Avalonia.UnitTests/TestRoot.cs b/tests/Avalonia.UnitTests/TestRoot.cs index fcfd845602..f62afaf74d 100644 --- a/tests/Avalonia.UnitTests/TestRoot.cs +++ b/tests/Avalonia.UnitTests/TestRoot.cs @@ -35,7 +35,6 @@ namespace Avalonia.UnitTests public TestRoot(Control child) : this(false, child) { - Child = child; } public TestRoot(bool useGlobalStyles, Control child)