Benedikt Schroeder 7 years ago
parent
commit
0adceda20c
100 changed files with 6068 additions and 1714 deletions
  1. 10 4
      .gitignore
  2. 0 0
      .ncrunch/Avalonia.DesktopRuntime.v3.ncrunchproject
  3. 0 6
      .ncrunch/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject
  4. 0 5
      .ncrunch/Avalonia.Gtk.v3.ncrunchproject
  5. 0 5
      .ncrunch/Avalonia.HtmlRenderer.v3.ncrunchproject
  6. 0 3
      .ncrunch/Avalonia.Win32.NetStandard.v3.ncrunchproject
  7. 0 3
      .ncrunch/Avalonia.Win32.Shared.v3.ncrunchproject
  8. 0 6
      .ncrunch/BindingTest.v3.ncrunchproject
  9. 0 5
      .ncrunch/RemoteTest.v3.ncrunchproject
  10. 0 8
      .ncrunch/RenderTest.v3.ncrunchproject
  11. 0 6
      .ncrunch/VirtualizationTest.v3.ncrunchproject
  12. 2 0
      .travis.yml
  13. 135 111
      Avalonia.sln
  14. 5 0
      Directory.Build.props
  15. 128 0
      azure-pipelines.yml
  16. 6 0
      build-native.sh
  17. 113 191
      build.cake
  18. 20 0
      build/CoreLibraries.props
  19. 3 0
      build/LegacyProject.targets
  20. 0 5
      build/MonoMac.props
  21. 1 1
      build/ReactiveUI.props
  22. 6 0
      build/ReferenceCoreLibraries.props
  23. 0 4
      build/Rx.props
  24. 1 6
      build/SampleApp.props
  25. 2 2
      build/SharedVersion.props
  26. 1 1
      build/System.Drawing.Common.props
  27. 1 0
      dirs.proj
  28. 3 2
      global.json
  29. 5 0
      native/Avalonia.Native/inc/avalonia-native-guids.h
  30. 363 0
      native/Avalonia.Native/inc/avalonia-native.h
  31. 57 0
      native/Avalonia.Native/inc/com.h
  32. 184 0
      native/Avalonia.Native/inc/comimpl.h
  33. 1023 0
      native/Avalonia.Native/inc/key.h
  34. 4 0
      native/Avalonia.Native/src/OSX/.gitignore
  35. 328 0
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  36. 7 0
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  37. 91 0
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
  38. 12 0
      native/Avalonia.Native/src/OSX/KeyTransform.h
  39. 241 0
      native/Avalonia.Native/src/OSX/KeyTransform.mm
  40. 51 0
      native/Avalonia.Native/src/OSX/Screens.mm
  41. 262 0
      native/Avalonia.Native/src/OSX/SystemDialogs.mm
  42. 47 0
      native/Avalonia.Native/src/OSX/clipboard.mm
  43. 34 0
      native/Avalonia.Native/src/OSX/common.h
  44. 29 0
      native/Avalonia.Native/src/OSX/cursor.h
  45. 73 0
      native/Avalonia.Native/src/OSX/cursor.mm
  46. 255 0
      native/Avalonia.Native/src/OSX/gl.mm
  47. 178 0
      native/Avalonia.Native/src/OSX/main.mm
  48. 190 0
      native/Avalonia.Native/src/OSX/platformthreading.mm
  49. 33 0
      native/Avalonia.Native/src/OSX/window.h
  50. 1232 0
      native/Avalonia.Native/src/OSX/window.mm
  51. 0 504
      packages.cake
  52. 41 0
      packages/Avalonia/Avalonia.csproj
  53. 6 0
      packages/Avalonia/Avalonia.props
  54. 24 3
      parameters.cake
  55. 2 2
      readme.md
  56. 0 22
      samples/BindingDemo/App.config
  57. 1 19
      samples/BindingDemo/BindingDemo.csproj
  58. 1 0
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  59. 0 22
      samples/ControlCatalog.Desktop/App.config
  60. 0 7
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  61. 5 3
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  62. 1 0
      samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj
  63. 0 22
      samples/ControlCatalog/App.config
  64. 7 2
      samples/ControlCatalog/App.xaml
  65. 1 12
      samples/ControlCatalog/ControlCatalog.csproj
  66. 1 1
      samples/ControlCatalog/Pages/ButtonPage.xaml
  67. 2 1
      samples/ControlCatalog/Pages/CanvasPage.xaml
  68. 1 1
      samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml
  69. 39 22
      samples/ControlCatalog/Pages/MenuPage.xaml
  70. 97 0
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  71. 4 1
      samples/Directory.Build.props
  72. 4 14
      samples/Previewer/Previewer.csproj
  73. 2 13
      samples/RemoteDemo/RemoteDemo.csproj
  74. 12 6
      samples/RenderDemo/MainWindow.xaml
  75. 18 15
      samples/RenderDemo/Pages/AnimationsPage.xaml
  76. 16 0
      samples/RenderDemo/Pages/AnimationsPage.xaml.cs
  77. 6 6
      samples/RenderDemo/Pages/ClippingPage.xaml
  78. 2 2
      samples/RenderDemo/Pages/DrawingPage.xaml
  79. 1 19
      samples/RenderDemo/RenderDemo.csproj
  80. 1 1
      samples/RenderDemo/SideBar.xaml
  81. 7 21
      samples/RenderDemo/ViewModels/AnimationsPageViewModel.cs
  82. 0 22
      samples/VirtualizationDemo/App.config
  83. 1 0
      samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
  84. 1 19
      samples/VirtualizationDemo/VirtualizationDemo.csproj
  85. 2 4
      samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
  86. 150 128
      samples/interop/Direct3DInteropSample/MainWindow.cs
  87. 5 4
      samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
  88. 3 1
      src/Android/Avalonia.Android/AndroidPlatform.cs
  89. 1 8
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  90. 4 4
      src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
  91. 1 0
      src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
  92. 12 52
      src/Avalonia.Animation/Animatable.cs
  93. 54 37
      src/Avalonia.Animation/Animation.cs
  94. 213 0
      src/Avalonia.Animation/AnimationInstance`1.cs
  95. 5 0
      src/Avalonia.Animation/AnimatorKeyFrame.cs
  96. 0 273
      src/Avalonia.Animation/AnimatorStateMachine`1.cs
  97. 74 46
      src/Avalonia.Animation/Animator`1.cs
  98. 2 1
      src/Avalonia.Animation/Avalonia.Animation.csproj
  99. 30 0
      src/Avalonia.Animation/Clock.cs
  100. 72 0
      src/Avalonia.Animation/ClockBase.cs

+ 10 - 4
.gitignore

@@ -94,10 +94,6 @@ publish/
 *.Publish.xml
 *.pubxml
 
-# NuGet Packages Directory
-## TODO: If you have NuGet Package Restore enabled, uncomment the next line
-packages/
-
 # Windows Azure Build Output
 csx
 *.build.csdef
@@ -189,3 +185,13 @@ project.lock.json
 BenchmarkDotNet.Artifacts/
 
 dirs.sln
+
+
+##################
+# XCode
+##################
+Index/
+Logs/
+ModuleCache.noindex/
+Build/Intermediates.noindex/
+info.plist

+ 0 - 0
.ncrunch/Avalonia.DotNetCoreRuntime.v3.ncrunchproject → .ncrunch/Avalonia.DesktopRuntime.v3.ncrunchproject


+ 0 - 6
.ncrunch/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject

@@ -1,6 +0,0 @@
-<ProjectConfiguration>
-  <Settings>
-    <IgnoreThisComponentCompletely>False</IgnoreThisComponentCompletely>
-    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
-  </Settings>
-</ProjectConfiguration>

+ 0 - 5
.ncrunch/Avalonia.Gtk.v3.ncrunchproject

@@ -1,5 +0,0 @@
-<ProjectConfiguration>
-  <Settings>
-    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
-  </Settings>
-</ProjectConfiguration>

+ 0 - 5
.ncrunch/Avalonia.HtmlRenderer.v3.ncrunchproject

@@ -1,5 +0,0 @@
-<ProjectConfiguration>
-  <Settings>
-    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
-  </Settings>
-</ProjectConfiguration>

+ 0 - 3
.ncrunch/Avalonia.Win32.NetStandard.v3.ncrunchproject

@@ -1,3 +0,0 @@
-<ProjectConfiguration>
-  <Settings />
-</ProjectConfiguration>

+ 0 - 3
.ncrunch/Avalonia.Win32.Shared.v3.ncrunchproject

@@ -1,3 +0,0 @@
-<ProjectConfiguration>
-  <Settings />
-</ProjectConfiguration>

+ 0 - 6
.ncrunch/BindingTest.v3.ncrunchproject

@@ -1,6 +0,0 @@
-<ProjectConfiguration>
-  <Settings>
-    <IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
-    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
-  </Settings>
-</ProjectConfiguration>

+ 0 - 5
.ncrunch/RemoteTest.v3.ncrunchproject

@@ -1,5 +0,0 @@
-<ProjectConfiguration>
-  <Settings>
-    <IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
-  </Settings>
-</ProjectConfiguration>

+ 0 - 8
.ncrunch/RenderTest.v3.ncrunchproject

@@ -1,8 +0,0 @@
-<ProjectConfiguration>
-  <Settings>
-    <HiddenComponentWarnings>
-      <Value>MissingOrIgnoredProjectReference</Value>
-    </HiddenComponentWarnings>
-    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
-  </Settings>
-</ProjectConfiguration>

+ 0 - 6
.ncrunch/VirtualizationTest.v3.ncrunchproject

@@ -1,6 +0,0 @@
-<ProjectConfiguration>
-  <Settings>
-    <IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
-    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
-  </Settings>
-</ProjectConfiguration>

+ 2 - 0
.travis.yml

@@ -11,6 +11,8 @@ mono:
   - 5.2.0
 dotnet: 2.1.200
 script:
+  - sudo apt-get update
+  - sudo apt-get install castxml
   - ./build.sh --target "Travis" --configuration "Release"
 notifications:
   email: false

+ 135 - 111
Avalonia.sln

@@ -80,13 +80,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{3743B0F2-C
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Android", "src\Android\Avalonia.Android\Avalonia.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Android", "src\Android\Avalonia.Android\Avalonia.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.AndroidTestApplication", "src\Android\Avalonia.AndroidTestApplication\Avalonia.AndroidTestApplication.csproj", "{FF69B927-C545-49AE-8E16-3D14D621AA12}"
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOS", "iOS", "{0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.iOS", "src\iOS\Avalonia.iOS\Avalonia.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.iOS", "src\iOS\Avalonia.iOS\Avalonia.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.iOSTestApplication", "src\iOS\Avalonia.iOSTestApplication\Avalonia.iOSTestApplication.csproj", "{8C923867-8A8F-4F6B-8B80-47D9E8436166}"
 EndProject
@@ -116,14 +116,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interop", "Interop", "{A0CC
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{C7A69145-60B6-4882-97D6-A3921DD43978}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DotNetFrameworkRuntime", "src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj", "{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RenderDemo", "samples\RenderDemo\RenderDemo.csproj", "{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Android", "samples\ControlCatalog.Android\ControlCatalog.Android.csproj", "{29132311-1848-4FD6-AE0C-4FF841151BD3}"
 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}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Gtk3", "src\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj", "{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}"
@@ -164,7 +160,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.LinuxFramebuffer",
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Direct3DInteropSample", "samples\interop\Direct3DInteropSample\Direct3DInteropSample.csproj", "{638580B0-7910-40EF-B674-DCB34DA308CD}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.Skia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
 EndProject
@@ -178,21 +174,25 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Designer.HostApp",
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Previewer", "samples\Previewer\Previewer.csproj", "{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}"
 EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OSX", "OSX", "{A59C4C0A-64DF-4621-B450-2BA00D6F61E2}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", "tests\Avalonia.Skia.UnitTests\Avalonia.Skia.UnitTests.csproj", "{E1240B49-7B4B-4371-A00E-068778C5CF0B}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MonoMac", "src\OSX\Avalonia.MonoMac\Avalonia.MonoMac.csproj", "{CBFD5788-567D-401B-9DFA-74E4224025A0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.OpenGL", "src\Avalonia.OpenGL\Avalonia.OpenGL.csproj", "{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Designer.HostApp.NetFX", "src\tools\Avalonia.Designer.HostApp.NetFX\Avalonia.Designer.HostApp.NetFX.csproj", "{4ADA61C8-D191-428D-9066-EF4F0D86520F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{12A91A62-C064-42CA-9A8C-A1272F354388}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", "tests\Avalonia.Skia.UnitTests\Avalonia.Skia.UnitTests.csproj", "{E1240B49-7B4B-4371-A00E-068778C5CF0B}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesktopRuntime", "src\Avalonia.DesktopRuntime\Avalonia.DesktopRuntime.csproj", "{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{E870DCD7-F46A-498D-83FC-D0FD13E0A11C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia", "packages\Avalonia\Avalonia.csproj", "{D49233F8-F29C-47DD-9975-C4C9E4502720}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Desktop", "src\Avalonia.Desktop\Avalonia.Desktop.csproj", "{3C471044-3640-45E3-B1B2-16D2FF8399EE}"
 EndProject
 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\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
 		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{dabfd304-d6a4-4752-8123-c2ccf7ac7831}*SharedItemsImports = 4
@@ -1219,30 +1219,6 @@ Global
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|iPhone.Build.0 = Release|Any CPU
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Release|iPhone.Build.0 = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -1303,30 +1279,6 @@ Global
 		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.Deploy.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
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|iPhone.Build.0 = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 		{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
 		{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
 		{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -1591,54 +1543,6 @@ Global
 		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhone.Build.0 = Release|Any CPU
 		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|Any CPU.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhone.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhone.Build.0 = Release|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|iPhone.Build.0 = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 		{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
 		{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
 		{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
@@ -1663,6 +1567,126 @@ Global
 		{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhone.Build.0 = Release|Any CPU
 		{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhone.Build.0 = Release|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.Build.0 = Release|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhone.Build.0 = Release|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Release|Any CPU.Build.0 = Release|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Release|iPhone.Build.0 = Release|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|iPhone.Build.0 = Release|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhone.Build.0 = Release|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -1713,9 +1737,9 @@ Global
 		{E2999E4A-9086-401F-898C-AEB0AD38E676} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{050CC912-FF49-4A8B-B534-9544017446DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
 		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE} = {9B9E3891-2366-4253-A952-D08BCEB71098}
-		{CBFD5788-567D-401B-9DFA-74E4224025A0} = {A59C4C0A-64DF-4621-B450-2BA00D6F61E2}
-		{4ADA61C8-D191-428D-9066-EF4F0D86520F} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
 		{E1240B49-7B4B-4371-A00E-068778C5CF0B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+		{D49233F8-F29C-47DD-9975-C4C9E4502720} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
+		{3C471044-3640-45E3-B1B2-16D2FF8399EE} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

+ 5 - 0
Directory.Build.props

@@ -0,0 +1,5 @@
+<Project>
+  <PropertyGroup>
+      <PackageOutputPath Condition="'$(PackageOutputPath)' == ''">$(MSBuildThisFileDirectory)artifacts/nuget</PackageOutputPath>
+  </PropertyGroup>
+</Project>

+ 128 - 0
azure-pipelines.yml

@@ -0,0 +1,128 @@
+jobs:
+- job: Linux
+  pool:
+    vmImage: 'ubuntu-16.04'
+  steps:
+  - task: CmdLine@2
+    displayName: 'Install CastXML'
+    inputs:
+      script: |
+        sudo apt-get update
+        sudo apt-get install castxml
+
+  - task: CmdLine@2
+    displayName: 'Install Cake'
+    inputs:
+      script: |
+        dotnet tool install -g Cake.Tool --version 0.30.0
+  
+  - task: CmdLine@2
+    displayName: 'Run Cake'
+    inputs:
+      script: |
+        export PATH="$PATH:$HOME/.dotnet/tools"
+        dotnet --info
+        printenv
+        dotnet cake build.cake -target="Azure-Linux" -configuration="Release"
+
+  - task: PublishTestResults@2
+    inputs:
+      testResultsFormat: 'VSTest'
+      testResultsFiles: '$(Build.SourcesDirectory)/artifacts/test-results/*.trx'
+    condition: not(canceled())
+     
+- job: macOS
+  pool:
+    vmImage: 'xcode9-macos10.13'
+  steps:
+  - task: DotNetCoreInstaller@0
+    inputs:
+      version: '2.1.403'
+
+  - task: Xcode@5
+    inputs:
+      actions: 'build'
+      scheme: ''
+      sdk: 'macosx10.13'
+      configuration: 'Release'
+      xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
+      xcodeVersion: 'default' # Options: 8, 9, default, specifyPath
+      args: '-derivedDataPath ./'
+
+  - task: CmdLine@2
+    displayName: 'Install CastXML'
+    inputs:
+      script: brew install castxml
+
+  - task: CmdLine@2
+    displayName: 'Install Cake'
+    inputs:
+      script: |
+        dotnet tool install -g Cake.Tool --version 0.30.0
+
+  - task: CmdLine@2
+    displayName: 'Run Cake'
+    inputs:
+      script: |
+        export COREHOST_TRACE=0
+        export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+        export DOTNET_CLI_TELEMETRY_OPTOUT=1
+        which dotnet
+        dotnet --info
+        export PATH="$PATH:$HOME/.dotnet/tools"
+        dotnet --info
+        printenv
+        dotnet cake build.cake -target="Azure-OSX" -configuration="Release"
+
+  - task: PublishTestResults@2
+    inputs:
+      testResultsFormat: 'VSTest'
+      testResultsFiles: '$(Build.SourcesDirectory)/artifacts/test-results/*.trx'
+    condition: not(canceled())
+  
+  - task: PublishBuildArtifacts@1
+    inputs:
+      pathToPublish: '$(Build.SourcesDirectory)/Build/Products/Release/'
+      artifactName: 'Avalonia.Native.OSX'
+    condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false))
+    
+  - task: PublishBuildArtifacts@1
+    inputs:
+      pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget'
+      artifactName: 'NuGetOSX'
+    condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false))
+
+- job: Windows
+  pool:
+    vmImage: 'vs2017-win2016'
+  steps:
+  - task: CmdLine@2
+    displayName: 'Install Cake'
+    inputs:
+      script: |
+        dotnet tool install -g Cake.Tool --version 0.30.0
+
+  - task: CmdLine@2
+    displayName: 'Run Cake'
+    inputs:
+      script: |
+        set PATH=%PATH%;%USERPROFILE%\.dotnet\tools
+        dotnet cake build.cake -target="Azure-Windows" -configuration="Release"
+      
+  - task: PublishTestResults@2
+    inputs:
+      testResultsFormat: 'VSTest'
+      testResultsFiles: '$(Build.SourcesDirectory)/artifacts/test-results/*.trx'
+    condition: not(canceled())
+
+  - task: PublishBuildArtifacts@1
+    inputs:
+      pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget'
+      artifactName: 'NuGet'
+    condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false))
+
+  - task: PublishBuildArtifacts@1
+    inputs:
+      pathToPublish: '$(Build.SourcesDirectory)/artifacts/zip'
+      artifactName: 'Samples'
+    condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false))

+ 6 - 0
build-native.sh

@@ -0,0 +1,6 @@
+# /bin/sh
+
+mkdir native-build
+cd native-build
+cmake -DCMAKE_BUILD_TYPE=$1 ../native
+cmake --build . --target install

+ 113 - 191
build.cake

@@ -1,15 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// ADDINS
-///////////////////////////////////////////////////////////////////////////////
-
-#addin "nuget:?package=NuGet.Core&version=2.14.0"
-#tool "nuget:?package=NuGet.CommandLine&version=4.3.0"
-#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2017.1.20170613.162720"
-
 ///////////////////////////////////////////////////////////////////////////////
 // TOOLS
 ///////////////////////////////////////////////////////////////////////////////
 
+#tool "nuget:?package=NuGet.CommandLine&version=4.7.1"
+#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2018.2.3"
 #tool "nuget:?package=xunit.runner.console&version=2.3.1"
 #tool "nuget:?package=JetBrains.dotMemoryUnit&version=3.0.20171219.105559"
 
@@ -21,39 +15,20 @@ using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
-using NuGet;
 
 ///////////////////////////////////////////////////////////////////////////////
 // SCRIPTS
 ///////////////////////////////////////////////////////////////////////////////
 
 #load "./parameters.cake"
-#load "./packages.cake"
-
-//////////////////////////////////////////////////////////////////////
-// PARAMETERS
-//////////////////////////////////////////////////////////////////////
-
-class AvaloniaBuildData
-{
-    public AvaloniaBuildData(Parameters parameters, Packages packages)
-    {
-        Parameters = parameters;
-        Packages = packages;
-    }
-
-    public Parameters Parameters { get; }
-    public Packages Packages { get; }
-}
 
 ///////////////////////////////////////////////////////////////////////////////
 // SETUP
 ///////////////////////////////////////////////////////////////////////////////
 
-Setup<AvaloniaBuildData>(context =>
+Setup<Parameters>(context =>
 {
     var parameters = new Parameters(context);
-    var buildContext = new AvaloniaBuildData(parameters, new Packages(context, parameters));
 
     Information("Building version {0} of Avalonia ({1}) using version {2} of Cake.", 
         parameters.Version,
@@ -71,22 +46,24 @@ Setup<AvaloniaBuildData>(context =>
     Information("IsRunningOnUnix: " + parameters.IsRunningOnUnix);
     Information("IsRunningOnWindows: " + parameters.IsRunningOnWindows);
     Information("IsRunningOnAppVeyor: " + parameters.IsRunningOnAppVeyor);
+    Information("IsRunnongOnAzure:" + parameters.IsRunningOnAzure);
     Information("IsPullRequest: " + parameters.IsPullRequest);
     Information("IsMainRepo: " + parameters.IsMainRepo);
     Information("IsMasterBranch: " + parameters.IsMasterBranch);
+    Information("IsReleaseBranch: " + parameters.IsReleaseBranch);
     Information("IsTagged: " + parameters.IsTagged);
     Information("IsReleasable: " + parameters.IsReleasable);
     Information("IsMyGetRelease: " + parameters.IsMyGetRelease);
     Information("IsNuGetRelease: " + parameters.IsNuGetRelease);
 
-    return buildContext;
+    return parameters;
 });
 
 ///////////////////////////////////////////////////////////////////////////////
 // TEARDOWN
 ///////////////////////////////////////////////////////////////////////////////
 
-Teardown<AvaloniaBuildData>((context, buildContext) =>
+Teardown<Parameters>((context, buildContext) =>
 {
     Information("Finished running tasks.");
 });
@@ -96,13 +73,13 @@ Teardown<AvaloniaBuildData>((context, buildContext) =>
 ///////////////////////////////////////////////////////////////////////////////
 
 Task("Clean-Impl")
-    .Does<AvaloniaBuildData>(data =>
+    .Does<Parameters>(data =>
 {
-    CleanDirectories(data.Parameters.BuildDirs);
-    CleanDirectory(data.Parameters.ArtifactsDir);
-    CleanDirectory(data.Parameters.NugetRoot);
-    CleanDirectory(data.Parameters.ZipRoot);
-    CleanDirectory(data.Parameters.BinRoot);
+    CleanDirectories(data.BuildDirs);
+    CleanDirectory(data.ArtifactsDir);
+    CleanDirectory(data.NugetRoot);
+    CleanDirectory(data.ZipRoot);
+    CleanDirectory(data.TestResultsRoot);
 });
 
 void DotNetCoreBuild(Parameters parameters)
@@ -110,27 +87,35 @@ void DotNetCoreBuild(Parameters parameters)
     var settings = new DotNetCoreBuildSettings 
     {
         Configuration = parameters.Configuration,
+        MSBuildSettings = new DotNetCoreMSBuildSettings
+        {
+            Properties =
+            {
+                { "PackageVersion", new [] { parameters.Version } }
+            }
+        }
     };
 
     DotNetCoreBuild(parameters.MSBuildSolution, settings);
 }
 
 Task("Build-Impl")
-    .Does<AvaloniaBuildData>(data =>
+    .Does<Parameters>(data =>
 {
-    if(data.Parameters.IsRunningOnWindows)
+    if(data.IsRunningOnWindows)
     {
-        MSBuild(data.Parameters.MSBuildSolution, settings => {
-            settings.SetConfiguration(data.Parameters.Configuration);
+        MSBuild(data.MSBuildSolution, settings => {
+            settings.SetConfiguration(data.Configuration);
             settings.SetVerbosity(Verbosity.Minimal);
             settings.WithProperty("iOSRoslynPathHackRequired", "true");
+            settings.WithProperty("PackageVersion", data.Version);
             settings.UseToolVersion(MSBuildToolVersion.VS2017);
             settings.WithRestore();
         });
     }
     else
     {
-        DotNetCoreBuild(data.Parameters);
+        DotNetCoreBuild(data);
     }
 });
 
@@ -146,55 +131,63 @@ void RunCoreTest(string project, Parameters parameters, bool coreOnly = false)
             continue;
         Information("Running for " + fw);
         
-        DotNetCoreTest(project,
-            new DotNetCoreTestSettings {
-                Configuration = parameters.Configuration,
-                Framework = fw,
-                NoBuild = true,
-                NoRestore = true
-            });
+        var settings = new DotNetCoreTestSettings {
+            Configuration = parameters.Configuration,
+            Framework = fw,
+            NoBuild = true,
+            NoRestore = true
+        };
+
+        if (parameters.PublishTestResults)
+        {
+            settings.Logger = "trx";
+            settings.ResultsDirectory = parameters.TestResultsRoot;
+        }
+
+        DotNetCoreTest(project, settings);
     }
 }
 
 Task("Run-Unit-Tests-Impl")
-    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.SkipTests)
-    .Does<AvaloniaBuildData>(data =>
+    .WithCriteria<Parameters>((context, data) => !data.SkipTests)
+    .Does<Parameters>(data =>
 {
-    RunCoreTest("./tests/Avalonia.Base.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Controls.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Input.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Layout.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Markup.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Styling.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Visuals.UnitTests", data.Parameters, false);
-    RunCoreTest("./tests/Avalonia.Skia.UnitTests", data.Parameters, false);
-    if (data.Parameters.IsRunningOnWindows)
+    RunCoreTest("./tests/Avalonia.Base.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Controls.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Input.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Layout.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Markup.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Styling.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Visuals.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.Skia.UnitTests", data, false);
+    RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests", data, false);
+    if (data.IsRunningOnWindows)
     {
-        RunCoreTest("./tests/Avalonia.Direct2D1.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Direct2D1.UnitTests", data, false);
     }
 });
 
 Task("Run-Designer-Tests-Impl")
-    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.SkipTests)
-    .Does<AvaloniaBuildData>(data =>
+    .WithCriteria<Parameters>((context, data) => !data.SkipTests)
+    .Does<Parameters>(data =>
 {
-    RunCoreTest("./tests/Avalonia.DesignerSupport.Tests", data.Parameters, false);
+    RunCoreTest("./tests/Avalonia.DesignerSupport.Tests", data, false);
 });
 
 Task("Run-Render-Tests-Impl")
-    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.SkipTests)
-    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsRunningOnWindows)
-    .Does<AvaloniaBuildData>(data =>
+    .WithCriteria<Parameters>((context, data) => !data.SkipTests)
+    .WithCriteria<Parameters>((context, data) => data.IsRunningOnWindows)
+    .Does<Parameters>(data =>
 {
-    RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", data.Parameters, true);
-    RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", data.Parameters, true);
+    RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", data, true);
+    RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", data, true);
 });
 
 Task("Run-Leak-Tests-Impl")
-    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.SkipTests)
-    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsRunningOnWindows)
+    .WithCriteria<Parameters>((context, data) => !data.SkipTests)
+    .WithCriteria<Parameters>((context, data) => data.IsRunningOnWindows)
     .Does(() =>
 {
     var dotMemoryUnit = Context.Tools.Resolve("dotMemoryUnit.exe");
@@ -214,136 +207,58 @@ Task("Run-Leak-Tests-Impl")
     }
 });
 
-Task("Copy-Files-Impl")
-    .Does<AvaloniaBuildData>(data =>
-{
-    CopyFiles(data.Packages.BinFiles, data.Parameters.BinRoot);
-});
-
 Task("Zip-Files-Impl")
-    .Does<AvaloniaBuildData>(data =>
+    .Does<Parameters>(data =>
 {
-    Zip(data.Parameters.BinRoot, data.Parameters.ZipCoreArtifacts);
+    Zip(data.BinRoot, data.ZipCoreArtifacts);
 
-    Zip(data.Parameters.NugetRoot, data.Parameters.ZipNuGetArtifacts);
+    Zip(data.NugetRoot, data.ZipNuGetArtifacts);
 
-    Zip(data.Parameters.ZipSourceControlCatalogDesktopDirs, 
-        data.Parameters.ZipTargetControlCatalogDesktopDirs, 
-        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") + 
-        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.config") + 
-        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.so") + 
-        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dylib") + 
-        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
+    Zip(data.ZipSourceControlCatalogDesktopDirs, 
+        data.ZipTargetControlCatalogDesktopDirs, 
+        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") + 
+        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.config") + 
+        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.so") + 
+        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dylib") + 
+        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
 });
 
-Task("Create-NuGet-Packages-Impl")
-    .Does<AvaloniaBuildData>(data =>
+void DotNetCorePack(Parameters parameters)
 {
-    foreach(var nuspec in data.Packages.NuspecNuGetSettings)
+    var settings = new DotNetCorePackSettings 
     {
-        NuGetPack(nuspec);
-    }
-});
-
-Task("Publish-MyGet-Impl")
-    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.IsLocalBuild)
-    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.IsPullRequest)
-    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsMainRepo)
-    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsMasterBranch)
-    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsMyGetRelease)
-    .Does<AvaloniaBuildData>(data =>
-{
-    var apiKey = EnvironmentVariable("MYGET_API_KEY");
-    if(string.IsNullOrEmpty(apiKey)) 
-    {
-        throw new InvalidOperationException("Could not resolve MyGet API key.");
-    }
-
-    var apiUrl = EnvironmentVariable("MYGET_API_URL");
-    if(string.IsNullOrEmpty(apiUrl)) 
-    {
-        throw new InvalidOperationException("Could not resolve MyGet API url.");
-    }
+        Configuration = parameters.Configuration,
+        MSBuildSettings = new DotNetCoreMSBuildSettings
+        {
+            Properties =
+            {
+                { "PackageVersion", new [] { parameters.Version } }
+            }
+        }
+    };
 
-    foreach(var nupkg in data.Packages.NugetPackages)
-    {
-        NuGetPush(nupkg, new NuGetPushSettings {
-            Source = apiUrl,
-            ApiKey = apiKey
-        });
-    }
-})
-.OnError(exception =>
-{
-    Information("Publish-MyGet Task failed, but continuing with next Task...");
-});
+    DotNetCorePack(parameters.MSBuildSolution, settings);
+}
 
-Task("Publish-NuGet-Impl")
-    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.IsLocalBuild)
-    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.IsPullRequest)
-    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsMainRepo)
-    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsNuGetRelease)
-    .Does<AvaloniaBuildData>(data =>
+Task("Create-NuGet-Packages-Impl")
+    .Does<Parameters>(data =>
 {
-    var apiKey = EnvironmentVariable("NUGET_API_KEY");
-    if(string.IsNullOrEmpty(apiKey)) 
-    {
-        throw new InvalidOperationException("Could not resolve NuGet API key.");
-    }
-
-    var apiUrl = EnvironmentVariable("NUGET_API_URL");
-    if(string.IsNullOrEmpty(apiUrl)) 
+    if(data.IsRunningOnWindows)
     {
-        throw new InvalidOperationException("Could not resolve NuGet API url.");
-    }
-
-    foreach(var nupkg in data.Packages.NugetPackages)
-    {
-        NuGetPush(nupkg, new NuGetPushSettings {
-            ApiKey = apiKey,
-            Source = apiUrl
+        MSBuild(data.MSBuildSolution, settings => {
+            settings.SetConfiguration(data.Configuration);
+            settings.SetVerbosity(Verbosity.Minimal);
+            settings.WithProperty("iOSRoslynPathHackRequired", "true");
+            settings.WithProperty("PackageVersion", data.Version);
+            settings.UseToolVersion(MSBuildToolVersion.VS2017);
+            settings.WithRestore();
+            settings.WithTarget("Pack");
         });
     }
-})
-.OnError(exception =>
-{
-    Information("Publish-NuGet Task failed, but continuing with next Task...");
-});
-
-Task("Inspect-Impl")
-    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsRunningOnWindows)
-    .Does(() =>
-{
-    var badIssues = new []{"PossibleNullReferenceException"};
-    var whitelist = new []{"tests", "src\\android", "src\\ios",
-        "src\\markup\\avalonia.markup.xaml\\portablexaml\\portable.xaml.github"};
-    Information("Running code inspections");
-    
-    var exitCode = StartProcess(Context.Tools.Resolve("inspectcode.exe"),
-        new ProcessSettings
-        {
-            Arguments = "--output=artifacts\\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln",
-            RedirectStandardOutput = true
-        });
-
-    Information("Analyzing report");
-    var doc = XDocument.Parse(System.IO.File.ReadAllText("artifacts\\inspectcode.xml"));
-    var failBuild = false;
-    foreach(var xml in doc.Descendants("Issue"))
+    else
     {
-        var typeId = xml.Attribute("TypeId").Value.ToString();
-        if(badIssues.Contains(typeId))
-        {
-            var file = xml.Attribute("File").Value.ToString().ToLower();
-            if(whitelist.Any(wh => file.StartsWith(wh)))
-                continue;
-            var line = xml.Attribute("Line").Value.ToString();
-            Error(typeId + " - " + file + " on line " + line);
-            failBuild = true;
-        }
+        DotNetCorePack(data);
     }
-    if(failBuild)
-        throw new Exception("Issues found");
 });
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -363,19 +278,26 @@ Task("Run-Tests")
 
 Task("Package")
     .IsDependentOn("Run-Tests")
-    .IsDependentOn("Inspect-Impl")
     .IsDependentOn("Create-NuGet-Packages-Impl");
 
 Task("AppVeyor")
   .IsDependentOn("Package")
-  .IsDependentOn("Copy-Files-Impl")
-  .IsDependentOn("Zip-Files-Impl")
-  .IsDependentOn("Publish-MyGet-Impl")
-  .IsDependentOn("Publish-NuGet-Impl");
+  .IsDependentOn("Zip-Files-Impl");
 
 Task("Travis")
   .IsDependentOn("Run-Tests");
 
+Task("Azure-Linux")
+  .IsDependentOn("Run-Tests");
+
+Task("Azure-OSX")
+  .IsDependentOn("Package")
+  .IsDependentOn("Zip-Files-Impl");
+
+Task("Azure-Windows")
+  .IsDependentOn("Package")
+  .IsDependentOn("Zip-Files-Impl");
+
 ///////////////////////////////////////////////////////////////////////////////
 // EXECUTE
 ///////////////////////////////////////////////////////////////////////////////

+ 20 - 0
build/CoreLibraries.props

@@ -0,0 +1,20 @@
+<Project>
+  <ItemGroup>
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Base/Avalonia.Base.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Animation/Avalonia.Animation.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Controls/Avalonia.Controls.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Input/Avalonia.Input.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Interactivity/Avalonia.Interactivity.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Layout/Avalonia.Layout.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Visuals/Avalonia.Visuals.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Styling/Avalonia.Styling.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.OpenGL/Avalonia.OpenGL.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup/Avalonia.Markup.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" />
+      <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
+  </ItemGroup>
+</Project>

+ 3 - 0
build/LegacyProject.targets

@@ -0,0 +1,3 @@
+<Project>
+  <Target Name="Pack" />
+</Project>

+ 0 - 5
build/MonoMac.props

@@ -1,5 +0,0 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
-  </ItemGroup>
-</Project>

+ 1 - 1
build/ReactiveUI.props

@@ -1,5 +1,5 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <PackageReference Include="reactiveui" Version="8.7.1" />
+    <PackageReference Include="reactiveui" Version="9.0.1" />
   </ItemGroup>
 </Project>

+ 6 - 0
build/ReferenceCoreLibraries.props

@@ -0,0 +1,6 @@
+<Project>
+  <Import Condition="'$(TargetFramework)' == 'netcoreapp2.0'" Project="CoreLibraries.props" />
+  <ItemGroup>
+      <ProjectReference Include="$(MSBuildThisFileDirectory)../packages/Avalonia/Avalonia.csproj" />
+  </ItemGroup>
+</Project>

+ 0 - 4
build/Rx.props

@@ -1,9 +1,5 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
     <PackageReference Include="System.Reactive" Version="4.0.0" />
-    <PackageReference Include="System.Reactive.Core" Version="4.0.0" />
-    <PackageReference Include="System.Reactive.Interfaces" Version="4.0.0" />
-    <PackageReference Include="System.Reactive.Linq" Version="4.0.0" />
-    <PackageReference Include="System.Reactive.PlatformServices" Version="4.0.0" />
   </ItemGroup>
 </Project>

+ 1 - 6
build/SampleApp.props

@@ -2,12 +2,7 @@
   <PropertyGroup Condition="'$(TargetFramework)'=='net461'" >
     <OutputType>WinExe</OutputType>
   </PropertyGroup>
-
-  <!-- Should be a Condition="'$(TargetFramework)'=='net461'" here but that doesn't work due
-       to https://github.com/dotnet/sdk/issues/1227 -->
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" />
-    <ProjectReference Include="..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
+    <ProjectReference Include="$(MSBuildThisFileDirectory)..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
   </ItemGroup>
-  <Import Condition="'$(TargetFramework)'=='net461'" Project="SharpDX.props" />
 </Project>

+ 2 - 2
build/SharedVersion.props

@@ -2,8 +2,8 @@
   xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Product>Avalonia</Product>
-    <Version>0.6.2</Version>
-    <Copyright>Copyright 2016 &#169; The AvaloniaUI Project</Copyright>
+    <Version>0.7.1</Version>
+    <Copyright>Copyright 2018 &#169; The AvaloniaUI Project</Copyright>
     <PackageLicenseUrl>https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md</PackageLicenseUrl>
     <PackageProjectUrl>https://github.com/AvaloniaUI/Avalonia/</PackageProjectUrl>
     <RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>

+ 1 - 1
build/System.Drawing.Common.props

@@ -1,5 +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" />
+    <PackageReference Include="System.Drawing.Common" Version="4.5.0" />
   </ItemGroup>
 </Project>

+ 1 - 0
dirs.proj

@@ -3,6 +3,7 @@
     <ProjectReference Include="src/**/*.*proj" />
     <ProjectReference Include="samples/**/*.*proj" />
     <ProjectReference Include="tests/**/*.*proj" />
+    <ProjectReference Include="packages/**/*.*proj" />
     <ProjectReference Remove="**/*.shproj" />
     <ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/PortableXaml/**/*.*proj" />
   </ItemGroup>

+ 3 - 2
global.json

@@ -1,6 +1,7 @@
 {
     "msbuild-sdks": {
-        "Microsoft.Build.Traversal": "1.0.41",
-        "MSBuild.Sdk.Extras": "1.6.46"
+        "Microsoft.Build.Traversal": "1.0.43",
+        "MSBuild.Sdk.Extras": "1.6.46",
+        "AggregatePackage.NuGet.Sdk" : "0.1.12"
     }
 }

+ 5 - 0
native/Avalonia.Native/inc/avalonia-native-guids.h

@@ -0,0 +1,5 @@
+// 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.
+
+#define COM_GUIDS_MATERIALIZE
+#include "avalonia-native.h"

+ 363 - 0
native/Avalonia.Native/inc/avalonia-native.h

@@ -0,0 +1,363 @@
+// 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.
+
+#include "com.h"
+#include "key.h"
+
+#define AVNCOM(name, id) COMINTERFACE(name, 2e2cda0a, 9ae5, 4f1b, 8e, 20, 08, 1a, 04, 27, 9f, id)
+
+struct IAvnWindowEvents;
+struct IAvnWindow;
+struct IAvnPopup;
+struct IAvnMacOptions;
+struct IAvnPlatformThreadingInterface;
+struct IAvnSystemDialogEvents;
+struct IAvnSystemDialogs;
+struct IAvnScreens;
+struct IAvnClipboard;
+struct IAvnCursor;
+struct IAvnCursorFactory;
+struct IAvnGlFeature;
+struct IAvnGlContext;
+struct IAvnGlDisplay;
+struct IAvnGlSurfaceRenderTarget;
+struct IAvnGlSurfaceRenderingSession;
+
+struct AvnSize
+{
+    double Width, Height;
+};
+
+struct AvnPixelSize
+{
+    int Width, Height;
+};
+
+struct AvnRect
+{
+    double X, Y, Width, Height;
+};
+
+struct AvnVector
+{
+    double X, Y;
+};
+
+struct AvnPoint
+{
+    double X, Y;
+};
+
+struct AvnScreen
+{
+    AvnRect Bounds;
+    AvnRect WorkingArea;
+    bool Primary;
+};
+
+enum AvnPixelFormat
+{
+    kAvnRgb565,
+    kAvnRgba8888,
+    kAvnBgra8888
+};
+
+struct AvnFramebuffer
+{
+    void* Data;
+    int Width;
+    int Height;
+    int Stride;
+    AvnVector Dpi;
+    AvnPixelFormat PixelFormat;
+};
+
+struct AvnColor
+{
+    unsigned char Alpha;
+    unsigned char Red;
+    unsigned char Green;
+    unsigned char Blue;
+};
+
+enum AvnRawMouseEventType
+{
+    LeaveWindow,
+    LeftButtonDown,
+    LeftButtonUp,
+    RightButtonDown,
+    RightButtonUp,
+    MiddleButtonDown,
+    MiddleButtonUp,
+    Move,
+    Wheel,
+    NonClientLeftButtonDown
+};
+
+enum AvnRawKeyEventType
+{
+    KeyDown,
+    KeyUp
+};
+
+enum AvnInputModifiers
+{
+    AvnInputModifiersNone = 0,
+    Alt = 1,
+    Control = 2,
+    Shift = 4,
+    Windows = 8,
+    LeftMouseButton = 16,
+    RightMouseButton = 32,
+    MiddleMouseButton = 64
+};
+
+enum AvnWindowState
+{
+    Normal,
+    Minimized,
+    Maximized,
+};
+
+enum AvnStandardCursorType
+{
+    CursorArrow,
+    CursorIbeam,
+    CursorWait,
+    CursorCross,
+    CursorUpArrow,
+    CursorSizeWestEast,
+    CursorSizeNorthSouth,
+    CursorSizeAll,
+    CursorNo,
+    CursorHand,
+    CursorAppStarting,
+    CursorHelp,
+    CursorTopSide,
+    CursorBottomSize,
+    CursorLeftSide,
+    CursorRightSide,
+    CursorTopLeftCorner,
+    CursorTopRightCorner,
+    CursorBottomLeftCorner,
+    CursorBottomRightCorner,
+    CursorDragMove,
+    CursorDragCopy,
+    CursorDragLink,
+};
+
+enum AvnWindowEdge
+{
+    WindowEdgeNorthWest,
+    WindowEdgeNorth,
+    WindowEdgeNorthEast,
+    WindowEdgeWest,
+    WindowEdgeEast,
+    WindowEdgeSouthWest,
+    WindowEdgeSouth,
+    WindowEdgeSouthEast
+};
+
+AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown
+{
+public:
+    virtual HRESULT Initialize() = 0;
+    virtual IAvnMacOptions* GetMacOptions() = 0;
+    virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv) = 0;
+    virtual HRESULT CreatePopup (IAvnWindowEvents* cb, IAvnPopup** ppv) = 0;
+    virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) = 0;
+    virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0;
+    virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0;
+    virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0;
+    virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0;
+    virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) = 0;
+};
+
+AVNCOM(IAvnWindowBase, 02) : IUnknown
+{
+    virtual HRESULT Show() = 0;
+    virtual HRESULT Hide () = 0;
+    virtual HRESULT Close() = 0;
+    virtual HRESULT Activate () = 0;
+    virtual HRESULT GetClientSize(AvnSize*ret) = 0;
+    virtual HRESULT GetMaxClientSize(AvnSize* ret) = 0;
+    virtual HRESULT GetScaling(double*ret)=0;
+    virtual HRESULT SetMinMaxSize(AvnSize minSize, AvnSize maxSize) = 0;
+    virtual HRESULT Resize(double width, double height) = 0;
+    virtual HRESULT Invalidate (AvnRect rect) = 0;
+    virtual HRESULT BeginMoveDrag () = 0;
+    virtual HRESULT BeginResizeDrag (AvnWindowEdge edge) = 0;
+    virtual HRESULT GetPosition (AvnPoint*ret) = 0;
+    virtual HRESULT SetPosition (AvnPoint point) = 0;
+    virtual HRESULT PointToClient (AvnPoint point, AvnPoint*ret) = 0;
+    virtual HRESULT PointToScreen (AvnPoint point, AvnPoint*ret) = 0;
+    virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer* fb, IUnknown* dispose) = 0;
+    virtual HRESULT SetTopMost (bool value) = 0;
+    virtual HRESULT SetCursor(IAvnCursor* cursor) = 0;
+    virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0;
+    virtual HRESULT GetSoftwareFramebuffer(AvnFramebuffer*ret) = 0;
+    virtual bool TryLock() = 0;
+    virtual void Unlock() = 0;
+};
+
+AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
+{
+    
+};
+
+AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
+{
+    virtual HRESULT ShowDialog (IUnknown**ppv) = 0;
+    virtual HRESULT SetCanResize(bool value) = 0;
+    virtual HRESULT SetHasDecorations(bool value) = 0;
+    virtual HRESULT SetTitle (const char* title) = 0;
+    virtual HRESULT SetTitleBarColor (AvnColor color) = 0;
+    virtual HRESULT SetWindowState(AvnWindowState state) = 0;
+    virtual HRESULT GetWindowState(AvnWindowState*ret) = 0;
+};
+
+AVNCOM(IAvnWindowBaseEvents, 05) : IUnknown
+{
+    virtual HRESULT Paint() = 0;
+    virtual void Closed() = 0;
+    virtual void Activated() = 0;
+    virtual void Deactivated() = 0;
+    virtual void Resized(const AvnSize& size) = 0;
+    virtual void PositionChanged (AvnPoint position) = 0;
+    virtual void RawMouseEvent (AvnRawMouseEventType type,
+                                unsigned int timeStamp,
+                                AvnInputModifiers modifiers,
+                                AvnPoint point,
+                                AvnVector delta) = 0;
+    virtual bool RawKeyEvent (AvnRawKeyEventType type, unsigned int timeStamp, AvnInputModifiers modifiers, unsigned int key) = 0;
+    virtual bool RawTextInputEvent (unsigned int timeStamp, const char* text) = 0;
+    virtual void ScalingChanged(double scaling) = 0;
+    virtual void RunRenderPriorityJobs() = 0;
+};
+
+
+AVNCOM(IAvnWindowEvents, 06) : IAvnWindowBaseEvents
+{
+    /**
+     * Closing Event
+     * Called when the user presses the OS window close button.
+     * return true to allow the close, return false to prevent close.
+     */
+    virtual bool Closing () = 0;
+    
+    virtual void WindowStateChanged (AvnWindowState state) = 0;
+};
+
+AVNCOM(IAvnMacOptions, 07) : IUnknown
+{
+    virtual HRESULT SetShowInDock(int show) = 0;
+};
+
+AVNCOM(IAvnActionCallback, 08) : IUnknown
+{
+    virtual void Run() = 0;
+};
+
+AVNCOM(IAvnSignaledCallback, 09) : IUnknown
+{
+    virtual void Signaled(int priority, bool priorityContainsMeaningfulValue) = 0;
+};
+
+AVNCOM(IAvnLoopCancellation, 0a) : IUnknown
+{
+    virtual void Cancel() = 0;
+};
+
+AVNCOM(IAvnPlatformThreadingInterface, 0b) : IUnknown
+{
+    virtual bool GetCurrentThreadIsLoopThread() = 0;
+    virtual void SetSignaledCallback(IAvnSignaledCallback* cb) = 0;
+    virtual IAvnLoopCancellation* CreateLoopCancellation() = 0;
+    virtual void RunLoop(IAvnLoopCancellation* cancel) = 0;
+    // Can't pass int* to sharpgentools for some reason
+    virtual void Signal(int priority) = 0;
+    virtual IUnknown* StartTimer(int priority, int ms, IAvnActionCallback* callback) = 0;
+};
+
+AVNCOM(IAvnSystemDialogEvents, 0c) : IUnknown
+{
+    virtual void OnCompleted (int numResults, void* ptrFirstResult) = 0;
+};
+
+AVNCOM(IAvnSystemDialogs, 0d) : IUnknown
+{
+    virtual void SelectFolderDialog (IAvnWindow* parentWindowHandle,
+                                     IAvnSystemDialogEvents* events,
+                                     const char* title,
+                                     const char* initialPath) = 0;
+    
+    virtual void OpenFileDialog (IAvnWindow* parentWindowHandle,
+                                 IAvnSystemDialogEvents* events,
+                                 bool allowMultiple,
+                                 const char* title,
+                                 const char* initialDirectory,
+                                 const char* initialFile,
+                                 const char* filters) = 0;
+    
+    virtual void SaveFileDialog (IAvnWindow* parentWindowHandle,
+                                 IAvnSystemDialogEvents* events,
+                                 const char* title,
+                                 const char* initialDirectory,
+                                 const char* initialFile,
+                                 const char* filters) = 0;
+};
+
+AVNCOM(IAvnScreens, 0e) : IUnknown
+{
+    virtual HRESULT GetScreenCount (int* ret) = 0;
+    virtual HRESULT GetScreen (int index, AvnScreen* ret) = 0;
+};
+
+AVNCOM(IAvnClipboard, 0f) : IUnknown
+{
+    virtual HRESULT GetText (void** retOut) = 0;
+    virtual HRESULT SetText (char* text) = 0;
+    virtual HRESULT Clear() = 0;
+};
+
+AVNCOM(IAvnCursor, 10) : IUnknown
+{
+};
+
+AVNCOM(IAvnCursorFactory, 11) : IUnknown
+{
+    virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut) = 0;
+};
+
+
+AVNCOM(IAvnGlFeature, 12) : IUnknown
+{
+    virtual HRESULT ObtainDisplay(IAvnGlDisplay**retOut) = 0;
+    virtual HRESULT ObtainImmediateContext(IAvnGlContext**retOut) = 0;
+};
+
+AVNCOM(IAvnGlDisplay, 13) : IUnknown
+{
+    virtual HRESULT GetSampleCount(int* ret) = 0;
+    virtual HRESULT GetStencilSize(int* ret) = 0;
+    virtual HRESULT ClearContext() = 0;
+    virtual void* GetProcAddress(char* proc) = 0;
+};
+
+AVNCOM(IAvnGlContext, 14) : IUnknown
+{
+    virtual HRESULT MakeCurrent() = 0;
+};
+
+AVNCOM(IAvnGlSurfaceRenderTarget, 15) : IUnknown
+{
+    virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret) = 0;
+};
+
+AVNCOM(IAvnGlSurfaceRenderingSession, 16) : IUnknown
+{
+    virtual HRESULT GetPixelSize(AvnPixelSize* ret) = 0;
+    virtual HRESULT GetScaling(double* ret) = 0;
+};
+
+extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();

+ 57 - 0
native/Avalonia.Native/inc/com.h

@@ -0,0 +1,57 @@
+// 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.
+
+#pragma clang diagnostic push
+#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
+#ifndef COM_H_INCLUDED
+#define COM_H_INCLUDED
+
+
+typedef struct _GUID {
+    unsigned int  Data1;
+    unsigned short Data2;
+    unsigned short Data3;
+    unsigned char  Data4[ 8 ];
+} GUID;
+typedef GUID IID;
+typedef const IID* REFIID;
+typedef unsigned int HRESULT;
+typedef unsigned int DWORD;
+typedef DWORD ULONG;
+
+#define STDMETHODCALLTYPE
+
+#define S_OK                             0x0L
+
+#define E_NOTIMPL                        0x80004001L
+#define E_NOINTERFACE                    0x80004002L
+#define E_POINTER                        0x80004003L
+#define E_ABORT                          0x80004004L
+#define E_FAIL                           0x80004005L
+#define E_UNEXPECTED                     0x8000FFFFL
+#define E_HANDLE                         0x80070006L
+#define E_INVALIDARG                     0x80070057L
+
+struct IUnknown
+{
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+            REFIID riid,
+            void **ppvObject) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
+
+};
+
+#ifdef COM_GUIDS_MATERIALIZE
+#define __IID_DEF(name,d1,d2,d3, d41, d42, d43, d44, d45, d46, d47, d48) extern "C" const GUID IID_ ## name = {0x ## d1, 0x ## d2, 0x ## d3, \
+{0x ## d41, 0x ## d42, 0x ## d42, 0x ## d42, 0x ## d42, 0x ## d42, 0x ## d42, 0x ## d42 } };
+#else
+#define __IID_DEF(name,d1,d2,d3, d41, d42, d43, d44, d45, d46, d47, d48) extern "C" const GUID IID_ ## name;
+#endif
+#define COMINTERFACE(name,d1,d2,d3, d41, d42, d43, d44, d45, d46, d47, d48) __IID_DEF(name,d1,d2,d3, d41, d42, d43, d44, d45, d46, d47, d48) \
+struct __attribute__((annotate("uuid(" #d1 "-" #d2 "-" #d3 "-" #d41 #d42 "-" #d43 #d44 #d45 #d46 #d47 #d48 ")" ))) name
+
+#endif // COM_H_INCLUDED
+#pragma clang diagnostic pop

+ 184 - 0
native/Avalonia.Native/inc/comimpl.h

@@ -0,0 +1,184 @@
+// 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.
+#include "com.h"
+#pragma clang diagnostic push
+#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
+#ifndef COMIMPL_H_INCLUDED
+#define COMIMPL_H_INCLUDED
+
+#include <cstring>
+
+__IID_DEF(IUnknown, 0, 0, 0, C0, 00, 00, 00, 00, 00, 00, 46);
+
+class ComObject : public virtual IUnknown
+{
+private:
+    unsigned int _refCount;
+public:
+    
+    virtual ULONG AddRef()
+    {
+        _refCount++;
+        return _refCount;
+    }
+    
+    
+    virtual ULONG Release()
+    {
+        _refCount--;
+        ULONG rv = _refCount;
+        if(_refCount == 0)
+            delete(this);
+        return rv;
+    }
+    
+    ComObject()
+    {
+        _refCount = 1;
+        
+    }
+    virtual ~ComObject()
+    {
+    }
+    
+    
+    virtual ::HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID riid, void **ppvObject) = 0;
+    
+    virtual ::HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
+                                                     void **ppvObject)
+    {
+        if(0 == memcmp(riid, &IID_IUnknown, sizeof(GUID)))
+            *ppvObject = (IUnknown*)this;
+        else
+        {
+            auto rv = QueryInterfaceImpl(riid, ppvObject);
+            if(rv != S_OK)
+                return rv;
+        }
+        _refCount++;
+        return S_OK;
+    }
+
+};
+
+
+#define FORWARD_IUNKNOWN() \
+virtual ULONG Release() override \
+{ \
+return ComObject::Release(); \
+} \
+virtual ULONG AddRef() override \
+{ \
+    return ComObject::AddRef(); \
+} \
+virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) override \
+{ \
+    return ComObject::QueryInterface(riid, ppvObject); \
+}
+
+#define BEGIN_INTERFACE_MAP() public: virtual HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID riid, void **ppvObject) override {
+#define INTERFACE_MAP_ENTRY(TInterface, IID) if(0 == memcmp(riid, &IID, sizeof(GUID))) { TInterface* casted = this; *ppvObject = casted; return S_OK; }
+#define END_INTERFACE_MAP() return E_NOINTERFACE; }
+#define INHERIT_INTERFACE_MAP(TBase) if(TBase::QueryInterfaceImpl(riid, ppvObject) == S_OK) return S_OK;
+
+
+
+class ComUnknownObject : public ComObject
+{
+public:
+    FORWARD_IUNKNOWN()
+    virtual ::HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID riid, void **ppvObject) override
+    {
+        return E_NOINTERFACE;
+    };
+    virtual ~ComUnknownObject(){}
+};
+
+template<class TInterface, GUID const* TIID> class ComSingleObject : public ComObject, public virtual TInterface
+{
+    BEGIN_INTERFACE_MAP()
+    INTERFACE_MAP_ENTRY(TInterface, *TIID)
+    END_INTERFACE_MAP()
+    
+public:
+    virtual ~ComSingleObject(){}
+};
+
+template<class TInterface>
+class ComPtr
+{
+private:
+    TInterface* _obj;
+public:
+    ComPtr()
+    {
+        _obj = 0;
+    }
+    
+    ComPtr(TInterface* pObj)
+    {
+        _obj = 0;
+
+        if (pObj)
+        {
+            _obj = pObj;
+            _obj->AddRef();
+        }
+    }
+    
+    ComPtr(const ComPtr& ptr)
+    {
+        _obj = 0;
+        
+        if (ptr._obj)
+        {
+            _obj = ptr._obj;
+            _obj->AddRef();
+        }
+
+    }
+    
+    ComPtr& operator=(ComPtr other)
+    {
+        if(_obj != NULL)
+            _obj->Release();
+        _obj = other._obj;
+        if(_obj != NULL)
+            _obj->AddRef();
+        return *this;
+    }
+
+    ~ComPtr()
+    {
+        if (_obj)
+        {
+            _obj->Release();
+            _obj = 0;
+        }
+    }
+    
+    TInterface* getRaw()
+    {
+        return _obj;
+    }
+    
+    operator TInterface*() const
+    {
+        return _obj;
+    }
+    TInterface& operator*() const
+    {
+        return *_obj;
+    }
+    TInterface** operator&()
+    {
+        return &_obj;
+    }
+    TInterface* operator->() const
+    {
+        return _obj;
+    }
+};
+
+#endif // COMIMPL_H_INCLUDED
+#pragma clang diagnostic pop

+ 1023 - 0
native/Avalonia.Native/inc/key.h

@@ -0,0 +1,1023 @@
+// 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.
+
+#ifndef _KEY_H_
+#define _KEY_H_
+
+/// <summary>
+/// Defines the keys available on a keyboard.
+/// </summary>
+enum AvnKey
+{
+    /// <summary>
+    /// No key pressed.
+    /// </summary>
+    AvnKeyNone = 0,
+    
+    /// <summary>
+    /// The Cancel key.
+    /// </summary>
+    AvnKeyCancel = 1,
+    
+    /// <summary>
+    /// The Back key.
+    /// </summary>
+    AvnKeyBack = 2,
+    
+    /// <summary>
+    /// The Tab key.
+    /// </summary>
+    AvnKeyTab = 3,
+    
+    /// <summary>
+    /// The Linefeed key.
+    /// </summary>
+    AvnKeyLineFeed = 4,
+    
+    /// <summary>
+    /// The Clear key.
+    /// </summary>
+    AvnKeyClear = 5,
+    
+    /// <summary>
+    /// The Return key.
+    /// </summary>
+    AvnKeyReturn = 6,
+    
+    /// <summary>
+    /// The Enter key.
+    /// </summary>
+    AvnKeyEnter = 6,
+    
+    /// <summary>
+    /// The Pause key.
+    /// </summary>
+    AvnKeyPause = 7,
+    
+    /// <summary>
+    /// The Caps Lock key.
+    /// </summary>
+    AvnKeyCapsLock = 8,
+    
+    /// <summary>
+    /// The Caps Lock key.
+    /// </summary>
+    AvnKeyCapital = 8,
+    
+    /// <summary>
+    /// The IME Hangul mode key.
+    /// </summary>
+    AvnKeyHangulMode = 9,
+    
+    /// <summary>
+    /// The IME Kana mode key.
+    /// </summary>
+    AvnKeyKanaMode = 9,
+    
+    /// <summary>
+    /// The IME Junja mode key.
+    /// </summary>
+    AvnKeyJunjaMode = 10,
+    
+    /// <summary>
+    /// The IME Final mode key.
+    /// </summary>
+    AvnKeyFinalMode = 11,
+    
+    /// <summary>
+    /// The IME Kanji mode key.
+    /// </summary>
+    AvnKeyKanjiMode = 12,
+    
+    /// <summary>
+    /// The IME Hanja mode key.
+    /// </summary>
+    HanjaMode = 12,
+    
+    /// <summary>
+    /// The Escape key.
+    /// </summary>
+    Escape = 13,
+    
+    /// <summary>
+    /// The IME Convert key.
+    /// </summary>
+    ImeConvert = 14,
+    
+    /// <summary>
+    /// The IME NonConvert key.
+    /// </summary>
+    ImeNonConvert = 15,
+    
+    /// <summary>
+    /// The IME Accept key.
+    /// </summary>
+    ImeAccept = 16,
+    
+    /// <summary>
+    /// The IME Mode change key.
+    /// </summary>
+    ImeModeChange = 17,
+    
+    /// <summary>
+    /// The space bar.
+    /// </summary>
+    Space = 18,
+    
+    /// <summary>
+    /// The Page Up key.
+    /// </summary>
+    PageUp = 19,
+    
+    /// <summary>
+    /// The Page Up key.
+    /// </summary>
+    Prior = 19,
+    
+    /// <summary>
+    /// The Page Down key.
+    /// </summary>
+    PageDown = 20,
+    
+    /// <summary>
+    /// The Page Down key.
+    /// </summary>
+    Next = 20,
+    
+    /// <summary>
+    /// The End key.
+    /// </summary>
+    End = 21,
+    
+    /// <summary>
+    /// The Home key.
+    /// </summary>
+    Home = 22,
+    
+    /// <summary>
+    /// The Left arrow key.
+    /// </summary>
+    Left = 23,
+    
+    /// <summary>
+    /// The Up arrow key.
+    /// </summary>
+    Up = 24,
+    
+    /// <summary>
+    /// The Right arrow key.
+    /// </summary>
+    Right = 25,
+    
+    /// <summary>
+    /// The Down arrow key.
+    /// </summary>
+    Down = 26,
+    
+    /// <summary>
+    /// The Select key.
+    /// </summary>
+    Select = 27,
+    
+    /// <summary>
+    /// The Print key.
+    /// </summary>
+    Print = 28,
+    
+    /// <summary>
+    /// The Execute key.
+    /// </summary>
+    Execute = 29,
+    
+    /// <summary>
+    /// The Print Screen key.
+    /// </summary>
+    Snapshot = 30,
+    
+    /// <summary>
+    /// The Print Screen key.
+    /// </summary>
+    PrintScreen = 30,
+    
+    /// <summary>
+    /// The Insert key.
+    /// </summary>
+    Insert = 31,
+    
+    /// <summary>
+    /// The Delete key.
+    /// </summary>
+    Delete = 32,
+    
+    /// <summary>
+    /// The Help key.
+    /// </summary>
+    Help = 33,
+    
+    /// <summary>
+    /// The 0 key.
+    /// </summary>
+    D0 = 34,
+    
+    /// <summary>
+    /// The 1 key.
+    /// </summary>
+    D1 = 35,
+    
+    /// <summary>
+    /// The 2 key.
+    /// </summary>
+    D2 = 36,
+    
+    /// <summary>
+    /// The 3 key.
+    /// </summary>
+    D3 = 37,
+    
+    /// <summary>
+    /// The 4 key.
+    /// </summary>
+    D4 = 38,
+    
+    /// <summary>
+    /// The 5 key.
+    /// </summary>
+    D5 = 39,
+    
+    /// <summary>
+    /// The 6 key.
+    /// </summary>
+    D6 = 40,
+    
+    /// <summary>
+    /// The 7 key.
+    /// </summary>
+    D7 = 41,
+    
+    /// <summary>
+    /// The 8 key.
+    /// </summary>
+    D8 = 42,
+    
+    /// <summary>
+    /// The 9 key.
+    /// </summary>
+    D9 = 43,
+    
+    /// <summary>
+    /// The A key.
+    /// </summary>
+    A = 44,
+    
+    /// <summary>
+    /// The B key.
+    /// </summary>
+    B = 45,
+    
+    /// <summary>
+    /// The C key.
+    /// </summary>
+    C = 46,
+    
+    /// <summary>
+    /// The D key.
+    /// </summary>
+    D = 47,
+    
+    /// <summary>
+    /// The E key.
+    /// </summary>
+    E = 48,
+    
+    /// <summary>
+    /// The F key.
+    /// </summary>
+    F = 49,
+    
+    /// <summary>
+    /// The G key.
+    /// </summary>
+    G = 50,
+    
+    /// <summary>
+    /// The H key.
+    /// </summary>
+    H = 51,
+    
+    /// <summary>
+    /// The I key.
+    /// </summary>
+    I = 52,
+    
+    /// <summary>
+    /// The J key.
+    /// </summary>
+    J = 53,
+    
+    /// <summary>
+    /// The K key.
+    /// </summary>
+    AvnKeyK = 54,
+    
+    /// <summary>
+    /// The L key.
+    /// </summary>
+    L = 55,
+    
+    /// <summary>
+    /// The M key.
+    /// </summary>
+    M = 56,
+    
+    /// <summary>
+    /// The N key.
+    /// </summary>
+    N = 57,
+    
+    /// <summary>
+    /// The O key.
+    /// </summary>
+    O = 58,
+    
+    /// <summary>
+    /// The P key.
+    /// </summary>
+    P = 59,
+    
+    /// <summary>
+    /// The Q key.
+    /// </summary>
+    Q = 60,
+    
+    /// <summary>
+    /// The R key.
+    /// </summary>
+    R = 61,
+    
+    /// <summary>
+    /// The S key.
+    /// </summary>
+    S = 62,
+    
+    /// <summary>
+    /// The T key.
+    /// </summary>
+    T = 63,
+    
+    /// <summary>
+    /// The U key.
+    /// </summary>
+    U = 64,
+    
+    /// <summary>
+    /// The V key.
+    /// </summary>
+    V = 65,
+    
+    /// <summary>
+    /// The W key.
+    /// </summary>
+    W = 66,
+    
+    /// <summary>
+    /// The X key.
+    /// </summary>
+    X = 67,
+    
+    /// <summary>
+    /// The Y key.
+    /// </summary>
+    Y = 68,
+    
+    /// <summary>
+    /// The Z key.
+    /// </summary>
+    Z = 69,
+    
+    /// <summary>
+    /// The left Windows key.
+    /// </summary>
+    LWin = 70,
+    
+    /// <summary>
+    /// The right Windows key.
+    /// </summary>
+    RWin = 71,
+    
+    /// <summary>
+    /// The Application key.
+    /// </summary>
+    Apps = 72,
+    
+    /// <summary>
+    /// The Sleep key.
+    /// </summary>
+    Sleep = 73,
+    
+    /// <summary>
+    /// The 0 key on the numeric keypad.
+    /// </summary>
+    NumPad0 = 74,
+    
+    /// <summary>
+    /// The 1 key on the numeric keypad.
+    /// </summary>
+    NumPad1 = 75,
+    
+    /// <summary>
+    /// The 2 key on the numeric keypad.
+    /// </summary>
+    NumPad2 = 76,
+    
+    /// <summary>
+    /// The 3 key on the numeric keypad.
+    /// </summary>
+    NumPad3 = 77,
+    
+    /// <summary>
+    /// The 4 key on the numeric keypad.
+    /// </summary>
+    NumPad4 = 78,
+    
+    /// <summary>
+    /// The 5 key on the numeric keypad.
+    /// </summary>
+    NumPad5 = 79,
+    
+    /// <summary>
+    /// The 6 key on the numeric keypad.
+    /// </summary>
+    NumPad6 = 80,
+    
+    /// <summary>
+    /// The 7 key on the numeric keypad.
+    /// </summary>
+    NumPad7 = 81,
+    
+    /// <summary>
+    /// The 8 key on the numeric keypad.
+    /// </summary>
+    NumPad8 = 82,
+    
+    /// <summary>
+    /// The 9 key on the numeric keypad.
+    /// </summary>
+    NumPad9 = 83,
+    
+    /// <summary>
+    /// The Multiply key.
+    /// </summary>
+    Multiply = 84,
+    
+    /// <summary>
+    /// The Add key.
+    /// </summary>
+    Add = 85,
+    
+    /// <summary>
+    /// The Separator key.
+    /// </summary>
+    Separator = 86,
+    
+    /// <summary>
+    /// The Subtract key.
+    /// </summary>
+    Subtract = 87,
+    
+    /// <summary>
+    /// The Decimal key.
+    /// </summary>
+    Decimal = 88,
+    
+    /// <summary>
+    /// The Divide key.
+    /// </summary>
+    Divide = 89,
+    
+    /// <summary>
+    /// The F1 key.
+    /// </summary>
+    F1 = 90,
+    
+    /// <summary>
+    /// The F2 key.
+    /// </summary>
+    F2 = 91,
+    
+    /// <summary>
+    /// The F3 key.
+    /// </summary>
+    F3 = 92,
+    
+    /// <summary>
+    /// The F4 key.
+    /// </summary>
+    F4 = 93,
+    
+    /// <summary>
+    /// The F5 key.
+    /// </summary>
+    F5 = 94,
+    
+    /// <summary>
+    /// The F6 key.
+    /// </summary>
+    F6 = 95,
+    
+    /// <summary>
+    /// The F7 key.
+    /// </summary>
+    F7 = 96,
+    
+    /// <summary>
+    /// The F8 key.
+    /// </summary>
+    F8 = 97,
+    
+    /// <summary>
+    /// The F9 key.
+    /// </summary>
+    F9 = 98,
+    
+    /// <summary>
+    /// The F10 key.
+    /// </summary>
+    F10 = 99,
+    
+    /// <summary>
+    /// The F11 key.
+    /// </summary>
+    F11 = 100,
+    
+    /// <summary>
+    /// The F12 key.
+    /// </summary>
+    F12 = 101,
+    
+    /// <summary>
+    /// The F13 key.
+    /// </summary>
+    F13 = 102,
+    
+    /// <summary>
+    /// The F14 key.
+    /// </summary>
+    F14 = 103,
+    
+    /// <summary>
+    /// The F15 key.
+    /// </summary>
+    F15 = 104,
+    
+    /// <summary>
+    /// The F16 key.
+    /// </summary>
+    F16 = 105,
+    
+    /// <summary>
+    /// The F17 key.
+    /// </summary>
+    F17 = 106,
+    
+    /// <summary>
+    /// The F18 key.
+    /// </summary>
+    F18 = 107,
+    
+    /// <summary>
+    /// The F19 key.
+    /// </summary>
+    F19 = 108,
+    
+    /// <summary>
+    /// The F20 key.
+    /// </summary>
+    F20 = 109,
+    
+    /// <summary>
+    /// The F21 key.
+    /// </summary>
+    F21 = 110,
+    
+    /// <summary>
+    /// The F22 key.
+    /// </summary>
+    F22 = 111,
+    
+    /// <summary>
+    /// The F23 key.
+    /// </summary>
+    F23 = 112,
+    
+    /// <summary>
+    /// The F24 key.
+    /// </summary>
+    F24 = 113,
+    
+    /// <summary>
+    /// The Numlock key.
+    /// </summary>
+    NumLock = 114,
+    
+    /// <summary>
+    /// The Scroll key.
+    /// </summary>
+    Scroll = 115,
+    
+    /// <summary>
+    /// The left Shift key.
+    /// </summary>
+    LeftShift = 116,
+    
+    /// <summary>
+    /// The right Shift key.
+    /// </summary>
+    RightShift = 117,
+    
+    /// <summary>
+    /// The left Ctrl key.
+    /// </summary>
+    LeftCtrl = 118,
+    
+    /// <summary>
+    /// The right Ctrl key.
+    /// </summary>
+    RightCtrl = 119,
+    
+    /// <summary>
+    /// The left Alt key.
+    /// </summary>
+    LeftAlt = 120,
+    
+    /// <summary>
+    /// The right Alt key.
+    /// </summary>
+    RightAlt = 121,
+    
+    /// <summary>
+    /// The browser Back key.
+    /// </summary>
+    BrowserBack = 122,
+    
+    /// <summary>
+    /// The browser Forward key.
+    /// </summary>
+    BrowserForward = 123,
+    
+    /// <summary>
+    /// The browser Refresh key.
+    /// </summary>
+    BrowserRefresh = 124,
+    
+    /// <summary>
+    /// The browser Stop key.
+    /// </summary>
+    BrowserStop = 125,
+    
+    /// <summary>
+    /// The browser Search key.
+    /// </summary>
+    BrowserSearch = 126,
+    
+    /// <summary>
+    /// The browser Favorites key.
+    /// </summary>
+    BrowserFavorites = 127,
+    
+    /// <summary>
+    /// The browser Home key.
+    /// </summary>
+    BrowserHome = 128,
+    
+    /// <summary>
+    /// The Volume Mute key.
+    /// </summary>
+    VolumeMute = 129,
+    
+    /// <summary>
+    /// The Volume Down key.
+    /// </summary>
+    VolumeDown = 130,
+    
+    /// <summary>
+    /// The Volume Up key.
+    /// </summary>
+    VolumeUp = 131,
+    
+    /// <summary>
+    /// The media Next Track key.
+    /// </summary>
+    MediaNextTrack = 132,
+    
+    /// <summary>
+    /// The media Previous Track key.
+    /// </summary>
+    MediaPreviousTrack = 133,
+    
+    /// <summary>
+    /// The media Stop key.
+    /// </summary>
+    MediaStop = 134,
+    
+    /// <summary>
+    /// The media Play/Pause key.
+    /// </summary>
+    MediaPlayPause = 135,
+    
+    /// <summary>
+    /// The Launch Mail key.
+    /// </summary>
+    LaunchMail = 136,
+    
+    /// <summary>
+    /// The Select Media key.
+    /// </summary>
+    SelectMedia = 137,
+    
+    /// <summary>
+    /// The Launch Application 1 key.
+    /// </summary>
+    LaunchApplication1 = 138,
+    
+    /// <summary>
+    /// The Launch Application 2 key.
+    /// </summary>
+    LaunchApplication2 = 139,
+    
+    /// <summary>
+    /// The OEM Semicolon key.
+    /// </summary>
+    OemSemicolon = 140,
+    
+    /// <summary>
+    /// The OEM 1 key.
+    /// </summary>
+    Oem1 = 140,
+    
+    /// <summary>
+    /// The OEM Plus key.
+    /// </summary>
+    OemPlus = 141,
+    
+    /// <summary>
+    /// The OEM Comma key.
+    /// </summary>
+    OemComma = 142,
+    
+    /// <summary>
+    /// The OEM Minus key.
+    /// </summary>
+    OemMinus = 143,
+    
+    /// <summary>
+    /// The OEM Period key.
+    /// </summary>
+    OemPeriod = 144,
+    
+    /// <summary>
+    /// The OEM Question Mark key.
+    /// </summary>
+    OemQuestion = 145,
+    
+    /// <summary>
+    /// The OEM 2 key.
+    /// </summary>
+    Oem2 = 145,
+    
+    /// <summary>
+    /// The OEM Tilde key.
+    /// </summary>
+    OemTilde = 146,
+    
+    /// <summary>
+    /// The OEM 3 key.
+    /// </summary>
+    Oem3 = 146,
+    
+    /// <summary>
+    /// The ABNT_C1 (Brazilian) key.
+    /// </summary>
+    AbntC1 = 147,
+    
+    /// <summary>
+    /// The ABNT_C2 (Brazilian) key.
+    /// </summary>
+    AbntC2 = 148,
+    
+    /// <summary>
+    /// The OEM Open Brackets key.
+    /// </summary>
+    OemOpenBrackets = 149,
+    
+    /// <summary>
+    /// The OEM 4 key.
+    /// </summary>
+    Oem4 = 149,
+    
+    /// <summary>
+    /// The OEM Pipe key.
+    /// </summary>
+    OemPipe = 150,
+    
+    /// <summary>
+    /// The OEM 5 key.
+    /// </summary>
+    Oem5 = 150,
+    
+    /// <summary>
+    /// The OEM Close Brackets key.
+    /// </summary>
+    OemCloseBrackets = 151,
+    
+    /// <summary>
+    /// The OEM 6 key.
+    /// </summary>
+    Oem6 = 151,
+    
+    /// <summary>
+    /// The OEM Quotes key.
+    /// </summary>
+    OemQuotes = 152,
+    
+    /// <summary>
+    /// The OEM 7 key.
+    /// </summary>
+    Oem7 = 152,
+    
+    /// <summary>
+    /// The OEM 8 key.
+    /// </summary>
+    Oem8 = 153,
+    
+    /// <summary>
+    /// The OEM Backslash key.
+    /// </summary>
+    OemBackslash = 154,
+    
+    /// <summary>
+    /// The OEM 3 key.
+    /// </summary>
+    Oem102 = 154,
+    
+    /// <summary>
+    /// A special key masking the real key being processed by an IME.
+    /// </summary>
+    ImeProcessed = 155,
+    
+    /// <summary>
+    /// A special key masking the real key being processed as a system key.
+    /// </summary>
+    System = 156,
+    
+    /// <summary>
+    /// The OEM ATTN key.
+    /// </summary>
+    OemAttn = 157,
+    
+    /// <summary>
+    /// The DBE_ALPHANUMERIC key.
+    /// </summary>
+    DbeAlphanumeric = 157,
+    
+    /// <summary>
+    /// The OEM Finish key.
+    /// </summary>
+    OemFinish = 158,
+    
+    /// <summary>
+    /// The DBE_KATAKANA key.
+    /// </summary>
+    DbeKatakana = 158,
+    
+    /// <summary>
+    /// The DBE_HIRAGANA key.
+    /// </summary>
+    DbeHiragana = 159,
+    
+    /// <summary>
+    /// The OEM Copy key.
+    /// </summary>
+    OemCopy = 159,
+    
+    /// <summary>
+    /// The DBE_SBCSCHAR key.
+    /// </summary>
+    DbeSbcsChar = 160,
+    
+    /// <summary>
+    /// The OEM Auto key.
+    /// </summary>
+    OemAuto = 160,
+    
+    /// <summary>
+    /// The DBE_DBCSCHAR key.
+    /// </summary>
+    DbeDbcsChar = 161,
+    
+    /// <summary>
+    /// The OEM ENLW key.
+    /// </summary>
+    OemEnlw = 161,
+    
+    /// <summary>
+    /// The OEM BackTab key.
+    /// </summary>
+    OemBackTab = 162,
+    
+    /// <summary>
+    /// The DBE_ROMAN key.
+    /// </summary>
+    DbeRoman = 162,
+    
+    /// <summary>
+    /// The DBE_NOROMAN key.
+    /// </summary>
+    DbeNoRoman = 163,
+    
+    /// <summary>
+    /// The ATTN key.
+    /// </summary>
+    Attn = 163,
+    
+    /// <summary>
+    /// The CRSEL key.
+    /// </summary>
+    CrSel = 164,
+    
+    /// <summary>
+    /// The DBE_ENTERWORDREGISTERMODE key.
+    /// </summary>
+    DbeEnterWordRegisterMode = 164,
+    
+    /// <summary>
+    /// The EXSEL key.
+    /// </summary>
+    ExSel = 165,
+    
+    /// <summary>
+    /// The DBE_ENTERIMECONFIGMODE key.
+    /// </summary>
+    DbeEnterImeConfigureMode = 165,
+    
+    /// <summary>
+    /// The ERASE EOF Key.
+    /// </summary>
+    EraseEof = 166,
+    
+    /// <summary>
+    /// The DBE_FLUSHSTRING key.
+    /// </summary>
+    DbeFlushString = 166,
+    
+    /// <summary>
+    /// The Play key.
+    /// </summary>
+    Play = 167,
+    
+    /// <summary>
+    /// The DBE_CODEINPUT key.
+    /// </summary>
+    DbeCodeInput = 167,
+    
+    /// <summary>
+    /// The DBE_NOCODEINPUT key.
+    /// </summary>
+    DbeNoCodeInput = 168,
+    
+    /// <summary>
+    /// The Zoom key.
+    /// </summary>
+    Zoom = 168,
+    
+    /// <summary>
+    /// Reserved for future use.
+    /// </summary>
+    NoName = 169,
+    
+    /// <summary>
+    /// The DBE_DETERMINESTRING key.
+    /// </summary>
+    DbeDetermineString = 169,
+    
+    /// <summary>
+    /// The DBE_ENTERDLGCONVERSIONMODE key.
+    /// </summary>
+    DbeEnterDialogConversionMode = 170,
+    
+    /// <summary>
+    /// The PA1 key.
+    /// </summary>
+    Pa1 = 170,
+    
+    /// <summary>
+    /// The OEM Clear key.
+    /// </summary>
+    OemClear = 171,
+    
+    /// <summary>
+    /// The key is used with another key to create a single combined character.
+    /// </summary>
+    DeadCharProcessed = 172,
+};
+
+#endif

+ 4 - 0
native/Avalonia.Native/src/OSX/.gitignore

@@ -0,0 +1,4 @@
+build
+
+Avalonia.Native.OSX.xcodeproj/xcuserdata
+Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcuserdata

+ 328 - 0
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@@ -0,0 +1,328 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; };
+		37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; };
+		37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; };
+		5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; };
+		5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
+		AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
+		AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; };
+		AB573DC4217605E400D389A2 /* gl.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB573DC3217605E400D389A2 /* gl.mm */; };
+		AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
+		AB661C202148286E00291242 /* window.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB661C1F2148286E00291242 /* window.mm */; };
+		AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = "<group>"; };
+		37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = "<group>"; };
+		37A517B22159597E00FBA241 /* Screens.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Screens.mm; sourceTree = "<group>"; };
+		37C09D8721580FE4006A6758 /* SystemDialogs.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SystemDialogs.mm; sourceTree = "<group>"; };
+		37C09D8A21581EF2006A6758 /* window.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = window.h; sourceTree = "<group>"; };
+		37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = "<group>"; };
+		5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = "<group>"; };
+		5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = "<group>"; };
+		5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = "<group>"; };
+		AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
+		AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+		AB573DC3217605E400D389A2 /* gl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = gl.mm; sourceTree = "<group>"; };
+		AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
+		AB661C1F2148286E00291242 /* window.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = window.mm; sourceTree = "<group>"; };
+		AB661C212148288600291242 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+		AB7A61EF2147C815003C5833 /* libAvalonia.Native.OSX.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libAvalonia.Native.OSX.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+		AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platformthreading.mm; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		AB7A61EC2147C814003C5833 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */,
+				AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		AB661C1C2148230E00291242 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				AB1E522B217613570091CD71 /* OpenGL.framework */,
+				AB661C1D2148230F00291242 /* AppKit.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		AB7A61E62147C814003C5833 = {
+			isa = PBXGroup;
+			children = (
+				37A4E71A2178846A00EACBCD /* headers */,
+				AB573DC3217605E400D389A2 /* gl.mm */,
+				5BF943652167AD1D009CAE35 /* cursor.h */,
+				5B21A981216530F500CEE36E /* cursor.mm */,
+				5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */,
+				AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */,
+				AB661C212148288600291242 /* common.h */,
+				379860FE214DA0C000CD0246 /* KeyTransform.h */,
+				37E2330E21583241000CB7E2 /* KeyTransform.mm */,
+				AB661C1F2148286E00291242 /* window.mm */,
+				37C09D8A21581EF2006A6758 /* window.h */,
+				AB00E4F62147CA920032A60A /* main.mm */,
+				37A517B22159597E00FBA241 /* Screens.mm */,
+				37C09D8721580FE4006A6758 /* SystemDialogs.mm */,
+				AB7A61F02147C815003C5833 /* Products */,
+				AB661C1C2148230E00291242 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		AB7A61F02147C815003C5833 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				AB7A61EF2147C815003C5833 /* libAvalonia.Native.OSX.dylib */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		AB7A61ED2147C814003C5833 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		AB7A61EE2147C814003C5833 /* Avalonia.Native.OSX */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = AB7A61F82147C815003C5833 /* Build configuration list for PBXNativeTarget "Avalonia.Native.OSX" */;
+			buildPhases = (
+				AB7A61EB2147C814003C5833 /* Sources */,
+				AB7A61EC2147C814003C5833 /* Frameworks */,
+				AB7A61ED2147C814003C5833 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Avalonia.Native.OSX;
+			productName = Avalonia.Native.OSX;
+			productReference = AB7A61EF2147C815003C5833 /* libAvalonia.Native.OSX.dylib */;
+			productType = "com.apple.product-type.library.dynamic";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		AB7A61E72147C814003C5833 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 1000;
+				ORGANIZATIONNAME = Avalonia;
+				TargetAttributes = {
+					AB7A61EE2147C814003C5833 = {
+						CreatedOnToolsVersion = 8.3.2;
+						ProvisioningStyle = Automatic;
+					};
+				};
+			};
+			buildConfigurationList = AB7A61EA2147C814003C5833 /* Build configuration list for PBXProject "Avalonia.Native.OSX" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = AB7A61E62147C814003C5833;
+			productRefGroup = AB7A61F02147C815003C5833 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				AB7A61EE2147C814003C5833 /* Avalonia.Native.OSX */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		AB7A61EB2147C814003C5833 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */,
+				5B21A982216530F500CEE36E /* cursor.mm in Sources */,
+				AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */,
+				37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */,
+				37A517B32159597E00FBA241 /* Screens.mm in Sources */,
+				AB00E4F72147CA920032A60A /* main.mm in Sources */,
+				37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */,
+				AB573DC4217605E400D389A2 /* gl.mm in Sources */,
+				AB661C202148286E00291242 /* window.mm in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		AB7A61F62147C815003C5833 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.12;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		AB7A61F72147C815003C5833 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.12;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		AB7A61F92147C815003C5833 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXECUTABLE_PREFIX = lib;
+				HEADER_SEARCH_PATHS = ../../inc;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		AB7A61FA2147C815003C5833 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXECUTABLE_PREFIX = lib;
+				HEADER_SEARCH_PATHS = ../../inc;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		AB7A61EA2147C814003C5833 /* Build configuration list for PBXProject "Avalonia.Native.OSX" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				AB7A61F62147C815003C5833 /* Debug */,
+				AB7A61F72147C815003C5833 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		AB7A61F82147C815003C5833 /* Build configuration list for PBXNativeTarget "Avalonia.Native.OSX" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				AB7A61F92147C815003C5833 /* Debug */,
+				AB7A61FA2147C815003C5833 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = AB7A61E72147C814003C5833 /* Project object */;
+}

+ 7 - 0
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:Avalonia.Native.OSX.xcodeproj">
+   </FileRef>
+</Workspace>

+ 91 - 0
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1000"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "AB7A61EE2147C814003C5833"
+               BuildableName = "libAvalonia.Native.OSX.dylib"
+               BlueprintName = "Avalonia.Native.OSX"
+               ReferencedContainer = "container:Avalonia.Native.OSX.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "YES"
+      customWorkingDirectory = "$PROJECT_DIR/../../../../samples/ControlCatalog.NetCore"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <PathRunnable
+         runnableDebuggingMode = "0"
+         FilePath = "/usr/local/share/dotnet/dotnet">
+      </PathRunnable>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "AB7A61EE2147C814003C5833"
+            BuildableName = "libAvalonia.Native.OSX.dylib"
+            BlueprintName = "Avalonia.Native.OSX"
+            ReferencedContainer = "container:Avalonia.Native.OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <CommandLineArguments>
+         <CommandLineArgument
+            argument = "bin/Debug/netcoreapp2.0/ControlCatalog.NetCore.dll"
+            isEnabled = "YES">
+         </CommandLineArgument>
+      </CommandLineArguments>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "AB7A61EE2147C814003C5833"
+            BuildableName = "libAvalonia.Native.OSX.dylib"
+            BlueprintName = "Avalonia.Native.OSX"
+            ReferencedContainer = "container:Avalonia.Native.OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 12 - 0
native/Avalonia.Native/src/OSX/KeyTransform.h

@@ -0,0 +1,12 @@
+// 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.
+
+#ifndef keytransform_h
+#define keytransform_h
+#include "common.h"
+#include "key.h"
+#include <map>
+
+extern std::map<int, AvnKey> s_KeyMap;
+
+#endif

+ 241 - 0
native/Avalonia.Native/src/OSX/KeyTransform.mm

@@ -0,0 +1,241 @@
+// 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.
+
+#include "KeyTransform.h"
+
+const int kVK_ANSI_A = 0x00;
+const int kVK_ANSI_S = 0x01;
+const int kVK_ANSI_D = 0x02;
+const int kVK_ANSI_F = 0x03;
+const int kVK_ANSI_H = 0x04;
+const int kVK_ANSI_G = 0x05;
+const int kVK_ANSI_Z = 0x06;
+const int kVK_ANSI_X = 0x07;
+const int kVK_ANSI_C = 0x08;
+const int kVK_ANSI_V = 0x09;
+const int kVK_ANSI_B = 0x0B;
+const int kVK_ANSI_Q = 0x0C;
+const int kVK_ANSI_W = 0x0D;
+const int kVK_ANSI_E = 0x0E;
+const int kVK_ANSI_R = 0x0F;
+const int kVK_ANSI_Y = 0x10;
+const int kVK_ANSI_T = 0x11;
+const int kVK_ANSI_1 = 0x12;
+const int kVK_ANSI_2 = 0x13;
+const int kVK_ANSI_3 = 0x14;
+const int kVK_ANSI_4 = 0x15;
+const int kVK_ANSI_6 = 0x16;
+const int kVK_ANSI_5 = 0x17;
+//const int kVK_ANSI_Equal = 0x18;
+const int kVK_ANSI_9 = 0x19;
+const int kVK_ANSI_7 = 0x1A;
+const int kVK_ANSI_Minus = 0x1B;
+const int kVK_ANSI_8 = 0x1C;
+const int kVK_ANSI_0 = 0x1D;
+const int kVK_ANSI_RightBracket = 0x1E;
+const int kVK_ANSI_O = 0x1F;
+const int kVK_ANSI_U = 0x20;
+const int kVK_ANSI_LeftBracket = 0x21;
+const int kVK_ANSI_I = 0x22;
+const int kVK_ANSI_P = 0x23;
+const int kVK_ANSI_L = 0x25;
+const int kVK_ANSI_J = 0x26;
+const int kVK_ANSI_Quote = 0x27;
+const int kVK_ANSI_K = 0x28;
+const int kVK_ANSI_Semicolon = 0x29;
+const int kVK_ANSI_Backslash = 0x2A;
+const int kVK_ANSI_Comma = 0x2B;
+//const int kVK_ANSI_Slash = 0x2C;
+const int kVK_ANSI_N = 0x2D;
+const int kVK_ANSI_M = 0x2E;
+const int kVK_ANSI_Period = 0x2F;
+//const int kVK_ANSI_Grave = 0x32;
+const int kVK_ANSI_KeypadDecimal = 0x41;
+const int kVK_ANSI_KeypadMultiply = 0x43;
+const int kVK_ANSI_KeypadPlus = 0x45;
+const int kVK_ANSI_KeypadClear = 0x47;
+const int kVK_ANSI_KeypadDivide = 0x4B;
+const int kVK_ANSI_KeypadEnter = 0x4C;
+const int kVK_ANSI_KeypadMinus = 0x4E;
+//const int kVK_ANSI_KeypadEquals = 0x51;
+const int kVK_ANSI_Keypad0 = 0x52;
+const int kVK_ANSI_Keypad1 = 0x53;
+const int kVK_ANSI_Keypad2 = 0x54;
+const int kVK_ANSI_Keypad3 = 0x55;
+const int kVK_ANSI_Keypad4 = 0x56;
+const int kVK_ANSI_Keypad5 = 0x57;
+const int kVK_ANSI_Keypad6 = 0x58;
+const int kVK_ANSI_Keypad7 = 0x59;
+const int kVK_ANSI_Keypad8 = 0x5B;
+const int kVK_ANSI_Keypad9 = 0x5C;
+const int kVK_Return = 0x24;
+const int kVK_Tab = 0x30;
+const int kVK_Space = 0x31;
+const int kVK_Delete = 0x33;
+const int kVK_Escape = 0x35;
+const int kVK_Command = 0x37;
+const int kVK_Shift = 0x38;
+const int kVK_CapsLock = 0x39;
+const int kVK_Option = 0x3A;
+const int kVK_Control = 0x3B;
+const int kVK_RightCommand = 0x36;
+const int kVK_RightShift = 0x3C;
+const int kVK_RightOption = 0x3D;
+const int kVK_RightControl = 0x3E;
+//const int kVK_Function = 0x3F;
+const int kVK_F17 = 0x40;
+const int kVK_VolumeUp = 0x48;
+const int kVK_VolumeDown = 0x49;
+const int kVK_Mute = 0x4A;
+const int kVK_F18 = 0x4F;
+const int kVK_F19 = 0x50;
+const int kVK_F20 = 0x5A;
+const int kVK_F5 = 0x60;
+const int kVK_F6 = 0x61;
+const int kVK_F7 = 0x62;
+const int kVK_F3 = 0x63;
+const int kVK_F8 = 0x64;
+const int kVK_F9 = 0x65;
+const int kVK_F11 = 0x67;
+const int kVK_F13 = 0x69;
+const int kVK_F16 = 0x6A;
+const int kVK_F14 = 0x6B;
+const int kVK_F10 = 0x6D;
+const int kVK_F12 = 0x6F;
+const int kVK_F15 = 0x71;
+const int kVK_Help = 0x72;
+const int kVK_Home = 0x73;
+const int kVK_PageUp = 0x74;
+const int kVK_ForwardDelete = 0x75;
+const int kVK_F4 = 0x76;
+const int kVK_End = 0x77;
+const int kVK_F2 = 0x78;
+const int kVK_PageDown = 0x79;
+const int kVK_F1 = 0x7A;
+const int kVK_LeftArrow = 0x7B;
+const int kVK_RightArrow = 0x7C;
+const int kVK_DownArrow = 0x7D;
+const int kVK_UpArrow = 0x7E;
+//const int kVK_ISO_Section = 0x0A;
+//const int kVK_JIS_Yen = 0x5D;
+//const int kVK_JIS_Underscore = 0x5E;
+//const int kVK_JIS_KeypadComma = 0x5F;
+//const int kVK_JIS_Eisu = 0x66;
+//const int kVK_JIS_Kana = 0x68;
+
+ std::map<int, AvnKey> s_KeyMap =
+ {
+    {kVK_ANSI_A, A},
+    {kVK_ANSI_S, S},
+    {kVK_ANSI_D, D},
+    {kVK_ANSI_F, F},
+    {kVK_ANSI_H, H},
+    {kVK_ANSI_G, G},
+    {kVK_ANSI_Z, Z},
+    {kVK_ANSI_X, X},
+    {kVK_ANSI_C, C},
+    {kVK_ANSI_V, V},
+    {kVK_ANSI_B, B},
+    {kVK_ANSI_Q, Q},
+    {kVK_ANSI_W, W},
+    {kVK_ANSI_E, E},
+    {kVK_ANSI_R, R},
+    {kVK_ANSI_Y, Y},
+    {kVK_ANSI_T, T},
+    {kVK_ANSI_1, D1},
+    {kVK_ANSI_2, D2},
+    {kVK_ANSI_3, D3},
+    {kVK_ANSI_4, D4},
+    {kVK_ANSI_6, D6},
+    {kVK_ANSI_5, D5},
+    //{kVK_ANSI_Equal, ?},
+    {kVK_ANSI_9, D9},
+    {kVK_ANSI_7, D7},
+    {kVK_ANSI_Minus, OemMinus},
+    {kVK_ANSI_8, D8},
+    {kVK_ANSI_0, D0},
+    {kVK_ANSI_RightBracket, OemCloseBrackets},
+    {kVK_ANSI_O, O},
+    {kVK_ANSI_U, U},
+    {kVK_ANSI_LeftBracket, OemOpenBrackets},
+    {kVK_ANSI_I, I},
+    {kVK_ANSI_P, P},
+    {kVK_ANSI_L, L},
+    {kVK_ANSI_J, J},
+    {kVK_ANSI_Quote, OemQuotes},
+    {kVK_ANSI_K, AvnKeyK},
+    {kVK_ANSI_Semicolon, OemSemicolon},
+    {kVK_ANSI_Backslash, OemBackslash},
+    {kVK_ANSI_Comma, OemComma},
+    //{kVK_ANSI_Slash, ?},
+    {kVK_ANSI_N, N},
+    {kVK_ANSI_M, M},
+    {kVK_ANSI_Period, OemPeriod},
+    //{kVK_ANSI_Grave, ?},
+    {kVK_ANSI_KeypadDecimal, Decimal},
+    {kVK_ANSI_KeypadMultiply, Multiply},
+    {kVK_ANSI_KeypadPlus, OemPlus},
+    {kVK_ANSI_KeypadClear, AvnKeyClear},
+    {kVK_ANSI_KeypadDivide, Divide},
+    {kVK_ANSI_KeypadEnter, AvnKeyEnter},
+    {kVK_ANSI_KeypadMinus, OemMinus},
+    //{kVK_ANSI_KeypadEquals, ?},
+    {kVK_ANSI_Keypad0, NumPad0},
+    {kVK_ANSI_Keypad1, NumPad1},
+    {kVK_ANSI_Keypad2, NumPad2},
+    {kVK_ANSI_Keypad3, NumPad3},
+    {kVK_ANSI_Keypad4, NumPad4},
+    {kVK_ANSI_Keypad5, NumPad5},
+    {kVK_ANSI_Keypad6, NumPad6},
+    {kVK_ANSI_Keypad7, NumPad7},
+    {kVK_ANSI_Keypad8, NumPad8},
+    {kVK_ANSI_Keypad9, NumPad9},
+    {kVK_Return, AvnKeyReturn},
+    {kVK_Tab, AvnKeyTab},
+    {kVK_Space, Space},
+    {kVK_Delete, AvnKeyBack},
+    {kVK_Escape, Escape},
+    {kVK_Command, LWin},
+    {kVK_Shift, LeftShift},
+    {kVK_CapsLock, AvnKeyCapsLock},
+    {kVK_Option, LeftAlt},
+    {kVK_Control, LeftCtrl},
+    {kVK_RightCommand, RWin},
+    {kVK_RightShift, RightShift},
+    {kVK_RightOption, RightAlt},
+    {kVK_RightControl, RightCtrl},
+    //{kVK_Function, ?},
+    {kVK_F17, F17},
+    {kVK_VolumeUp, VolumeUp},
+    {kVK_VolumeDown, VolumeDown},
+    {kVK_Mute, VolumeMute},
+    {kVK_F18, F18},
+    {kVK_F19, F19},
+    {kVK_F20, F20},
+    {kVK_F5, F5},
+    {kVK_F6, F6},
+    {kVK_F7, F7},
+    {kVK_F3, F3},
+    {kVK_F8, F8},
+    {kVK_F9, F9},
+    {kVK_F11, F11},
+    {kVK_F13, F13},
+    {kVK_F16, F16},
+    {kVK_F14, F14},
+    {kVK_F10, F10},
+    {kVK_F12, F12},
+    {kVK_F15, F15},
+    {kVK_Help, Help},
+    {kVK_Home, Home},
+    {kVK_PageUp, PageUp},
+    {kVK_ForwardDelete, Delete},
+    {kVK_F4, F4},
+    {kVK_End, End},
+    {kVK_F2, F2},
+    {kVK_PageDown, PageDown},
+    {kVK_F1, F1},
+    {kVK_LeftArrow, Left},
+    {kVK_RightArrow, Right},
+    {kVK_DownArrow, Down},
+    {kVK_UpArrow, Up}
+};

+ 51 - 0
native/Avalonia.Native/src/OSX/Screens.mm

@@ -0,0 +1,51 @@
+// 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.
+
+#include "common.h"
+
+class Screens : public ComSingleObject<IAvnScreens, &IID_IAvnScreens>
+{
+    public:
+    FORWARD_IUNKNOWN()
+    virtual HRESULT GetScreenCount (int* ret) override
+    {
+        @autoreleasepool
+        {
+            *ret = (int)[NSScreen screens].count;
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT GetScreen (int index, AvnScreen* ret) override
+    {
+        @autoreleasepool
+        {
+            if(index < 0 || index >= [NSScreen screens].count)
+            {
+                return E_INVALIDARG;
+            }
+            
+            auto screen = [[NSScreen screens] objectAtIndex:index];
+            
+            ret->Bounds.X = [screen frame].origin.x;
+            ret->Bounds.Y = [screen frame].origin.y;
+            ret->Bounds.Height = [screen frame].size.height;
+            ret->Bounds.Width = [screen frame].size.width;
+            
+            ret->WorkingArea.X = [screen visibleFrame].origin.x;
+            ret->WorkingArea.Y = [screen visibleFrame].origin.y;
+            ret->WorkingArea.Height = [screen visibleFrame].size.height;
+            ret->WorkingArea.Width = [screen visibleFrame].size.width;
+            
+            ret->Primary = index == 0;
+            
+            return S_OK;
+        }
+    }
+};
+
+extern IAvnScreens* CreateScreens()
+{
+    return new Screens();
+}

+ 262 - 0
native/Avalonia.Native/src/OSX/SystemDialogs.mm

@@ -0,0 +1,262 @@
+// 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.
+
+#include "common.h"
+#include "window.h"
+
+class SystemDialogs : public ComSingleObject<IAvnSystemDialogs, &IID_IAvnSystemDialogs>
+{
+public:
+    FORWARD_IUNKNOWN()
+    virtual void SelectFolderDialog (IAvnWindow* parentWindowHandle,
+                                     IAvnSystemDialogEvents* events,
+                                     const char* title,
+                                     const char* initialDirectory) override
+    {
+        @autoreleasepool
+        {
+            auto panel = [NSOpenPanel openPanel];
+            
+            panel.canChooseDirectories = true;
+            panel.canCreateDirectories = true;
+            panel.canChooseFiles = false;
+            
+            if(title != nullptr)
+            {
+                panel.title = [NSString stringWithUTF8String:title];
+            }
+            
+            if(initialDirectory != nullptr)
+            {
+                auto directoryString = [NSString stringWithUTF8String:initialDirectory];
+                panel.directoryURL = [NSURL fileURLWithPath:directoryString];
+            }
+            
+            auto handler = ^(NSModalResponse result) {
+                if(result == NSFileHandlingPanelOKButton)
+                {
+                    auto urls = [panel URLs];
+                    
+                    if(urls.count > 0)
+                    {
+                        void* strings[urls.count];
+                        
+                        for(int i = 0; i < urls.count; i++)
+                        {
+                            auto url = [urls objectAtIndex:i];
+                            
+                            auto string = [url absoluteString];
+                            string = [string substringFromIndex:7];
+                            
+                            strings[i] = (void*)[string UTF8String];
+                        }
+                        
+                        events->OnCompleted((int)urls.count, &strings[0]);
+                        
+                        [panel orderOut:panel];
+                        
+                        if(parentWindowHandle != nullptr)
+                        {
+                            auto windowHolder = dynamic_cast<INSWindowHolder*>(parentWindowHandle);
+                            [windowHolder->GetNSWindow() makeKeyAndOrderFront:windowHolder->GetNSWindow()];
+                        }
+                        
+                        return;
+                    }
+                }
+                
+                events->OnCompleted(0, nullptr);
+                
+            };
+            
+            if(parentWindowHandle != nullptr)
+            {
+                auto windowBase = dynamic_cast<INSWindowHolder*>(parentWindowHandle);
+                
+                [panel beginSheetModalForWindow:windowBase->GetNSWindow() completionHandler:handler];
+            }
+            else
+            {
+                [panel beginWithCompletionHandler: handler];
+            }
+        }
+    }
+    
+    virtual void OpenFileDialog (IAvnWindow* parentWindowHandle,
+                                 IAvnSystemDialogEvents* events,
+                                 bool allowMultiple,
+                                 const char* title,
+                                 const char* initialDirectory,
+                                 const char* initialFile,
+                                 const char* filters) override
+    {
+        @autoreleasepool
+        {
+            auto panel = [NSOpenPanel openPanel];
+            
+            panel.allowsMultipleSelection = allowMultiple;
+            
+            if(title != nullptr)
+            {
+                panel.title = [NSString stringWithUTF8String:title];
+            }
+            
+            if(initialDirectory != nullptr)
+            {
+                auto directoryString = [NSString stringWithUTF8String:initialDirectory];
+                panel.directoryURL = [NSURL fileURLWithPath:directoryString];
+            }
+            
+            if(initialFile != nullptr)
+            {
+                panel.nameFieldStringValue = [NSString stringWithUTF8String:initialFile];
+            }
+            
+            if(filters != nullptr)
+            {
+                auto filtersString = [NSString stringWithUTF8String:filters];
+                
+                if(filtersString.length > 0)
+                {
+                    auto allowedTypes = [filtersString componentsSeparatedByString:@";"];
+                    
+                    panel.allowedFileTypes = allowedTypes;
+                }
+            }
+            
+            auto handler = ^(NSModalResponse result) {
+                if(result == NSFileHandlingPanelOKButton)
+                {
+                    auto urls = [panel URLs];
+                    
+                    if(urls.count > 0)
+                    {
+                        void* strings[urls.count];
+                        
+                        for(int i = 0; i < urls.count; i++)
+                        {
+                            auto url = [urls objectAtIndex:i];
+                            
+                            auto string = [url absoluteString];
+                            string = [string substringFromIndex:7];
+                            
+                            strings[i] = (void*)[string UTF8String];
+                        }
+                        
+                        events->OnCompleted((int)urls.count, &strings[0]);
+                        
+                        [panel orderOut:panel];
+                        
+                        if(parentWindowHandle != nullptr)
+                        {
+                            auto windowHolder = dynamic_cast<INSWindowHolder*>(parentWindowHandle);
+                            [windowHolder->GetNSWindow() makeKeyAndOrderFront:windowHolder->GetNSWindow()];
+                        }
+                        
+                        return;
+                    }
+                }
+                
+                events->OnCompleted(0, nullptr);
+                
+            };
+            
+            if(parentWindowHandle != nullptr)
+            {
+                auto windowHolder = dynamic_cast<INSWindowHolder*>(parentWindowHandle);
+                
+                [panel beginSheetModalForWindow:windowHolder->GetNSWindow() completionHandler:handler];
+            }
+            else
+            {
+                [panel beginWithCompletionHandler: handler];
+            }
+        }
+    }
+    
+    virtual void SaveFileDialog (IAvnWindow* parentWindowHandle,
+                                 IAvnSystemDialogEvents* events,
+                                 const char* title,
+                                 const char* initialDirectory,
+                                 const char* initialFile,
+                                 const char* filters) override
+    {
+        @autoreleasepool
+        {
+            auto panel = [NSSavePanel savePanel];
+            
+            if(title != nullptr)
+            {
+                panel.title = [NSString stringWithUTF8String:title];
+            }
+            
+            if(initialDirectory != nullptr)
+            {
+                auto directoryString = [NSString stringWithUTF8String:initialDirectory];
+                panel.directoryURL = [NSURL fileURLWithPath:directoryString];
+            }
+            
+            if(initialFile != nullptr)
+            {
+                panel.nameFieldStringValue = [NSString stringWithUTF8String:initialFile];
+            }
+            
+            if(filters != nullptr)
+            {
+                auto filtersString = [NSString stringWithUTF8String:filters];
+                
+                if(filtersString.length > 0)
+                {
+                    auto allowedTypes = [filtersString componentsSeparatedByString:@";"];
+                    
+                    panel.allowedFileTypes = allowedTypes;
+                }
+            }
+            
+            auto handler = ^(NSModalResponse result) {
+                if(result == NSFileHandlingPanelOKButton)
+                {
+                    void* strings[1];
+                    
+                    auto url = [panel URL];
+                    
+                    auto string = [url absoluteString];
+                    string = [string substringFromIndex:7];     
+                    strings[0] = (void*)[string UTF8String];
+               
+                    events->OnCompleted(1, &strings[0]);
+                    
+                    [panel orderOut:panel];
+                    
+                    if(parentWindowHandle != nullptr)
+                    {
+                        auto windowHolder = dynamic_cast<INSWindowHolder*>(parentWindowHandle);
+                        [windowHolder->GetNSWindow() makeKeyAndOrderFront:windowHolder->GetNSWindow()];
+                    }
+                    
+                    return;
+                }
+                
+                events->OnCompleted(0, nullptr);
+                
+            };
+            
+            if(parentWindowHandle != nullptr)
+            {
+                auto windowBase = dynamic_cast<INSWindowHolder*>(parentWindowHandle);
+                
+                [panel beginSheetModalForWindow:windowBase->GetNSWindow() completionHandler:handler];
+            }
+            else
+            {
+                [panel beginWithCompletionHandler: handler];
+            }
+        }
+    }
+
+};
+
+extern IAvnSystemDialogs* CreateSystemDialogs()
+{
+    return new SystemDialogs();
+}

+ 47 - 0
native/Avalonia.Native/src/OSX/clipboard.mm

@@ -0,0 +1,47 @@
+// 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.
+
+#include "common.h"
+
+class Clipboard : public ComSingleObject<IAvnClipboard, &IID_IAvnClipboard>
+{
+public:
+    FORWARD_IUNKNOWN()
+    virtual HRESULT GetText (void** retOut) override
+    {
+        @autoreleasepool
+        {
+            NSString *str = [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString];
+            *retOut = (void *)str.UTF8String;
+        }
+        
+        return S_OK;
+    }
+    
+    virtual HRESULT SetText (char* text) override
+    {
+        @autoreleasepool
+        {
+            NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
+            [pasteBoard clearContents];
+            [pasteBoard setString:@(text) forType:NSPasteboardTypeString];
+        }
+        
+        return S_OK;
+    }
+
+    virtual HRESULT Clear() override
+    {
+        @autoreleasepool
+        {
+            [[NSPasteboard generalPasteboard] clearContents];
+        }
+        
+        return S_OK;
+    }
+};
+
+extern IAvnClipboard* CreateClipboard()
+{
+    return new Clipboard();
+}

+ 34 - 0
native/Avalonia.Native/src/OSX/common.h

@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef common_h
+#define common_h
+#include "comimpl.h"
+#include "avalonia-native.h"
+#include <stdio.h>
+#import <Foundation/Foundation.h>
+#import <AppKit/AppKit.h>
+#include <pthread.h>
+
+extern IAvnPlatformThreadingInterface* CreatePlatformThreading();
+extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events);
+extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events);
+extern IAvnSystemDialogs* CreateSystemDialogs();
+extern IAvnScreens* CreateScreens();
+extern IAvnClipboard* CreateClipboard();
+extern IAvnCursorFactory* CreateCursorFactory();
+extern IAvnGlFeature* GetGlFeature();
+extern IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(NSWindow* window, NSView* view);
+
+extern NSPoint ToNSPoint (AvnPoint p);
+extern AvnPoint ToAvnPoint (NSPoint p);
+extern AvnPoint ConvertPointY (AvnPoint p);
+extern NSSize ToNSSize (AvnSize s);
+
+#ifdef DEBUG
+#define NSDebugLog(...) NSLog(__VA_ARGS__)
+#else
+#define NSDebugLog(...) (void)0
+#endif
+
+#endif

+ 29 - 0
native/Avalonia.Native/src/OSX/cursor.h

@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef cursor_h
+#define cursor_h
+
+#include "common.h"
+#include <map>
+
+class Cursor : public ComSingleObject<IAvnCursor, &IID_IAvnCursor>
+{
+private:
+    NSCursor * _native;
+
+public:
+    FORWARD_IUNKNOWN()
+    Cursor(NSCursor * cursor)
+    {
+        _native = cursor;
+    }
+
+    NSCursor* GetNative()
+    {
+        return _native;
+    }
+};
+
+extern std::map<AvnStandardCursorType, Cursor*> s_cursorMap;
+#endif /* cursor_h */

+ 73 - 0
native/Avalonia.Native/src/OSX/cursor.mm

@@ -0,0 +1,73 @@
+// 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.
+
+#include "common.h"
+#include "cursor.h"
+#include <map>
+
+class CursorFactory : public ComSingleObject<IAvnCursorFactory, &IID_IAvnCursorFactory>
+{
+    Cursor* arrowCursor = new Cursor([NSCursor arrowCursor]);
+    Cursor* crossCursor = new Cursor([NSCursor crosshairCursor]);
+    Cursor* resizeUpCursor = new Cursor([NSCursor resizeUpCursor]);
+    Cursor* resizeDownCursor = new Cursor([NSCursor resizeDownCursor]);
+    Cursor* resizeUpDownCursor = new Cursor([NSCursor resizeUpDownCursor]);
+    Cursor* dragCopyCursor = new Cursor([NSCursor dragCopyCursor]);
+    Cursor* dragLinkCursor = new Cursor([NSCursor dragLinkCursor]);
+    Cursor* pointingHandCursor = new Cursor([NSCursor pointingHandCursor]);
+    Cursor* contextualMenuCursor = new Cursor([NSCursor contextualMenuCursor]);
+    Cursor* IBeamCursor = new Cursor([NSCursor IBeamCursor]);
+    Cursor* resizeLeftCursor = new Cursor([NSCursor resizeLeftCursor]);
+    Cursor* resizeRightCursor = new Cursor([NSCursor resizeRightCursor]);
+    Cursor* resizeWestEastCursor = new Cursor([NSCursor resizeLeftRightCursor]);
+    Cursor* operationNotAllowedCursor = new Cursor([NSCursor operationNotAllowedCursor]);
+
+    std::map<AvnStandardCursorType, Cursor*> s_cursorMap =
+    {
+        { CursorArrow, arrowCursor },
+        { CursorAppStarting, arrowCursor },
+        { CursorWait, arrowCursor },
+        { CursorTopLeftCorner, crossCursor },
+        { CursorTopRightCorner, crossCursor },
+        { CursorBottomLeftCorner, crossCursor },
+        { CursorBottomRightCorner, crossCursor },
+        { CursorCross, crossCursor },
+        { CursorSizeAll, crossCursor },
+        { CursorSizeNorthSouth, resizeUpDownCursor},
+        { CursorSizeWestEast, resizeWestEastCursor},
+        { CursorTopSide, resizeUpCursor },
+        { CursorUpArrow, resizeUpCursor },
+        { CursorBottomSize, resizeDownCursor },
+        { CursorDragCopy, dragCopyCursor },
+        { CursorDragMove, dragCopyCursor },
+        { CursorDragLink, dragLinkCursor },
+        { CursorHand, pointingHandCursor },
+        { CursorHelp, contextualMenuCursor },
+        { CursorIbeam, IBeamCursor },
+        { CursorLeftSide, resizeLeftCursor },
+        { CursorRightSide, resizeRightCursor },
+        { CursorNo, operationNotAllowedCursor }
+    };
+
+public:
+    FORWARD_IUNKNOWN()
+    virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut) override
+    {
+        *retOut = s_cursorMap[cursorType];
+        
+        if(*retOut != nullptr)
+        {
+            (*retOut)->AddRef();
+        }
+            
+        return S_OK;
+    }
+};
+
+extern IAvnCursorFactory* CreateCursorFactory()
+{
+    @autoreleasepool
+    {
+        return new CursorFactory();
+    }
+}

+ 255 - 0
native/Avalonia.Native/src/OSX/gl.mm

@@ -0,0 +1,255 @@
+#include "common.h"
+#include <OpenGL/gl.h>
+#include <dlfcn.h>
+
+template <typename T, size_t N> char (&ArrayCounter(T (&a)[N]))[N];
+#define ARRAY_COUNT(a) (sizeof(ArrayCounter(a)))
+
+NSOpenGLPixelFormat* CreateFormat()
+{
+    NSOpenGLPixelFormatAttribute attribs[] =
+    {
+        NSOpenGLPFADoubleBuffer,
+        NSOpenGLPFAColorSize, 32,
+        NSOpenGLPFAStencilSize, 8,
+        NSOpenGLPFADepthSize, 8,
+        0
+    };
+    return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
+}
+
+class AvnGlContext : public virtual ComSingleObject<IAvnGlContext, &IID_IAvnGlContext>
+{
+public:
+    FORWARD_IUNKNOWN()
+    NSOpenGLContext* GlContext;
+    GLuint Framebuffer, RenderBuffer, StencilBuffer;
+    AvnGlContext(NSOpenGLContext* gl, bool offscreen)
+    {
+        Framebuffer = 0;
+        RenderBuffer = 0;
+        StencilBuffer = 0;
+        GlContext = gl;
+        if(offscreen)
+        {
+            [GlContext makeCurrentContext];
+
+            glGenFramebuffersEXT(1, &Framebuffer);
+            glBindFramebufferEXT(GL_FRAMEBUFFER, Framebuffer);
+            glGenRenderbuffersEXT(1, &RenderBuffer);
+            glGenRenderbuffersEXT(1, &StencilBuffer);
+
+            glBindRenderbufferEXT(GL_RENDERBUFFER, StencilBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, StencilBuffer);
+            glBindRenderbufferEXT(GL_RENDERBUFFER, RenderBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, RenderBuffer);
+        }
+        
+    }
+    
+    
+    virtual HRESULT MakeCurrent()  override
+    {
+        [GlContext makeCurrentContext];/*
+        glBindFramebufferEXT(GL_FRAMEBUFFER, Framebuffer);
+        glBindRenderbufferEXT(GL_RENDERBUFFER, RenderBuffer);
+        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, RenderBuffer);
+        glBindRenderbufferEXT(GL_RENDERBUFFER, StencilBuffer);
+        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, StencilBuffer);*/
+        return S_OK;
+    }
+};
+
+class AvnGlDisplay : public virtual ComSingleObject<IAvnGlDisplay, &IID_IAvnGlDisplay>
+{
+    int _sampleCount, _stencilSize;
+    void* _libgl;
+    
+public:
+    FORWARD_IUNKNOWN()
+    
+    AvnGlDisplay(int sampleCount, int stencilSize)
+    {
+        _sampleCount = sampleCount;
+        _stencilSize = stencilSize;
+        _libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", RTLD_LAZY);
+    }
+    
+    virtual HRESULT GetSampleCount(int* ret)  override
+    {
+        *ret = _sampleCount;
+        return S_OK;
+    }
+    virtual HRESULT GetStencilSize(int* ret) override
+    {
+        *ret = _stencilSize;
+        return S_OK;
+    }
+    
+    virtual HRESULT ClearContext()  override
+    {
+        [NSOpenGLContext clearCurrentContext];
+        return S_OK;
+    }
+    
+    virtual void* GetProcAddress(char* proc)  override
+    {
+        return dlsym(_libgl, proc);
+    }
+};
+
+
+class GlFeature : public virtual ComSingleObject<IAvnGlFeature, &IID_IAvnGlFeature>
+{
+    IAvnGlDisplay* _display;
+    AvnGlContext *_immediate;
+    NSOpenGLContext* _shared;
+public:
+    FORWARD_IUNKNOWN()
+    NSOpenGLPixelFormat* _format;
+    GlFeature(IAvnGlDisplay* display, AvnGlContext* immediate, NSOpenGLPixelFormat* format)
+    {
+        _display = display;
+        _immediate = immediate;
+        _format = format;
+        _shared = [[NSOpenGLContext alloc] initWithFormat:_format shareContext:_immediate->GlContext];
+    }
+    
+    NSOpenGLContext* CreateContext()
+    {
+        return _shared;
+        //return [[NSOpenGLContext alloc] initWithFormat:_format shareContext:nil];
+    }
+    
+    virtual HRESULT ObtainDisplay(IAvnGlDisplay**retOut)  override
+    {
+        *retOut = _display;
+        _display->AddRef();
+        return S_OK;
+    }
+    
+    virtual HRESULT ObtainImmediateContext(IAvnGlContext**retOut)  override
+    {
+        *retOut = _immediate;
+        _immediate->AddRef();
+        return S_OK;
+    }
+};
+
+static GlFeature* Feature;
+
+GlFeature* CreateGlFeature()
+{
+    auto format = CreateFormat();
+    if(format == nil)
+    {
+        NSLog(@"Unable to choose pixel format");
+        return NULL;
+    }
+    
+    auto immediateContext = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
+    if(immediateContext == nil)
+    {
+        NSLog(@"Unable to create NSOpenGLContext");
+        return NULL;
+    }
+
+    int stencilBits = 0, sampleCount = 0;
+    
+    auto fmt = CGLGetPixelFormat([immediateContext CGLContextObj]);
+    CGLDescribePixelFormat(fmt, 0, kCGLPFASamples, &sampleCount);
+    CGLDescribePixelFormat(fmt, 0, kCGLPFAStencilSize, &stencilBits);
+    
+    auto offscreen = new AvnGlContext(immediateContext, true);
+    auto display = new AvnGlDisplay(sampleCount, stencilBits);
+    
+    return new GlFeature(display, offscreen, format);
+}
+
+
+static GlFeature* GetFeature()
+{
+    if(Feature == nil)
+        Feature = CreateGlFeature();
+    return Feature;
+}
+
+extern IAvnGlFeature* GetGlFeature()
+{
+    return GetFeature();
+}
+
+class AvnGlRenderingSession : public ComSingleObject<IAvnGlSurfaceRenderingSession, &IID_IAvnGlSurfaceRenderingSession>
+{
+    NSView* _view;
+    NSWindow* _window;
+    NSOpenGLContext* _context;
+public:
+    FORWARD_IUNKNOWN()
+    AvnGlRenderingSession(NSWindow*window, NSView* view, NSOpenGLContext* context)
+    {
+        _context = context;
+        _window = window;
+        _view = view;
+    }
+    
+    virtual HRESULT GetPixelSize(AvnPixelSize* ret)  override
+    {
+        auto fsize = [_view convertSizeToBacking: [_view frame].size];
+        ret->Width = (int)fsize.width;
+        ret->Height = (int)fsize.height;
+        return S_OK;
+    }
+    virtual HRESULT GetScaling(double* ret)  override
+    {
+        *ret = [_window backingScaleFactor];
+        return S_OK;
+    }
+    
+    virtual ~AvnGlRenderingSession()
+    {
+        glFlush();
+        [_context flushBuffer];
+        [_context setView:nil];
+        CGLUnlockContext([_context CGLContextObj]);
+        [_view unlockFocus];
+    }
+};
+
+class AvnGlRenderTarget : public ComSingleObject<IAvnGlSurfaceRenderTarget, &IID_IAvnGlSurfaceRenderTarget>
+{
+    NSView* _view;
+    NSWindow* _window;
+    NSOpenGLContext* _context;
+public:
+    FORWARD_IUNKNOWN()
+    AvnGlRenderTarget(NSWindow* window, NSView*view)
+    {
+        _window = window;
+        _view = view;
+        _context = GetFeature()->CreateContext();
+    }
+    
+    virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret)  override
+    {
+        auto f = GetFeature();
+        if(f == NULL)
+            return E_FAIL;
+        if(![_view lockFocusIfCanDraw])
+            return E_ABORT;
+        
+        auto gl = _context;
+        CGLLockContext([_context CGLContextObj]);
+        [gl setView: _view];
+        [gl makeCurrentContext];
+        auto frame = [_view frame];
+        
+        *ret = new AvnGlRenderingSession(_window, _view, gl);
+        return S_OK;
+    }
+};
+
+extern IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(NSWindow* window, NSView* view)
+{
+    return new AvnGlRenderTarget(window, view);
+}

+ 178 - 0
native/Avalonia.Native/src/OSX/main.mm

@@ -0,0 +1,178 @@
+// 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.
+
+//This file will contain actual IID structures
+#define COM_GUIDS_MATERIALIZE
+#include "common.h"
+
+static BOOL ShowInDock = 1;
+
+static void SetActivationPolicy()
+{
+    [[NSApplication sharedApplication] setActivationPolicy: (ShowInDock ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory)];
+}
+
+class MacOptions : public ComSingleObject<IAvnMacOptions, &IID_IAvnMacOptions>
+{
+public:
+    FORWARD_IUNKNOWN()
+    virtual HRESULT SetShowInDock(int show)  override
+    {
+        ShowInDock = show;
+        SetActivationPolicy();
+        return S_OK;
+    }
+};
+
+
+
+/// See "Using POSIX Threads in a Cocoa Application" section here:
+/// https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/20000738-125024
+@interface ThreadingInitializer : NSObject
+- (void) do;
+@end
+@implementation ThreadingInitializer
+
+pthread_mutex_t mutex;
+pthread_cond_t cond;
+
+- (void) runOnce
+{
+    pthread_mutex_lock(&mutex);
+    pthread_cond_signal(&cond);
+    pthread_mutex_unlock(&mutex);
+}
+
+- (void) do
+{
+    pthread_mutex_init(&mutex, NULL);
+    pthread_cond_init(&cond, NULL);
+    [[[NSThread alloc] initWithTarget:self selector:@selector(runOnce) object:nil] start];
+    pthread_mutex_lock(&mutex);
+    pthread_cond_wait(&cond, &mutex);
+    pthread_mutex_unlock(&mutex);
+    pthread_cond_destroy(&cond);
+    pthread_mutex_destroy(&mutex);
+}
+
+
+@end
+
+
+class AvaloniaNative : public ComSingleObject<IAvaloniaNativeFactory, &IID_IAvaloniaNativeFactory>
+{
+    
+public:
+    FORWARD_IUNKNOWN()
+    virtual HRESULT Initialize() override
+    {
+        @autoreleasepool{
+            [[ThreadingInitializer new] do];
+            return S_OK;
+        }
+    };
+    
+    virtual IAvnMacOptions* GetMacOptions()  override
+    {
+        return (IAvnMacOptions*)new MacOptions();
+    }
+    
+    virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv)  override
+    {
+        if(cb == nullptr || ppv == nullptr)
+            return E_POINTER;
+        *ppv = CreateAvnWindow(cb);
+        return S_OK;
+    };
+    
+    virtual HRESULT CreatePopup(IAvnWindowEvents* cb, IAvnPopup** ppv) override
+    {
+        if(cb == nullptr || ppv == nullptr)
+            return E_POINTER;
+        
+        *ppv = CreateAvnPopup(cb);
+        return S_OK;
+    }
+    
+    virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv)  override
+    {
+        *ppv = CreatePlatformThreading();
+        return S_OK;
+    }
+    
+    virtual HRESULT CreateSystemDialogs(IAvnSystemDialogs** ppv) override
+    {
+        *ppv = ::CreateSystemDialogs();
+        return  S_OK;
+    }
+    
+    virtual HRESULT CreateScreens (IAvnScreens** ppv) override
+    {
+        *ppv = ::CreateScreens ();
+        return S_OK;
+    }
+
+    virtual HRESULT CreateClipboard(IAvnClipboard** ppv) override
+    {
+        *ppv = ::CreateClipboard ();
+        return S_OK;
+    }
+
+    virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) override
+    {
+        *ppv = ::CreateCursorFactory();
+        return S_OK;
+    }
+    
+    virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) override
+    {
+        auto rv = ::GetGlFeature();
+        if(rv == NULL)
+            return E_FAIL;
+        rv->AddRef();
+        *ppv = rv;
+        return S_OK;
+    }
+};
+
+extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()
+{
+    return new AvaloniaNative();
+};
+
+NSSize ToNSSize (AvnSize s)
+{
+    NSSize result;
+    result.width = s.Width;
+    result.height = s.Height;
+    
+    return result;
+}
+
+NSPoint ToNSPoint (AvnPoint p)
+{
+    NSPoint result;
+    result.x = p.X;
+    result.y = p.Y;
+    
+    return result;
+}
+
+AvnPoint ToAvnPoint (NSPoint p)
+{
+    AvnPoint result;
+    result.X = p.x;
+    result.Y = p.y;
+    
+    return result;
+}
+
+AvnPoint ConvertPointY (AvnPoint p)
+{
+    auto sw = [NSScreen.screens objectAtIndex:0].frame;
+    
+    auto t = MAX(sw.origin.y, sw.origin.y + sw.size.height);
+    p.Y = t - p.Y;
+    
+    return p;
+}

+ 190 - 0
native/Avalonia.Native/src/OSX/platformthreading.mm

@@ -0,0 +1,190 @@
+// 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.
+
+#include "common.h"
+
+class PlatformThreadingInterface;
+@interface Signaler : NSObject
+-(void) setParent: (PlatformThreadingInterface*)parent;
+-(void) signal: (int) priority;
+-(Signaler*) init;
+@end
+
+
+@interface ActionCallback : NSObject
+- (ActionCallback*) initWithCallback: (IAvnActionCallback*) callback;
+- (void) action;
+@end
+
+@implementation ActionCallback
+{
+    ComPtr<IAvnActionCallback> _callback;
+
+}
+- (ActionCallback*) initWithCallback: (IAvnActionCallback*) callback
+{
+    _callback = callback;
+    return self;
+}
+
+- (void) action
+{
+    _callback->Run();
+}
+
+
+@end
+
+class TimerWrapper : public ComUnknownObject
+{
+    NSTimer* _timer;
+public:
+    TimerWrapper(IAvnActionCallback* callback, int ms)
+    {
+        auto cb = [[ActionCallback alloc] initWithCallback:callback];
+        _timer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(double)ms/1000 target:cb selector:@selector(action) userInfo:nullptr repeats:true];
+    }
+                  
+    virtual ~TimerWrapper()
+    {
+         [_timer invalidate];
+    }
+};
+
+
+
+class PlatformThreadingInterface : public ComSingleObject<IAvnPlatformThreadingInterface, &IID_IAvnPlatformThreadingInterface>
+{
+private:
+    Signaler* _signaler;
+    
+    class LoopCancellation : public ComSingleObject<IAvnLoopCancellation, &IID_IAvnLoopCancellation>
+    {
+    public:
+        FORWARD_IUNKNOWN()
+        bool Cancelled = 0;
+        virtual void Cancel() override
+        {
+            Cancelled = 1;
+        }
+    };
+    
+public:
+    FORWARD_IUNKNOWN()
+    ComPtr<IAvnSignaledCallback> SignaledCallback;
+
+    PlatformThreadingInterface()
+    {
+        _signaler = [Signaler new];
+        [_signaler setParent:this];
+    }
+    
+    ~PlatformThreadingInterface()
+    {
+        if(_signaler)
+            [_signaler setParent: NULL];
+        _signaler = NULL;
+    }
+    
+    virtual bool GetCurrentThreadIsLoopThread() override
+    {
+        return [[NSThread currentThread] isMainThread];
+    }
+    virtual void SetSignaledCallback(IAvnSignaledCallback* cb) override
+    {
+        SignaledCallback = cb;
+    }
+    virtual IAvnLoopCancellation* CreateLoopCancellation() override
+    {
+        return new LoopCancellation();
+    }
+    
+    virtual void RunLoop(IAvnLoopCancellation* cancel) override
+    {
+        @autoreleasepool {
+            auto can = dynamic_cast<LoopCancellation*>(cancel);
+            [[NSApplication sharedApplication] activateIgnoringOtherApps:true];
+            while(true)
+            {
+                @autoreleasepool
+                {
+                    if(can != NULL && can->Cancelled)
+                        return;
+                    NSEvent* ev = [[NSApplication sharedApplication]
+                                   nextEventMatchingMask:NSEventMaskAny
+                                   untilDate: [NSDate dateWithTimeIntervalSinceNow:1]
+                                   inMode:NSDefaultRunLoopMode
+                                   dequeue:true];
+                    if(can != NULL && can->Cancelled)
+                        return;
+                    if(ev != NULL)
+                        [[NSApplication sharedApplication] sendEvent:ev];
+                }
+            }
+            NSDebugLog(@"RunLoop exited");
+        }
+    }
+    
+    virtual void Signal(int priority) override
+    {
+        [_signaler signal:priority];
+    }
+    
+    virtual IUnknown* StartTimer(int priority, int ms, IAvnActionCallback* callback) override
+    {
+        @autoreleasepool {
+            
+            return new TimerWrapper(callback, ms);
+        }
+    }
+};
+
+@implementation Signaler
+
+PlatformThreadingInterface* _parent = 0;
+bool _signaled = 0;
+NSArray<NSString*>* _modes;
+
+-(Signaler*) init
+{
+    if(self = [super init])
+    {
+        _modes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, NSRunLoopCommonModes, NSConnectionReplyMode, nil];
+    }
+    return self;
+}
+
+-(void) perform
+{
+    @synchronized (self) {
+        _signaled  = false;
+        if(_parent != NULL && _parent->SignaledCallback != NULL)
+            _parent->SignaledCallback->Signaled(0, false);
+    }
+}
+
+-(void) setParent:(PlatformThreadingInterface *)parent
+{
+    @synchronized (self) {
+        _parent = parent;
+    }
+}
+
+-(void) signal: (int) priority
+{
+
+    @synchronized (self) {
+        if(_signaled)
+            return;
+        _signaled = true;
+        [self performSelector:@selector(perform) onThread:[NSThread mainThread] withObject:NULL waitUntilDone:false modes:_modes];
+    }
+    
+}
+@end
+
+
+extern IAvnPlatformThreadingInterface* CreatePlatformThreading()
+{
+    return new PlatformThreadingInterface();
+}

+ 33 - 0
native/Avalonia.Native/src/OSX/window.h

@@ -0,0 +1,33 @@
+// 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.
+
+#ifndef window_h
+#define window_h
+
+class WindowBaseImpl;
+
+@interface AvnView : NSView<NSTextInputClient>
+-(AvnView* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent;
+-(NSEvent* _Nonnull) lastMouseDownEvent;
+-(AvnPoint) translateLocalPoint:(AvnPoint)pt;
+-(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose;
+-(void) onClosed;
+@end
+
+@interface AvnWindow : NSWindow <NSWindowDelegate>
+-(AvnWindow* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent;
+-(void) setCanBecomeKeyAndMain;
+-(void) pollModalSession: (NSModalSession _Nonnull) session;
+@end
+
+struct INSWindowHolder
+{
+    virtual AvnWindow* _Nonnull GetNSWindow () = 0;
+};
+
+struct IWindowStateChanged
+{
+    virtual void WindowStateChanged () = 0;
+};
+
+#endif /* window_h */

+ 1232 - 0
native/Avalonia.Native/src/OSX/window.mm

@@ -0,0 +1,1232 @@
+// 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.
+
+#include "common.h"
+#include "window.h"
+#include "KeyTransform.h"
+#include "cursor.h"
+#include <OpenGL/gl.h>
+
+class SoftwareDrawingOperation
+{
+public:
+    void* Data = 0;
+    AvnFramebuffer Desc;
+    void Alloc(NSView* view)
+    {
+        auto logicalSize = [view frame].size;
+        auto pixelSize = [view convertSizeToBacking:logicalSize];
+        int w = pixelSize.width;
+        int h = pixelSize.height;
+        int stride = w * 4;
+        Data = malloc(h * stride);
+        Desc = {
+            .Data = Data,
+            .Stride = stride,
+            .Width = w,
+            .Height = h,
+            .PixelFormat = kAvnRgba8888,
+            .Dpi = AvnVector { .X = w / logicalSize.width * 96, .Y = h / logicalSize.height * 96}
+        };
+    }
+    
+    void Dealloc()
+    {
+        if(Data != NULL)
+        {
+            free(Data);
+            Data = NULL;
+        }
+    }
+    
+    ~SoftwareDrawingOperation()
+    {
+        Dealloc();
+    }
+};
+
+class WindowBaseImpl : public virtual ComSingleObject<IAvnWindowBase, &IID_IAvnWindowBase>, public INSWindowHolder
+{
+private:
+    NSCursor* cursor;
+
+public:
+    FORWARD_IUNKNOWN()
+    virtual ~WindowBaseImpl()
+    {
+        NSDebugLog(@"~WindowBaseImpl()");
+        View = NULL;
+        Window = NULL;
+    }
+    AvnView* View;
+    AvnWindow* Window;
+    ComPtr<IAvnWindowBaseEvents> BaseEvents;
+    SoftwareDrawingOperation CurrentSwDrawingOperation;
+    AvnPoint lastPositionSet;
+    NSString* _lastTitle;
+    
+    WindowBaseImpl(IAvnWindowBaseEvents* events)
+    {
+        BaseEvents = events;
+        View = [[AvnView alloc] initWithParent:this];
+
+        Window = [[AvnWindow alloc] initWithParent:this];
+        
+        lastPositionSet.X = 100;
+        lastPositionSet.Y = 100;
+        _lastTitle = @"";
+        
+        [Window setStyleMask:NSWindowStyleMaskBorderless];
+        [Window setBackingType:NSBackingStoreBuffered];
+        [Window setContentView: View];
+    }
+    
+    virtual AvnWindow* GetNSWindow() override
+    {
+        return Window;
+    }
+    
+    virtual HRESULT Show() override
+    {
+        @autoreleasepool
+        {
+            SetPosition(lastPositionSet);
+            UpdateStyle();
+            
+            [Window makeKeyAndOrderFront:Window];
+            
+            [Window setTitle:_lastTitle];
+            [Window setTitleVisibility:NSWindowTitleVisible];
+        
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT Hide () override
+    {
+        @autoreleasepool
+        {
+            if(Window != nullptr)
+            {
+                [Window orderOut:Window];
+            }
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT Activate () override
+    {
+        @autoreleasepool
+        {
+            if(Window != nullptr)
+            {
+                [Window makeKeyWindow];
+            }
+        }
+        
+        return S_OK;
+    }
+    
+    virtual HRESULT SetTopMost (bool value) override
+    {
+        @autoreleasepool
+        {
+            [Window setLevel: value ? NSFloatingWindowLevel : NSNormalWindowLevel];
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT Close() override
+    {
+        @autoreleasepool
+        {
+            [Window close];
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT GetClientSize(AvnSize* ret) override
+    {
+        @autoreleasepool
+        {
+            if(ret == nullptr)
+                return E_POINTER;
+            auto frame = [View frame];
+            ret->Width = frame.size.width;
+            ret->Height = frame.size.height;
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT GetMaxClientSize(AvnSize* ret) override
+    {
+        @autoreleasepool
+        {
+            if(ret == nullptr)
+                return E_POINTER;
+            
+            auto size = [NSScreen.screens objectAtIndex:0].frame.size;
+            
+            ret->Height = size.height;
+            ret->Width = size.width;
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT GetScaling (double* ret) override
+    {
+        @autoreleasepool
+        {
+            if(ret == nullptr)
+                return E_POINTER;
+            
+            if(Window == nullptr)
+            {
+                *ret = 1;
+                return S_OK;
+            }
+            
+            *ret = [Window backingScaleFactor];
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT SetMinMaxSize (AvnSize minSize, AvnSize maxSize) override
+    {
+        @autoreleasepool
+        {
+            [Window setMinSize: ToNSSize(minSize)];
+            [Window setMaxSize: ToNSSize(maxSize)];
+        
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT Resize(double x, double y) override
+    {
+        @autoreleasepool
+        {
+            [Window setContentSize:NSSize{x, y}];
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT Invalidate (AvnRect rect) override
+    {
+        @autoreleasepool
+        {
+            [View setNeedsDisplayInRect:[View frame]];
+            
+            return S_OK;
+        }
+    }
+    
+    virtual bool TryLock() override
+    {
+        @autoreleasepool
+        {
+            return [View lockFocusIfCanDraw] == YES;
+        }
+    }
+    
+    virtual void Unlock() override
+    {
+        @autoreleasepool
+        {
+            [View unlockFocus];
+        }
+    }
+    
+    virtual HRESULT BeginMoveDrag () override
+    {
+        @autoreleasepool
+        {
+            auto lastEvent = [View lastMouseDownEvent];
+            
+            if(lastEvent == nullptr)
+            {
+                return S_OK;
+            }
+            
+            [Window performWindowDragWithEvent:lastEvent];
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT BeginResizeDrag (AvnWindowEdge edge) override
+    {
+        return S_OK;
+    }
+    
+    virtual HRESULT GetPosition (AvnPoint* ret) override
+    {
+        @autoreleasepool
+        {
+            if(ret == nullptr)
+            {
+                return E_POINTER;
+            }
+            
+            auto frame = [Window frame];
+            
+            ret->X = frame.origin.x;
+            ret->Y = frame.origin.y + frame.size.height;
+            
+            *ret = ConvertPointY(*ret);
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT SetPosition (AvnPoint point) override
+    {
+        @autoreleasepool
+        {
+            lastPositionSet = point;
+            [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(point))];
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT PointToClient (AvnPoint point, AvnPoint* ret) override
+    {
+        @autoreleasepool
+        {
+            if(ret == nullptr)
+            {
+                return E_POINTER;
+            }
+            
+            point = ConvertPointY(point);
+            auto viewPoint = [Window convertScreenToBase:ToNSPoint(point)];
+            
+            *ret = [View translateLocalPoint:ToAvnPoint(viewPoint)];
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT PointToScreen (AvnPoint point, AvnPoint* ret) override
+    {
+        @autoreleasepool
+        {
+            if(ret == nullptr)
+            {
+                return E_POINTER;
+            }
+            
+            auto cocoaViewPoint =  ToNSPoint([View translateLocalPoint:point]);
+            auto cocoaScreenPoint = [Window convertBaseToScreen:cocoaViewPoint];
+            *ret = ConvertPointY(ToAvnPoint(cocoaScreenPoint));
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer* fb, IUnknown* dispose) override
+    {
+        [View setSwRenderedFrame: fb dispose: dispose];
+        return S_OK;
+    }
+    
+    virtual HRESULT GetSoftwareFramebuffer(AvnFramebuffer*ret) override
+    {
+        if(![[NSThread currentThread] isMainThread])
+            return E_FAIL;
+        if(CurrentSwDrawingOperation.Data == NULL)
+            CurrentSwDrawingOperation.Alloc(View);
+        *ret = CurrentSwDrawingOperation.Desc;
+        return S_OK;
+    }
+    
+    virtual HRESULT SetCursor(IAvnCursor* cursor) override
+    {
+        @autoreleasepool
+        {
+            Cursor* avnCursor = dynamic_cast<Cursor*>(cursor);
+            this->cursor = avnCursor->GetNative();
+            UpdateCursor();
+            return S_OK;
+        }
+    }
+
+    virtual void UpdateCursor()
+    {
+        [View resetCursorRects];
+        if (cursor != nil)
+        {
+             auto rect = [Window frame];
+             [View addCursorRect:rect cursor:cursor];
+             [cursor set];
+        }
+    }
+    
+    virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ppv) override
+    {
+        if(View == NULL)
+            return E_FAIL;
+        *ppv = ::CreateGlRenderTarget(Window, View);
+        return S_OK;
+    }
+
+protected:
+    virtual NSWindowStyleMask GetStyle()
+    {
+        return NSWindowStyleMaskBorderless;
+    }
+    
+    void UpdateStyle()
+    {
+        [Window setStyleMask:GetStyle()];
+    }
+    
+    virtual void OnResized ()
+    {
+        
+    }
+};
+
+class ModalDisposable : public ComUnknownObject
+{
+    NSModalSession _session;
+    AvnWindow* _window;
+    
+    void Dispose ()
+    {
+        [_window orderOut:_window];
+        [NSApp endModalSession:_session];
+    }
+    
+public:
+    ModalDisposable(AvnWindow* window, NSModalSession session)
+    {
+        _session = session;
+        _window = window;
+    }
+    
+    virtual ~ModalDisposable()
+    {
+        Dispose();
+    }
+};
+
+class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged
+{
+private:
+    bool _canResize = true;
+    bool _hasDecorations = true;
+    CGRect _lastUndecoratedFrame;
+    AvnWindowState _lastWindowState;
+    
+    FORWARD_IUNKNOWN()
+    BEGIN_INTERFACE_MAP()
+    INHERIT_INTERFACE_MAP(WindowBaseImpl)
+    INTERFACE_MAP_ENTRY(IAvnWindow, IID_IAvnWindow)
+    END_INTERFACE_MAP()
+    virtual ~WindowImpl(){
+        NSDebugLog(@"~WindowImpl");
+    }
+    
+    ComPtr<IAvnWindowEvents> WindowEvents;
+    WindowImpl(IAvnWindowEvents* events) : WindowBaseImpl(events)
+    {
+        WindowEvents = events;
+        [Window setCanBecomeKeyAndMain];
+    }
+    
+    virtual HRESULT Show () override
+    {
+        @autoreleasepool
+        {
+            WindowBaseImpl::Show();
+            
+            return SetWindowState(_lastWindowState);
+        }
+    }
+    
+    virtual HRESULT ShowDialog (IUnknown**ppv) override
+    {
+        @autoreleasepool
+        {
+            if(ppv == nullptr)
+            {
+                return E_POINTER;
+            }
+            
+            auto session = [NSApp beginModalSessionForWindow:Window];
+            auto disposable = new ModalDisposable(Window, session);
+            *ppv = disposable;
+            
+            SetPosition(lastPositionSet);
+            UpdateStyle();
+            
+            [Window setTitle:_lastTitle];
+            [Window setTitleVisibility:NSWindowTitleVisible];
+            
+            [Window pollModalSession:session];
+            
+            return S_OK;
+        }
+    }
+    
+    void WindowStateChanged () override
+    {
+        AvnWindowState state;
+        GetWindowState(&state);
+        WindowEvents->WindowStateChanged(state);
+    }
+    
+    bool UndecoratedIsMaximized ()
+    {
+        return CGRectEqualToRect([Window frame], [Window screen].visibleFrame);
+    }
+    
+    bool IsZoomed ()
+    {
+        return _hasDecorations ? [Window isZoomed] : UndecoratedIsMaximized();
+    }
+    
+    void DoZoom()
+    {
+        if (_hasDecorations)
+        {
+            [Window performZoom:Window];
+        }
+        else
+        {
+            if (!UndecoratedIsMaximized())
+            {
+                _lastUndecoratedFrame = [Window frame];
+            }
+            
+            [Window zoom:Window];
+        }
+    }
+    
+    virtual HRESULT SetCanResize(bool value) override
+    {
+        @autoreleasepool
+        {
+            _canResize = value;
+            UpdateStyle();
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT SetHasDecorations(bool value) override
+    {
+        @autoreleasepool
+        {
+            _hasDecorations = value;
+            UpdateStyle();
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT SetTitle (const char* title) override
+    {
+        @autoreleasepool
+        {
+            _lastTitle = [NSString stringWithUTF8String:title];
+            [Window setTitle:_lastTitle];
+            [Window setTitleVisibility:NSWindowTitleVisible];
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT SetTitleBarColor(AvnColor color) override
+    {
+        @autoreleasepool
+        {
+            float a = (float)color.Alpha / 255.0f;
+            float r = (float)color.Red / 255.0f;
+            float g = (float)color.Green / 255.0f;
+            float b = (float)color.Blue / 255.0f;
+            
+            auto nscolor = [NSColor colorWithSRGBRed:r green:g blue:b alpha:a];
+            
+            // Based on the titlebar color we have to choose either light or dark
+            // OSX doesnt let you set a foreground color for titlebar.
+            if ((r*0.299 + g*0.587 + b*0.114) > 186.0f / 255.0f)
+            {
+                [Window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
+            }
+            else
+            {
+                [Window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
+            }
+            
+            [Window setTitlebarAppearsTransparent:true];
+            [Window setBackgroundColor:nscolor];
+        }
+        
+        return S_OK;
+    }
+    
+    virtual HRESULT GetWindowState (AvnWindowState*ret) override
+    {
+        @autoreleasepool
+        {
+            if(ret == nullptr)
+            {
+                return E_POINTER;
+            }
+            
+            if([Window isMiniaturized])
+            {
+                *ret = Minimized;
+                return S_OK;
+            }
+            
+            if([Window isZoomed])
+            {
+                *ret = Maximized;
+                return S_OK;
+            }
+            
+            *ret = Normal;
+            
+            return S_OK;
+        }
+    }
+    
+    virtual HRESULT SetWindowState (AvnWindowState state) override
+    {
+        @autoreleasepool
+        {
+            _lastWindowState = state;
+            
+            switch (state) {
+                case Maximized:
+                    lastPositionSet.X = 0;
+                    lastPositionSet.Y = 0;
+                    
+                    if([Window isMiniaturized])
+                    {
+                        [Window deminiaturize:Window];
+                    }
+                    
+                    if(!IsZoomed())
+                    {
+                        DoZoom();
+                    }
+                    break;
+                    
+                case Minimized:
+                    [Window miniaturize:Window];
+                    break;
+                    
+                default:
+                    if([Window isMiniaturized])
+                    {
+                        [Window deminiaturize:Window];
+                    }
+                    
+                    if(IsZoomed())
+                    {
+                        DoZoom();
+                    }
+                    break;
+            }
+            
+            return S_OK;
+        }
+    }
+    
+protected:
+    virtual void OnResized () override
+    {
+        auto windowState = [Window isMiniaturized] ? Minimized
+        : (IsZoomed() ? Maximized : Normal);
+        
+        if (windowState != _lastWindowState)
+        {
+            _lastWindowState = windowState;
+            
+            WindowEvents->WindowStateChanged(windowState);
+        }
+    }
+    
+    virtual NSWindowStyleMask GetStyle() override
+    {
+        unsigned long s = NSWindowStyleMaskBorderless;
+        if(_hasDecorations)
+            s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
+        if(_canResize)
+            s = s | NSWindowStyleMaskResizable;
+        return s;
+    }
+};
+
+NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, NSRunLoopCommonModes, NSConnectionReplyMode, nil];
+
+@implementation AvnView
+{
+    ComPtr<WindowBaseImpl> _parent;
+    ComPtr<IUnknown> _swRenderedFrame;
+    AvnFramebuffer _swRenderedFrameBuffer;
+    bool _queuedDisplayFromThread;
+    NSTrackingArea* _area;
+    bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isMouseOver;
+    NSEvent* _lastMouseDownEvent;
+    bool _lastKeyHandled;
+}
+
+- (void)dealloc
+{
+    NSDebugLog(@"AvnView dealloc");
+}
+
+
+- (void)onClosed
+{
+    _parent = NULL;
+}
+
+- (NSEvent*) lastMouseDownEvent
+{
+    return _lastMouseDownEvent;
+}
+
+-(AvnView*)  initWithParent: (WindowBaseImpl*) parent
+{
+    self = [super init];
+    [self setWantsBestResolutionOpenGLSurface:true];
+    _parent = parent;
+    _area = nullptr;
+    return self;
+}
+
+- (BOOL)isOpaque
+{
+    return YES;
+}
+
+- (BOOL)acceptsFirstResponder
+{
+    return true;
+}
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)event
+{
+    return true;
+}
+
+- (BOOL)canBecomeKeyView
+{
+    return true;
+}
+
+-(void)setFrameSize:(NSSize)newSize
+{
+    [super setFrameSize:newSize];
+    
+    if(_area != nullptr)
+    {
+        [self removeTrackingArea:_area];
+        _area = nullptr;
+    }
+    
+    NSRect rect = NSZeroRect;
+    rect.size = newSize;
+    
+    NSTrackingAreaOptions options = NSTrackingActiveAlways | NSTrackingMouseMoved | NSTrackingEnabledDuringMouseDrag;
+    _area = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nullptr];
+    [self addTrackingArea:_area];
+    
+    _parent->UpdateCursor();
+
+    _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
+}
+
+- (void) drawFb: (AvnFramebuffer*) fb
+{
+    auto colorSpace = CGColorSpaceCreateDeviceRGB();
+    auto dataProvider = CGDataProviderCreateWithData(NULL, fb->Data, fb->Height*fb->Stride, NULL);
+
+    
+    auto image = CGImageCreate(fb->Width, fb->Height, 8, 32, fb->Stride, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast,
+                               dataProvider, nullptr, false, kCGRenderingIntentDefault);
+    
+    auto ctx = [NSGraphicsContext currentContext];
+    
+    [ctx saveGraphicsState];
+    auto cgc = [ctx CGContext];
+    
+    CGContextDrawImage(cgc, CGRect{0,0, fb->Width/(fb->Dpi.X/96), fb->Height/(fb->Dpi.Y/96)}, image);
+    CGImageRelease(image);
+    CGColorSpaceRelease(colorSpace);
+    CGDataProviderRelease(dataProvider);
+    
+    [ctx restoreGraphicsState];
+
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+    _parent->BaseEvents->RunRenderPriorityJobs();
+    @synchronized (self) {
+        if(_swRenderedFrame != NULL)
+        {
+            [self drawFb: &_swRenderedFrameBuffer];
+            return;
+        }
+    }
+    
+    auto swOp = &_parent->CurrentSwDrawingOperation;
+    _parent->BaseEvents->Paint();
+    if(swOp->Data != NULL)
+        [self drawFb: &swOp->Desc];
+    
+    swOp->Dealloc();
+    return;
+}
+
+-(void) redrawSelf
+{
+    @autoreleasepool
+    {
+        @synchronized(self)
+        {
+            if(!_queuedDisplayFromThread)
+                return;
+            _queuedDisplayFromThread = false;
+        }
+        [self setNeedsDisplayInRect:[self frame]];
+        [self display];
+        
+    }
+}
+
+-(void) setSwRenderedFrame: (AvnFramebuffer*) fb dispose: (IUnknown*) dispose
+{
+    @autoreleasepool {
+        @synchronized (self) {
+            _swRenderedFrame = dispose;
+            _swRenderedFrameBuffer = *fb;
+            if(!_queuedDisplayFromThread)
+            {
+                _queuedDisplayFromThread = true;
+                [self performSelector:@selector(redrawSelf) onThread:[NSThread mainThread] withObject:NULL waitUntilDone:false modes: AllLoopModes];
+            }
+        }
+    }
+}
+
+- (AvnPoint) translateLocalPoint:(AvnPoint)pt
+{
+    pt.Y = [self bounds].size.height - pt.Y;
+    return pt;
+}
+
+- (AvnPoint)toAvnPoint:(CGPoint)p
+{
+    AvnPoint result;
+    
+    result.X = p.x;
+    result.Y = p.y;
+    
+    return result;
+}
+
+- (void) viewDidChangeBackingProperties
+{
+    _parent->BaseEvents->ScalingChanged([_parent->Window backingScaleFactor]);
+    [super viewDidChangeBackingProperties];
+}
+
+- (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
+{
+    [self becomeFirstResponder];
+    auto localPoint = [self convertPoint:[event locationInWindow] toView:self];
+    auto avnPoint = [self toAvnPoint:localPoint];
+    auto point = [self translateLocalPoint:avnPoint];
+    AvnVector delta;
+    
+    if(type == Wheel)
+    {
+        delta.X = [event scrollingDeltaX] / 5;
+        delta.Y = [event scrollingDeltaY] / 5;
+        
+        if(delta.X == 0 && delta.Y == 0)
+        {
+            return;
+        }
+    }
+    
+    auto timestamp = [event timestamp] * 1000;
+    auto modifiers = [self getModifiers:[event modifierFlags]];
+    
+    [self becomeFirstResponder];
+    _parent->BaseEvents->RawMouseEvent(type, timestamp, modifiers, point, delta);
+    [super mouseMoved:event];
+}
+
+- (void)mouseMoved:(NSEvent *)event
+{
+    [self mouseEvent:event withType:Move];
+}
+
+- (void)mouseDown:(NSEvent *)event
+{
+    _isLeftPressed = true;
+    _lastMouseDownEvent = event;
+    [self mouseEvent:event withType:LeftButtonDown];
+}
+
+- (void)otherMouseDown:(NSEvent *)event
+{
+    _isMiddlePressed = true;
+    _lastMouseDownEvent = event;
+    [self mouseEvent:event withType:MiddleButtonDown];
+}
+
+- (void)rightMouseDown:(NSEvent *)event
+{
+    _isRightPressed = true;
+    _lastMouseDownEvent = event;
+    [self mouseEvent:event withType:RightButtonDown];
+}
+
+- (void)mouseUp:(NSEvent *)event
+{
+    _isLeftPressed = false;
+    [self mouseEvent:event withType:LeftButtonUp];
+}
+
+- (void)otherMouseUp:(NSEvent *)event
+{
+    _isMiddlePressed = false;
+    [self mouseEvent:event withType:MiddleButtonUp];
+}
+
+- (void)rightMouseUp:(NSEvent *)event
+{
+    _isRightPressed = false;
+    [self mouseEvent:event withType:RightButtonUp];
+}
+
+- (void)mouseDragged:(NSEvent *)event
+{
+    [self mouseEvent:event withType:Move];
+    [super mouseDragged:event];
+}
+
+- (void)otherMouseDragged:(NSEvent *)event
+{
+    [self mouseEvent:event withType:Move];
+    [super otherMouseDragged:event];
+}
+
+- (void)rightMouseDragged:(NSEvent *)event
+{
+    [self mouseEvent:event withType:Move];
+    [super rightMouseDragged:event];
+}
+
+- (void)scrollWheel:(NSEvent *)event
+{
+    [self mouseEvent:event withType:Wheel];
+    [super scrollWheel:event];
+}
+
+- (void)mouseEntered:(NSEvent *)event
+{
+    _isMouseOver = true;
+    [super mouseEntered:event];
+}
+
+- (void)mouseExited:(NSEvent *)event
+{
+    _isMouseOver = false;
+    [self mouseEvent:event withType:LeaveWindow];
+    [super mouseExited:event];
+} 
+
+- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
+{ 
+    auto key = s_KeyMap[[event keyCode]];
+    
+    auto timestamp = [event timestamp] * 1000;
+    auto modifiers = [self getModifiers:[event modifierFlags]];
+     
+    _lastKeyHandled = _parent->BaseEvents->RawKeyEvent(type, timestamp, modifiers, key);
+}
+
+- (BOOL)performKeyEquivalent:(NSEvent *)event
+{
+    bool result = _lastKeyHandled;
+    
+    _lastKeyHandled = false;
+    
+    return result;
+}
+
+- (void)keyDown:(NSEvent *)event
+{
+    [self keyboardEvent:event withType:KeyDown];
+    [[self inputContext] handleEvent:event];
+    [super keyDown:event];
+}
+
+- (void)keyUp:(NSEvent *)event
+{
+    [self keyboardEvent:event withType:KeyUp];
+    [super keyUp:event];
+}
+
+- (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod
+{
+    unsigned int rv = 0;
+    
+    if (mod & NSEventModifierFlagControl)
+        rv |= Control;
+    if (mod & NSEventModifierFlagShift)
+        rv |= Shift;
+    if (mod & NSEventModifierFlagOption)
+        rv |= Alt;
+    if (mod & NSEventModifierFlagCommand)
+        rv |= Windows;
+    
+    if (_isLeftPressed)
+        rv |= LeftMouseButton;
+    if (_isMiddlePressed)
+        rv |= MiddleMouseButton;
+    if (_isRightPressed)
+        rv |= RightMouseButton;
+    
+    return (AvnInputModifiers)rv;
+}
+
+- (BOOL)hasMarkedText
+{
+    return _lastKeyHandled;
+}
+
+- (NSRange)markedRange
+{
+    return NSMakeRange(NSNotFound, 0);
+}
+
+- (NSRange)selectedRange
+{
+    return NSMakeRange(NSNotFound, 0);
+}
+
+- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+{
+    
+}
+
+- (void)unmarkText
+{
+    
+}
+
+- (NSArray<NSString *> *)validAttributesForMarkedText
+{
+    return [NSArray new];
+}
+
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange
+{
+    return [NSAttributedString new];
+}
+
+- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
+{
+    if(!_lastKeyHandled)
+    {
+        _lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(0, [string UTF8String]);
+    }
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)point
+{
+    return 0;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange
+{
+    CGRect result;
+    
+    return result;
+}
+@end
+
+
+@implementation AvnWindow
+{
+    ComPtr<WindowBaseImpl> _parent;
+    bool _canBecomeKeyAndMain;
+    bool _closed;
+}
+
+- (void)dealloc
+{
+    NSDebugLog(@"AvnWindow dealloc");
+}
+
+- (void)pollModalSession:(nonnull NSModalSession)session
+{
+    auto response = [NSApp runModalSession:session];
+    
+    if(response == NSModalResponseContinue)
+    {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [self pollModalSession:session];
+        });
+    }
+    else if (!_closed)
+    {
+        [self orderOut:self];
+        [NSApp endModalSession:session];
+    }
+}
+
+-(void) setCanBecomeKeyAndMain
+{
+    _canBecomeKeyAndMain = true;
+}
+
+-(AvnWindow*)  initWithParent: (WindowBaseImpl*) parent
+{
+    self = [super init];
+    [self setReleasedWhenClosed:false];
+    _parent = parent;
+    [self setDelegate:self];
+    return self;
+}
+
+- (BOOL)windowShouldClose:(NSWindow *)sender
+{
+    auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
+    
+    if(window != nullptr)
+    {
+        return !window->WindowEvents->Closing();
+    }
+    
+    return true;
+}
+
+- (void)windowWillClose:(NSNotification *)notification
+{
+    _closed = true;
+    if(_parent)
+    {
+        ComPtr<WindowBaseImpl> parent = _parent;
+        _parent = NULL;
+        parent->BaseEvents->Closed();
+        [parent->View onClosed];
+        [self setContentView: nil];
+    }
+}
+
+
+-(BOOL)canBecomeKeyWindow
+{
+    return _canBecomeKeyAndMain;
+}
+
+-(BOOL)canBecomeMainWindow
+{
+    return _canBecomeKeyAndMain;
+}
+
+-(void)becomeKeyWindow
+{
+    _parent->BaseEvents->Activated();
+    [super becomeKeyWindow];
+}
+
+- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
+{
+    return true;
+}
+
+-(void)resignKeyWindow
+{
+    if(_parent)
+        _parent->BaseEvents->Deactivated();
+    [super resignKeyWindow];
+}
+
+- (void)windowDidMove:(NSNotification *)notification
+{
+    AvnPoint position;
+    _parent->GetPosition(&position);
+    _parent->BaseEvents->PositionChanged(position);
+}
+
+// TODO this breaks resizing.
+/*- (void)windowDidResize:(NSNotification *)notification
+{
+    
+    auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
+    
+    if(parent != nullptr)
+    {
+        parent->WindowStateChanged();
+    }
+}*/
+@end
+
+class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup
+{
+private:
+    BEGIN_INTERFACE_MAP()
+    INHERIT_INTERFACE_MAP(WindowBaseImpl)
+    INTERFACE_MAP_ENTRY(IAvnPopup, IID_IAvnPopup)
+    END_INTERFACE_MAP()
+    virtual ~PopupImpl(){}
+    ComPtr<IAvnWindowEvents> WindowEvents;
+    PopupImpl(IAvnWindowEvents* events) : WindowBaseImpl(events)
+    {
+        WindowEvents = events;
+        [Window setLevel:NSPopUpMenuWindowLevel];
+    }
+    
+protected:
+    virtual NSWindowStyleMask GetStyle() override
+    {
+        return NSWindowStyleMaskBorderless;
+    }
+    
+    virtual HRESULT Resize(double x, double y) override
+    {
+        @autoreleasepool
+        {
+            [Window setContentSize:NSSize{x, y}];
+            
+            [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))];
+            return S_OK;
+        }
+    }
+};
+
+extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events)
+{
+    @autoreleasepool
+    {
+        IAvnPopup* ptr = dynamic_cast<IAvnPopup*>(new PopupImpl(events));
+        return ptr;
+    }
+}
+
+extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events)
+{
+    @autoreleasepool
+    {
+        IAvnWindow* ptr = (IAvnWindow*)new WindowImpl(events);
+        return ptr;
+    }
+}

+ 0 - 504
packages.cake

@@ -1,504 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Xml.Linq;
-
-public class Packages
-{
-    public List<NuGetPackSettings> NuspecNuGetSettings { get; private set; }
-    public FilePath[] NugetPackages { get; private set; }
-    public FilePath[] BinFiles { get; private set; }
-    public string NugetPackagesDir {get; private set;}
-    public string SkiaSharpVersion {get; private set; }
-    public string SkiaSharpLinuxVersion {get; private set; }
-    public Dictionary<string, IList<Tuple<string,string>>> PackageVersions{get; private set;}
-
-    class DependencyBuilder : List<NuSpecDependency>
-    {
-        Packages _parent;
-
-        public DependencyBuilder(Packages parent)
-        {
-            _parent = parent;
-        }
-        
-        string GetVersion(string name)
-        {
-            return _parent.PackageVersions[name].First().Item1;
-        }
-
-        public DependencyBuilder Dep(string name, params string[] fws)
-        {
-            if(fws.Length == 0)
-                Add(new NuSpecDependency() { Id = name, Version = GetVersion(name) });
-            foreach(var fw in fws)
-                Add(new NuSpecDependency() { Id = name, TargetFramework = fw, Version = GetVersion(name) });
-            return this;
-        }
-        public DependencyBuilder Deps(string[] fws, params string[] deps)
-        {
-            foreach(var fw in fws)
-                foreach(var name in deps)
-                    Add(new NuSpecDependency() { Id = name, TargetFramework = fw, Version = GetVersion(name) });
-            return this;
-        }
-    }
-        
-    public Packages(ICakeContext context, Parameters parameters)
-    {
-        // NUGET NUSPECS
-        context.Information("Getting git modules:");
-
-        var ignoredSubModulesPaths = System.IO.File.ReadAllLines(".git/config").Where(m=>m.StartsWith("[submodule ")).Select(m => 
-        {
-            var path = m.Split(' ')[1].Trim("\"[] \t".ToArray());
-            context.Information(path);
-            return ((DirectoryPath)context.Directory(path)).FullPath;
-        }).ToList();
-
-        var normalizePath = new Func<string, string>(
-            path => path.Replace(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar).ToUpperInvariant());
-
-        // Key: Package Id
-        // Value is Tuple where Item1: Package Version, Item2: The *.csproj/*.props file path.
-        var packageVersions = new Dictionary<string, IList<Tuple<string,string>>>();
-        PackageVersions = packageVersions;
-        System.IO.Directory.EnumerateFiles(((DirectoryPath)context.Directory("./build")).FullPath,
-            "*.props", SearchOption.AllDirectories).ToList().ForEach(fileName =>
-        {
-            if (!ignoredSubModulesPaths.Any(i => normalizePath(fileName).Contains(normalizePath(i))))
-            {
-                var xdoc = XDocument.Load(fileName);
-                foreach (var reference in xdoc.Descendants().Where(x => x.Name.LocalName == "PackageReference"))
-                {
-                    var name = reference.Attribute("Include").Value;
-                    var versionAttribute = reference.Attribute("Version");
-                    var version = versionAttribute != null 
-                        ? versionAttribute.Value 
-                        : reference.Elements().First(x=>x.Name.LocalName == "Version").Value;
-                    IList<Tuple<string, string>> versions;
-                    packageVersions.TryGetValue(name, out versions);
-                    if (versions == null)
-                    {
-                        versions = new List<Tuple<string, string>>();
-                        packageVersions[name] = versions;
-                    }
-                    versions.Add(Tuple.Create(version, fileName));
-                }
-            }
-        });
-
-        context.Information("Checking installed NuGet package dependencies versions:");
-
-        packageVersions.ToList().ForEach(package =>
-        {
-            var packageVersion = package.Value.First().Item1;
-            bool isValidVersion = package.Value.All(x => x.Item1 == packageVersion);
-            if (!isValidVersion)
-            {
-                context.Information("Error: package {0} has multiple versions installed:", package.Key);
-                foreach (var v in package.Value)
-                {
-                    context.Information("{0}, file: {1}", v.Item1, v.Item2);
-                }
-                throw new Exception("Detected multiple NuGet package version installed for different projects.");
-            }
-        });
-
-        context.Information("Setting NuGet package dependencies versions:");
-
-        var SerilogVersion = packageVersions["Serilog"].FirstOrDefault().Item1;
-        var SerilogSinksDebugVersion = packageVersions["Serilog.Sinks.Debug"].FirstOrDefault().Item1;
-        var SerilogSinksTraceVersion = packageVersions["Serilog.Sinks.Trace"].FirstOrDefault().Item1;
-        var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1;
-        var ReactiveUIVersion = packageVersions["reactiveui"].FirstOrDefault().Item1;
-        var SystemValueTupleVersion = packageVersions["System.ValueTuple"].FirstOrDefault().Item1;
-        SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
-		SkiaSharpLinuxVersion = packageVersions["Avalonia.Skia.Linux.Natives"].FirstOrDefault().Item1;
-        var SharpDXVersion = packageVersions["SharpDX"].FirstOrDefault().Item1;
-        var SharpDXDirect2D1Version = packageVersions["SharpDX.Direct2D1"].FirstOrDefault().Item1;
-        var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1;
-        var SharpDXDirect3D9Version = packageVersions["SharpDX.Direct3D9"].FirstOrDefault().Item1;
-        var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1;
-        var SystemMemoryVersion = packageVersions["System.Memory"].FirstOrDefault().Item1;
-
-        context.Information("Package: Serilog, version: {0}", SerilogVersion);
-        context.Information("Package: System.Reactive, version: {0}", SystemReactiveVersion);
-        context.Information("Package: reactiveui, version: {0}", ReactiveUIVersion);
-        context.Information("Package: System.ValueTuple, version: {0}", SystemValueTupleVersion);
-        context.Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion);
-        context.Information("Package: Avalonia.Skia.Linux.Natives, version: {0}", SkiaSharpLinuxVersion);
-        context.Information("Package: SharpDX, version: {0}", SharpDXVersion);
-        context.Information("Package: SharpDX.Direct2D1, version: {0}", SharpDXDirect2D1Version);
-        context.Information("Package: SharpDX.Direct3D11, version: {0}", SharpDXDirect3D11Version);
-        context.Information("Package: SharpDX.Direct3D9, version: {0}", SharpDXDirect3D9Version);
-        context.Information("Package: SharpDX.DXGI, version: {0}", SharpDXDXGIVersion);
-        context.Information("Package: System.Memory, version: {0}", SystemMemoryVersion);
-
-        var nugetPackagesDir = System.Environment.GetEnvironmentVariable("NUGET_HOME")
-            ?? System.IO.Path.Combine(System.Environment.GetEnvironmentVariable("USERPROFILE") ?? System.Environment.GetEnvironmentVariable("HOME"), ".nuget");
-        
-        NugetPackagesDir = System.IO.Path.Combine(nugetPackagesDir, "packages");
-        
-        var SetNuGetNuspecCommonProperties = new Action<NuGetPackSettings> ((nuspec) => {
-            nuspec.Version = parameters.Version;
-            nuspec.Authors = new [] { "Avalonia Team" };
-            nuspec.Owners = new [] { "stevenk" };
-            nuspec.LicenseUrl = new Uri("http://opensource.org/licenses/MIT");
-            nuspec.ProjectUrl = new Uri("https://github.com/AvaloniaUI/Avalonia/");
-            nuspec.RequireLicenseAcceptance = false;
-            nuspec.Symbols = false;
-            nuspec.NoPackageAnalysis = true;
-            nuspec.Description = "The Avalonia UI framework";
-            nuspec.Copyright = "Copyright 2015";
-            nuspec.Tags = new [] { "Avalonia" };
-        });
-
-        var coreLibraries = new string[][]
-        {
-            new [] { "./src/", "Avalonia.Animation"},
-            new [] { "./src/", "Avalonia.Base"},
-            new [] { "./src/", "Avalonia.Controls"},
-            new [] { "./src/", "Avalonia.DesignerSupport"},
-            new [] { "./src/", "Avalonia.Diagnostics"},
-            new [] { "./src/", "Avalonia.Input"},
-            new [] { "./src/", "Avalonia.Interactivity"},
-            new [] { "./src/", "Avalonia.Layout"},
-            new [] { "./src/", "Avalonia.Logging.Serilog"},
-            new [] { "./src/", "Avalonia.Visuals"},
-            new [] { "./src/", "Avalonia.Styling"},
-            new [] { "./src/", "Avalonia.Themes.Default"},
-            new [] { "./src/Markup/", "Avalonia.Markup"},
-            new [] { "./src/Markup/", "Avalonia.Markup.Xaml"},
-        };
-
-        var extensionsToPack = new [] {".dll", ".xml", ".pdb"};
-
-        var coreLibrariesFiles = coreLibraries
-            .SelectMany(lib => extensionsToPack.Select(ext => new {lib, ext}))
-            .Select((lib) => {
-                return (FilePath)context.File(lib.lib[0] + lib.lib[1] + "/bin/" + parameters.DirSuffix + "/netstandard2.0/" + lib.lib[1] + lib.ext);
-        }).ToList();
-
-        var coreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
-            return new NuSpecContent { 
-                Source = file.FullPath, Target = "lib/netstandard2.0" 
-            };
-        });
-
-        var netFrameworkCoreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
-            return new NuSpecContent { 
-                Source = file.FullPath, Target = "lib/net461" 
-            };
-        });
-
-        var netcoreappCoreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
-            return new NuSpecContent { 
-                Source = file.FullPath, Target = "lib/netcoreapp2.0" 
-            };
-        });
-
-        var netFrameworkRuntimePlatform = extensionsToPack.Select(libSuffix => {
-            return new NuSpecContent {
-                Source = ((FilePath)context.File("./src/Avalonia.DotNetFrameworkRuntime/bin/" + parameters.DirSuffix + "/net461/Avalonia.DotNetFrameworkRuntime" + libSuffix)).FullPath, 
-                Target = "lib/net461" 
-            };
-        });
-
-        var netCoreRuntimePlatform = extensionsToPack.Select(libSuffix => {
-            return new NuSpecContent {
-                Source = ((FilePath)context.File("./src/Avalonia.DotNetCoreRuntime/bin/" + parameters.DirSuffix + "/netcoreapp2.0/Avalonia.DotNetCoreRuntime" + libSuffix)).FullPath, 
-                Target = "lib/netcoreapp2.0" 
-            };
-        });
-
-        var toolHostApp = new NuSpecContent{
-            Source = ((FilePath)context.File("./src/tools/Avalonia.Designer.HostApp/bin/" + parameters.DirSuffix + "/netcoreapp2.0/Avalonia.Designer.HostApp.dll")).FullPath, 
-            Target = "tools/netcoreapp2.0/previewer"
-        };
-
-        var toolHostAppNetFx = new NuSpecContent{
-            Source = ((FilePath)context.File("./src/tools/Avalonia.Designer.HostApp.NetFx/bin/" + parameters.DirSuffix + "/net461/Avalonia.Designer.HostApp.exe")).FullPath, 
-            Target = "tools/net461/previewer"
-        };
-
-        var toolsContent = new[] { toolHostApp, toolHostAppNetFx };
-        var coreFiles = coreLibrariesNuSpecContent
-            .Concat(netFrameworkCoreLibrariesNuSpecContent).Concat(netFrameworkRuntimePlatform)
-            .Concat(netcoreappCoreLibrariesNuSpecContent).Concat(netCoreRuntimePlatform)
-            .Concat(toolsContent)
-            .ToList();
-
-        var nuspecNuGetSettingsCore = new []
-        {
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia",
-                Dependencies = new DependencyBuilder(this)
-                {
-                    new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", Version = parameters.Version, TargetFramework="netstandard2.0" },
-                    new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", Version = parameters.Version, TargetFramework="netcoreapp2.0" },
-                    new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", Version = parameters.Version, TargetFramework="net461" },
-                    new NuSpecDependency() { Id = "System.ValueTuple", Version = SystemValueTupleVersion, TargetFramework="net461" },
-                    new NuSpecDependency() { Id = "System.ComponentModel.TypeConverter", Version = "4.3.0", TargetFramework="net461" },
-                    new NuSpecDependency() { Id = "NETStandard.Library", Version = "2.0.0", TargetFramework="net461"}
-                }
-                .Deps(new string[]{"netstandard2.0", "netcoreapp2.0", "net461"},
-                    "Serilog", "Serilog.Sinks.Debug", "Serilog.Sinks.Trace",
-                    "System.Memory", "System.Reactive", "System.ComponentModel.Annotations")
-                .ToArray(),
-                Files = coreFiles,
-                BasePath = context.Directory("./"),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.ReactiveUI
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.ReactiveUI",
-                Dependencies = new DependencyBuilder(this)
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
-                }.Deps(new string[] {null}, "reactiveui"),
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.ReactiveUI.dll", Target = "lib/netstandard2.0" }
-                },
-                BasePath = context.Directory("./src/Avalonia.ReactiveUI/bin/" + parameters.DirSuffix + "/netstandard2.0"),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Remote.Protocol
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Remote.Protocol",
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.Remote.Protocol.dll", Target = "lib/netstandard2.0" }
-                },
-                BasePath = context.Directory("./src/Avalonia.Remote.Protocol/bin/" + parameters.DirSuffix + "/netstandard2.0"),
-                OutputDirectory = parameters.NugetRoot
-            },
-        };
-
-        var nuspecNuGetSettingsMobile = new []
-        {
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Android
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Android",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Skia", Version = parameters.Version }
-                },
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.Android.dll", Target = "lib/MonoAndroid10" }
-                },
-                BasePath = context.Directory("./src/Android/Avalonia.Android/bin/" + parameters.DirSuffix + "/monoandroid44/MonoAndroid44/"),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.iOS
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.iOS",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Skia", Version = parameters.Version }
-                },
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.iOS.dll", Target = "lib/Xamarin.iOS10" }
-                },
-                BasePath = context.Directory("./src/iOS/Avalonia.iOS/bin/" + parameters.DirSuffix + "/xamarin.ios10/"),
-                OutputDirectory = parameters.NugetRoot
-            }
-        };
-
-        var nuspecNuGetSettingsDesktop = new []
-        {
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Win32
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Win32",
-                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 + "/netstandard2.0/Avalonia.Win32.dll", Target = "lib/netstandard2.0" }
-                },
-                BasePath = context.Directory("./src/Windows"),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Direct2D1
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Direct2D1",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "SharpDX", Version = SharpDXVersion },
-                    new NuSpecDependency() { Id = "SharpDX.Direct2D1", Version = SharpDXDirect2D1Version },
-                    new NuSpecDependency() { Id = "SharpDX.Direct3D11", Version = SharpDXDirect3D11Version },
-                    new NuSpecDependency() { Id = "SharpDX.DXGI", Version = SharpDXDXGIVersion }
-                },
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.Direct2D1.dll", Target = "lib/netstandard2.0" }
-                },
-                BasePath = context.Directory("./src/Windows/Avalonia.Direct2D1/bin/" + parameters.DirSuffix + "/netstandard2.0"),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Gtk3
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Gtk3",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
-                },
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.Gtk3.dll", Target = "lib/netstandard2.0" }
-                },
-                BasePath = context.Directory("./src/Gtk/Avalonia.Gtk3/bin/" + parameters.DirSuffix + "/netstandard2.0"),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Skia
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Skia",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion },
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version, TargetFramework="netcoreapp2.0" },
-                    new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion, TargetFramework="netcoreapp2.0" },
-                    new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpLinuxVersion, TargetFramework="netcoreapp2.0" },
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version, TargetFramework="net461" },
-                    new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion, TargetFramework="net461" },
-                    new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpLinuxVersion, TargetFramework="net461" }
-                },
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.Skia.dll", Target = "lib/netstandard2.0" }
-                },
-                BasePath = context.Directory("./src/Skia/Avalonia.Skia/bin/" + parameters.DirSuffix + "/netstandard2.0"),
-                OutputDirectory = parameters.NugetRoot
-            },
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.MonoMac",
-                Dependencies = new DependencyBuilder(this)
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
-                }.Dep("MonoMac.NetStandard").ToArray(),
-                Files = new []
-                {
-                    new NuSpecContent { Source = "netstandard2.0/Avalonia.MonoMac.dll", Target = "lib/netstandard2.0" },
-                },
-                BasePath = context.Directory("./src/OSX/Avalonia.MonoMac/bin/" + parameters.DirSuffix),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Desktop
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Desktop",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Skia", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Gtk3", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.MonoMac", Version = parameters.Version }
-                },
-                Files = new NuSpecContent[]
-                {
-                    new NuSpecContent { Source = "licence.md", Target = "" }
-                },
-                BasePath = context.Directory("./"),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.LinuxFramebuffer
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.LinuxFramebuffer",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Skia", Version = parameters.Version }
-                },
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.LinuxFramebuffer/bin/" + parameters.DirSuffix + "/netstandard2.0/Avalonia.LinuxFramebuffer.dll", Target = "lib/netstandard2.0" }
-                },
-                BasePath = context.Directory("./src/Linux/"),
-                OutputDirectory = parameters.NugetRoot
-            }
-        };
-
-        var nuspecNuGetSettingInterop = new NuGetPackSettings()
-        {
-            Id = "Avalonia.Win32.Interoperability",
-            Dependencies = new []
-            {
-                new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version },
-                new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = parameters.Version },
-                new NuSpecDependency() { Id = "SharpDX.Direct3D9", Version = SharpDXDirect3D9Version },
-            },
-            Files = new []
-            {
-                new NuSpecContent { Source = "Avalonia.Win32.Interop/bin/" + parameters.DirSuffix + "/net461/Avalonia.Win32.Interop.dll", Target = "lib/net461" }
-            },
-            BasePath = context.Directory("./src/Windows"),
-            OutputDirectory = parameters.NugetRoot
-        };
-
-        NuspecNuGetSettings = new List<NuGetPackSettings>();
-
-        NuspecNuGetSettings.AddRange(nuspecNuGetSettingsCore);
-        NuspecNuGetSettings.AddRange(nuspecNuGetSettingsDesktop);
-
-        if (parameters.IsRunningOnWindows) {
-            NuspecNuGetSettings.Add(nuspecNuGetSettingInterop);
-            NuspecNuGetSettings.AddRange(nuspecNuGetSettingsMobile);
-        }
-
-        NuspecNuGetSettings.ForEach((nuspec) => SetNuGetNuspecCommonProperties(nuspec));
-
-        NugetPackages = NuspecNuGetSettings.Select(nuspec => {
-            return nuspec.OutputDirectory.CombineWithFilePath(string.Concat(nuspec.Id, ".", nuspec.Version, ".nupkg"));
-        }).ToArray();
-
-        BinFiles = NuspecNuGetSettings.SelectMany(nuspec => {
-            return nuspec.Files.Select(file => {
-                return ((DirectoryPath)nuspec.BasePath).CombineWithFilePath(file.Source);
-            });
-        }).GroupBy(f => f.FullPath).Select(g => g.First()).ToArray();
-    }
-}

+ 41 - 0
packages/Avalonia/Avalonia.csproj

@@ -0,0 +1,41 @@
+<Project Sdk="AggregatePackage.NuGet.Sdk">
+  <PropertyGroup>
+      <TargetFrameworks>netstandard2.0;net461;netcoreapp2.0</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+      <ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" EmbedReference="false" />
+  </ItemGroup>
+
+  <PropertyGroup>
+      <DesignerHostAppPath>../../src/tools</DesignerHostAppPath>
+  </PropertyGroup>
+
+  <Target Name="AddDesignerHostAppsToPackage" BeforeTargets="GenerateNuspec">
+    <MSBuild Projects="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj"
+             Properties="Configuration=$(Configuration);
+                         Platform=$(Platform)" />
+
+    <ItemGroup>
+      <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/netcoreapp2.0/Avalonia.Designer.HostApp.dll">
+        <PackagePath>tools/netcoreapp2.0/designer</PackagePath>
+        <Visible>false</Visible>
+        <BuildAction>None</BuildAction>
+      </_PackageFiles>
+      <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/net461/Avalonia.Designer.HostApp.exe">
+        <PackagePath>tools/net461/designer</PackagePath>
+        <Visible>false</Visible>
+        <BuildAction>None</BuildAction>
+      </_PackageFiles>
+      <_PackageFiles Include="Avalonia.props">
+        <PackagePath>build/Avalonia.props</PackagePath>
+        <Visible>false</Visible>
+        <BuildAction>None</BuildAction>
+      </_PackageFiles>
+    </ItemGroup>
+  </Target>
+
+  <Import Project="..\..\build\SharedVersion.props" />
+  <Import Project="..\..\build\NetFX.props" />
+  <Import Project="..\..\build\CoreLibraries.props" />
+</Project>

+ 6 - 0
packages/Avalonia/Avalonia.props

@@ -0,0 +1,6 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)\..\tools\netcoreapp2.0\designer\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
+    <AvaloniaPreviewerNetFullToolPath>$(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe</AvaloniaPreviewerNetFullToolPath>
+  </PropertyGroup>
+</Project>

+ 24 - 3
parameters.cake

@@ -9,23 +9,28 @@ public class Parameters
     public string MasterBranch { get; private set; }
     public string ReleasePlatform { get; private set; }
     public string ReleaseConfiguration { get; private set; }
+    public string ReleaseBranchPrefix { get; private set; }
     public string MSBuildSolution { get; private set; }
     public bool IsLocalBuild { get; private set; }
     public bool IsRunningOnUnix { get; private set; }
     public bool IsRunningOnWindows { get; private set; }
     public bool IsRunningOnAppVeyor { get; private set; }
+    public bool IsRunningOnAzure { get; private set; }
     public bool IsPullRequest { get; private set; }
     public bool IsMainRepo { get; private set; }
     public bool IsMasterBranch { get; private set; }
+    public bool IsReleaseBranch { get; private set; }
     public bool IsTagged { get; private set; }
     public bool IsReleasable { get; private set; }
     public bool IsMyGetRelease { get; private set; }
     public bool IsNuGetRelease { get; private set; }
+    public bool PublishTestResults { get; private set; }
     public string Version { get; private set; } 
     public DirectoryPath ArtifactsDir { get; private set; }
     public DirectoryPath NugetRoot { get; private set; }
     public DirectoryPath ZipRoot { get; private set; }
     public DirectoryPath BinRoot { get; private set; }
+    public DirectoryPath TestResultsRoot { get; private set; }
     public string DirSuffix { get; private set; }
     public DirectoryPathCollection BuildDirs { get; private set; }
     public string FileZipSuffix { get; private set; }
@@ -43,8 +48,9 @@ public class Parameters
         SkipTests = context.HasArgument("skip-tests");
 
         // CONFIGURATION
-        MainRepo = "AvaloniaUI/Avalonia";
+        MainRepo = "https://github.com/AvaloniaUI/Avalonia";
         MasterBranch = "master";
+        ReleaseBranchPrefix = "refs/heads/release/";
         ReleaseConfiguration = "Release";
         MSBuildSolution = "./dirs.proj";
 
@@ -53,13 +59,17 @@ public class Parameters
         IsRunningOnUnix = context.IsRunningOnUnix();
         IsRunningOnWindows = context.IsRunningOnWindows();
         IsRunningOnAppVeyor = buildSystem.AppVeyor.IsRunningOnAppVeyor;
+        IsRunningOnAzure = buildSystem.IsRunningOnVSTS || buildSystem.IsRunningOnTFS || context.EnvironmentVariable("LOGNAME") == "vsts";
+        
         IsPullRequest = buildSystem.AppVeyor.Environment.PullRequest.IsPullRequest;
-        IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, buildSystem.AppVeyor.Environment.Repository.Name);
-        IsMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch, buildSystem.AppVeyor.Environment.Repository.Branch);
+        IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, context.EnvironmentVariable("BUILD_REPOSITORY_URI"));
+        IsMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch, context.EnvironmentVariable("BUILD_SOURCEBRANCHNAME"));
+        IsReleaseBranch = (context.EnvironmentVariable("BUILD_SOURCEBRANCH")??"").StartsWith(ReleaseBranchPrefix, StringComparison.OrdinalIgnoreCase);
         IsTagged = buildSystem.AppVeyor.Environment.Repository.Tag.IsTag 
                 && !string.IsNullOrWhiteSpace(buildSystem.AppVeyor.Environment.Repository.Tag.Name);
         IsReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, Configuration);
         IsMyGetRelease = !IsTagged && IsReleasable;
+        IsNuGetRelease = IsMainRepo && IsReleasable && IsReleaseBranch;
 
         // VERSION
         Version = context.Argument("force-nuget-version", GetVersion());
@@ -85,12 +95,23 @@ public class Parameters
                 Version += "-build" + context.EnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-beta";
             }
         }
+        else if (IsRunningOnAzure)
+        {
+            if(!IsNuGetRelease)
+            {
+                // Use AssemblyVersion with Build as version
+                Version += "-build" + context.EnvironmentVariable("BUILD_BUILDID") + "-beta";
+            }
+
+            PublishTestResults = true; 
+        }
 
         // DIRECTORIES
         ArtifactsDir = (DirectoryPath)context.Directory("./artifacts");
         NugetRoot = ArtifactsDir.Combine("nuget");
         ZipRoot = ArtifactsDir.Combine("zip");
         BinRoot = ArtifactsDir.Combine("bin");
+        TestResultsRoot = ArtifactsDir.Combine("test-results");
         BuildDirs = context.GetDirectories("**/bin") + context.GetDirectories("**/obj");
         DirSuffix = Configuration;
         FileZipSuffix = Version + ".zip";

+ 2 - 2
readme.md

@@ -2,9 +2,9 @@
 
 # Avalonia
 
-| Gitter Chat | Windows Build Status | Linux/Mac Build Status | Open Collective |
+| Gitter Chat | Build Status (Win, Linux, OSX) | Appveyor 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) |
+|  [![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://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master) | [![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
 

+ 0 - 22
samples/BindingDemo/App.config

@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
-    </startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0"/>
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0"/>
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>

+ 1 - 19
samples/BindingDemo/BindingDemo.csproj

@@ -4,27 +4,8 @@
     <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
   </PropertyGroup>
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
-    
-    <ProjectReference Condition="'$(TargetFramework)'=='netcoreapp2.0'" Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
-                      
-    <ProjectReference Condition="'$(TargetFramework)'=='net461'" Include="..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj" />
-
     <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Logging.Serilog\Avalonia.Logging.Serilog.csproj" />
   </ItemGroup>
   <Import Project="..\..\build\SampleApp.props" />
   <Import Project="..\..\build\EmbedXaml.props" />
@@ -32,4 +13,5 @@
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\ReactiveUI.props" />
   <Import Condition="'$(TargetFramework)'=='net461'" Project="..\..\build\NetFX.props" />
+  <Import Project="..\..\build\ReferenceCoreLibraries.props" />
 </Project>

+ 1 - 0
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@@ -155,4 +155,5 @@
   <Import Project="..\..\build\Rx.props" />
   <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
   <Import Project="..\..\build\AndroidWorkarounds.props" />
+  <Import Project="..\..\build\LegacyProject.targets" />
 </Project>

+ 0 - 22
samples/ControlCatalog.Desktop/App.config

@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
-    </startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0"/>
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>

+ 0 - 7
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@@ -6,16 +6,9 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Logging.Serilog\Avalonia.Logging.Serilog.csproj" />
     <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
   </ItemGroup>
 
-  <ItemGroup>
-    <Folder Include="Properties\" />
-  </ItemGroup>
-
   <Import Project="..\..\build\SampleApp.props" />
   <Import Project="..\..\build\Serilog.props" />
   <Import Project="..\..\build\NetFX.props" />

+ 5 - 3
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@@ -6,10 +6,12 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
     <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
     <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
+    <ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
   </ItemGroup>
 
-</Project>
+
+  <Import Project="..\..\build\SampleApp.props" />
+  <Import Project="..\..\build\ReferenceCoreLibraries.props" />
+</Project>

+ 1 - 0
samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj

@@ -176,4 +176,5 @@
   </ItemGroup>
   <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
   <Import Project="..\..\build\iOSWorkarounds.props" />
+  <Import Project="..\..\build\LegacyProject.targets" />
 </Project>

+ 0 - 22
samples/ControlCatalog/App.config

@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
-    </startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.0.2.0" newVersion="3.0.2.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.0.2.0" newVersion="3.0.2.0" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>

+ 7 - 2
samples/ControlCatalog/App.xaml

@@ -14,6 +14,11 @@
       <Setter Property="FontSize" Value="13"/>
     </Style>
 
-    <StyleInclude Source="resm:ControlCatalog.SideBar.xaml"/>
+      <Style Selector="TextBlock.h3">
+          <Setter Property="Foreground" Value="#a2a2a2"/>
+          <Setter Property="FontSize" Value="13"/>
+      </Style>
+
+      <StyleInclude Source="resm:ControlCatalog.SideBar.xaml"/>
   </Application.Styles>
-</Application>
+</Application>

+ 1 - 12
samples/ControlCatalog/ControlCatalog.csproj

@@ -22,19 +22,8 @@
   </ItemGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
+    <ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
   </ItemGroup>
 
   <ItemGroup>

+ 1 - 1
samples/ControlCatalog/Pages/ButtonPage.xaml

@@ -18,7 +18,7 @@
             <Style>
               <Style.Resources>
                 <SolidColorBrush x:Key="ThemeBorderMidBrush">Red</SolidColorBrush>
-                <SolidColorBrush x:Key="ThemeControlDarkBrush">DarkRed</SolidColorBrush>
+                <SolidColorBrush x:Key="ThemeControlHighBrush">DarkRed</SolidColorBrush>
               </Style.Resources>
             </Style>
           </Button.Styles>          

+ 2 - 1
samples/ControlCatalog/Pages/CanvasPage.xaml

@@ -11,7 +11,8 @@
               <GradientStop Offset="1" Color="Transparent"/>
             </LinearGradientBrush.GradientStops>
           </LinearGradientBrush>
-        </Rectangle.OpacityMask>      </Rectangle>
+        </Rectangle.OpacityMask>     
+      </Rectangle>
       <Ellipse Fill="Green" Width="58" Height="58" Canvas.Left="88" Canvas.Top="100"/>
       <Path Fill="Orange" Data="M 0,0 c 0,0 50,0 50,-50 c 0,0 50,0 50,50 h -50 v 50 l -50,-50 Z" Canvas.Left="30" Canvas.Top="250"/>
       <Path Fill="OrangeRed" Canvas.Left="180" Canvas.Top="250">

+ 1 - 1
samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml

@@ -19,7 +19,7 @@
         <LayoutTransformControl.LayoutTransform>
           <RotateTransform Angle="{Binding #rotation.Value}"/>
         </LayoutTransformControl.LayoutTransform>
-        <TextBlock>Layout Transform</TextBlock>
+          <Button Background="White">Layout Transform</Button>
       </LayoutTransformControl>
     </Grid>
   </DockPanel>

+ 39 - 22
samples/ControlCatalog/Pages/MenuPage.xaml

@@ -7,29 +7,46 @@
               Margin="0,16,0,0"
               HorizontalAlignment="Center"
               Spacing="16">
-            <Menu>
-                <MenuItem Header="_First">
-                    <MenuItem Header="Standard _Menu Item"/>
-                    <Separator/>
-                    <MenuItem Header="Menu with _Submenu">
-                        <MenuItem Header="Submenu _1"/>
-                        <MenuItem Header="Submenu _2"/>
+            <StackPanel>
+                <TextBlock Classes="h3" Margin="4 8">Defined in XAML</TextBlock>
+                <Menu>
+                    <MenuItem Header="_First">
+                        <MenuItem Header="Standard _Menu Item"/>
+                        <Separator/>
+                        <MenuItem Header="Menu with _Submenu">
+                            <MenuItem Header="Submenu _1"/>
+                            <MenuItem Header="Submenu _2"/>
+                        </MenuItem>
+                        <MenuItem Header="Menu Item with _Icon">
+                            <MenuItem.Icon>
+                                <Image Source="resm:ControlCatalog.Assets.github_icon.png"/>
+                            </MenuItem.Icon>
+                        </MenuItem>
+                        <MenuItem Header="Menu Item with _Checkbox">
+                            <MenuItem.Icon>
+                                <CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/>
+                            </MenuItem.Icon>
+                        </MenuItem>
                     </MenuItem>
-                    <MenuItem Header="Menu Item with _Icon">
-                        <MenuItem.Icon>
-                            <Image Source="resm:ControlCatalog.Assets.github_icon.png"/>
-                        </MenuItem.Icon>
+                    <MenuItem Header="_Second">
+                        <MenuItem Header="Second _Menu Item"/>
                     </MenuItem>
-                    <MenuItem Header="Menu Item with _Checkbox">
-                        <MenuItem.Icon>
-                            <CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/>
-                        </MenuItem.Icon>
-                    </MenuItem>
-                </MenuItem>
-                <MenuItem Header="_Second">
-                    <MenuItem Header="Second _Menu Item"/>
-                </MenuItem>
-            </Menu>
+                </Menu>
+            </StackPanel>
+
+            <StackPanel>
+                <TextBlock Classes="h3" Margin="4 8">Dyanamically generated</TextBlock>
+                <Menu Items="{Binding MenuItems}">
+                    <Menu.Styles>
+                        <Style Selector="MenuItem">
+                            <Setter Property="Header" Value="{Binding Header}"/>
+                            <Setter Property="Items" Value="{Binding Items}"/>
+                            <Setter Property="Command" Value="{Binding Command}"/>
+                            <Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
+                        </Style>
+                    </Menu.Styles>
+                </Menu>
+            </StackPanel>
         </StackPanel>
     </StackPanel>
-</UserControl>
+</UserControl>

+ 97 - 0
samples/ControlCatalog/Pages/MenuPage.xaml.cs

@@ -1,5 +1,10 @@
+using System.Collections.Generic;
+using System.Reactive;
+using System.Threading.Tasks;
+using System.Windows.Input;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
+using ReactiveUI;
 
 namespace ControlCatalog.Pages
 {
@@ -8,6 +13,51 @@ namespace ControlCatalog.Pages
         public MenuPage()
         {
             this.InitializeComponent();
+            var vm = new MenuPageViewModel();
+
+            vm.MenuItems = new[]
+            {
+                new MenuItemViewModel
+                {
+                    Header = "_File",
+                    Items = new[]
+                    {
+                        new MenuItemViewModel { Header = "_Open...", Command = vm.OpenCommand },
+                        new MenuItemViewModel { Header = "Save", Command = vm.SaveCommand },
+                        new MenuItemViewModel { Header = "-" },
+                        new MenuItemViewModel
+                        {
+                            Header = "Recent",
+                            Items = new[]
+                            {
+                                new MenuItemViewModel
+                                {
+                                    Header = "File1.txt",
+                                    Command = vm.OpenRecentCommand,
+                                    CommandParameter = @"c:\foo\File1.txt"
+                                },
+                                new MenuItemViewModel
+                                {
+                                    Header = "File2.txt",
+                                    Command = vm.OpenRecentCommand,
+                                    CommandParameter = @"c:\foo\File2.txt"
+                                },
+                            }
+                        },
+                    }
+                },
+                new MenuItemViewModel
+                {
+                    Header = "_Edit",
+                    Items = new[]
+                    {
+                        new MenuItemViewModel { Header = "_Copy" },
+                        new MenuItemViewModel { Header = "_Paste" },
+                    }
+                }
+            };
+
+            DataContext = vm;
         }
 
         private void InitializeComponent()
@@ -15,4 +65,51 @@ namespace ControlCatalog.Pages
             AvaloniaXamlLoader.Load(this);
         }
     }
+
+    public class MenuPageViewModel
+    {
+        public MenuPageViewModel()
+        {
+            OpenCommand = ReactiveCommand.CreateFromTask(Open);
+            SaveCommand = ReactiveCommand.Create(Save);
+            OpenRecentCommand = ReactiveCommand.Create<string>(OpenRecent);
+        }
+
+        public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; }
+        public ReactiveCommand<Unit, Unit> OpenCommand { get; }
+        public ReactiveCommand<Unit, Unit> SaveCommand { get; }
+        public ReactiveCommand<string, Unit> OpenRecentCommand { get; }
+
+        public async Task Open()
+        {
+            var dialog = new OpenFileDialog();
+            var result = await dialog.ShowAsync();
+
+            if (result != null)
+            {
+                foreach (var path in result)
+                {
+                    System.Diagnostics.Debug.WriteLine($"Opened: {path}");
+                }
+            }
+        }
+
+        public void Save()
+        {
+            System.Diagnostics.Debug.WriteLine("Save");
+        }
+
+        public void OpenRecent(string path)
+        {
+            System.Diagnostics.Debug.WriteLine($"Open recent: {path}");
+        }
+    }
+
+    public class MenuItemViewModel
+    {
+        public string Header { get; set; }
+        public ICommand Command { get; set; }
+        public object CommandParameter { get; set; }
+        public IList<MenuItemViewModel> Items { get; set; }
+    }
 }

+ 4 - 1
samples/Directory.Build.props

@@ -1,3 +1,6 @@
 <Project>
+  <PropertyGroup>
+      <IsPackable>false</IsPackable>
+  </PropertyGroup>
   <Import Project="..\build\SharedVersion.props" />
-</Project>
+</Project>

+ 4 - 14
samples/Previewer/Previewer.csproj

@@ -8,19 +8,9 @@
       <DependentUpon>%(Filename)</DependentUpon>
     </Compile>
     <EmbeddedResource Include="**\*.xaml" />
-    <ProjectReference Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
   </ItemGroup>
-</Project>
+  
+  <Import Project="..\..\build\SampleApp.props" />
+  <Import Project="..\..\build\ReferenceCoreLibraries.props" />
+</Project>

+ 2 - 13
samples/RemoteDemo/RemoteDemo.csproj

@@ -6,20 +6,9 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
     <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
   </ItemGroup>
+  <Import Project="..\..\build\SampleApp.props" />
+  <Import Project="..\..\build\ReferenceCoreLibraries.props" />
 
 </Project>

+ 12 - 6
samples/RenderDemo/MainWindow.xaml

@@ -8,12 +8,13 @@
       <MenuItem Header="Rendering">
         <MenuItem Header="Draw Dirty Rects" Command="{Binding ToggleDrawDirtyRects}">
           <MenuItem.Icon>
-            <CheckBox BorderThickness="0" 
+            <CheckBox BorderThickness="0"
                       IsHitTestVisible="False"
                       IsChecked="{Binding DrawDirtyRects}"/>
           </MenuItem.Icon>
         </MenuItem>
-        <MenuItem Header="Draw FPS" Command="{Binding ToggleDrawFps}">
+        <MenuItem Header="Draw FPS"
+                  Command="{Binding ToggleDrawFps}">
           <MenuItem.Icon>
             <CheckBox BorderThickness="0"
                       IsHitTestVisible="False"
@@ -22,14 +23,19 @@
         </MenuItem>
       </MenuItem>
     </Menu>
-    
     <TabControl Classes="sidebar">
       <TabControl.PageTransition>
         <CrossFade Duration="0.25"/>
       </TabControl.PageTransition>
-      <TabItem Header="Animations"><pages:AnimationsPage/></TabItem>
-      <TabItem Header="Clipping"><pages:ClippingPage/></TabItem>
-      <TabItem Header="Drawing"><pages:DrawingPage/></TabItem>
+      <TabItem Header="Animations">
+        <pages:AnimationsPage/>
+      </TabItem>
+      <TabItem Header="Clipping">
+        <pages:ClippingPage/>
+      </TabItem>
+      <TabItem Header="Drawing">
+        <pages:DrawingPage/>
+      </TabItem>
     </TabControl>
   </DockPanel>
 </Window>

+ 18 - 15
samples/RenderDemo/Pages/AnimationsPage.xaml

@@ -1,12 +1,12 @@
-<UserControl 
-  xmlns="https://github.com/avaloniaui" 
-  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+<UserControl
+xmlns="https://github.com/avaloniaui"
+xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <UserControl.Styles>
     <Styles>
       <Styles.Resources>
         <Template x:Key="Acorn">
-          <Path Fill="White" Stretch="Uniform" 
-          Data="F1 M 16.6309,18.6563C 17.1309,
+          <Path Fill="White" Stretch="Uniform"
+                Data="F1 M 16.6309,18.6563C 17.1309,
                 8.15625 29.8809,14.1563 29.8809,
                 14.1563C 30.8809,11.1563 34.1308,
                 11.4063 34.1308,11.4063C 33.5,12 
@@ -42,17 +42,17 @@
       </Style>
       <Style Selector="Border.Rect1:pointerover">
         <Style.Animations>
-          <Animation Duration="0:0:2.5" 
-                     RepeatCount="4" 
+          <Animation Duration="0:0:2.5"
+                     RepeatCount="4"
                      FillMode="None"
-                     PlaybackDirection="AlternateReverse" 
+                     PlaybackDirection="AlternateReverse"
                      Easing="SineEaseInOut">
             <KeyFrame Cue="20%">
               <Setter Property="RotateTransform.Angle" Value="45"/>
-             </KeyFrame>
+            </KeyFrame>
             <KeyFrame Cue="50%">
               <Setter Property="ScaleTransform.ScaleX" Value="1.5"/>
-             </KeyFrame>
+            </KeyFrame>
             <KeyFrame Cue="80%">
               <Setter Property="RotateTransform.Angle" Value="120"/>
             </KeyFrame>
@@ -70,7 +70,6 @@
         </Style.Animations>
       </Style>
       <Style Selector="Border.Rect3">
-        <Setter Property="Child" Value="{StaticResource Heart}"/>
         <Style.Animations>
           <Animation Duration="0:0:0.5"
                      Easing="QuadraticEaseInOut"
@@ -79,12 +78,13 @@
               <Setter Property="ScaleTransform.ScaleX" Value="0.8"/>
               <Setter Property="ScaleTransform.ScaleY" Value="0.8"/>
             </KeyFrame>
-           </Animation>
+          </Animation>
         </Style.Animations>
+        <Setter Property="Child" Value="{StaticResource Heart}"/>
       </Style>
       <Style Selector="Border.Rect4:pointerover">
         <Style.Animations>
-          <Animation Duration="0:0:3" Easing="BounceEaseInOut"> 
+          <Animation Duration="0:0:3" Easing="BounceEaseInOut">
             <KeyFrame Cue="48%">
               <Setter Property="TranslateTransform.Y" Value="-100"/>
             </KeyFrame>
@@ -107,9 +107,12 @@
   </UserControl.Styles>
   <Grid>
     <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="False">
+      <StackPanel.Clock>
+        <Clock />
+      </StackPanel.Clock>
       <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
         <TextBlock VerticalAlignment="Center">Hover to activate Transform Keyframe Animations.</TextBlock>
-        <Button Content="{Binding PlayStateText}" Command="{Binding ToggleGlobalPlayState}"/>
+        <Button Content="{Binding PlayStateText}" Command="{Binding TogglePlayState}" Click="ToggleClock" />
       </StackPanel>
       <WrapPanel ClipToBounds="False">
         <Border Classes="Test Rect1" Background="DarkRed"/>
@@ -120,4 +123,4 @@
       </WrapPanel>
     </StackPanel>
   </Grid>
-</UserControl>
+</UserControl>

+ 16 - 0
samples/RenderDemo/Pages/AnimationsPage.xaml.cs

@@ -5,6 +5,7 @@ using Avalonia.Controls;
 using Avalonia.Controls.Shapes;
 using Avalonia.Data;
 using Avalonia.Input;
+using Avalonia.Interactivity;
 using Avalonia.Markup.Xaml;
 using Avalonia.Media;
 using RenderDemo.ViewModels;
@@ -23,5 +24,20 @@ namespace RenderDemo.Pages
         {
             AvaloniaXamlLoader.Load(this);
         }
+
+        private void ToggleClock(object sender, RoutedEventArgs args)
+        {
+            var button = sender as Button;
+            var clock = button.Clock;
+
+            if (clock.PlayState == PlayState.Run)
+            {
+                clock.PlayState = PlayState.Pause;
+            }
+            else if (clock.PlayState == PlayState.Pause)
+            {
+                clock.PlayState = PlayState.Run;
+            }
+        }
     }
 }

+ 6 - 6
samples/RenderDemo/Pages/ClippingPage.xaml

@@ -1,5 +1,5 @@
-<UserControl 
-  xmlns="https://github.com/avaloniaui">
+<UserControl
+xmlns="https://github.com/avaloniaui">
   <Grid ColumnDefinitions="Auto" RowDefinitions="Auto,Auto">
     <Grid.Styles>
       <Styles>
@@ -17,7 +17,7 @@
         </Style>
       </Styles>
     </Grid.Styles>
-    <Border Name="clipped" 
+    <Border Name="clipped"
             Background="Yellow"
             Width="100"
             Height="100"
@@ -44,9 +44,9 @@
       <Border Name="clipChild" Background="{DynamicResource ThemeAccentBrush}" Margin="4">
         <!-- Setting opacity puts the TextBox on a new layer -->
         <TextBox Text="Avalonia" Opacity="0.9" VerticalAlignment="Center"/>
-          <Border.RenderTransform>
-            <RotateTransform/>
-          </Border.RenderTransform>
+        <Border.RenderTransform>
+          <RotateTransform/>
+        </Border.RenderTransform>
       </Border>
     </Border>
     <CheckBox Name="useMask" IsChecked="True" Grid.Row="1">Apply Geometry Clip</CheckBox>

+ 2 - 2
samples/RenderDemo/Pages/DrawingPage.xaml

@@ -98,7 +98,7 @@
         </Border>
 
         <!-- For comparison -->
-        
+
         <Ellipse Grid.Row="2"
                  Grid.Column="0"
                  Width="100"
@@ -127,6 +127,6 @@
                  Stretch="UniformToFill"
                  Fill="Blue"
                  Margin="5" />
-        
+
     </Grid>
 </UserControl>

+ 1 - 19
samples/RenderDemo/RenderDemo.csproj

@@ -4,27 +4,8 @@
     <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
   </PropertyGroup>
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
-    
-    <ProjectReference Condition="'$(TargetFramework)'=='netcoreapp2.0'" Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
-                      
-    <ProjectReference Condition="'$(TargetFramework)'=='net461'" Include="..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj" />
-
     <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Logging.Serilog\Avalonia.Logging.Serilog.csproj" />
   </ItemGroup>
   <Import Project="..\..\build\SampleApp.props" />
   <Import Project="..\..\build\EmbedXaml.props" />
@@ -32,4 +13,5 @@
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\ReactiveUI.props" />
   <Import Condition="'$(TargetFramework)'=='net461'" Project="..\..\build\NetFX.props" />
+  <Import Project="..\..\build\ReferenceCoreLibraries.props" />
 </Project>

+ 1 - 1
samples/RenderDemo/SideBar.xaml

@@ -37,7 +37,7 @@
     <Setter Property="Opacity" Value="0.5"/>
     <Setter Property="Transitions">
       <Transitions>
-        <DoubleTransition Property="Opacity" Duration="0:0:0.5"/>
+        <DoubleTransition Property="Opacity" Duration="0:0:0.2"/>
       </Transitions>
     </Setter>
   </Style>

+ 7 - 21
samples/RenderDemo/ViewModels/AnimationsPageViewModel.cs

@@ -6,27 +6,15 @@ namespace RenderDemo.ViewModels
 {
     public class AnimationsPageViewModel : ReactiveObject
     {
-        private string _playStateText = "Pause all animations";
+        private bool _isPlaying = true;
 
-        public AnimationsPageViewModel()
-        {
-            ToggleGlobalPlayState = ReactiveCommand.Create(()=>TogglePlayState());
-        }
+        private string _playStateText = "Pause animations on this page";
 
-        void TogglePlayState()
+        public void TogglePlayState()
         {
-            switch (Timing.GetGlobalPlayState())
-            {
-                case PlayState.Run:
-                    PlayStateText = "Resume all animations";
-                    Timing.SetGlobalPlayState(PlayState.Pause);
-                    break;
-
-                case PlayState.Pause:
-                    PlayStateText = "Pause all animations";
-                    Timing.SetGlobalPlayState(PlayState.Run);
-                    break;
-            }
+            PlayStateText = _isPlaying
+                ? "Resume animations on this page" : "Pause animations on this page";
+            _isPlaying = !_isPlaying;
         }
 
         public string PlayStateText
@@ -34,7 +22,5 @@ namespace RenderDemo.ViewModels
             get { return _playStateText; }
             set { this.RaiseAndSetIfChanged(ref _playStateText, value); }
         }
-
-        public ReactiveCommand ToggleGlobalPlayState { get; }
-     }
+    }
 }

+ 0 - 22
samples/VirtualizationDemo/App.config

@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
-    </startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0"/>
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>

+ 1 - 0
samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs

@@ -7,6 +7,7 @@ using System.Linq;
 using Avalonia.Collections;
 using Avalonia.Controls;
 using Avalonia.Controls.Primitives;
+using ReactiveUI.Legacy;
 using ReactiveUI;
 
 namespace VirtualizationDemo.ViewModels

+ 1 - 19
samples/VirtualizationDemo/VirtualizationDemo.csproj

@@ -4,27 +4,8 @@
     <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
   </PropertyGroup>
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
-    
-    <ProjectReference Condition="'$(TargetFramework)'=='netcoreapp2.0'" Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
-                      
-    <ProjectReference Condition="'$(TargetFramework)'=='net461'" Include="..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj" />
-
     <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
-    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.Logging.Serilog\Avalonia.Logging.Serilog.csproj" />
   </ItemGroup>
   <Import Project="..\..\build\SampleApp.props" />
   <Import Project="..\..\build\EmbedXaml.props" />
@@ -32,4 +13,5 @@
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\ReactiveUI.props" />
   <Import Condition="'$(TargetFramework)'=='net461'" Project="..\..\build\NetFX.props" />
+  <Import Project="..\..\build\ReferenceCoreLibraries.props" />
 </Project>

+ 2 - 4
samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj

@@ -22,13 +22,11 @@
       </EmbeddedResource>
     </ItemGroup>
     <ItemGroup>
-        <ProjectReference Include="..\..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
-        <ProjectReference Include="..\..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj" />
         <ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
-        <ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
         <ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
         <ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" />
     </ItemGroup>
     <Import Project="..\..\..\build\Serilog.props" />
     <Import Project="..\..\..\build\Rx.props" />
-</Project>
+    <Import Project="..\..\..\build\ReferenceCoreLibraries.props" />
+</Project>

+ 150 - 128
samples/interop/Direct3DInteropSample/MainWindow.cs

@@ -1,81 +1,83 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+// 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 Avalonia;
 using Avalonia.Controls;
+using Avalonia.Direct2D1;
 using Avalonia.Direct2D1.Media;
 using Avalonia.Markup.Xaml;
 using Avalonia.Platform;
 using Avalonia.Rendering;
+
 using SharpDX;
 using SharpDX.D3DCompiler;
 using SharpDX.Direct2D1;
 using SharpDX.Direct3D;
 using SharpDX.Direct3D11;
 using SharpDX.DXGI;
-using SharpDX.WIC;
-using SharpDX.Mathematics;
+
 using AlphaMode = SharpDX.Direct2D1.AlphaMode;
 using Buffer = SharpDX.Direct3D11.Buffer;
-using DeviceContext = SharpDX.Direct3D11.DeviceContext;
-using Factory1 = SharpDX.DXGI.Factory1;
+using DeviceContext = SharpDX.Direct2D1.DeviceContext;
+using Factory2 = SharpDX.DXGI.Factory2;
 using InputElement = SharpDX.Direct3D11.InputElement;
 using Matrix = SharpDX.Matrix;
 using PixelFormat = SharpDX.Direct2D1.PixelFormat;
+using Resource = SharpDX.Direct3D11.Resource;
 
 namespace Direct3DInteropSample
 {
-    class MainWindow : Window
+    public class MainWindow : Window
     {
-        private SharpDX.Direct3D11.Device _d3dDevice;
-        private SharpDX.DXGI.Device _dxgiDevice;
-        Texture2D backBuffer = null;
-        RenderTargetView renderView = null;
-        Texture2D depthBuffer = null;
-        DepthStencilView depthView = null;
+        Texture2D _backBuffer;
+        RenderTargetView _renderView;
+        Texture2D _depthBuffer;
+        DepthStencilView _depthView;
         private readonly SwapChain _swapChain;
-        private SwapChainDescription _desc;
+        private SwapChainDescription1 _desc;
         private Matrix _proj = Matrix.Identity;
-        private Matrix _view;
+        private readonly Matrix _view;
         private Buffer _contantBuffer;
-        private SharpDX.Direct2D1.Device _d2dDevice;
-        private SharpDX.Direct2D1.DeviceContext _d2dContext;
-        private RenderTarget _d2dRenderTarget;
-        private MainWindowViewModel _model;
+        private DeviceContext _deviceContext;
+        private readonly MainWindowViewModel _model;
 
         public MainWindow()
         {
-            _dxgiDevice = AvaloniaLocator.Current.GetService<SharpDX.DXGI.Device>();
-            _d3dDevice = _dxgiDevice.QueryInterface<SharpDX.Direct3D11.Device>();
-            _d2dDevice = AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Device>();
             DataContext = _model = new MainWindowViewModel();
-            _desc = new SwapChainDescription()
+
+            _desc = new SwapChainDescription1()
             {
                 BufferCount = 1,
-                ModeDescription =
-                   new ModeDescription((int)ClientSize.Width, (int)ClientSize.Height,
-                            new Rational(60, 1), Format.R8G8B8A8_UNorm),
-                IsWindowed = true,
-                OutputHandle = PlatformImpl?.Handle.Handle ?? IntPtr.Zero,
+                Width = (int)ClientSize.Width,
+                Height = (int)ClientSize.Height,
+                Format = Format.R8G8B8A8_UNorm,                
                 SampleDescription = new SampleDescription(1, 0),
                 SwapEffect = SwapEffect.Discard,
                 Usage = Usage.RenderTargetOutput
             };
 
-            _swapChain = new SwapChain(new Factory1(), _d3dDevice, _desc);
+            using (var factory = Direct2D1Platform.DxgiDevice.Adapter.GetParent<Factory2>())
+            {
+                _swapChain = new SwapChain1(factory, Direct2D1Platform.DxgiDevice, PlatformImpl?.Handle.Handle ?? IntPtr.Zero, ref _desc);
+            }              
 
-            _d2dContext = new SharpDX.Direct2D1.DeviceContext(_d2dDevice, DeviceContextOptions.None)
+            _deviceContext = new DeviceContext(Direct2D1Platform.Direct2D1Device, DeviceContextOptions.None)
             {
                 DotsPerInch = new Size2F(96, 96)
             };
 
             CreateMesh();
+
             _view = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
+
             this.GetObservable(ClientSizeProperty).Subscribe(Resize);
+
             Resize(ClientSize);
+
             AvaloniaXamlLoader.Load(this);
+
             Background = Avalonia.Media.Brushes.Transparent;
         }
 
@@ -83,29 +85,32 @@ namespace Direct3DInteropSample
         protected override void HandlePaint(Rect rect)
         {
             var viewProj = Matrix.Multiply(_view, _proj);
-            var context = _d3dDevice.ImmediateContext;
+            var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
+
             // Clear views
-            context.ClearDepthStencilView(depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
-            context.ClearRenderTargetView(renderView, Color.White);
+            context.ClearDepthStencilView(_depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
+            context.ClearRenderTargetView(_renderView, Color.White);
 
             // Update WorldViewProj Matrix
-            var worldViewProj = Matrix.RotationX((float) _model.RotationX) * Matrix.RotationY((float) _model.RotationY) *
-                                Matrix.RotationZ((float) _model.RotationZ)
-                                * Matrix.Scaling((float) _model.Zoom) * viewProj;
+            var worldViewProj = Matrix.RotationX((float)_model.RotationX) * Matrix.RotationY((float)_model.RotationY)
+                                                                          * Matrix.RotationZ((float)_model.RotationZ)
+                                                                          * Matrix.Scaling((float)_model.Zoom)
+                                                                          * viewProj;
             worldViewProj.Transpose();
             context.UpdateSubresource(ref worldViewProj, _contantBuffer);
 
             // Draw the cube
             context.Draw(36, 0);
             base.HandlePaint(rect);
+
             // Present!
             _swapChain.Present(0, PresentFlags.None);
         }
 
-        
-        void CreateMesh()
+        private void CreateMesh()
         {
-            var device = _d3dDevice;
+            var device = Direct2D1Platform.Direct3D11Device;
+
             // Compile Vertex and Pixel shaders
             var vertexShaderByteCode = ShaderBytecode.CompileFromFile("MiniCube.fx", "VS", "vs_4_0");
             var vertexShader = new VertexShader(device, vertexShaderByteCode);
@@ -114,63 +119,72 @@ namespace Direct3DInteropSample
             var pixelShader = new PixelShader(device, pixelShaderByteCode);
 
             var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
+
+            var inputElements = new[]
+                                {
+                                    new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
+                                    new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
+                                };
+
             // Layout from VertexShader input signature
-            var layout = new InputLayout(device, signature, new[]
-                    {
-                        new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
-                        new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
-                    });
-            
-            // Instantiate Vertex buiffer from vertex data
-            var vertices = Buffer.Create(device, BindFlags.VertexBuffer, new[]
-                                  {
-                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
-                                      new Vector4(-1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
-                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
-                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
-                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
-                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
-
-                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
-                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
-                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
-                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
-                                      new Vector4( 1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
-                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
-
-                                      new Vector4(-1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
-                                      new Vector4(-1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
-                                      new Vector4( 1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
-                                      new Vector4(-1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
-                                      new Vector4( 1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
-                                      new Vector4( 1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
-
-                                      new Vector4(-1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
-                                      new Vector4( 1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
-                                      new Vector4(-1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
-                                      new Vector4(-1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
-                                      new Vector4( 1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
-                                      new Vector4( 1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
-
-                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
-                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
-                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
-                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
-                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
-                                      new Vector4(-1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
-
-                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
-                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
-                                      new Vector4( 1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
-                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
-                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
-                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
-                            });
+            var layout = new InputLayout(
+                device,
+                signature,
+                inputElements);
+
+            // Instantiate Vertex buffer from vertex data
+            var vertices = Buffer.Create(
+                device,
+                BindFlags.VertexBuffer,
+                new[]
+                {
+                    new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
+                    new Vector4(-1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                    new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                    new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                    new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                    new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+
+                    new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
+                    new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                    new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                    new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                    new Vector4( 1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                    new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+
+                    new Vector4(-1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
+                    new Vector4(-1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                    new Vector4( 1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                    new Vector4(-1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                    new Vector4( 1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                    new Vector4( 1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+
+                    new Vector4(-1.0f, -1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
+                    new Vector4( 1.0f, -1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                    new Vector4(-1.0f, -1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                    new Vector4(-1.0f, -1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                    new Vector4( 1.0f, -1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                    new Vector4( 1.0f, -1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+
+                    new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
+                    new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                    new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                    new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                    new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                    new Vector4(-1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+
+                    new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
+                    new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                    new Vector4( 1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                    new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                    new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                    new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                });
 
             // Create Constant Buffer
             _contantBuffer = new Buffer(device, Utilities.SizeOf<Matrix>(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
 
-            var context = _d3dDevice.ImmediateContext;
+            var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
 
             // Prepare All the stages
             context.InputAssembler.InputLayout = layout;
@@ -181,63 +195,73 @@ namespace Direct3DInteropSample
             context.PixelShader.Set(pixelShader);
         }
 
-        void Resize(Size size)
+        private void Resize(Size size)
         {
-            Utilities.Dispose(ref _d2dRenderTarget);
-            Utilities.Dispose(ref backBuffer);
-            Utilities.Dispose(ref renderView);
-            Utilities.Dispose(ref depthBuffer);
-            Utilities.Dispose(ref depthView);
-            var context = _d3dDevice.ImmediateContext;
+            Utilities.Dispose(ref _deviceContext);
+            Utilities.Dispose(ref _backBuffer);
+            Utilities.Dispose(ref _renderView);
+            Utilities.Dispose(ref _depthBuffer);
+            Utilities.Dispose(ref _depthView);
+            var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
+
             // Resize the backbuffer
-            _swapChain.ResizeBuffers(_desc.BufferCount, (int)size.Width, (int)size.Height, Format.Unknown, SwapChainFlags.None);
+            _swapChain.ResizeBuffers(0, 0, 0, Format.Unknown, SwapChainFlags.None);
 
             // Get the backbuffer from the swapchain
-            backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);
+            _backBuffer = Resource.FromSwapChain<Texture2D>(_swapChain, 0);
 
             // Renderview on the backbuffer
-            renderView = new RenderTargetView(_d3dDevice, backBuffer);
+            _renderView = new RenderTargetView(Direct2D1Platform.Direct3D11Device, _backBuffer);
 
             // Create the depth buffer
-            depthBuffer = new Texture2D(_d3dDevice, new Texture2DDescription()
-            {
-                Format = Format.D32_Float_S8X24_UInt,
-                ArraySize = 1,
-                MipLevels = 1,
-                Width = (int)size.Width,
-                Height = (int)size.Height,
-                SampleDescription = new SampleDescription(1, 0),
-                Usage = ResourceUsage.Default,
-                BindFlags = BindFlags.DepthStencil,
-                CpuAccessFlags = CpuAccessFlags.None,
-                OptionFlags = ResourceOptionFlags.None
-            });
+            _depthBuffer = new Texture2D(
+                Direct2D1Platform.Direct3D11Device,
+                new Texture2DDescription()
+                {
+                    Format = Format.D32_Float_S8X24_UInt,
+                    ArraySize = 1,
+                    MipLevels = 1,
+                    Width = (int)size.Width,
+                    Height = (int)size.Height,
+                    SampleDescription = new SampleDescription(1, 0),
+                    Usage = ResourceUsage.Default,
+                    BindFlags = BindFlags.DepthStencil,
+                    CpuAccessFlags = CpuAccessFlags.None,
+                    OptionFlags = ResourceOptionFlags.None
+                });
 
             // Create the depth buffer view
-            depthView = new DepthStencilView(_d3dDevice, depthBuffer);
+            _depthView = new DepthStencilView(Direct2D1Platform.Direct3D11Device, _depthBuffer);
 
             // Setup targets and viewport for rendering
             context.Rasterizer.SetViewport(new Viewport(0, 0, (int)size.Width, (int)size.Height, 0.0f, 1.0f));
-            context.OutputMerger.SetTargets(depthView, renderView);
+            context.OutputMerger.SetTargets(_depthView, _renderView);
 
             // Setup new projection matrix with correct aspect ratio
             _proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, (float)(size.Width / size.Height), 0.1f, 100.0f);
 
             using (var dxgiBackBuffer = _swapChain.GetBackBuffer<Surface>(0))
             {
-                _d2dRenderTarget = new RenderTarget(AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Factory>()
-                    , dxgiBackBuffer, new RenderTargetProperties
+                var renderTarget = new SharpDX.Direct2D1.RenderTarget(
+                    Direct2D1Platform.Direct2D1Factory,
+                    dxgiBackBuffer,
+                    new RenderTargetProperties
                     {
                         DpiX = 96,
                         DpiY = 96,
                         Type = RenderTargetType.Default,
-                        PixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Premultiplied)
+                        PixelFormat = new PixelFormat(
+                            Format.Unknown,
+                            AlphaMode.Premultiplied)
                     });
-            }
 
+                _deviceContext = renderTarget.QueryInterface<DeviceContext>();
+
+                renderTarget.Dispose();
+            }
         }
 
-        class D3DRenderTarget: IRenderTarget
+        private class D3DRenderTarget : IRenderTarget
         {
             private readonly MainWindow _window;
 
@@ -245,16 +269,14 @@ namespace Direct3DInteropSample
             {
                 _window = window;
             }
+
             public void Dispose()
             {
-                
             }
 
             public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
             {
-                return new DrawingContextImpl(visualBrushRenderer, null, _window._d2dRenderTarget,
-                    AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>(),
-                    AvaloniaLocator.Current.GetService<ImagingFactory>());
+                return new DrawingContextImpl(visualBrushRenderer, null, _window._deviceContext);
             }
         }
 

+ 5 - 4
samples/interop/WindowsInteropTest/WindowsInteropTest.csproj

@@ -112,14 +112,14 @@
       <Project>{799a7bb5-3c2c-48b6-85a7-406a12c420da}</Project>
       <Name>Avalonia.DesignerSupport</Name>
     </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.DesktopRuntime\Avalonia.DesktopRuntime.csproj">
+      <Project>{878fefe0-cd14-41cb-90b0-dbcb163e8f15}</Project>
+      <Name>Avalonia.DesktopRuntime</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
       <Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
       <Name>Avalonia.Diagnostics</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj">
-      <Project>{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}</Project>
-      <Name>Avalonia.DotNetFrameworkRuntime</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\..\src\Avalonia.Input\Avalonia.Input.csproj">
       <Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
       <Name>Avalonia.Input</Name>
@@ -186,4 +186,5 @@
   <Import Project="..\..\..\build\Rx.props" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="..\..\..\build\SkiaSharp.props" />
+  <Import Project="..\..\..\build\LegacyProject.targets" />
 </Project>

+ 3 - 1
src/Android/Avalonia.Android/AndroidPlatform.cs

@@ -52,7 +52,9 @@ namespace Avalonia.Android
                 .Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
                 .Bind<IWindowingPlatform>().ToConstant(Instance)
                 .Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
-                .Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
+                .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
+                .Bind<IRenderLoop>().ToConstant(new RenderLoop())
+                .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
                 .Bind<IAssetLoader>().ToConstant(new AssetLoader(app.GetType().Assembly));
 
             SkiaPlatform.Initialize();

+ 1 - 8
src/Android/Avalonia.Android/Avalonia.Android.csproj

@@ -4,14 +4,7 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <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" />
+    <ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
     <ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
   </ItemGroup>
   <Import Project="..\..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />

+ 4 - 4
src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs

@@ -20,9 +20,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
             ANativeWindow_Buffer buffer;
             var rc = new ARect()
             {
-                right = Width = ANativeWindow_getWidth(_window),
-                bottom = Height = ANativeWindow_getHeight(_window)
+                right = ANativeWindow_getWidth(_window),
+                bottom = ANativeWindow_getHeight(_window)
             };
+            Size = new PixelSize(rc.right, rc.bottom);
             ANativeWindow_lock(_window, out buffer, ref rc);
 
             Format = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565
@@ -41,8 +42,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
         }
 
         public IntPtr Address { get; set; }
-        public int Width { get; }
-        public int Height { get; }
+        public PixelSize Size { get; }
         public int RowBytes { get; }
         public Vector Dpi { get; } = new Vector(96, 96);
         public PixelFormat Format { get; }

+ 1 - 0
src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj

@@ -153,4 +153,5 @@
   <Import Project="..\..\..\build\Rx.props" />
   <Import Project="..\..\..\build\System.Memory.props" />
   <Import Project="..\..\..\build\AndroidWorkarounds.props" />
+  <Import Project="..\..\..\build\LegacyProject.targets" />
 </Project>

+ 12 - 52
src/Avalonia.Animation/Animatable.cs

@@ -11,75 +11,36 @@ using Avalonia.Data;
 namespace Avalonia.Animation
 {
     /// <summary>
-    /// Base class for control which can have property transitions.
+    /// Base class for all animatable objects.
     /// </summary>
     public class Animatable : AvaloniaObject
     {
-        /// <summary>
-        /// Initializes this <see cref="Animatable"/> object.
-        /// </summary>
-        public Animatable()
-        {
-            Transitions = new Transitions();
-            AnimatableTimer = Timing.AnimationStateTimer
-                                .Select(p =>
-                                {
-                                    if (this._playState == PlayState.Pause)
-                                    {
-                                        return PlayState.Pause;
-                                    }
-                                    else return p;
-                                })
-                                .Publish()
-                                .RefCount();
-        }
-
-        /// <summary>
-        /// The specific animations timer for this control.
-        /// </summary>
-        /// <returns></returns>
-        public IObservable<PlayState> AnimatableTimer;
-
-        /// <summary>
-        /// Defines the <see cref="PlayState"/> property.
-        /// </summary>
-        public static readonly DirectProperty<Animatable, PlayState> PlayStateProperty =
-            AvaloniaProperty.RegisterDirect<Animatable, PlayState>(
-                nameof(PlayState),
-                o => o.PlayState,
-                (o, v) => o.PlayState = v);
+        public static readonly StyledProperty<IClock> ClockProperty =
+            AvaloniaProperty.Register<Animatable, IClock>(nameof(Clock), inherits: true);
 
-        private PlayState _playState = PlayState.Run;
-
-        /// <summary>
-        /// Gets or sets the state of the animation for this
-        /// control.
-        /// </summary>
-        public PlayState PlayState
+        public IClock Clock
         {
-            get { return _playState; }
-            set { SetAndRaise(PlayStateProperty, ref _playState, value); }
-
+            get => GetValue(ClockProperty);
+            set => SetValue(ClockProperty, value);
         }
 
-
         /// <summary>
         /// Defines the <see cref="Transitions"/> property.
         /// </summary>
-        public static readonly DirectProperty<Animatable, IEnumerable<ITransition>> TransitionsProperty =
-            AvaloniaProperty.RegisterDirect<Animatable, IEnumerable<ITransition>>(
+        public static readonly DirectProperty<Animatable, Transitions> TransitionsProperty =
+            AvaloniaProperty.RegisterDirect<Animatable, Transitions>(
                 nameof(Transitions),
                 o => o.Transitions,
                 (o, v) => o.Transitions = v);
 
-        private IEnumerable<ITransition> _transitions = new AvaloniaList<ITransition>();
+        private Transitions _transitions;
 
         /// <summary>
         /// Gets or sets the property transitions for the control.
         /// </summary>
-        public IEnumerable<ITransition> Transitions
+        public Transitions Transitions
         {
-            get { return _transitions; }
+            get { return _transitions ?? (_transitions = new Transitions()); }
             set { SetAndRaise(TransitionsProperty, ref _transitions, value); }
         }
 
@@ -96,10 +57,9 @@ namespace Avalonia.Animation
 
                 if (match != null)
                 {
-                    match.Apply(this, e.OldValue, e.NewValue);
+                    match.Apply(this, Clock ?? Avalonia.Animation.Clock.GlobalClock, e.OldValue, e.NewValue);
                 }
             }
         }
-
     }
 }

+ 54 - 37
src/Avalonia.Animation/Animation.cs

@@ -17,6 +17,55 @@ namespace Avalonia.Animation
     /// </summary>
     public class Animation : AvaloniaList<KeyFrame>, IAnimation
     {
+        /// <summary>
+        /// Gets or sets the active time of this animation.
+        /// </summary>
+        public TimeSpan Duration { get; set; }
+
+        /// <summary>
+        /// Gets or sets the repeat count for this animation.
+        /// </summary>
+        public RepeatCount RepeatCount { get; set; }
+
+        /// <summary>
+        /// Gets or sets the playback direction for this animation.
+        /// </summary>
+        public PlaybackDirection PlaybackDirection { get; set; }
+
+        /// <summary>
+        /// Gets or sets the value fill mode for this animation.
+        /// </summary>
+        public FillMode FillMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets the easing function to be used for this animation.
+        /// </summary>
+        public Easing Easing { get; set; } = new LinearEasing();
+
+        /// <summary>
+        /// Gets or sets the speed multiple for this animation.
+        /// </summary>
+        public double SpeedRatio { get; set; } = 1d;
+
+        /// <summary> 
+        /// Gets or sets the delay time for this animation. 
+        /// </summary> 
+        /// <remarks>
+        /// Describes a delay to be added before the animation starts, and optionally between 
+        /// repeats of the animation if <see cref="DelayBetweenIterations"/> is set. 
+        /// </remarks> 
+        public TimeSpan Delay { get; set; }
+
+        /// <summary> 
+        /// Gets or sets a value indicating whether <see cref="Delay"/> will be applied between 
+        /// iterations of the animation.
+        /// </summary> 
+        /// <remarks>
+        /// If this property is not set, then <see cref="Delay"/> will only be applied to the first 
+        /// iteration of the animation. 
+        /// </remarks> 
+        public bool DelayBetweenIterations { get; set; }
+
         private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator)> Animators = new List<(Func<AvaloniaProperty, bool>, Type)>
         {
             ( prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator) )
@@ -40,38 +89,6 @@ namespace Avalonia.Animation
             return null;
         }
 
-        public AvaloniaList<IAnimator> _animators { get; set; } = new AvaloniaList<IAnimator>();
-
-        /// <summary>
-        /// Run time of this animation.
-        /// </summary>
-        public TimeSpan Duration { get; set; }
-
-        /// <summary>
-        /// Delay time for this animation.
-        /// </summary>
-        public TimeSpan Delay { get; set; }
-
-        /// <summary>
-        /// The repeat count for this animation.
-        /// </summary>
-        public RepeatCount RepeatCount { get; set; }
-
-        /// <summary>
-        /// The playback direction for this animation.
-        /// </summary>
-        public PlaybackDirection PlaybackDirection { get; set; }
-
-        /// <summary>
-        /// The value fill mode for this animation.
-        /// </summary>
-        public FillMode FillMode { get; set; }
-
-        /// <summary>
-        /// Easing function to be used.
-        /// </summary>
-        public Easing Easing { get; set; } = new LinearEasing();
-
         private (IList<IAnimator> Animators, IList<IDisposable> subscriptions) InterpretKeyframes(Animatable control)
         {
             var handlerList = new List<(Type type, AvaloniaProperty property)>();
@@ -127,12 +144,12 @@ namespace Avalonia.Animation
         }
 
         /// <inheritdocs/>
-        public IDisposable Apply(Animatable control, IObservable<bool> match, Action onComplete)
+        public IDisposable Apply(Animatable control, IClock clock, IObservable<bool> match, Action onComplete)
         {
             var (animators, subscriptions) = InterpretKeyframes(control);
             if (animators.Count == 1)
             {
-                subscriptions.Add(animators[0].Apply(this, control, match, onComplete));
+                subscriptions.Add(animators[0].Apply(this, control, clock, match, onComplete));
             }
             else
             {
@@ -146,7 +163,7 @@ namespace Avalonia.Animation
                         animatorOnComplete = () => tcs.SetResult(null);
                         completionTasks.Add(tcs.Task);
                     }
-                    subscriptions.Add(animator.Apply(this, control, match, animatorOnComplete));
+                    subscriptions.Add(animator.Apply(this, control, clock, match, animatorOnComplete));
                 }
 
                 if (onComplete != null)
@@ -158,7 +175,7 @@ namespace Avalonia.Animation
         }
 
         /// <inheritdocs/>
-        public Task RunAsync(Animatable control)
+        public Task RunAsync(Animatable control, IClock clock = null)
         {
             var run = new TaskCompletionSource<object>();
 
@@ -166,7 +183,7 @@ namespace Avalonia.Animation
                 run.SetException(new InvalidOperationException("Looping animations must not use the Run method."));
 
             IDisposable subscriptions = null;
-            subscriptions = this.Apply(control, Observable.Return(true), () =>
+            subscriptions = this.Apply(control, clock, Observable.Return(true), () =>
             {
                 run.SetResult(null);
                 subscriptions?.Dispose();

+ 213 - 0
src/Avalonia.Animation/AnimationInstance`1.cs

@@ -0,0 +1,213 @@
+using System;
+using System.Linq;
+using System.Reactive.Linq;
+using Avalonia.Animation.Utils;
+using Avalonia.Data;
+using Avalonia.Reactive;
+
+namespace Avalonia.Animation
+{
+    /// <summary>
+    /// Handles interpolation and time-related functions 
+    /// for keyframe animations.
+    /// </summary>
+    internal class AnimationInstance<T> : SingleSubscriberObservableBase<T>
+    {
+        private T _lastInterpValue;
+        private T _firstKFValue;
+        private long _repeatCount;
+        private double _currentIteration;
+        private bool _isLooping;
+        private bool _gotFirstKFValue;
+        private bool _iterationDelay;
+        private FillMode _fillMode;
+        private PlaybackDirection _animationDirection;
+        private Animator<T> _parent;
+        private Animatable _targetControl;
+        private T _neutralValue;
+        private double _speedRatio;
+        private TimeSpan _delay;
+        private TimeSpan _duration;
+        private Easings.Easing _easeFunc;
+        private Action _onCompleteAction;
+        private Func<double, T, T> _interpolator;
+        private IDisposable _timerSubscription;
+        private readonly IClock _baseClock;
+        private IClock _clock;
+
+        public AnimationInstance(Animation animation, Animatable control, Animator<T> animator, IClock baseClock, Action OnComplete, Func<double, T, T> Interpolator)
+        {
+            if (animation.SpeedRatio <= 0)
+                throw new InvalidOperationException("Speed ratio cannot be negative or zero.");
+
+            if (animation.Duration.TotalSeconds <= 0)
+                throw new InvalidOperationException("Duration cannot be negative or zero.");
+
+            _parent = animator;
+            _easeFunc = animation.Easing;
+            _targetControl = control;
+            _neutralValue = (T)_targetControl.GetValue(_parent.Property);
+
+            _speedRatio = animation.SpeedRatio;
+
+            _delay = animation.Delay;
+            _duration = animation.Duration;
+            _iterationDelay = animation.DelayBetweenIterations;
+
+            switch (animation.RepeatCount.RepeatType)
+            {
+                case RepeatType.None:
+                    _repeatCount = 1;
+                    break;
+                case RepeatType.Loop:
+                    _isLooping = true;
+                    break;
+                case RepeatType.Repeat:
+                    _repeatCount = (long)animation.RepeatCount.Value;
+                    break;
+            }
+
+            _animationDirection = animation.PlaybackDirection;
+            _fillMode = animation.FillMode;
+            _onCompleteAction = OnComplete;
+            _interpolator = Interpolator;
+            _baseClock = baseClock;
+          }
+
+        protected override void Unsubscribed()
+        {
+            //Animation may have been stopped before it has finished
+            ApplyFinalFill();
+
+            _timerSubscription?.Dispose();
+            _clock.PlayState = PlayState.Stop;
+        }
+
+        protected override void Subscribed()
+        {
+            _clock = new Clock(_baseClock);
+            _timerSubscription = _clock.Subscribe(Step);
+        }
+
+        public void Step(TimeSpan frameTick)
+        {
+            try
+            {
+                InternalStep(frameTick);
+            }
+            catch (Exception e)
+            {
+                PublishError(e);
+            }
+        }
+
+        private void ApplyFinalFill()
+        {
+            if (_fillMode == FillMode.Forward || _fillMode == FillMode.Both)
+                _targetControl.SetValue(_parent.Property, _lastInterpValue, BindingPriority.LocalValue);
+        }
+
+        private void DoComplete()
+        {
+            ApplyFinalFill();
+            _onCompleteAction?.Invoke();
+            PublishCompleted();
+        }
+
+        private void DoDelay()
+        {
+            if (_fillMode == FillMode.Backward || _fillMode == FillMode.Both)
+                if (_currentIteration == 0)
+                    PublishNext(_firstKFValue);
+                else
+                    PublishNext(_lastInterpValue);
+        }
+
+        private void DoPlayStates()
+        {
+            if (_clock.PlayState == PlayState.Stop || _baseClock.PlayState == PlayState.Stop)
+                DoComplete();
+
+            if (!_gotFirstKFValue)
+            {
+                _firstKFValue = (T)_parent.First().Value;
+                _gotFirstKFValue = true;
+            }
+        }
+
+        private void InternalStep(TimeSpan time)
+        {
+            DoPlayStates();
+            var delayEndpoint = _delay;
+            var iterationEndpoint = delayEndpoint + _duration;
+            var iterationTime = time;
+
+            //determine if time is currently in the first iteration.
+            if (time >= TimeSpan.Zero & time <= iterationEndpoint)
+            {
+                _currentIteration = 1;
+            }
+            else if (time > iterationEndpoint)
+            {
+                //Subtract first iteration to properly get the subsequent iteration time
+                iterationTime -= iterationEndpoint;
+
+                if (!_iterationDelay & delayEndpoint > TimeSpan.Zero)
+                {
+                    delayEndpoint = TimeSpan.Zero;
+                    iterationEndpoint = _duration;
+                }
+
+                //Calculate the current iteration number
+                _currentIteration = Math.Min(_repeatCount,(int)Math.Floor((double)((double)iterationTime.Ticks / iterationEndpoint.Ticks)) + 2);
+            }
+            else
+            {
+                return;
+            }
+
+             // Determine if the current iteration should have its normalized time inverted.
+            bool isCurIterReverse = _animationDirection == PlaybackDirection.Normal ? false :
+                                    _animationDirection == PlaybackDirection.Alternate ? (_currentIteration % 2 == 0) ? false : true :
+                                    _animationDirection == PlaybackDirection.AlternateReverse ? (_currentIteration % 2 == 0) ? true : false :
+                                    _animationDirection == PlaybackDirection.Reverse ? true : false;
+   
+            if (!_isLooping)
+            {
+                var totalTime = _iterationDelay ? _repeatCount * ( _duration.Ticks + _delay.Ticks) : _repeatCount * _duration.Ticks + _delay.Ticks;
+                if (time.Ticks >= totalTime)
+                {
+                    var easedTime = _easeFunc.Ease(isCurIterReverse ? 0.0 : 1.0);
+                    _lastInterpValue = _interpolator(easedTime, _neutralValue);
+                   
+                    DoComplete();
+                    return;
+                }
+            }
+            iterationTime = TimeSpan.FromTicks((long)(iterationTime.Ticks % iterationEndpoint.Ticks));
+        
+            if (delayEndpoint > TimeSpan.Zero & iterationTime < delayEndpoint)
+            {
+                DoDelay();
+            }
+            else
+            {
+                // Offset the delay time            
+                iterationTime -= delayEndpoint;
+                iterationEndpoint -= delayEndpoint;
+
+                // Normalize time
+                var interpVal = (double)iterationTime.Ticks / iterationEndpoint.Ticks;
+
+                if (isCurIterReverse)
+                    interpVal = 1 - interpVal;
+
+                // Ease and interpolate
+                var easedTime = _easeFunc.Ease(interpVal);
+                _lastInterpValue = _interpolator(easedTime, _neutralValue);
+
+                PublishNext(_lastInterpValue);
+            }
+        }
+    }
+}

+ 5 - 0
src/Avalonia.Animation/AnimatorKeyFrame.cs

@@ -25,6 +25,7 @@ namespace Avalonia.Animation
             Cue = cue;
         }
 
+        internal bool isNeutral;
         public Type AnimatorType { get; }
         public Cue Cue { get; }
         public AvaloniaProperty Property { get; private set; }
@@ -60,6 +61,10 @@ namespace Avalonia.Animation
             {
                 throw new ArgumentNullException($"KeyFrame value can't be null.");
             }
+            if(Value is T typedValue)
+            {
+                return typedValue;
+            }
             if (!typeConv.CanConvertTo(Value.GetType()))
             {
                 throw new InvalidCastException($"KeyFrame value doesnt match property type.");

+ 0 - 273
src/Avalonia.Animation/AnimatorStateMachine`1.cs

@@ -1,273 +0,0 @@
-using System;
-using System.Linq;
-using Avalonia.Data;
-
-namespace Avalonia.Animation
-{
-    /// <summary>
-    /// Provides statefulness for an iteration of a keyframe animation.
-    /// </summary>
-    internal class AnimatorStateMachine<T> : IObservable<object>, IDisposable
-    {
-        object _lastInterpValue;
-        object _firstKFValue;
-
-        private ulong _delayTotalFrameCount;
-        private ulong _durationTotalFrameCount;
-        private ulong _delayFrameCount;
-        private ulong _durationFrameCount;
-        private ulong _repeatCount;
-        private ulong _currentIteration;
-
-        private bool _isLooping;
-        private bool _isRepeating;
-        private bool _isReversed;
-        private bool _checkLoopAndRepeat;
-        private bool _gotFirstKFValue;
-
-        private FillMode _fillMode;
-        private PlaybackDirection _animationDirection;
-        private KeyFramesStates _currentState;
-        private KeyFramesStates _savedState;
-        private Animator<T> _parent;
-        private Animation _targetAnimation;
-        private Animatable _targetControl;
-        private T _neutralValue;
-        internal bool _unsubscribe = false;
-        private IObserver<object> _targetObserver;
-        private readonly Action _onComplete;
-
-        [Flags]
-        private enum KeyFramesStates
-        {
-            Initialize,
-            DoDelay,
-            DoRun,
-            RunForwards,
-            RunBackwards,
-            RunApplyValue,
-            RunComplete,
-            Pause,
-            Stop,
-            Disposed
-        }
-
-        public AnimatorStateMachine(Animation animation, Animatable control, Animator<T> animator, Action onComplete)
-        {
-            _parent = animator;
-            _targetAnimation = animation;
-            _targetControl = control;
-            _neutralValue = (T)_targetControl.GetValue(_parent.Property);
-
-            _delayTotalFrameCount = (ulong)(animation.Delay.Ticks / Timing.FrameTick.Ticks);
-            _durationTotalFrameCount = (ulong)(animation.Duration.Ticks / Timing.FrameTick.Ticks);
-
-            switch (animation.RepeatCount.RepeatType)
-            {
-                case RepeatType.Loop:
-                    _isLooping = true;
-                    _checkLoopAndRepeat = true;
-                    break;
-                case RepeatType.Repeat:
-                    _isRepeating = true;
-                    _checkLoopAndRepeat = true;
-                    _repeatCount = animation.RepeatCount.Value;
-                    break;
-            }
-
-            _isReversed = (animation.PlaybackDirection & PlaybackDirection.Reverse) != 0;
-            _animationDirection = _targetAnimation.PlaybackDirection;
-            _fillMode = _targetAnimation.FillMode;
-
-            if (_durationTotalFrameCount > 0)
-                _currentState = KeyFramesStates.DoDelay;
-            else
-                _currentState = KeyFramesStates.DoRun;
-            _onComplete = onComplete;
-        }
-
-        public void Step(PlayState _playState, Func<double, T, T> Interpolator)
-        {
-            try
-            {
-                InternalStep(_playState, Interpolator);
-            }
-            catch (Exception e)
-            {
-                _targetObserver?.OnError(e);
-            }
-        }
-
-        private void InternalStep(PlayState _playState, Func<double, T, T> Interpolator)
-        {
-            if (!_gotFirstKFValue)
-            {
-                _firstKFValue = _parent.First().Value;
-                _gotFirstKFValue = true;
-            }
-
-            if (_currentState == KeyFramesStates.Disposed)
-                throw new InvalidProgramException("This KeyFrames Animation is already disposed.");
-
-            if (_playState == PlayState.Stop)
-                _currentState = KeyFramesStates.Stop;
-
-            // Save state and pause the machine
-            if (_playState == PlayState.Pause && _currentState != KeyFramesStates.Pause)
-            {
-                _savedState = _currentState;
-                _currentState = KeyFramesStates.Pause;
-            }
-
-            // Resume the previous state
-            if (_playState != PlayState.Pause && _currentState == KeyFramesStates.Pause)
-                _currentState = _savedState;
-
-            double _tempDuration = 0d, _easedTime;
-
-            bool handled = false;
-
-            while (!handled)
-            {
-                switch (_currentState)
-                {
-                    case KeyFramesStates.DoDelay:
-
-                        if (_fillMode == FillMode.Backward
-                         || _fillMode == FillMode.Both)
-                        {
-                            if (_currentIteration == 0)
-                            {
-                                _targetObserver.OnNext(_firstKFValue);
-                            }
-                            else
-                            {
-                                _targetObserver.OnNext(_lastInterpValue);
-                            }
-                        }
-
-                        if (_delayFrameCount > _delayTotalFrameCount)
-                        {
-                            _currentState = KeyFramesStates.DoRun;
-                        }
-                        else
-                        {
-                            handled = true;
-                            _delayFrameCount++;
-                        }
-                        break;
-
-                    case KeyFramesStates.DoRun:
-
-                        if (_isReversed)
-                            _currentState = KeyFramesStates.RunBackwards;
-                        else
-                            _currentState = KeyFramesStates.RunForwards;
-
-                        break;
-
-                    case KeyFramesStates.RunForwards:
-
-                        if (_durationFrameCount > _durationTotalFrameCount)
-                        {
-                            _currentState = KeyFramesStates.RunComplete;
-                        }
-                        else
-                        {
-                            _tempDuration = (double)_durationFrameCount / _durationTotalFrameCount;
-                            _currentState = KeyFramesStates.RunApplyValue;
-
-                        }
-                        break;
-
-                    case KeyFramesStates.RunBackwards:
-
-                        if (_durationFrameCount > _durationTotalFrameCount)
-                        {
-                            _currentState = KeyFramesStates.RunComplete;
-                        }
-                        else
-                        {
-                            _tempDuration = (double)(_durationTotalFrameCount - _durationFrameCount) / _durationTotalFrameCount;
-                            _currentState = KeyFramesStates.RunApplyValue;
-                        }
-                        break;
-
-                    case KeyFramesStates.RunApplyValue:
-
-                        _easedTime = _targetAnimation.Easing.Ease(_tempDuration);
-
-                        _durationFrameCount++;
-                        _lastInterpValue = Interpolator(_easedTime, _neutralValue);
-                        _targetObserver.OnNext(_lastInterpValue);
-                        _currentState = KeyFramesStates.DoRun;
-                        handled = true;
-                        break;
-
-                    case KeyFramesStates.RunComplete:
-
-                        if (_checkLoopAndRepeat)
-                        {
-                            _delayFrameCount = 0;
-                            _durationFrameCount = 0;
-
-                            if (_isLooping)
-                            {
-                                _currentState = KeyFramesStates.DoRun;
-                            }
-                            else if (_isRepeating)
-                            {
-                                if (_currentIteration >= _repeatCount)
-                                {
-                                    _currentState = KeyFramesStates.Stop;
-                                }
-                                else
-                                {
-                                    _currentState = KeyFramesStates.DoRun;
-                                }
-                                _currentIteration++;
-                            }
-
-                            if (_animationDirection == PlaybackDirection.Alternate
-                             || _animationDirection == PlaybackDirection.AlternateReverse)
-                                _isReversed = !_isReversed;
-
-                            break;
-                        }
-
-                        _currentState = KeyFramesStates.Stop;
-                        break;
-
-                    case KeyFramesStates.Stop:
-
-                        if (_fillMode == FillMode.Forward
-                         || _fillMode == FillMode.Both)
-                        {
-                            _targetControl.SetValue(_parent.Property, _lastInterpValue, BindingPriority.LocalValue);
-                        }
-
-                        _targetObserver.OnCompleted();
-                        _onComplete?.Invoke();
-                        Dispose();
-                        handled = true;
-                        break;
-                    default:
-                        handled = true;
-                        break;
-                }
-            }
-        }
-
-        public IDisposable Subscribe(IObserver<object> observer)
-        {
-            _targetObserver = observer;
-            return this;
-        }
-
-        public void Dispose()
-        {
-            _unsubscribe = true;
-            _currentState = KeyFramesStates.Disposed;
-        }
-    }
-}

+ 74 - 46
src/Avalonia.Animation/Animator`1.cs

@@ -1,10 +1,14 @@
-using System;
+// 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.Generic;
 using System.Linq;
 using System.Reactive.Linq;
 using Avalonia.Animation.Utils;
 using Avalonia.Collections;
 using Avalonia.Data;
+using Avalonia.Reactive;
 
 namespace Avalonia.Animation
 {
@@ -16,7 +20,7 @@ namespace Avalonia.Animation
         /// <summary>
         /// List of type-converted keyframes.
         /// </summary>
-        private readonly SortedList<double, (AnimatorKeyFrame, bool isNeutral)> _convertedKeyframes = new SortedList<double, (AnimatorKeyFrame, bool)>();
+        private readonly List<AnimatorKeyFrame> _convertedKeyframes = new List<AnimatorKeyFrame>();
 
         private bool _isVerifiedAndConverted;
 
@@ -32,18 +36,13 @@ namespace Avalonia.Animation
         }
 
         /// <inheritdoc/>
-        public virtual IDisposable Apply(Animation animation, Animatable control, IObservable<bool> obsMatch, Action onComplete)
+        public virtual IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> match, Action onComplete)
         {
             if (!_isVerifiedAndConverted)
                 VerifyConvertKeyFrames();
 
-            return obsMatch
-                // Ignore triggers when global timers are paused.
-                .Where(p => p && Timing.GetGlobalPlayState() != PlayState.Pause)
-                .Subscribe(_ =>
-                {
-                    var timerObs = RunKeyFrames(animation, control, onComplete);
-                });
+            var subject = new DisposeAnimationInstanceSubject<T>(this, animation, control, clock, onComplete);
+            return match.Subscribe(subject);
         }
 
         /// <summary>
@@ -53,56 +52,85 @@ namespace Avalonia.Animation
         /// (i.e., the normalized time between the selected keyframes, relative to the
         /// time parameter).
         /// </summary>
-        /// <param name="t">The time parameter, relative to the total animation time</param>
-        protected (double IntraKFTime, KeyFramePair<T> KFPair) GetKFPairAndIntraKFTime(double t)
+        /// <param name="animationTime">The time parameter, relative to the total animation time</param>
+        protected (double IntraKFTime, KeyFramePair<T> KFPair) GetKFPairAndIntraKFTime(double animationTime)
         {
-            KeyValuePair<double, (AnimatorKeyFrame frame, bool isNeutral)> firstCue, lastCue;
+            AnimatorKeyFrame firstKeyframe, lastKeyframe;
             int kvCount = _convertedKeyframes.Count;
             if (kvCount > 2)
             {
-                if (DoubleUtils.AboutEqual(t, 0.0) || t < 0.0)
+                if (animationTime <= 0.0)
                 {
-                    firstCue = _convertedKeyframes.First();
-                    lastCue = _convertedKeyframes.Skip(1).First();
+                    firstKeyframe = _convertedKeyframes[0];
+                    lastKeyframe = _convertedKeyframes[1];
                 }
-                else if (DoubleUtils.AboutEqual(t, 1.0) || t > 1.0)
+                else if (animationTime >= 1.0)
                 {
-                    firstCue = _convertedKeyframes.Skip(kvCount - 2).First();
-                    lastCue = _convertedKeyframes.Last();
+                    firstKeyframe = _convertedKeyframes[_convertedKeyframes.Count - 2];
+                    lastKeyframe = _convertedKeyframes[_convertedKeyframes.Count - 1];
                 }
                 else
                 {
-                    firstCue = _convertedKeyframes.Last(j => j.Key <= t);
-                    lastCue = _convertedKeyframes.First(j => j.Key >= t);
+                    int index = FindClosestBeforeKeyFrame(animationTime);
+                    firstKeyframe = _convertedKeyframes[index];
+                    lastKeyframe = _convertedKeyframes[index + 1];
                 }
             }
             else
             {
-                firstCue = _convertedKeyframes.First();
-                lastCue = _convertedKeyframes.Last();
+                firstKeyframe = _convertedKeyframes[0];
+                lastKeyframe = _convertedKeyframes[1];
             }
 
-            double t0 = firstCue.Key;
-            double t1 = lastCue.Key;
-            var intraframeTime = (t - t0) / (t1 - t0);
-            var firstFrameData = (firstCue.Value.frame.GetTypedValue<T>(), firstCue.Value.isNeutral);
-            var lastFrameData = (lastCue.Value.frame.GetTypedValue<T>(), lastCue.Value.isNeutral);
+            double t0 = firstKeyframe.Cue.CueValue;
+            double t1 = lastKeyframe.Cue.CueValue;
+            var intraframeTime = (animationTime - t0) / (t1 - t0);
+            var firstFrameData = (firstKeyframe.GetTypedValue<T>(), firstKeyframe.isNeutral);
+            var lastFrameData = (lastKeyframe.GetTypedValue<T>(), lastKeyframe.isNeutral);
             return (intraframeTime, new KeyFramePair<T>(firstFrameData, lastFrameData));
         }
 
+        private int FindClosestBeforeKeyFrame(double time)
+        {
+            int FindClosestBeforeKeyFrame(int startIndex, int length)
+            {
+                if (length == 0 || length == 1)
+                {
+                    return startIndex;
+                }
+
+                int middle = startIndex + (length / 2);
+
+                if (_convertedKeyframes[middle].Cue.CueValue < time)
+                {
+                    return FindClosestBeforeKeyFrame(middle, length - middle);
+                }
+                else if (_convertedKeyframes[middle].Cue.CueValue > time)
+                {
+                    return FindClosestBeforeKeyFrame(startIndex, middle - startIndex);
+                }
+                else
+                {
+                    return middle;
+                }
+            }
+
+            return FindClosestBeforeKeyFrame(0, _convertedKeyframes.Count);
+        }
 
         /// <summary>
         /// Runs the KeyFrames Animation.
         /// </summary>
-        private IDisposable RunKeyFrames(Animation animation, Animatable control, Action onComplete)
+        internal IDisposable Run(Animation animation, Animatable control, IClock clock, Action onComplete)
         {
-            var stateMachine = new AnimatorStateMachine<T>(animation, control, this, onComplete);
-
-            Timing.AnimationStateTimer
-                        .TakeWhile(_ => !stateMachine._unsubscribe)
-                        .Subscribe(p => stateMachine.Step(p, DoInterpolation));
-
-            return control.Bind(Property, stateMachine, BindingPriority.Animation);
+            var instance = new AnimationInstance<T>(
+                animation,
+                control,
+                this,
+                clock ?? control.Clock ?? Clock.GlobalClock,
+                onComplete,
+                DoInterpolation);
+            return control.Bind<T>((AvaloniaProperty<T>)Property, instance, BindingPriority.Animation);
         }
 
         /// <summary>
@@ -111,18 +139,18 @@ namespace Avalonia.Animation
         protected abstract T DoInterpolation(double time, T neutralValue);
 
         /// <summary>
-        /// Verifies and converts keyframe values according to this class's target type.
+        /// Verifies, converts and sorts keyframe values according to this class's target type.
         /// </summary>
         private void VerifyConvertKeyFrames()
         {
             foreach (AnimatorKeyFrame keyframe in this)
             {
-                _convertedKeyframes.Add(keyframe.Cue.CueValue, (keyframe, false));
+                _convertedKeyframes.Add(keyframe);
             }
 
             AddNeutralKeyFramesIfNeeded();
-            _isVerifiedAndConverted = true;
 
+            _isVerifiedAndConverted = true;
         }
 
         private void AddNeutralKeyFramesIfNeeded()
@@ -130,14 +158,14 @@ namespace Avalonia.Animation
             bool hasStartKey, hasEndKey;
             hasStartKey = hasEndKey = false;
 
-            // Make start and end keyframe mandatory.
-            foreach (var converted in _convertedKeyframes.Keys)
+            // Check if there's start and end keyframes.
+            foreach (var frame in _convertedKeyframes)
             {
-                if (DoubleUtils.AboutEqual(converted, 0.0))
+                if (frame.Cue.CueValue == 0.0d)
                 {
                     hasStartKey = true;
                 }
-                else if (DoubleUtils.AboutEqual(converted, 1.0))
+                else if (frame.Cue.CueValue == 1.0d)
                 {
                     hasEndKey = true;
                 }
@@ -151,13 +179,13 @@ namespace Avalonia.Animation
         {
             if (!hasStartKey)
             {
-                _convertedKeyframes.Add(0.0d, (new AnimatorKeyFrame { Value = default(T) }, true));
+                _convertedKeyframes.Insert(0, new AnimatorKeyFrame(null, new Cue(0.0d)) { Value = default(T), isNeutral = true });
             }
 
             if (!hasEndKey)
             {
-                _convertedKeyframes.Add(1.0d, (new AnimatorKeyFrame { Value = default(T) }, true));
+                _convertedKeyframes.Add(new AnimatorKeyFrame(null, new Cue(1.0d)) { Value = default(T), isNeutral = true });
             }
         }
     }
-}
+}

+ 2 - 1
src/Avalonia.Animation/Avalonia.Animation.csproj

@@ -1,9 +1,10 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
+    <IsPackable>false</IsPackable>
   </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
   </ItemGroup>
   <Import Project="..\..\build\Rx.props" />
-</Project>
+</Project>

+ 30 - 0
src/Avalonia.Animation/Clock.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Reactive.Linq;
+using System.Text;
+using Avalonia.Reactive;
+
+namespace Avalonia.Animation
+{
+    public class Clock : ClockBase
+    {
+        public static IClock GlobalClock => AvaloniaLocator.Current.GetService<IGlobalClock>();
+
+        private IDisposable _parentSubscription;
+
+        public Clock()
+            :this(GlobalClock)
+        {
+        }
+        
+        public Clock(IClock parent)
+        {
+            _parentSubscription = parent.Subscribe(Pulse);
+        }
+
+        protected override void Stop()
+        {
+            _parentSubscription?.Dispose();
+        }
+    }
+}

+ 72 - 0
src/Avalonia.Animation/ClockBase.cs

@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Reactive.Linq;
+using System.Text;
+using Avalonia.Reactive;
+
+namespace Avalonia.Animation
+{
+    public class ClockBase : IClock
+    {
+        private ClockObservable _observable;
+
+        private IObservable<TimeSpan> _connectedObservable;
+
+        private TimeSpan? _previousTime;
+        private TimeSpan _internalTime;
+
+        protected ClockBase()
+        {
+            _observable = new ClockObservable();
+            _connectedObservable = _observable.Publish().RefCount();
+        }
+
+        protected bool HasSubscriptions => _observable.HasSubscriptions;
+
+        public PlayState PlayState { get; set; }
+
+        protected void Pulse(TimeSpan systemTime)
+        {
+            if (!_previousTime.HasValue)
+            {
+                _previousTime = systemTime;
+                _internalTime = TimeSpan.Zero;
+            }
+            else
+            {
+                if (PlayState == PlayState.Pause)
+                {
+                    _previousTime = systemTime;
+                    return;
+                }
+                var delta = systemTime - _previousTime;
+                _internalTime += delta.Value;
+                _previousTime = systemTime;
+            }
+
+            _observable.Pulse(_internalTime);
+
+            if (PlayState == PlayState.Stop)
+            {
+                Stop();
+            }
+        }
+
+        protected virtual void Stop()
+        {
+        }
+
+        public IDisposable Subscribe(IObserver<TimeSpan> observer)
+        {
+            return _connectedObservable.Subscribe(observer);
+        }
+
+        private class ClockObservable : LightweightObservableBase<TimeSpan>
+        {
+            public bool HasSubscriptions { get; private set; }
+            public void Pulse(TimeSpan time) => PublishNext(time);
+            protected override void Initialize() => HasSubscriptions = true;
+            protected override void Deinitialize() => HasSubscriptions = false;
+        }
+    }
+}

Some files were not shown because too many files changed in this diff