Sfoglia il codice sorgente

Merge branch 'master' into t/lindexi

Steven Kirk 7 anni fa
parent
commit
e6c976b117
41 ha cambiato i file con 476 aggiunte e 932 eliminazioni
  1. 4 51
      Avalonia.sln
  2. 0 1
      build/Rx.props
  3. 5 0
      build/System.Drawing.Common.props
  4. 3 4
      packages.cake
  5. 1 1
      parameters.cake
  6. 33 3
      readme.md
  7. 2 3
      samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj
  8. 21 5
      src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
  9. 127 0
      src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs
  10. 2 0
      src/Avalonia.Base/Threading/Dispatcher.cs
  11. 5 7
      src/Avalonia.Controls/ItemsControl.cs
  12. 1 1
      src/Avalonia.Controls/Screens.cs
  13. 40 0
      src/Avalonia.Controls/Window.cs
  14. 19 0
      src/Avalonia.Controls/WindowBase.cs
  15. 23 0
      src/Avalonia.Controls/WindowStartupLocation.cs
  16. 2 2
      src/Avalonia.DesignerSupport/DesignWindowLoader.cs
  17. 3 0
      src/Avalonia.DotNetCoreRuntime/AppBuilder.cs
  18. 1 1
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  19. 0 3
      src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
  20. 31 0
      src/OSX/Avalonia.MonoMac/ClipboardImpl.cs
  21. 2 0
      src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs
  22. 3 3
      src/Shared/SharedAssemblyInfo.cs
  23. 4 0
      src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj
  24. 0 1
      src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs
  25. 0 49
      src/Windows/Avalonia.Win32.NetStandard/Avalonia.Win32.NetStandard.csproj
  26. 0 197
      src/Windows/Avalonia.Win32.NetStandard/ComStreamWrapper.cs
  27. 0 128
      src/Windows/Avalonia.Win32.NetStandard/Gdip.cs
  28. 0 45
      src/Windows/Avalonia.Win32.NetStandard/IconImpl.cs
  29. 0 30
      src/Windows/Avalonia.Win32.NetStandard/NativeWin32Platform.cs
  30. 0 12
      src/Windows/Avalonia.Win32.NetStandard/Win32Exception.cs
  31. 0 35
      src/Windows/Avalonia.Win32/Avalonia.Win32.Shared.projitems
  32. 12 98
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  33. 1 1
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  34. 0 2
      src/Windows/Avalonia.Win32/Properties/AssemblyInfo.cs
  35. 2 2
      src/Windows/Avalonia.Win32/ScreenImpl.cs
  36. 0 184
      src/Windows/Avalonia.Win32/Settings.StyleCop
  37. 37 1
      src/Windows/Avalonia.Win32/Win32Platform.cs
  38. 0 47
      src/Windows/Avalonia.Win32/WinFormsWin32Platform.cs
  39. 5 10
      src/Windows/Avalonia.Win32/WindowImpl.cs
  40. 7 2
      src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs
  41. 80 3
      tests/Avalonia.Controls.UnitTests/WindowTests.cs

+ 4 - 51
Avalonia.sln

@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
-VisualStudioVersion = 15.0.27130.2024
+VisualStudioVersion = 15.0.27130.2027
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
 EndProject
@@ -11,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Layout", "src\Aval
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A8919-9F95-48FE-AD7B-76E08B509888}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32", "src\Windows\Avalonia.Win32\Avalonia.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32", "src\Windows\Avalonia.Win32\Avalonia.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1", "src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}"
 EndProject
@@ -126,10 +126,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderTest", "samples\Rende
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Android", "samples\ControlCatalog.Android\ControlCatalog.Android.csproj", "{29132311-1848-4FD6-AE0C-4FF841151BD3}"
 EndProject
-Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Avalonia.Win32.Shared", "src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.shproj", "{9DEFC6B7-845B-4D8F-AFC0-D32BF0032B8C}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.NetStandard", "src\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj", "{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DotNetCoreRuntime", "src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj", "{7863EA94-F0FB-4386-BF8C-E5BFA761560A}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia", "src\Skia\Avalonia.Skia\Avalonia.Skia.csproj", "{7D2D3083-71DD-4CC9-8907-39A0D86FB322}"
@@ -196,14 +192,11 @@ Global
 	GlobalSection(SharedMSBuildProjectFiles) = preSolution
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4
-		src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{40759a76-d0f2-464e-8000-6ff0f5c4bd7c}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{7863ea94-f0fb-4386-bf8c-e5bfa761560a}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4
-		src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
-		src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{9defc6b7-845b-4d8f-afc0-d32bf0032b8c}*SharedItemsImports = 13
 		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{dabfd304-d6a4-4752-8123-c2ccf7ac7831}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
 	EndGlobalSection
@@ -369,6 +362,7 @@ Global
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|NetCoreOnly.ActiveCfg = Debug|Any CPU
+		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|NetCoreOnly.Build.0 = Debug|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|x86.ActiveCfg = Debug|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|x86.Build.0 = Debug|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -378,6 +372,7 @@ Global
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|NetCoreOnly.ActiveCfg = Release|Any CPU
+		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|NetCoreOnly.Build.0 = Release|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|x86.ActiveCfg = Release|Any CPU
 		{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|x86.Build.0 = Release|Any CPU
 		{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
@@ -1994,46 +1989,6 @@ Global
 		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.ActiveCfg = Release|Any CPU
 		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.Build.0 = Release|Any CPU
 		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.Deploy.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|NetCoreOnly.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|NetCoreOnly.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|x86.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|NetCoreOnly.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|NetCoreOnly.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|x86.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|x86.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|NetCoreOnly.ActiveCfg = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|NetCoreOnly.Build.0 = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|x86.Build.0 = Debug|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|iPhone.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|NetCoreOnly.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|NetCoreOnly.Build.0 = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|x86.ActiveCfg = Release|Any CPU
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|x86.Build.0 = Release|Any CPU
 		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
 		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
 		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -2623,8 +2578,6 @@ Global
 		{C7A69145-60B6-4882-97D6-A3921DD43978} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
-		{9DEFC6B7-845B-4D8F-AFC0-D32BF0032B8C} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
-		{40759A76-D0F2-464E-8000-6FF0F5C4BD7C} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
 		{7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
 		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658} = {B9894058-278A-46B5-B6ED-AD613FCC03B3}
 		{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3} = {9B9E3891-2366-4253-A952-D08BCEB71098}

+ 0 - 1
build/Rx.props

@@ -5,6 +5,5 @@
     <PackageReference Include="System.Reactive.Interfaces" Version="3.1.1" />
     <PackageReference Include="System.Reactive.Linq" Version="3.1.1" />
     <PackageReference Include="System.Reactive.PlatformServices" Version="3.1.1" />
-    <PackageReference Condition="$(TargetFramework.StartsWith('net4'))" Include="System.Reactive.Windows.Threading" Version="3.1.1" />
   </ItemGroup>
 </Project>

+ 5 - 0
build/System.Drawing.Common.props

@@ -0,0 +1,5 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <PackageReference Include="System.Drawing.Common" Version="4.5.0-preview1-25914-04" />
+  </ItemGroup>
+</Project>

+ 3 - 4
packages.cake

@@ -370,14 +370,13 @@ public class Packages
             new NuGetPackSettings()
             {
                 Id = "Avalonia.Win32",
-                Dependencies = new []
+                Dependencies = new DependencyBuilder(this)
                 {
                     new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
-                },
+                }.Deps(new string[]{null}, "System.Drawing.Common"),
                 Files = new []
                 {
-                    new NuSpecContent { Source = "Avalonia.Win32/bin/" + parameters.DirSuffix + "/Avalonia.Win32.dll", Target = "lib/net45" },
-                    new NuSpecContent { Source = "Avalonia.Win32.NetStandard/bin/" + parameters.DirSuffix + "/netstandard2.0/Avalonia.Win32.dll", Target = "lib/netstandard2.0" }
+                    new NuSpecContent { Source = "Avalonia.Win32/bin/" + parameters.DirSuffix + "/netstandard2.0/Avalonia.Win32.dll", Target = "lib/netstandard2.0" }
                 },
                 BasePath = context.Directory("./src/Windows"),
                 OutputDirectory = parameters.NugetRoot

+ 1 - 1
parameters.cake

@@ -97,7 +97,7 @@ public class Parameters
             else
             {
                 // Use AssemblyVersion with Build as version
-                Version += "-build" + context.EnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-alpha";
+                Version += "-build" + context.EnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-beta";
             }
         }
 

+ 33 - 3
readme.md

@@ -2,9 +2,9 @@
 
 # Avalonia
 
-| Gitter Chat | Windows Build Status | Linux/Mac Build Status |
-|---|---|---|
-| [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master) | [![Build Status](https://travis-ci.org/AvaloniaUI/Avalonia.svg?branch=master)](https://travis-ci.org/AvaloniaUI/Avalonia) |
+| Gitter Chat | Windows Build Status | Linux/Mac Build Status | Open Collective |
+|---|---|---|---|
+|  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master) | [![Build Status](https://travis-ci.org/AvaloniaUI/Avalonia.svg?branch=master)](https://travis-ci.org/AvaloniaUI/Avalonia) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) |
 
 ## About
 
@@ -48,3 +48,33 @@ See the [build instructions here](http://avaloniaui.net/contributing/build).
 ## Contributing
 
 Please read the [contribution guidelines](http://avaloniaui.net/contributing/contributing) before submitting a pull request.
+
+### Contributors
+
+This project exists thanks to all the people who contribute. [[Contribute](http://avaloniaui.net/contributing/contributing)].
+<a href="graphs/contributors"><img src="https://opencollective.com/Avalonia/contributors.svg?width=890&button=false" /></a>
+
+
+### Backers
+
+Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)]
+
+<a href="https://opencollective.com/Avalonia#backers" target="_blank"><img src="https://opencollective.com/Avalonia/backers.svg?width=890"></a>
+
+
+### Sponsors
+
+Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/Avalonia#sponsor)]
+
+<a href="https://opencollective.com/Avalonia/sponsor/0/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/0/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/1/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/1/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/2/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/2/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/3/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/3/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/4/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/4/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/5/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/5/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/6/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/6/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/7/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/7/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/8/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/8/avatar.svg"></a>
+<a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a>
+
+

+ 2 - 3
samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj

@@ -170,15 +170,14 @@
       <Name>Avalonia.Themes.Default</Name>
     </ProjectReference>
     <ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj">
-      <Project>{D2D3083-71DD-4CC9-8907-39A0D86FB322}</Project>
+      <Project>{7d2d3083-71dd-4cc9-8907-39a0d86fb322}</Project>
       <Name>Avalonia.Skia</Name>
-      <IsAppExtension>false</IsAppExtension>
-      <IsWatchApp>false</IsWatchApp>
     </ProjectReference>
     <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj">
       <Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project>
       <Name>ControlCatalog</Name>
     </ProjectReference>
   </ItemGroup>
+  <Import Project="..\..\build\Sprache.props" />
   <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
 </Project>

+ 21 - 5
src/Avalonia.Base/Collections/AvaloniaListExtensions.cs

@@ -34,14 +34,18 @@ namespace Avalonia.Collections
         /// <param name="reset">
         /// An action called when the collection is reset.
         /// </param>
+        /// <param name="weakSubscription">
+        /// Indicates if a weak subscription should be used to track changes to the collection.
+        /// </param>
         /// <returns>A disposable used to terminate the subscription.</returns>
         public static IDisposable ForEachItem<T>(
             this IAvaloniaReadOnlyList<T> collection,
             Action<T> added,
             Action<T> removed,
-            Action reset)
+            Action reset,
+            bool weakSubscription = false)
         {
-            return collection.ForEachItem((_, i) => added(i), (_, i) => removed(i), reset);
+            return collection.ForEachItem((_, i) => added(i), (_, i) => removed(i), reset, weakSubscription);
         }
 
         /// <summary>
@@ -63,12 +67,16 @@ namespace Avalonia.Collections
         /// An action called when the collection is reset. This will be followed by calls to 
         /// <paramref name="added"/> for each item present in the collection after the reset.
         /// </param>
+        /// <param name="weakSubscription">
+        /// Indicates if a weak subscription should be used to track changes to the collection.
+        /// </param>
         /// <returns>A disposable used to terminate the subscription.</returns>
         public static IDisposable ForEachItem<T>(
             this IAvaloniaReadOnlyList<T> collection,
             Action<int, T> added,
             Action<int, T> removed,
-            Action reset)
+            Action reset,
+            bool weakSubscription = false)
         {
             void Add(int index, IList items)
             {
@@ -118,9 +126,17 @@ namespace Avalonia.Collections
             };
 
             Add(0, (IList)collection);
-            collection.CollectionChanged += handler;
 
-            return Disposable.Create(() => collection.CollectionChanged -= handler);
+            if (weakSubscription)
+            {
+                return collection.WeakSubscribe(handler);
+            }
+            else
+            {
+                collection.CollectionChanged += handler;
+
+                return Disposable.Create(() => collection.CollectionChanged -= handler);
+            }
         }
 
         public static IAvaloniaReadOnlyList<TDerived> CreateDerivedList<TSource, TDerived>(

+ 127 - 0
src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs

@@ -0,0 +1,127 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Reactive;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+using System.Reactive.Subjects;
+using Avalonia.Utilities;
+
+namespace Avalonia.Collections
+{
+    public static class NotifyCollectionChangedExtensions
+    {
+        /// <summary>
+        /// Gets a weak observable for the CollectionChanged event.
+        /// </summary>
+        /// <param name="collection">The collection.</param>
+        /// <returns>An observable.</returns>
+        public static IObservable<NotifyCollectionChangedEventArgs> GetWeakCollectionChangedObservable(
+            this INotifyCollectionChanged collection)
+        {
+            Contract.Requires<ArgumentNullException>(collection != null);
+
+            return new WeakCollectionChangedObservable(new WeakReference<INotifyCollectionChanged>(collection));
+        }
+
+        /// <summary>
+        /// Subcribes to the CollectionChanged event using a weak subscription.
+        /// </summary>
+        /// <param name="collection">The collection.</param>
+        /// <param name="handler">
+        /// An action called when the collection event is raised.
+        /// </param>
+        /// <returns>A disposable used to terminate the subscription.</returns>
+        public static IDisposable WeakSubscribe(
+            this INotifyCollectionChanged collection, 
+            NotifyCollectionChangedEventHandler handler)
+        {
+            Contract.Requires<ArgumentNullException>(collection != null);
+            Contract.Requires<ArgumentNullException>(handler != null);
+
+            return
+                collection.GetWeakCollectionChangedObservable()
+                          .Subscribe(e => handler.Invoke(collection, e));
+        }
+
+        /// <summary>
+        /// Subcribes to the CollectionChanged event using a weak subscription.
+        /// </summary>
+        /// <param name="collection">The collection.</param>
+        /// <param name="handler">
+        /// An action called when the collection event is raised.
+        /// </param>
+        /// <returns>A disposable used to terminate the subscription.</returns>
+        public static IDisposable WeakSubscribe(
+            this INotifyCollectionChanged collection,
+            Action<NotifyCollectionChangedEventArgs> handler)
+        {
+            Contract.Requires<ArgumentNullException>(collection != null);
+            Contract.Requires<ArgumentNullException>(handler != null);
+
+            return
+                collection.GetWeakCollectionChangedObservable()
+                          .Subscribe(handler);
+        }
+
+        private class WeakCollectionChangedObservable : ObservableBase<NotifyCollectionChangedEventArgs>,
+            IWeakSubscriber<NotifyCollectionChangedEventArgs>
+        {
+            private WeakReference<INotifyCollectionChanged> _sourceReference;
+            private readonly Subject<NotifyCollectionChangedEventArgs> _changed = new Subject<NotifyCollectionChangedEventArgs>();
+
+            private int _count;
+
+            public WeakCollectionChangedObservable(WeakReference<INotifyCollectionChanged> source)
+            {
+                _sourceReference = source;
+            }
+
+            public void OnEvent(object sender, NotifyCollectionChangedEventArgs e)
+            {
+                _changed.OnNext(e);
+            }
+
+            protected override IDisposable SubscribeCore(IObserver<NotifyCollectionChangedEventArgs> observer)
+            {
+                if (_sourceReference.TryGetTarget(out INotifyCollectionChanged instance))
+                {
+                    if (_count++ == 0)
+                    {
+                        WeakSubscriptionManager.Subscribe(
+                            instance,
+                            nameof(instance.CollectionChanged),
+                            this);
+                    }
+
+                    return Observable.Using(() => Disposable.Create(DecrementCount), _ => _changed)
+                        .Subscribe(observer);
+                }
+                else
+                {
+                    _changed.OnCompleted();
+                    observer.OnCompleted();
+                    return Disposable.Empty;
+                }
+            }
+
+            private void DecrementCount()
+            {
+                if (--_count == 0)
+                {
+                    if (_sourceReference.TryGetTarget(out INotifyCollectionChanged instance))
+                    {
+                        WeakSubscriptionManager.Unsubscribe(
+                            instance,
+                            nameof(instance.CollectionChanged),
+                            this);
+                    }
+                }
+            }
+        }
+    }
+}

+ 2 - 0
src/Avalonia.Base/Threading/Dispatcher.cs

@@ -81,12 +81,14 @@ namespace Avalonia.Threading
         /// <inheritdoc/>
         public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
         {
+            Contract.Requires<ArgumentNullException>(action != null);
             return _jobRunner?.InvokeAsync(action, priority);
         }
 
         /// <inheritdoc/>
         public void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
         {
+            Contract.Requires<ArgumentNullException>(action != null);
             _jobRunner?.Post(action, priority);
         }
 

+ 5 - 7
src/Avalonia.Controls/ItemsControl.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Specialized;
@@ -54,6 +55,7 @@ namespace Avalonia.Controls
 
         private IEnumerable _items = new AvaloniaList<object>();
         private IItemContainerGenerator _itemContainerGenerator;
+        private IDisposable _itemsCollectionChangedSubscription;
 
         /// <summary>
         /// Initializes static members of the <see cref="ItemsControl"/> class.
@@ -326,12 +328,8 @@ namespace Avalonia.Controls
         /// <param name="e">The event args.</param>
         protected virtual void ItemsChanged(AvaloniaPropertyChangedEventArgs e)
         {
-            var incc = e.OldValue as INotifyCollectionChanged;
-
-            if (incc != null)
-            {
-                incc.CollectionChanged -= ItemsCollectionChanged;
-            }
+            _itemsCollectionChangedSubscription?.Dispose();
+            _itemsCollectionChangedSubscription = null;
 
             var oldValue = e.OldValue as IEnumerable;
             var newValue = e.NewValue as IEnumerable;
@@ -428,7 +426,7 @@ namespace Avalonia.Controls
 
             if (incc != null)
             {
-                incc.CollectionChanged += ItemsCollectionChanged;
+                _itemsCollectionChangedSubscription = incc.WeakSubscribe(ItemsCollectionChanged);
             }
         }
 

+ 1 - 1
src/Avalonia.Controls/Screens.cs

@@ -39,7 +39,7 @@ namespace Avalonia.Controls
             return currMaxScreen;
         }
         
-        public Screen SceenFromPoint(Point point)
+        public Screen ScreenFromPoint(Point point)
         {
             return All.FirstOrDefault(x=>x.Bounds.Contains(point));        
         }

+ 40 - 0
src/Avalonia.Controls/Window.cs

@@ -85,9 +85,19 @@ namespace Avalonia.Controls
         public static readonly StyledProperty<WindowIcon> IconProperty =
             AvaloniaProperty.Register<Window, WindowIcon>(nameof(Icon));
 
+        /// <summary>
+        /// Defines the <see cref="WindowStartupLocation"/> proeprty.
+        /// </summary>
+        public static readonly DirectProperty<Window, WindowStartupLocation> WindowStartupLocationProperty =
+            AvaloniaProperty.RegisterDirect<Window, WindowStartupLocation>(
+                nameof(WindowStartupLocation),
+                o => o.WindowStartupLocation,
+                (o, v) => o.WindowStartupLocation = v);
+
         private readonly NameScope _nameScope = new NameScope();
         private object _dialogResult;
         private readonly Size _maxPlatformClientSize;
+        private WindowStartupLocation _windowStartupLoction;
 
         /// <summary>
         /// Initializes static members of the <see cref="Window"/> class.
@@ -205,6 +215,15 @@ namespace Avalonia.Controls
             set { SetValue(IconProperty, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the startup location of the window.
+        /// </summary>
+        public WindowStartupLocation WindowStartupLocation
+        {
+            get { return _windowStartupLoction; }
+            set { SetAndRaise(WindowStartupLocationProperty, ref _windowStartupLoction, value); }
+        }
+
         /// <inheritdoc/>
         Size ILayoutRoot.MaxClientSize => _maxPlatformClientSize;
 
@@ -274,6 +293,7 @@ namespace Avalonia.Controls
             s_windows.Add(this);
 
             EnsureInitialized();
+            SetWindowStartupLocation();
             IsVisible = true;
             LayoutManager.Instance.ExecuteInitialLayoutPass(this);
 
@@ -314,6 +334,7 @@ namespace Avalonia.Controls
             s_windows.Add(this);
 
             EnsureInitialized();
+            SetWindowStartupLocation();
             IsVisible = true;
             LayoutManager.Instance.ExecuteInitialLayoutPass(this);
 
@@ -352,6 +373,25 @@ namespace Avalonia.Controls
             }
         }
 
+        void SetWindowStartupLocation()
+        {
+            if (WindowStartupLocation == WindowStartupLocation.CenterScreen)
+            {
+                var screen = Screens.ScreenFromPoint(Bounds.Position);
+
+                if (screen != null)
+                    Position = screen.WorkingArea.CenterRect(new Rect(ClientSize)).Position;
+            }
+            else if (WindowStartupLocation == WindowStartupLocation.CenterOwner)
+            {
+                if (Owner != null)
+                {
+                    var positionAsSize = Owner.ClientSize / 2 - ClientSize / 2;
+                    Position = Owner.Position + new Point(positionAsSize.Width, positionAsSize.Height);
+                }
+            }
+        }
+
         /// <inheritdoc/>
         void INameScope.Register(string name, object element)
         {

+ 19 - 0
src/Avalonia.Controls/WindowBase.cs

@@ -29,9 +29,19 @@ namespace Avalonia.Controls
         public static readonly DirectProperty<WindowBase, bool> IsActiveProperty =
             AvaloniaProperty.RegisterDirect<WindowBase, bool>(nameof(IsActive), o => o.IsActive);
 
+        /// <summary>
+        /// Defines the <see cref="Owner"/> property.
+        /// </summary>
+        public static readonly DirectProperty<WindowBase, WindowBase> OwnerProperty =
+            AvaloniaProperty.RegisterDirect<WindowBase, WindowBase>(
+                nameof(Owner),
+                o => o.Owner,
+                (o, v) => o.Owner = v);
+
         private bool _hasExecutedInitialLayoutPass;
         private bool _isActive;
         private bool _ignoreVisibilityChange;
+        private WindowBase _owner;
 
         static WindowBase()
         {
@@ -100,6 +110,15 @@ namespace Avalonia.Controls
             private set;
         }
 
+        /// <summary>
+        /// Gets or sets the owner of the window.
+        /// </summary>
+        public WindowBase Owner
+        {
+            get { return _owner; }
+            set { SetAndRaise(OwnerProperty, ref _owner, value); }
+        }
+
         /// <summary>
         /// Activates the window.
         /// </summary>

+ 23 - 0
src/Avalonia.Controls/WindowStartupLocation.cs

@@ -0,0 +1,23 @@
+namespace Avalonia.Controls
+{
+    /// <summary>
+    /// Determines the startup location of the window.
+    /// </summary>
+    public enum WindowStartupLocation
+    {
+        /// <summary>
+        /// The startup location is defined by the Position property.
+        /// </summary>
+        Manual,
+
+        /// <summary>
+        /// The startup location is the center of the screen.
+        /// </summary>
+        CenterScreen,
+
+        /// <summary>
+        /// The startup location is the center of the owner window. If the owner window is not specified, the startup location will be <see cref="Manual"/>.
+        /// </summary>
+        CenterOwner
+    }
+}

+ 2 - 2
src/Avalonia.DesignerSupport/DesignWindowLoader.cs

@@ -54,7 +54,7 @@ namespace Avalonia.DesignerSupport
                             }
                         };
                 }
-                if (loaded is Application)
+                else if (loaded is Application)
                     control = new TextBlock {Text = "Application can't be previewed in design view"};
                 else
                     control = (Control) loaded;
@@ -73,4 +73,4 @@ namespace Avalonia.DesignerSupport
             return window;
         }
     }
-}
+}

+ 3 - 0
src/Avalonia.DotNetCoreRuntime/AppBuilder.cs

@@ -10,6 +10,9 @@ using Avalonia.Shared.PlatformSupport;
 
 namespace Avalonia
 {
+    /// <summary>
+    /// Initializes platform-specific services for an <see cref="Application"/>.
+    /// </summary>
     public sealed class AppBuilder : AppBuilderBase<AppBuilder>
     {
         /// <summary>

+ 1 - 1
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj

@@ -19,7 +19,7 @@
     <ProjectReference Include="..\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj" />
     <ProjectReference Include="..\OSX\Avalonia.MonoMac\Avalonia.MonoMac.csproj" />
     <ProjectReference Include="..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
-    <ProjectReference Include="..\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj" />
+    <ProjectReference Include="..\Windows\Avalonia.Win32\Avalonia.Win32.csproj" />
   </ItemGroup>
   <Import Project="..\..\build\NetCore.props" />
   <Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" />

+ 0 - 3
src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj

@@ -8,9 +8,6 @@
     <Compile Include="..\..\Shared\SharedAssemblyInfo.cs" Link="SharedAssemblyInfo.cs" />
     <Compile Include="..\..\Shared\WindowResizeDragHelper.cs" Link="WindowResizeDragHelper.cs" />
   </ItemGroup>
-  <ItemGroup>
-    <PackageReference Include="MonoMac.NetStandard" Version="0.0.3" />
-  </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj" />
     <ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />

+ 31 - 0
src/OSX/Avalonia.MonoMac/ClipboardImpl.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Input.Platform;
+using MonoMac.AppKit;
+
+namespace Avalonia.MonoMac
+{
+    class ClipboardImpl : IClipboard
+    {
+        public Task<string> GetTextAsync()
+        {
+            return Task.FromResult(NSPasteboard.GeneralPasteboard.GetStringForType(NSPasteboard.NSStringType));
+        }
+
+        public Task SetTextAsync(string text)
+        {
+            NSPasteboard.GeneralPasteboard.ClearContents();
+            if (text != null)
+                NSPasteboard.GeneralPasteboard.SetStringForType(text, NSPasteboard.NSStringType);
+            return Task.CompletedTask;
+        }
+
+        public async Task ClearAsync()
+        {
+            NSPasteboard.GeneralPasteboard.ClearContents();
+        }
+    }
+}
+

+ 2 - 0
src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs

@@ -3,6 +3,7 @@ using System.Threading;
 using Avalonia.Controls;
 using Avalonia.Controls.Platform;
 using Avalonia.Input;
+using Avalonia.Input.Platform;
 using Avalonia.Platform;
 using Avalonia.Rendering;
 using MonoMac.AppKit;
@@ -32,6 +33,7 @@ namespace Avalonia.MonoMac
                 .Bind<IPlatformSettings>().ToConstant(this)
                 .Bind<IWindowingPlatform>().ToConstant(this)
                 .Bind<ISystemDialogImpl>().ToSingleton<SystemDialogsImpl>()
+                .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
                 .Bind<IRenderLoop>().ToConstant(s_renderLoop)
                 .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance);
         }

+ 3 - 3
src/Shared/SharedAssemblyInfo.cs

@@ -14,6 +14,6 @@ using System.Runtime.CompilerServices;
 [assembly: AssemblyTrademark("")]
 [assembly: NeutralResourcesLanguage("en")]
 
-[assembly: AssemblyVersion("0.6.0")]
-[assembly: AssemblyFileVersion("0.6.0")]
-[assembly: AssemblyInformationalVersion("0.6.0")]
+[assembly: AssemblyVersion("0.6.2")]
+[assembly: AssemblyFileVersion("0.6.2")]
+[assembly: AssemblyInformationalVersion("0.6.2")]

+ 4 - 0
src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj

@@ -34,6 +34,7 @@
     <Reference Include="PresentationFramework" />
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Windows.Forms" />
     <Reference Include="System.Xaml" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
@@ -48,6 +49,9 @@
       <Link>UnmanagedMethods.cs</Link>
     </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="WinForms\WinFormsAvaloniaControlHost.cs">
+      <SubType>Component</SubType>
+    </Compile>
     <Compile Include="Wpf\CursorShim.cs" />
     <Compile Include="Wpf\Direct2DImageSurface.cs" />
     <Compile Include="Wpf\IntSize.cs" />

+ 0 - 1
src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs → src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs

@@ -1,7 +1,6 @@
 using System;
 using System.ComponentModel;
 using System.Windows.Forms;
-using Avalonia.Controls;
 using Avalonia.Controls.Embedding;
 using Avalonia.Input;
 using Avalonia.VisualTree;

+ 0 - 49
src/Windows/Avalonia.Win32.NetStandard/Avalonia.Win32.NetStandard.csproj

@@ -1,49 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <TargetFramework>netstandard2.0</TargetFramework>
-    <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
-    <RootNamespace>Avalonia.Win32</RootNamespace>
-    <AssemblyName>Avalonia.Win32</AssemblyName>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>TRACE;DEBUG;NETSTANDARD</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE;NETSTANDARD</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-  </PropertyGroup>
-  <ItemGroup>
-    <Folder Include="Properties\" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj" />
-    <ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
-    <ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj" />
-    <ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj" />
-    <ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
-    <ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj" />
-    <ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj" />
-    <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="ComStreamWrapper.cs" />
-    <Compile Include="Gdip.cs" />
-    <Compile Include="IconImpl.cs" />
-    <Compile Include="NativeWin32Platform.cs" />
-    <Compile Include="Win32Exception.cs" />
-  </ItemGroup>
-  <Import Project="..\Avalonia.Win32\Avalonia.Win32.Shared.projitems" Label="Shared" />
-</Project>

+ 0 - 197
src/Windows/Avalonia.Win32.NetStandard/ComStreamWrapper.cs

@@ -1,197 +0,0 @@
-//
-// System.Drawing.ComIStreamWrapper.cs
-//
-// Author:
-//   Kornél Pál <http://www.kornelpal.hu/>
-//
-// Copyright (C) 2005-2008 Kornél Pál
-//
-
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.IO;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
-using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
-
-namespace Avalonia.Win32
-{
-    // Stream to IStream wrapper for COM interop
-    internal sealed class ComIStreamWrapper : IStream
-    {
-        private const int STG_E_INVALIDFUNCTION = unchecked((int)0x80030001);
-
-        private readonly Stream baseStream;
-        private long position = -1;
-
-        internal ComIStreamWrapper(Stream stream)
-        {
-            baseStream = stream;
-        }
-
-        private void SetSizeToPosition()
-        {
-            if (position != -1)
-            {
-                if (position > baseStream.Length)
-                    baseStream.SetLength(position);
-                baseStream.Position = position;
-                position = -1;
-            }
-        }
-
-        public void Read(byte[] pv, int cb, IntPtr pcbRead)
-        {
-            int read = 0;
-
-            if (cb != 0)
-            {
-                SetSizeToPosition();
-                read = baseStream.Read(pv, 0, cb);
-            }
-
-            if (pcbRead != IntPtr.Zero)
-                Marshal.WriteInt32(pcbRead, read);
-        }
-
-        public void Write(byte[] pv, int cb, IntPtr pcbWritten)
-        {
-            if (cb != 0)
-            {
-                SetSizeToPosition();
-                baseStream.Write(pv, 0, cb);
-            }
-
-            if (pcbWritten != IntPtr.Zero)
-                Marshal.WriteInt32(pcbWritten, cb);
-        }
-
-        public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
-        {
-            long length = baseStream.Length;
-            long newPosition;
-
-            switch ((SeekOrigin)dwOrigin)
-            {
-                case SeekOrigin.Begin:
-                    newPosition = dlibMove;
-                    break;
-                case SeekOrigin.Current:
-                    if (position == -1)
-                        newPosition = baseStream.Position + dlibMove;
-                    else
-                        newPosition = position + dlibMove;
-                    break;
-                case SeekOrigin.End:
-                    newPosition = length + dlibMove;
-                    break;
-                default:
-                    throw new COMException(null, STG_E_INVALIDFUNCTION);
-            }
-
-            if (newPosition > length)
-                position = newPosition;
-            else
-            {
-                baseStream.Position = newPosition;
-                position = -1;
-            }
-
-            if (plibNewPosition != IntPtr.Zero)
-                Marshal.WriteInt64(plibNewPosition, newPosition);
-        }
-
-        public void SetSize(long libNewSize)
-        {
-            baseStream.SetLength(libNewSize);
-        }
-
-        public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
-        {
-            byte[] buffer;
-            long written = 0;
-            int read;
-            int count;
-
-            if (cb != 0)
-            {
-                if (cb < 4096)
-                    count = (int)cb;
-                else
-                    count = 4096;
-                buffer = new byte[count];
-                SetSizeToPosition();
-                while (true)
-                {
-                    if ((read = baseStream.Read(buffer, 0, count)) == 0)
-                        break;
-                    pstm.Write(buffer, read, IntPtr.Zero);
-                    written += read;
-                    if (written >= cb)
-                        break;
-                    if (cb - written < 4096)
-                        count = (int)(cb - written);
-                }
-            }
-
-            if (pcbRead != IntPtr.Zero)
-                Marshal.WriteInt64(pcbRead, written);
-            if (pcbWritten != IntPtr.Zero)
-                Marshal.WriteInt64(pcbWritten, written);
-        }
-
-        public void Commit(int grfCommitFlags)
-        {
-            baseStream.Flush();
-            SetSizeToPosition();
-        }
-
-        public void Revert()
-        {
-            throw new COMException(null, STG_E_INVALIDFUNCTION);
-        }
-
-        public void LockRegion(long libOffset, long cb, int dwLockType)
-        {
-            throw new COMException(null, STG_E_INVALIDFUNCTION);
-        }
-
-        public void UnlockRegion(long libOffset, long cb, int dwLockType)
-        {
-            throw new COMException(null, STG_E_INVALIDFUNCTION);
-        }
-
-        public void Stat(out STATSTG pstatstg, int grfStatFlag)
-        {
-            pstatstg = new STATSTG();
-            pstatstg.cbSize = baseStream.Length;
-        }
-
-        public void Clone(out IStream ppstm)
-        {
-            ppstm = null;
-            throw new COMException(null, STG_E_INVALIDFUNCTION);
-        }
-    }
-}

+ 0 - 128
src/Windows/Avalonia.Win32.NetStandard/Gdip.cs

@@ -1,128 +0,0 @@
-//
-// Code copy-pasted from from Mono / System.Drawing.*.cs
-// Original license below:
-//
-// Authors: 
-//  Alexandre Pigolkine ([email protected])
-//  Jordi Mas ([email protected])
-//	Sanjay Gupta ([email protected])
-//	Ravindra ([email protected])
-//	Peter Dennis Bartok ([email protected])
-//	Sebastien Pouliot  <[email protected]>
-//
-//
-// Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Avalonia.Win32
-{
-    static class Gdip
-    {
-        public enum Status
-        {
-            Ok = 0,
-            GenericError = 1,
-            InvalidParameter = 2,
-            OutOfMemory = 3,
-            ObjectBusy = 4,
-            InsufficientBuffer = 5,
-            NotImplemented = 6,
-            Win32Error = 7,
-            WrongState = 8,
-            Aborted = 9,
-            FileNotFound = 10,
-            ValueOverflow = 11,
-            AccessDenied = 12,
-            UnknownImageFormat = 13,
-            FontFamilyNotFound = 14,
-            FontStyleNotFound = 15,
-            NotTrueTypeFont = 16,
-            UnsupportedGdiplusVersion = 17,
-            GdiplusNotInitialized = 18,
-            PropertyNotFound = 19,
-            PropertyNotSupported = 20,
-            ProfileNotFound = 21
-        }
-
-        [StructLayout(LayoutKind.Sequential)]
-        internal struct GdiplusStartupInput
-        {
-            // internalted to silent compiler
-            internal uint GdiplusVersion;
-            internal IntPtr DebugEventCallback;
-            internal int SuppressBackgroundThread;
-            internal int SuppressExternalCodecs;
-
-            internal static GdiplusStartupInput MakeGdiplusStartupInput()
-            {
-                GdiplusStartupInput result = new GdiplusStartupInput();
-                result.GdiplusVersion = 1;
-                result.DebugEventCallback = IntPtr.Zero;
-                result.SuppressBackgroundThread = 0;
-                result.SuppressExternalCodecs = 0;
-                return result;
-            }
-        }
-
-        [StructLayout(LayoutKind.Sequential)]
-        internal struct GdiplusStartupOutput
-        {
-            internal IntPtr NotificationHook;
-            internal IntPtr NotificationUnhook;
-
-            internal static GdiplusStartupOutput MakeGdiplusStartupOutput()
-            {
-                GdiplusStartupOutput result = new GdiplusStartupOutput();
-                result.NotificationHook = result.NotificationUnhook = IntPtr.Zero;
-                return result;
-            }
-        }
-
-
-        [DllImport("gdiplus.dll")]
-        public static extern Status GdiplusStartup(ref ulong token, ref GdiplusStartupInput input, ref GdiplusStartupOutput output);
-
-        [DllImport("gdiplus.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
-        public static extern Status GdipLoadImageFromStream([MarshalAs(UnmanagedType.Interface, MarshalTypeRef = typeof(IStream))] IStream stream, out IntPtr image);
-        [DllImport("gdiplus.dll")]
-        public static extern Status GdipCreateHICONFromBitmap(IntPtr bmp, out IntPtr HandleIcon);
-
-        [DllImport("gdiplus.dll")]
-        internal static extern Status GdipDisposeImage(IntPtr image);
-
-        static Gdip()
-        {
-            ulong token = 0;
-            var input = GdiplusStartupInput.MakeGdiplusStartupInput();
-            var output = GdiplusStartupOutput.MakeGdiplusStartupOutput();
-            GdiplusStartup(ref token, ref input, ref output);
-        }
-    }
-}

+ 0 - 45
src/Windows/Avalonia.Win32.NetStandard/IconImpl.cs

@@ -1,45 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Platform;
-
-namespace Avalonia.Win32
-{
-    public class IconImpl : IWindowIconImpl
-    {
-        private readonly MemoryStream _ms;
-
-        public IconImpl(Stream data)
-        {
-            _ms =  new MemoryStream();
-            data.CopyTo(_ms);
-            _ms.Seek(0, SeekOrigin.Begin);
-            IntPtr bitmap;
-            var status = Gdip.GdipLoadImageFromStream(new ComIStreamWrapper(_ms), out bitmap);
-            if (status != Gdip.Status.Ok)
-                throw new Exception("Unable to load icon, gdip status: " + (int) status);
-            IntPtr icon;
-            status = Gdip.GdipCreateHICONFromBitmap(bitmap, out icon);
-            if (status != Gdip.Status.Ok)
-                throw new Exception("Unable to create HICON, gdip status: " + (int)status);
-            Gdip.GdipDisposeImage(bitmap);
-            HIcon = icon;
-        }
-
-        public  IntPtr HIcon { get;}
-        public void Save(Stream outputStream)
-        {
-            lock (_ms)
-            {
-                _ms.Seek(0, SeekOrigin.Begin);
-                _ms.CopyTo(outputStream);
-            }
-        }
-        
-    }
-}

+ 0 - 30
src/Windows/Avalonia.Win32.NetStandard/NativeWin32Platform.cs

@@ -1,30 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Platform;
-
-namespace Avalonia.Win32
-{
-    partial class Win32Platform
-    {
-        //TODO: An actual implementation
-        public IWindowIconImpl LoadIcon(string fileName)
-        {
-            //No file IO for netstandard, still waiting for proper net core tooling
-            throw new NotSupportedException();
-        }
-
-        public IWindowIconImpl LoadIcon(Stream stream) => new IconImpl(stream);
-
-        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
-        {
-            var ms = new MemoryStream();
-            bitmap.Save(ms);
-            ms.Seek(0, SeekOrigin.Begin);
-            return new IconImpl(ms);
-        }
-    }
-}

+ 0 - 12
src/Windows/Avalonia.Win32.NetStandard/Win32Exception.cs

@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Avalonia.Win32.NetStandard
-{
-    class AvaloniaWin32Exception : Exception
-    {
-    }
-}

+ 0 - 35
src/Windows/Avalonia.Win32/Avalonia.Win32.Shared.projitems

@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
-    <HasSharedItems>true</HasSharedItems>
-    <SharedGUID>9defc6b7-845b-4d8f-afc0-d32bf0032b8c</SharedGUID>
-  </PropertyGroup>
-  <PropertyGroup Label="Configuration">
-    <Import_RootNamespace>Avalonia.Win32.Shared</Import_RootNamespace>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildThisFileDirectory)ClipboardImpl.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)CursorFactory.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)EmbeddedWindowImpl.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)FramebufferManager.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Input\KeyInterop.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Input\WindowsKeyboardDevice.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Input\WindowsMouseDevice.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Interop\UnmanagedMethods.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)PlatformConstants.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)PopupImpl.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Properties\AssemblyInfo.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)RenderLoop.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)ScreenImpl.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)SystemDialogImpl.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Win32Platform.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)WindowFramebuffer.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)WindowImpl.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)WinScreen.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)..\..\Shared\WindowResizeDragHelper.cs" />
-    <Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
-      <Link>Properties\SharedAssemblyInfo.cs</Link>
-    </Compile>
-  </ItemGroup>
-</Project>

+ 12 - 98
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@@ -1,103 +1,17 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{811A76CF-1CF6-440F-963B-BBE31BD72A82}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Avalonia.Win32</RootNamespace>
-    <AssemblyName>Avalonia.Win32</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <NuGetPackageImportStamp>
-    </NuGetPackageImportStamp>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Debug\Avalonia.Win32.xml</DocumentationFile>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <NoWarn>CS1591</NoWarn>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Release\Avalonia.Win32.xml</DocumentationFile>
+    <TargetFramework>netstandard2.0</TargetFramework>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <NoWarn>CS1591</NoWarn>
-    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="PresentationCore" />
-    <Reference Include="PresentationFramework" />
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.Windows.Forms" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Windows.Forms" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Xaml" />
-    <Reference Include="WindowsBase" />
-    <Reference Include="WindowsFormsIntegration" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Embedding\WinFormsAvaloniaControlHost.cs">
-      <SubType>Component</SubType>
-    </Compile>
-    <Compile Include="IconImpl.cs" />
-    <Compile Include="WinFormsWin32Platform.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj">
-      <Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project>
-      <Name>Avalonia.Animation</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj">
-      <Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
-      <Name>Avalonia.Base</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj">
-      <Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project>
-      <Name>Avalonia.Controls</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
-      <Project>{7062AE20-5DCC-4442-9645-8195BDECE63E}</Project>
-      <Name>Avalonia.Diagnostics</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj">
-      <Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project>
-      <Name>Avalonia.Input</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
-      <Project>{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}</Project>
-      <Name>Avalonia.Interactivity</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj">
-      <Project>{42472427-4774-4C81-8AFF-9F27B8E31721}</Project>
-      <Name>Avalonia.Layout</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj">
-      <Project>{EB582467-6ABB-43A1-B052-E981BA910E3A}</Project>
-      <Name>Avalonia.Visuals</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj">
-      <Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
-      <Name>Avalonia.Styling</Name>
-    </ProjectReference>
+    <ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj" />
+    <ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
+    <ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj" />
+    <ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj" />
+    <ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
+    <ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj" />
+    <ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj" />
+    <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
   </ItemGroup>
-  <Import Project="Avalonia.Win32.Shared.projitems" Label="Shared" />
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="..\..\..\build\Rx.props" />
-</Project>
+  <Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />
+</Project>

+ 1 - 1
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@@ -1098,7 +1098,7 @@ namespace Avalonia.Win32.Interop
             }
         }
 
-        [StructLayout(LayoutKind.Sequential)]
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
         public struct WNDCLASSEX
         {
             public int cbSize;

+ 0 - 2
src/Windows/Avalonia.Win32/Properties/AssemblyInfo.cs

@@ -3,7 +3,5 @@
 
 using Avalonia.Platform;
 using Avalonia.Win32;
-using System.Reflection;
 
-[assembly: AssemblyTitle("Avalonia.Win32")]
 [assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 1, "Win32", typeof(Win32Platform), nameof(Win32Platform.Initialize))]

+ 2 - 2
src/Windows/Avalonia.Win32/ScreenImpl.cs

@@ -41,8 +41,8 @@ namespace Avalonia.Win32
                                 Rect avaloniaBounds = new Rect(bounds.left, bounds.top, bounds.right - bounds.left,
                                     bounds.bottom - bounds.top);
                                 Rect avaloniaWorkArea =
-                                    new Rect(workingArea.left, workingArea.top, workingArea.right - bounds.left,
-                                        workingArea.bottom - bounds.top);
+                                    new Rect(workingArea.left, workingArea.top, workingArea.right - workingArea.left,
+                                        workingArea.bottom - workingArea.top);
                                 screens[index] =
                                     new WinScreen(avaloniaBounds, avaloniaWorkArea, monitorInfo.dwFlags == 1,
                                         monitor);

+ 0 - 184
src/Windows/Avalonia.Win32/Settings.StyleCop

@@ -1,184 +0,0 @@
-<StyleCopSettings Version="105">
-  <Analyzers>
-    <Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
-      <Rules>
-        <Rule Name="ElementsMustBeDocumented">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="PartialElementsMustBeDocumented">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="EnumerationItemsMustBeDocumented">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="DocumentationMustContainValidXml">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementDocumentationMustHaveSummary">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="PartialElementDocumentationMustHaveSummary">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementDocumentationMustHaveSummaryText">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="PartialElementDocumentationMustHaveSummaryText">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementDocumentationMustNotHaveDefaultSummary">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementParametersMustBeDocumented">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementParameterDocumentationMustMatchElementParameters">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementParameterDocumentationMustDeclareParameterName">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementParameterDocumentationMustHaveText">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementReturnValueMustBeDocumented">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementReturnValueDocumentationMustHaveText">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="VoidReturnValueMustNotBeDocumented">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="GenericTypeParametersMustBeDocumented">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="GenericTypeParametersMustBeDocumentedPartialClass">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="GenericTypeParameterDocumentationMustMatchTypeParameters">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="GenericTypeParameterDocumentationMustDeclareParameterName">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="GenericTypeParameterDocumentationMustHaveText">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="PropertySummaryDocumentationMustMatchAccessors">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="PropertySummaryDocumentationMustOmitSetAccessorWithRestrictedAccess">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="SingleLineCommentsMustNotUseDocumentationStyleSlashes">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="DocumentationTextMustNotBeEmpty">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="DocumentationTextMustContainWhitespace">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="DocumentationMustMeetCharacterPercentage">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="DestructorSummaryDocumentationMustBeginWithStandardText">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="DocumentationHeadersMustNotContainBlankLines">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="IncludedDocumentationXPathDoesNotExist">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="IncludeNodeDoesNotContainValidFileAndPath">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="InheritDocMustBeUsedWithInheritingClass">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-        <Rule Name="ElementDocumentationMustBeSpelledCorrectly">
-          <RuleSettings>
-            <BooleanProperty Name="Enabled">False</BooleanProperty>
-          </RuleSettings>
-        </Rule>
-      </Rules>
-      <AnalyzerSettings />
-    </Analyzer>
-  </Analyzers>
-</StyleCopSettings>

+ 37 - 1
src/Windows/Avalonia.Win32/Win32Platform.cs

@@ -16,6 +16,7 @@ using Avalonia.Win32.Interop;
 using Avalonia.Controls;
 using Avalonia.Rendering;
 using Avalonia.Threading;
+using System.IO;
 #if NETSTANDARD
 using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception;
 #else
@@ -40,7 +41,7 @@ namespace Avalonia
 
 namespace Avalonia.Win32
 {
-    partial class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform, IPlatformIconLoader
+    class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform, IPlatformIconLoader
     {
         private static readonly Win32Platform s_instance = new Win32Platform();
         private static uint _uiThread;
@@ -205,5 +206,40 @@ namespace Avalonia.Win32
         {
             return new PopupImpl();
         }
+
+        public IWindowIconImpl LoadIcon(string fileName)
+        {
+            using (var stream = File.OpenRead(fileName))
+            {
+                return CreateIconImpl(stream);
+            }
+        }
+
+        public IWindowIconImpl LoadIcon(Stream stream)
+        {
+            return CreateIconImpl(stream);
+        }
+
+        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
+        {
+            using (var memoryStream = new MemoryStream())
+            {
+                bitmap.Save(memoryStream);
+                return new IconImpl(new System.Drawing.Bitmap(memoryStream));
+            }
+        }
+
+        private static IconImpl CreateIconImpl(Stream stream)
+        {
+            try
+            {
+                return new IconImpl(new System.Drawing.Icon(stream));
+            }
+            catch (ArgumentException)
+            {
+                return new IconImpl(new System.Drawing.Bitmap(stream));
+            }
+        }
+
     }
 }

+ 0 - 47
src/Windows/Avalonia.Win32/WinFormsWin32Platform.cs

@@ -1,47 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Platform;
-
-namespace Avalonia.Win32
-{
-    partial class Win32Platform
-    {
-        public IWindowIconImpl LoadIcon(string fileName)
-        {
-            using (var stream = File.OpenRead(fileName))
-            {
-                return CreateImpl(stream);
-            }
-        }
-
-        public IWindowIconImpl LoadIcon(Stream stream)
-        {
-            return CreateImpl(stream);
-        }
-
-        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
-        {
-            using (var memoryStream = new MemoryStream())
-            {
-                bitmap.Save(memoryStream);
-                return new IconImpl(new System.Drawing.Bitmap(memoryStream));
-            }
-        }
-
-        private static IconImpl CreateImpl(Stream stream)
-        {
-            try
-            {
-                return new IconImpl(new System.Drawing.Icon(stream));
-            }
-            catch (ArgumentException)
-            {
-                return new IconImpl(new System.Drawing.Bitmap(stream));
-            }
-        }
-    }
-}

+ 5 - 10
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -1,29 +1,24 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
-using Avalonia.Input;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Diagnostics.CodeAnalysis;
-using System.Linq;
+using System.Reactive.Disposables;
 using System.Runtime.InteropServices;
 using Avalonia.Controls;
-using System.Reactive.Disposables;
+using Avalonia.Input;
 using Avalonia.Input.Raw;
 using Avalonia.Platform;
+using Avalonia.Rendering;
 using Avalonia.Win32.Input;
 using Avalonia.Win32.Interop;
 using static Avalonia.Win32.Interop.UnmanagedMethods;
-using Avalonia.Rendering;
-using Avalonia.Threading;
-#if NETSTANDARD
-using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception;
-#endif
 
 namespace Avalonia.Win32
 {
-    class WindowImpl : IWindowImpl
+    public class WindowImpl : IWindowImpl
     {
         private static readonly List<WindowImpl> s_instances = new List<WindowImpl>();
 
@@ -646,7 +641,7 @@ namespace Avalonia.Win32
             // Ensure that the delegate doesn't get garbage collected by storing it as a field.
             _wndProcDelegate = new UnmanagedMethods.WndProc(WndProc);
 
-            _className = Guid.NewGuid().ToString();
+            _className = "Avalonia-" + Guid.NewGuid();
 
             UnmanagedMethods.WNDCLASSEX wndClassEx = new UnmanagedMethods.WNDCLASSEX
             {

+ 7 - 2
src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs

@@ -16,11 +16,15 @@ namespace Avalonia.iOS
     /// </summary>
     class EmulatedFramebuffer : ILockedFramebuffer
     {
+        private nfloat _viewWidth;
+        private nfloat _viewHeight;
 
         public EmulatedFramebuffer(UIView view)
         {
             var factor = (int) UIScreen.MainScreen.Scale;
             var frame = view.Frame;
+            _viewWidth = frame.Width;
+            _viewHeight = frame.Height;
             Width = (int) frame.Width * factor;
             Height = (int) frame.Height * factor;
             RowBytes = Width * 4;
@@ -41,9 +45,9 @@ namespace Avalonia.iOS
             using (var context = UIGraphics.GetCurrentContext())
             {
                 // flip the image for CGContext.DrawImage
-                context.TranslateCTM(0, Height);
+                context.TranslateCTM(0, _viewHeight);
                 context.ScaleCTM(1, -1);
-                context.DrawImage(new CGRect(0, 0, Width, Height), image);
+                context.DrawImage(new CGRect(0, 0, _viewWidth, _viewHeight), image);
             }
             Marshal.FreeHGlobal(Address);
             Address = IntPtr.Zero;
@@ -57,3 +61,4 @@ namespace Avalonia.iOS
         public PixelFormat Format { get; }
     }
 }
+

+ 80 - 3
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@@ -70,7 +70,7 @@ namespace Avalonia.Controls.UnitTests
         }
 
         [Fact]
-        public void IsVisible_Should_Be_False_Atfer_Hide()
+        public void IsVisible_Should_Be_False_After_Hide()
         {
             using (UnitTestApplication.Start(TestServices.StyledWindow))
             {
@@ -84,7 +84,7 @@ namespace Avalonia.Controls.UnitTests
         }
 
         [Fact]
-        public void IsVisible_Should_Be_False_Atfer_Close()
+        public void IsVisible_Should_Be_False_After_Close()
         {
             using (UnitTestApplication.Start(TestServices.StyledWindow))
             {
@@ -98,7 +98,7 @@ namespace Avalonia.Controls.UnitTests
         }
 
         [Fact]
-        public void IsVisible_Should_Be_False_Atfer_Impl_Signals_Close()
+        public void IsVisible_Should_Be_False_After_Impl_Signals_Close()
         {
             var windowImpl = new Mock<IWindowImpl>();
             windowImpl.SetupProperty(x => x.Closed);
@@ -238,6 +238,83 @@ namespace Avalonia.Controls.UnitTests
             ((IList<Window>)Window.OpenWindows).Clear();
         }
 
+        [Fact]
+        public void Window_Should_Be_Centered_When_WindowStartupLocation_Is_CenterScreen()
+        {
+            var screen1 = new Mock<Screen>(new Rect(new Size(1920, 1080)), new Rect(new Size(1920, 1040)), true);
+            var screen2 = new Mock<Screen>(new Rect(new Size(1366, 768)), new Rect(new Size(1366, 728)), false);
+
+            var screens = new Mock<IScreenImpl>();
+            screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object, screen2.Object });
+
+            var windowImpl = new Mock<IWindowImpl>();
+            windowImpl.SetupProperty(x => x.Position);
+            windowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480));
+            windowImpl.Setup(x => x.Scaling).Returns(1);
+            windowImpl.Setup(x => x.Screen).Returns(screens.Object);
+
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var window = new Window(windowImpl.Object);
+                window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
+                window.Position = new Point(60, 40);
+
+                window.Show();
+
+                var expectedPosition = new Point(
+                    screen1.Object.WorkingArea.Size.Width / 2 - window.ClientSize.Width / 2,
+                    screen1.Object.WorkingArea.Size.Height / 2 - window.ClientSize.Height / 2);
+
+                Assert.Equal(window.Position, expectedPosition);
+            }
+        }
+
+        [Fact]
+        public void Window_Should_Be_Centered_Relative_To_Owner_When_WindowStartupLocation_Is_CenterOwner()
+        {
+            var parentWindowImpl = new Mock<IWindowImpl>();
+            parentWindowImpl.SetupProperty(x => x.Position);
+            parentWindowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480));
+            parentWindowImpl.Setup(x => x.MaxClientSize).Returns(new Size(1920, 1080));
+            parentWindowImpl.Setup(x => x.Scaling).Returns(1);
+
+            var windowImpl = new Mock<IWindowImpl>();
+            windowImpl.SetupProperty(x => x.Position);
+            windowImpl.Setup(x => x.ClientSize).Returns(new Size(320, 200));
+            windowImpl.Setup(x => x.MaxClientSize).Returns(new Size(1920, 1080));
+            windowImpl.Setup(x => x.Scaling).Returns(1);
+
+            var parentWindowServices = TestServices.StyledWindow.With(
+                windowingPlatform: new MockWindowingPlatform(() => parentWindowImpl.Object));
+
+            var windowServices = TestServices.StyledWindow.With(
+                windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object));
+
+            using (UnitTestApplication.Start(parentWindowServices))
+            {
+                var parentWindow = new Window();
+                parentWindow.Position = new Point(60, 40);
+
+                parentWindow.Show();
+
+                using (UnitTestApplication.Start(windowServices))
+                {
+                    var window = new Window();
+                    window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
+                    window.Position = new Point(60, 40);
+                    window.Owner = parentWindow;
+
+                    window.Show();
+
+                    var expectedPosition = new Point(
+                        parentWindow.Position.X + parentWindow.ClientSize.Width / 2 - window.ClientSize.Width / 2,
+                        parentWindow.Position.Y + parentWindow.ClientSize.Height / 2 - window.ClientSize.Height / 2);
+
+                    Assert.Equal(window.Position, expectedPosition);
+                }
+            }
+        }
+
         private IWindowImpl CreateImpl(Mock<IRenderer> renderer)
         {
             return Mock.Of<IWindowImpl>(x =>