diff --git a/Documentation/build.md b/Documentation/build.md index 9f5436e68e..ddd38be887 100644 --- a/Documentation/build.md +++ b/Documentation/build.md @@ -1,6 +1,6 @@ # Windows -Avalonia requires at least Visual Studio 2019 and .NET Core SDK 3.1 to build on Windows. +Avalonia requires at least Visual Studio 2022 and dotnet 6 SDK 6.0.100 to build on all platforms. ### Clone the Avalonia repository @@ -16,7 +16,7 @@ Go to https://dotnet.microsoft.com/download/visual-studio-sdks and install the l ### Open in Visual Studio -Open the `Avalonia.sln` solution in Visual Studio 2019 or newer. The free Visual Studio Community edition works fine. Build and run the `Samples\ControlCatalog.Desktop` or `ControlCatalog.NetCore` project to see the sample application. +Open the `Avalonia.sln` solution in Visual Studio 2022 or newer. The free Visual Studio Community edition works fine. Build and run the `Samples\ControlCatalog.Desktop` or `ControlCatalog.NetCore` project to see the sample application. ### Troubleshooting @@ -43,27 +43,6 @@ Go to https://www.microsoft.com/net/core and follow the instructions for your OS The build process needs [Xcode](https://developer.apple.com/xcode/) to build the native library. Following the install instructions at the [Xcode](https://developer.apple.com/xcode/) website to properly install. -Linux operating systems ship with their own respective package managers however we will use [Homebrew](https://brew.sh/) to manage packages on macOS. To install follow the instructions [here](https://docs.brew.sh/Installation). - -### Install CastXML (pre Nov 2020) - -Avalonia requires [CastXML](https://github.com/CastXML/CastXML) for XML processing during the build process. The easiest way to install this is via the operating system's package managers, such as below. - -On macOS: -``` -brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8a004a91a7fcd3f6620d5b01b6541ff0a640ffba/Formula/castxml.rb -``` - -On Debian based Linux (Debian, Ubuntu, Mint, etc): -``` -sudo apt install castxml -``` - -On Red Hat based Linux (Fedora, CentOS, RHEL, etc) using `yum` (`dnf` takes same arguments though): -``` -sudo yum install castxml -``` - ### Clone the Avalonia repository diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 11ef36d43f..9fa79ec5ba 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,21 +1,28 @@ +variables: + MSBuildEnableWorkloadResolver: 'false' + jobs: - job: Linux pool: vmImage: 'ubuntu-20.04' steps: - - task: CmdLine@2 - displayName: 'Install Nuke' + - task: UseDotNet@2 + displayName: 'Use .NET Core SDK 3.1.414' inputs: - script: | - dotnet tool install --global Nuke.GlobalTool --version 0.24.0 + version: 3.1.414 + + - task: UseDotNet@2 + displayName: 'Use .NET Core SDK 6.0.100' + inputs: + version: 6.0.100 + - task: CmdLine@2 - displayName: 'Run Nuke' + displayName: 'Run Build' inputs: script: | - export PATH="$PATH:$HOME/.dotnet/tools" dotnet --info printenv - nuke --target CiAzureLinux --configuration=Release + ./build.sh --target CiAzureLinux --configuration=Release - task: PublishTestResults@2 inputs: @@ -23,6 +30,7 @@ jobs: testResultsFiles: '$(Build.SourcesDirectory)/artifacts/test-results/*.trx' condition: not(canceled()) + - job: macOS variables: SolutionDir: '$(Build.SourcesDirectory)' @@ -30,10 +38,15 @@ jobs: vmImage: 'macOS-10.15' steps: - task: UseDotNet@2 - displayName: 'Use .NET Core SDK 3.1.401' + displayName: 'Use .NET Core SDK 3.1.414' inputs: - version: 3.1.401 + version: 3.1.414 + - task: UseDotNet@2 + displayName: 'Use .NET Core SDK 6.0.100' + inputs: + version: 6.0.100 + - task: CmdLine@2 displayName: 'Install Mono 5.18' inputs: @@ -45,7 +58,8 @@ jobs: displayName: 'Generate avalonia-native' inputs: script: | - cd src/tools/MicroComGenerator; dotnet run -i ../../Avalonia.Native/avn.idl --cpp ../../../native/Avalonia.Native/inc/avalonia-native.h + export PATH="`pwd`/sdk:$PATH" + cd src/tools/MicroComGenerator; dotnet run -f net6.0 -i ../../Avalonia.Native/avn.idl --cpp ../../../native/Avalonia.Native/inc/avalonia-native.h - task: Xcode@5 inputs: @@ -58,13 +72,7 @@ jobs: args: '-derivedDataPath ./' - task: CmdLine@2 - displayName: 'Install Nuke' - inputs: - script: | - dotnet tool install --global Nuke.GlobalTool --version 0.24.0 - - - task: CmdLine@2 - displayName: 'Run Nuke' + displayName: 'Run Build' inputs: script: | export COREHOST_TRACE=0 @@ -72,10 +80,8 @@ jobs: export DOTNET_CLI_TELEMETRY_OPTOUT=1 which dotnet dotnet --info - export PATH="$PATH:$HOME/.dotnet/tools" - dotnet --info printenv - nuke --target CiAzureOSX --configuration Release --skip-previewer + ./build.sh --target CiAzureOSX --configuration Release --skip-previewer - task: PublishTestResults@2 inputs: @@ -102,9 +108,14 @@ jobs: SolutionDir: '$(Build.SourcesDirectory)' steps: - task: UseDotNet@2 - displayName: 'Use .NET Core SDK 3.1.401' + displayName: 'Use .NET Core SDK 3.1.414' + inputs: + version: 3.1.414 + + - task: UseDotNet@2 + displayName: 'Use .NET Core SDK 6.0.100' inputs: - version: 3.1.401 + version: 6.0.100 - task: CmdLine@2 displayName: 'Install Nuke' diff --git a/build.sh b/build.sh index bd162fab9b..9532b4fbe0 100755 --- a/build.sh +++ b/build.sh @@ -20,55 +20,11 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) ########################################################################### BUILD_PROJECT_FILE="$SCRIPT_DIR/nukebuild/_build.csproj" -TEMP_DIRECTORY="$SCRIPT_DIR//.tmp" - -DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" -DOTNET_INSTALL_URL="https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.sh" -DOTNET_CHANNEL="Current" export DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 export NUGET_XMLDOC_MODE="skip" -########################################################################### -# EXECUTION -########################################################################### - -function FirstJsonValue { - perl -nle 'print $1 if m{"'$1'": "([^"\-]+)",?}' <<< ${@:2} -} - -# If global.json exists, load expected version -if [ -f "$DOTNET_GLOBAL_FILE" ]; then - DOTNET_VERSION=$(FirstJsonValue "version" $(cat "$DOTNET_GLOBAL_FILE")) - if [ "$DOTNET_VERSION" == "" ]; then - unset DOTNET_VERSION - fi -fi - -# If dotnet is installed locally, and expected version is not set or installation matches the expected version -if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") || "$SKIP_DOTNET_DOWNLOAD" == "1" ]]; then - export DOTNET_EXE="$(command -v dotnet)" -else - DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" - export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" - - # Download install script - DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" - mkdir -p "$TEMP_DIRECTORY" - curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" - chmod +x "$DOTNET_INSTALL_FILE" - - # Install by channel or version - if [ -z ${DOTNET_VERSION+x} ]; then - "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path - else - "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path - fi -fi - -export PATH=$DOTNET_DIRECTORY:$PATH - -echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)" +dotnet --info -"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]} +dotnet run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]} diff --git a/build/HarfBuzzSharp.props b/build/HarfBuzzSharp.props index 13419eb173..16aab3911e 100644 --- a/build/HarfBuzzSharp.props +++ b/build/HarfBuzzSharp.props @@ -1,6 +1,6 @@  - - + + diff --git a/build/MicroCom.targets b/build/MicroCom.targets index 49d2cdce72..1ed388f689 100644 --- a/build/MicroCom.targets +++ b/build/MicroCom.targets @@ -15,7 +15,7 @@ Inputs="@(AvnComIdl);$(MSBuildThisFileDirectory)../src/tools/MicroComGenerator/**/*.cs" Outputs="%(AvnComIdl.OutputFile)"> - diff --git a/build/SharedVersion.props b/build/SharedVersion.props index 75bada4bfc..7d75901288 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -17,7 +17,6 @@ git $(MSBuildThisFileDirectory)\avalonia.snk true - $(DefineConstants);SIGNED_BUILD diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props index f2e7df36cd..97b29a192d 100644 --- a/build/SkiaSharp.props +++ b/build/SkiaSharp.props @@ -1,6 +1,6 @@  - - + + diff --git a/global.json b/global.json index b2b2da7c4f..e3e652761c 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { - "sdk": { - "version": "3.1.401" - }, + "sdk": { + "version": "6.0.100" + }, "msbuild-sdks": { "Microsoft.Build.Traversal": "1.0.43", "MSBuild.Sdk.Extras": "2.0.54", diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index bd93de0e78..9208848b4c 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -52,7 +52,6 @@ public: [Window setBackingType:NSBackingStoreBuffered]; [Window setOpaque:false]; - [Window setContentView: StandardContainer]; } virtual HRESULT ObtainNSWindowHandle(void** ret) override @@ -125,6 +124,8 @@ public: SetPosition(lastPositionSet); UpdateStyle(); + [Window setContentView: StandardContainer]; + [Window setTitle:_lastTitle]; if(ShouldTakeFocusOnShow() && activate) @@ -205,7 +206,11 @@ public: auto window = Window; Window = nullptr; - [window close]; + try{ + // Seems to throw sometimes on application exit. + [window close]; + } + catch(NSException*){} } return S_OK; @@ -323,6 +328,7 @@ public: BaseEvents->Resized(AvnSize{x,y}, reason); } + [StandardContainer setFrameSize:NSSize{x,y}]; [Window setContentSize:NSSize{x, y}]; } @finally @@ -722,6 +728,7 @@ private: if (cparent->WindowState() == Minimized) cparent->SetWindowState(Normal); + [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; [cparent->Window addChildWindow:Window ordered:NSWindowAbove]; UpdateStyle(); @@ -1487,7 +1494,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent NSRect rect = NSZeroRect; rect.size = newSize; - NSTrackingAreaOptions options = NSTrackingActiveAlways | NSTrackingMouseMoved | NSTrackingEnabledDuringMouseDrag; + NSTrackingAreaOptions options = NSTrackingActiveAlways | NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingEnabledDuringMouseDrag; _area = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nullptr]; [self addTrackingArea:_area]; @@ -2387,17 +2394,27 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent - (void)sendEvent:(NSEvent *)event { - if(_parent != nullptr) + [super sendEvent:event]; + + /// This is to detect non-client clicks. This can only be done on Windows... not popups, hence the dynamic_cast. + if(_parent != nullptr && dynamic_cast(_parent.getRaw()) != nullptr) { switch(event.type) { case NSEventTypeLeftMouseDown: { - auto avnPoint = [AvnView toAvnPoint:[event locationInWindow]]; - auto point = [self translateLocalPoint:avnPoint]; - AvnVector delta; + AvnView* view = _parent->View; + NSPoint windowPoint = [event locationInWindow]; + NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil]; - _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, [event timestamp] * 1000, AvnInputModifiersNone, point, delta); + if (!NSPointInRect(viewPoint, view.bounds)) + { + auto avnPoint = [AvnView toAvnPoint:windowPoint]; + auto point = [self translateLocalPoint:avnPoint]; + AvnVector delta; + + _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, [event timestamp] * 1000, AvnInputModifiersNone, point, delta); + } } break; @@ -2417,8 +2434,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent break; } } - - [super sendEvent:event]; } @end diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index e08ffd0413..b28d3eb700 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -15,6 +15,7 @@ + @@ -36,10 +37,10 @@ - - - - + + MicroComGenerator\%(Filename)%(Extension) + + diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets index de3830ffea..d43a5c1624 100644 --- a/packages/Avalonia/AvaloniaBuildTasks.targets +++ b/packages/Avalonia/AvaloniaBuildTasks.targets @@ -54,6 +54,7 @@ + @@ -87,6 +88,7 @@ $(IntermediateOutputPath)/Avalonia/references $(IntermediateOutputPath)/Avalonia/original.dll false + false + Please read the [contribution guidelines](CONTRIBUTING.md) before submitting a pull request. ## Code of Conduct @@ -71,11 +74,6 @@ For more information see the [.NET Foundation Code of Conduct](https://dotnetfou Avalonia is licenced under the [MIT licence](licence.md). -## Contributors - -This project exists thanks to all the people who contribute. [[Contribute](https://avaloniaui.net/contributing)]. - - ### Backers Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)] @@ -95,7 +93,8 @@ Support this project by becoming a sponsor. Your logo will show up here with a l - + + ## .NET Foundation diff --git a/samples/BindingDemo/BindingDemo.csproj b/samples/BindingDemo/BindingDemo.csproj index d898b737a9..2c6ff74e5e 100644 --- a/samples/BindingDemo/BindingDemo.csproj +++ b/samples/BindingDemo/BindingDemo.csproj @@ -1,7 +1,7 @@  Exe - netcoreapp3.1 + net6.0 diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj index 3c2d2ee359..2d4fc45171 100644 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj @@ -2,7 +2,7 @@ WinExe - netcoreapp3.1 + net6.0 true diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index ee42e7a54b..375345f64e 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -63,11 +63,11 @@ - - + + - - + + diff --git a/samples/ControlCatalog/Pages/ButtonPage.xaml b/samples/ControlCatalog/Pages/ButtonPage.xaml index be114bbbc9..b35c112a68 100644 --- a/samples/ControlCatalog/Pages/ButtonPage.xaml +++ b/samples/ControlCatalog/Pages/ButtonPage.xaml @@ -10,7 +10,7 @@ HorizontalAlignment="Center" Spacing="16"> - + diff --git a/samples/ControlCatalog/Pages/CheckBoxPage.xaml b/samples/ControlCatalog/Pages/CheckBoxPage.xaml index 1359cfa2ef..769ef26699 100644 --- a/samples/ControlCatalog/Pages/CheckBoxPage.xaml +++ b/samples/ControlCatalog/Pages/CheckBoxPage.xaml @@ -11,9 +11,9 @@ Spacing="16"> - Unchecked - Checked - Indeterminate + _Unchecked + _Checked + _Indeterminate Disabled Use filters - - - - - - - - - - + + + + + + + + + + diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml index 392ccb57c3..4d0bd663df 100644 --- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml +++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml @@ -1,17 +1,33 @@ + + + + + + - - diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml b/samples/ControlCatalog/Pages/ListBoxPage.xaml index f515db84d4..b36629fb2a 100644 --- a/samples/ControlCatalog/Pages/ListBoxPage.xaml +++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml @@ -2,9 +2,20 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ControlCatalog.Pages.ListBoxPage"> + + + + ListBox Hosts a collection of ListBoxItem. + Each 5th item is highlighted with nth-child(5n+3) and nth-last-child(5n+4) rules. Multiple diff --git a/samples/ControlCatalog/Pages/RadioButtonPage.xaml b/samples/ControlCatalog/Pages/RadioButtonPage.xaml index bf31c40e2a..408f9c2411 100644 --- a/samples/ControlCatalog/Pages/RadioButtonPage.xaml +++ b/samples/ControlCatalog/Pages/RadioButtonPage.xaml @@ -11,9 +11,9 @@ Spacing="16"> - Option 1 - Option 2 - Option 3 + _Option 1 + O_ption 2 + Op_tion 3 Disabled - + @@ -24,7 +24,7 @@ - @@ -40,7 +40,7 @@ ContentOff="Off" />" - + diff --git a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj index 86d762a5bc..9660d2a90d 100644 --- a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj +++ b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net6.0 diff --git a/samples/Previewer/Previewer.csproj b/samples/Previewer/Previewer.csproj index cfedb7ad9e..c1d14cba26 100644 --- a/samples/Previewer/Previewer.csproj +++ b/samples/Previewer/Previewer.csproj @@ -1,7 +1,7 @@  Exe - netcoreapp3.1 + net6.0 diff --git a/samples/RemoteDemo/RemoteDemo.csproj b/samples/RemoteDemo/RemoteDemo.csproj index 530cad805f..607222c2e2 100644 --- a/samples/RemoteDemo/RemoteDemo.csproj +++ b/samples/RemoteDemo/RemoteDemo.csproj @@ -1,7 +1,7 @@ Exe - netcoreapp3.1 + net6.0 diff --git a/samples/RenderDemo/RenderDemo.csproj b/samples/RenderDemo/RenderDemo.csproj index 0d33b4c111..eed6fa9e89 100644 --- a/samples/RenderDemo/RenderDemo.csproj +++ b/samples/RenderDemo/RenderDemo.csproj @@ -1,7 +1,7 @@  Exe - netcoreapp3.1 + net6.0 diff --git a/samples/Sandbox/Sandbox.csproj b/samples/Sandbox/Sandbox.csproj index 0c19440a1e..8f2812e048 100644 --- a/samples/Sandbox/Sandbox.csproj +++ b/samples/Sandbox/Sandbox.csproj @@ -2,7 +2,7 @@ WinExe - netcoreapp3.1 + net6.0 true diff --git a/samples/VirtualizationDemo/VirtualizationDemo.csproj b/samples/VirtualizationDemo/VirtualizationDemo.csproj index d898b737a9..2c6ff74e5e 100644 --- a/samples/VirtualizationDemo/VirtualizationDemo.csproj +++ b/samples/VirtualizationDemo/VirtualizationDemo.csproj @@ -1,7 +1,7 @@  Exe - netcoreapp3.1 + net6.0 diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs index 172782c5a9..a4515db514 100644 --- a/src/Avalonia.Animation/Animation.cs +++ b/src/Avalonia.Animation/Animation.cs @@ -353,6 +353,12 @@ namespace Avalonia.Animation return new CompositeDisposable(subscriptions); } + /// + public Task RunAsync(Animatable control, IClock clock = null) + { + return RunAsync(control, clock, default); + } + /// public Task RunAsync(Animatable control, IClock clock = null, CancellationToken cancellationToken = default) { diff --git a/src/Avalonia.Animation/Animators/Animator`1.cs b/src/Avalonia.Animation/Animators/Animator`1.cs index d784227620..23afa76bf6 100644 --- a/src/Avalonia.Animation/Animators/Animator`1.cs +++ b/src/Avalonia.Animation/Animators/Animator`1.cs @@ -79,15 +79,15 @@ namespace Avalonia.Animation.Animators T oldValue, newValue; - if (firstKeyframe.isNeutral) - oldValue = neutralValue; + if (!firstKeyframe.isNeutral && firstKeyframe.Value is T firstKeyframeValue) + oldValue = firstKeyframeValue; else - oldValue = (T)firstKeyframe.Value; + oldValue = neutralValue; - if (lastKeyframe.isNeutral) - newValue = neutralValue; + if (!lastKeyframe.isNeutral && lastKeyframe.Value is T lastKeyframeValue) + newValue = lastKeyframeValue; else - newValue = (T)lastKeyframe.Value; + newValue = neutralValue; if (lastKeyframe.KeySpline != null) progress = lastKeyframe.KeySpline.GetSplineProgress(progress); diff --git a/src/Avalonia.Animation/ApiCompatBaseline.txt b/src/Avalonia.Animation/ApiCompatBaseline.txt index 58cb7830e7..973698f872 100644 --- a/src/Avalonia.Animation/ApiCompatBaseline.txt +++ b/src/Avalonia.Animation/ApiCompatBaseline.txt @@ -1,6 +1,5 @@ Compat issues with assembly Avalonia.Animation: -MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.Animation.RunAsync(Avalonia.Animation.Animatable, Avalonia.Animation.IClock)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Tasks.Task Avalonia.Animation.IAnimation.RunAsync(Avalonia.Animation.Animatable, Avalonia.Animation.IClock)' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.IAnimation.RunAsync(Avalonia.Animation.Animatable, Avalonia.Animation.IClock)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Tasks.Task Avalonia.Animation.IAnimation.RunAsync(Avalonia.Animation.Animatable, Avalonia.Animation.IClock, System.Threading.CancellationToken)' is present in the implementation but not in the contract. -Total Issues: 4 +Total Issues: 3 diff --git a/src/Avalonia.Animation/Properties/AssemblyInfo.cs b/src/Avalonia.Animation/Properties/AssemblyInfo.cs index 221b51e95a..6b539b075b 100644 --- a/src/Avalonia.Animation/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Animation/Properties/AssemblyInfo.cs @@ -1,15 +1,9 @@ using Avalonia.Metadata; -using System.Reflection; using System.Runtime.CompilerServices; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Easings")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Animators")] -#if SIGNED_BUILD [assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -#else -[assembly: InternalsVisibleTo("Avalonia.LeakTests")] -[assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests")] -#endif diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index 93948e54ee..e8c84ffb21 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -247,7 +247,7 @@ namespace Avalonia.Data UnsetValueType _ => Unset, DoNothingType _ => DoNothing, BindingNotification n => n.ToBindingValue().Cast(), - _ => new BindingValue((T)value) + _ => new BindingValue((T?)value) }; } diff --git a/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs b/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs index 7ff0a8ceca..251dbb458d 100644 --- a/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs +++ b/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs @@ -140,18 +140,9 @@ namespace Avalonia.Data.Converters ); } - Action action = null; - try - { - action = Expression - .Lambda>(body, parameter) - .Compile(); - } - catch (Exception ex) - { - throw ex; - } - return action; + return Expression + .Lambda>(body, parameter) + .Compile(); } static Func CreateCanExecute(object target @@ -170,7 +161,7 @@ namespace Avalonia.Data.Converters .Compile(); } - private static Expression? ConvertTarget(object? target, MethodInfo method) => + private static Expression ConvertTarget(object target, MethodInfo method) => target is null ? null : Expression.Convert(Expression.Constant(target), method.DeclaringType); internal class WeakPropertyChangedProxy diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs index b054c186ae..053c7a7547 100644 --- a/src/Avalonia.Base/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs @@ -5,18 +5,10 @@ using System.Runtime.CompilerServices; using Avalonia.Metadata; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data.Converters")] -#if SIGNED_BUILD [assembly: InternalsVisibleTo("Avalonia.Base.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] [assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.Visuals, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -#else -[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")] -[assembly: InternalsVisibleTo("Avalonia.UnitTests")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] -[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")] -[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")] -[assembly: InternalsVisibleTo("Avalonia.Visuals")] -#endif + diff --git a/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs b/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs index b85991fb77..62a9ed27be 100644 --- a/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs +++ b/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs @@ -1,9 +1,6 @@ using System; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; -using System.Threading; using Microsoft.Build.Framework; namespace Avalonia.Build.Tasks @@ -41,7 +38,7 @@ namespace Avalonia.Build.Tasks File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(), ProjectDirectory, OutputPath, VerifyIl, outputImportance, (SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null, - EnableComInteropPatching, SkipXamlCompilation); + EnableComInteropPatching, SkipXamlCompilation, DebuggerLaunch); if (!res.Success) return false; if (!res.WrittenFile) @@ -87,5 +84,7 @@ namespace Avalonia.Build.Tasks public IBuildEngine BuildEngine { get; set; } public ITaskHost HostObject { get; set; } + + public bool DebuggerLaunch { get; set; } } } diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs index 508045dccb..593d79471e 100644 --- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs +++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using System.Text; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; using Microsoft.Build.Framework; using Mono.Cecil; -using Avalonia.Utilities; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; using XamlX; @@ -44,16 +41,23 @@ namespace Avalonia.Build.Tasks string projectDirectory, string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool patchCom, bool skipXamlCompilation) + { + return Compile(engine, input, references, projectDirectory, output, verifyIl, logImportance, strongNameKey, patchCom, skipXamlCompilation, debuggerLaunch:false); + } + + internal static CompileResult Compile(IBuildEngine engine, string input, string[] references, + string projectDirectory, + string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool patchCom, bool skipXamlCompilation, bool debuggerLaunch) { var typeSystem = new CecilTypeSystem(references .Where(r => !r.ToLowerInvariant().EndsWith("avalonia.build.tasks.dll")) .Concat(new[] { input }), input); - + var asm = typeSystem.TargetAssemblyDefinition; if (!skipXamlCompilation) { - var compileRes = CompileCore(engine, typeSystem, projectDirectory, verifyIl, logImportance); + var compileRes = CompileCore(engine, typeSystem, projectDirectory, verifyIl, logImportance, debuggerLaunch); if (compileRes == null && !patchCom) return new CompileResult(true); if (compileRes == false) @@ -62,7 +66,7 @@ namespace Avalonia.Build.Tasks if (patchCom) ComInteropHelper.PatchAssembly(asm, typeSystem); - + var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols }; if (!string.IsNullOrWhiteSpace(strongNameKey)) writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey); @@ -70,13 +74,43 @@ namespace Avalonia.Build.Tasks asm.Write(output, writerParameters); return new CompileResult(true, true); - + } - + static bool? CompileCore(IBuildEngine engine, CecilTypeSystem typeSystem, string projectDirectory, bool verifyIl, - MessageImportance logImportance) + MessageImportance logImportance + , bool debuggerLaunch = false) { + if (debuggerLaunch) + { + // According this https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.debugger.launch?view=net-6.0#remarks + // documentation, on not windows platform Debugger.Launch() always return true without running a debugger. + if (System.Diagnostics.Debugger.Launch()) + { + // Set timeout at 1 minut. + var time = new System.Diagnostics.Stopwatch(); + var timeout = TimeSpan.FromMinutes(1); + time.Start(); + + // wait for the debugger to be attacked or timeout. + while (!System.Diagnostics.Debugger.IsAttached && time.Elapsed < timeout) + { + engine.LogMessage($"[PID:{System.Diagnostics.Process.GetCurrentProcess().Id}] Wating attach debugger. Elapsed {time.Elapsed}...", MessageImportance.High); + System.Threading.Thread.Sleep(100); + } + + time.Stop(); + if (time.Elapsed >= timeout) + { + engine.LogMessage("Wating attach debugger timeout.", MessageImportance.Normal); + } + } + else + { + engine.LogMessage("Debugging cancelled.", MessageImportance.Normal); + } + } var asm = typeSystem.TargetAssemblyDefinition; var emres = new EmbeddedResources(asm); var avares = new AvaloniaResources(asm, projectDirectory); diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs index 85fd55800a..915b36687c 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs @@ -35,6 +35,7 @@ namespace Avalonia.Controls private const int DATAGRIDCOLUMNHEADER_resizeRegionWidth = 5; private const double DATAGRIDCOLUMNHEADER_separatorThickness = 1; + private const int DATAGRIDCOLUMNHEADER_columnsDragTreshold = 5; private bool _areHandlersSuspended; private static DragMode _dragMode; @@ -448,19 +449,6 @@ namespace Avalonia.Controls OnMouseMove_Reorder(ref handled, mousePosition, mousePositionHeaders, distanceFromLeft, distanceFromRight); - // if we still haven't done anything about moving the mouse while - // the button is down, we remember that we're dragging, but we don't - // claim to have actually handled the event - if (_dragMode == DragMode.MouseDown) - { - _dragMode = DragMode.Drag; - } - - _lastMousePositionHeaders = mousePositionHeaders; - - if (args.Pointer.Captured != this && _dragMode == DragMode.Drag) - args.Pointer.Capture(this); - SetDragCursor(mousePosition); } @@ -732,15 +720,19 @@ namespace Avalonia.Controls { return; } - + //handle entry into reorder mode - if (_dragMode == DragMode.MouseDown && _dragColumn == null && (distanceFromRight > DATAGRIDCOLUMNHEADER_resizeRegionWidth && distanceFromLeft > DATAGRIDCOLUMNHEADER_resizeRegionWidth)) + if (_dragMode == DragMode.MouseDown && _dragColumn == null && _lastMousePositionHeaders != null && (distanceFromRight > DATAGRIDCOLUMNHEADER_resizeRegionWidth && distanceFromLeft > DATAGRIDCOLUMNHEADER_resizeRegionWidth)) { - handled = CanReorderColumn(OwningColumn); - - if (handled) + var distanceFromInitial = (Vector)(mousePositionHeaders - _lastMousePositionHeaders); + if (distanceFromInitial.Length > DATAGRIDCOLUMNHEADER_columnsDragTreshold) { - OnMouseMove_BeginReorder(mousePosition); + handled = CanReorderColumn(OwningColumn); + + if (handled) + { + OnMouseMove_BeginReorder(mousePosition); + } } } diff --git a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs index 1b122996d2..d61c05ab6e 100644 --- a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs @@ -1,13 +1,9 @@ -using System.Reflection; using System.Runtime.CompilerServices; using Avalonia.Metadata; -#if SIGNED_BUILD + [assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -#else -[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests")] -[assembly: InternalsVisibleTo("Avalonia.DesignerSupport")] -#endif + [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")] diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs index 157bebe02b..df55d9e250 100644 --- a/src/Avalonia.Controls/Application.cs +++ b/src/Avalonia.Controls/Application.cs @@ -104,7 +104,7 @@ namespace Avalonia /// /// The application's focus manager. /// - public IFocusManager FocusManager + public IFocusManager? FocusManager { get; private set; @@ -116,7 +116,7 @@ namespace Avalonia /// /// The application's input manager. /// - public InputManager InputManager + public InputManager? InputManager { get; private set; @@ -175,7 +175,7 @@ namespace Avalonia /// - /// - /// - public IApplicationLifetime ApplicationLifetime { get; set; } + public IApplicationLifetime? ApplicationLifetime { get; set; } event Action> IGlobalStyles.GlobalStylesAdded { diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs index 2a42d99ac5..3a2fd68af5 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -122,12 +123,23 @@ namespace Avalonia.Controls.ApplicationLifetimes lifetimeEvents.ShutdownRequested += OnShutdownRequested; _cts = new CancellationTokenSource(); - MainWindow?.Show(); + + // Note due to a bug in the JIT we wrap this in a method, otherwise MainWindow + // gets stuffed into a local var and can not be GCed until after the program stops. + // this method never exits until program end. + ShowMainWindow(); + Dispatcher.UIThread.MainLoop(_cts.Token); Environment.ExitCode = _exitCode; return _exitCode; } + [MethodImpl(MethodImplOptions.NoInlining)] + private void ShowMainWindow() + { + MainWindow?.Show(); + } + public void Dispose() { if (_activeLifetime == this) diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index 614a18c6b5..8b22cdd4ec 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -99,6 +99,7 @@ namespace Avalonia.Controls CommandParameterProperty.Changed.Subscribe(CommandParameterChanged); IsDefaultProperty.Changed.Subscribe(IsDefaultChanged); IsCancelProperty.Changed.Subscribe(IsCancelChanged); + AccessKeyHandler.AccessKeyPressedEvent.AddClassHandler