Browse Source

Merge branch 'master' into DropdownKeyboardTweaks

Steven Kirk 8 years ago
parent
commit
a5ac9309df
100 changed files with 4116 additions and 1170 deletions
  1. 1 0
      .gitignore
  2. 5 0
      .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject
  3. 5 0
      .ncrunch/RemoteTest.v3.ncrunchproject
  4. 0 1
      .travis.yml
  5. 217 170
      Avalonia.sln
  6. 0 3
      appveyor.yml
  7. 0 2
      build/NetCore.props
  8. 0 6
      docs/guidelines/build.md
  9. 32 47
      packages.cake
  10. 2 2
      readme.md
  11. 0 8
      samples/BindingTest/BindingTest.csproj
  12. 0 8
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  13. 7 3
      samples/ControlCatalog.Desktop/Program.cs
  14. 6 11
      samples/ControlCatalog.NetCore/Program.cs
  15. BIN
      samples/ControlCatalog/Assets/test_icon.ico
  16. 6 0
      samples/ControlCatalog/ControlCatalog.csproj
  17. 1 0
      samples/ControlCatalog/MainView.xaml
  18. 1 0
      samples/ControlCatalog/MainWindow.xaml.cs
  19. 24 0
      samples/ControlCatalog/Pages/ProgressBarPage.xaml
  20. 18 0
      samples/ControlCatalog/Pages/ProgressBarPage.xaml.cs
  21. 2 2
      samples/ControlCatalog/Pages/ToolTipPage.xaml
  22. 0 126
      samples/ControlCatalog/Program.cs
  23. 6 0
      samples/Previewer/App.xaml
  24. 14 0
      samples/Previewer/App.xaml.cs
  25. 19 0
      samples/Previewer/Center.cs
  26. 12 0
      samples/Previewer/MainWindow.xaml
  27. 86 0
      samples/Previewer/MainWindow.xaml.cs
  28. 27 0
      samples/Previewer/Previewer.csproj
  29. 13 0
      samples/Previewer/Program.cs
  30. 53 0
      samples/RemoteTest/Program.cs
  31. 25 0
      samples/RemoteTest/RemoteTest.csproj
  32. 0 8
      samples/RenderTest/RenderTest.csproj
  33. 0 8
      samples/VirtualizationTest/VirtualizationTest.csproj
  34. 3 2
      samples/interop/Direct3DInteropSample/MainWindow.cs
  35. 0 6
      samples/interop/GtkInteropDemo/App.config
  36. 0 154
      samples/interop/GtkInteropDemo/GtkInteropDemo.csproj
  37. 0 30
      samples/interop/GtkInteropDemo/MainWindow.cs
  38. 0 24
      samples/interop/GtkInteropDemo/Program.cs
  39. 0 36
      samples/interop/GtkInteropDemo/Properties/AssemblyInfo.cs
  40. 0 71
      samples/interop/GtkInteropDemo/Properties/Resources.Designer.cs
  41. 0 117
      samples/interop/GtkInteropDemo/Properties/Resources.resx
  42. 0 30
      samples/interop/GtkInteropDemo/Properties/Settings.Designer.cs
  43. 0 7
      samples/interop/GtkInteropDemo/Properties/Settings.settings
  44. 4 5
      scripts/ReplaceNugetCache.ps1
  45. 3 4
      scripts/ReplaceNugetCache.sh
  46. 4 5
      scripts/ReplaceNugetCacheRelease.ps1
  47. 5 4
      src/Android/Avalonia.Android/AndroidThreadingInterface.cs
  48. 2 1
      src/Avalonia.Base/AvaloniaObject.cs
  49. 5 3
      src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
  50. 9 0
      src/Avalonia.Base/Platform/IRuntimePlatform.cs
  51. 2 2
      src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
  52. 15 2
      src/Avalonia.Base/Threading/Dispatcher.cs
  53. 17 7
      src/Avalonia.Base/Threading/DispatcherPriority.cs
  54. 4 14
      src/Avalonia.Base/Threading/DispatcherTimer.cs
  55. 32 15
      src/Avalonia.Base/Threading/JobRunner.cs
  56. 0 60
      src/Avalonia.Base/Threading/SingleThreadDispatcher.cs
  57. 0 1
      src/Avalonia.Base/Utilities/WeakTimer.cs
  58. 2 1
      src/Avalonia.Controls/Avalonia.Controls.csproj
  59. 4 6
      src/Avalonia.Controls/Control.cs
  60. 1 1
      src/Avalonia.Controls/Design.cs
  61. 10 10
      src/Avalonia.Controls/DropDown.cs
  62. 63 0
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
  63. 66 0
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  64. 15 0
      src/Avalonia.Controls/MenuItem.cs
  65. 21 0
      src/Avalonia.Controls/Orientation.cs
  66. 12 13
      src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs
  67. 1 1
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  68. 23 3
      src/Avalonia.Controls/Primitives/Track.cs
  69. 136 3
      src/Avalonia.Controls/ProgressBar.cs
  70. 40 0
      src/Avalonia.Controls/Remote/RemoteServer.cs
  71. 79 0
      src/Avalonia.Controls/Remote/RemoteWidget.cs
  72. 176 0
      src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
  73. 10 17
      src/Avalonia.Controls/StackPanel.cs
  74. 1 3
      src/Avalonia.Controls/TreeView.cs
  75. 1 1
      src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
  76. 76 0
      src/Avalonia.DesignerSupport/DesignWindowLoader.cs
  77. 2 58
      src/Avalonia.DesignerSupport/DesignerAssist.cs
  78. 35 0
      src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs
  79. 96 0
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  80. 66 0
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs
  81. 172 0
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs
  82. 146 0
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  83. 2 1
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  84. 0 42
      src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs
  85. 0 1
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  86. 4 1
      src/Avalonia.Input/Key.cs
  87. 20 2
      src/Avalonia.Input/MouseDevice.cs
  88. 1 1
      src/Avalonia.Layout/LayoutManager.cs
  89. 9 0
      src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj
  90. 19 0
      src/Avalonia.Remote.Protocol/AvaloniaRemoteMessageGuidAttribute.cs
  91. 150 0
      src/Avalonia.Remote.Protocol/BsonStreamTransport.cs
  92. 27 0
      src/Avalonia.Remote.Protocol/BsonTcpTransport.cs
  93. 35 0
      src/Avalonia.Remote.Protocol/DefaultMessageTypeResolver.cs
  94. 17 0
      src/Avalonia.Remote.Protocol/DesignMessages.cs
  95. 74 0
      src/Avalonia.Remote.Protocol/EventStash.cs
  96. 10 0
      src/Avalonia.Remote.Protocol/IMessageTypeResolver.cs
  97. 15 0
      src/Avalonia.Remote.Protocol/ITransport.cs
  98. 82 0
      src/Avalonia.Remote.Protocol/InputMessages.cs
  99. 1632 0
      src/Avalonia.Remote.Protocol/MetsysBson.cs
  100. 78 0
      src/Avalonia.Remote.Protocol/TcpTransportBase.cs

+ 1 - 0
.gitignore

@@ -175,3 +175,4 @@ artifacts/
 nuget
 Avalonia.XBuild.sln
 project.lock.json
+.idea/*

+ 5 - 0
.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject

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

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

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

+ 0 - 1
.travis.yml

@@ -1,7 +1,6 @@
 language: csharp
 os:
   - linux
-  - osx
 dist: trusty
 osx_image: xcode8.3
 env:

+ 217 - 170
Avalonia.sln

@@ -1,3 +1,4 @@
+
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
 VisualStudioVersion = 15.0.26730.3
@@ -50,8 +51,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Input.UnitTests",
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Direct2D1.UnitTests", "tests\Avalonia.Direct2D1.UnitTests\Avalonia.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Cairo.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Cairo.RenderTests.csproj", "{E106CF37-4066-4615-B684-172A6D30B058}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.UnitTests", "tests\Avalonia.Markup.Xaml.UnitTests\Avalonia.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}"
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}"
@@ -67,10 +66,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DE
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gtk", "Gtk", "{B9894058-278A-46B5-B6ED-AD613FCC03B3}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Gtk", "src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj", "{54F237D5-A70A-4752-9656-0C70B1A7B047}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Cairo", "src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj", "{FB05AC90-89BA-4F2F-A924-F37875FB547C}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.HtmlRenderer", "src\Avalonia.HtmlRenderer\Avalonia.HtmlRenderer.csproj", "{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}"
@@ -127,8 +122,6 @@ 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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GtkInteropDemo", "samples\interop\GtkInteropDemo\GtkInteropDemo.csproj", "{BD7F352C-6DC1-4740-BAF2-2D34A038728C}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DotNetFrameworkRuntime", "src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj", "{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderTest", "samples\RenderTest\RenderTest.csproj", "{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}"
@@ -186,10 +179,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Interop", "s
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Remote.Protocol", "src\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj", "{D78A720C-C0C6-478B-8564-F167F9BDD01B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteTest", "samples\RemoteTest\RemoteTest.csproj", "{E2999E4A-9086-401F-898C-AEB0AD38E676}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{4ED8B739-6F4E-4CD4-B993-545E6B5CE637}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Designer.HostApp", "src\tools\Avalonia.Designer.HostApp\Avalonia.Designer.HostApp.csproj", "{050CC912-FF49-4A8B-B534-9544017446DD}"
+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}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MonoMac", "src\OSX\Avalonia.MonoMac\Avalonia.MonoMac.csproj", "{CBFD5788-567D-401B-9DFA-74E4224025A0}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Designer.HostApp.NetFX", "src\tools\Avalonia.Designer.HostApp.NetFX\Avalonia.Designer.HostApp.NetFX.csproj", "{4ADA61C8-D191-428D-9066-EF4F0D86520F}"
+EndProject
 Global
 	GlobalSection(SharedMSBuildProjectFiles) = preSolution
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@@ -199,14 +204,11 @@ Global
 		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{48840edd-24bf-495d-911e-2eb12ae75d3b}*SharedItemsImports = 13
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{7863ea94-f0fb-4386-bf8c-e5bfa761560a}*SharedItemsImports = 4
-		src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4
 		src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
 		src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{9defc6b7-845b-4d8f-afc0-d32bf0032b8c}*SharedItemsImports = 13
 		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{dabfd304-d6a4-4752-8123-c2ccf7ac7831}*SharedItemsImports = 4
-		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{e106cf37-4066-4615-b684-172a6d30b058}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
-		src\Shared\RenderHelpers\RenderHelpers.projitems*{fb05ac90-89ba-4f2f-a924-f37875fb547c}*SharedItemsImports = 4
 	EndGlobalSection
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@@ -1053,44 +1055,6 @@ Global
 		{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Mono.ActiveCfg = Release|Any CPU
 		{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|x86.ActiveCfg = Release|Any CPU
 		{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|x86.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|Mono.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|x86.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.AppStore|x86.Build.0 = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|Mono.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|Mono.Build.0 = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Debug|x86.Build.0 = Debug|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhone.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|Mono.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|Mono.Build.0 = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|x86.ActiveCfg = Release|Any CPU
-		{E106CF37-4066-4615-B684-172A6D30B058}.Release|x86.Build.0 = Release|Any CPU
 		{99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
 		{99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
 		{99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -1167,82 +1131,6 @@ Global
 		{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Mono.Build.0 = Release|Any CPU
 		{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|x86.ActiveCfg = Release|Any CPU
 		{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|x86.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|Mono.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|x86.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|x86.Build.0 = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|Mono.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|Mono.Build.0 = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|x86.Build.0 = Debug|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|Any CPU.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhone.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|Mono.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|Mono.Build.0 = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|x86.ActiveCfg = Release|Any CPU
-		{54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|x86.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|Mono.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|x86.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|x86.Build.0 = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|Mono.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|Mono.Build.0 = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|x86.Build.0 = Debug|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhone.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|Mono.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|Mono.Build.0 = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|x86.ActiveCfg = Release|Any CPU
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|x86.Build.0 = Release|Any CPU
 		{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
 		{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
 		{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -1985,46 +1873,6 @@ Global
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|Mono.ActiveCfg = Release|Any CPU
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|x86.ActiveCfg = Release|Any CPU
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|x86.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|x86.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Mono.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Mono.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|x86.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|x86.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Mono.ActiveCfg = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Mono.Build.0 = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|x86.Build.0 = Debug|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhone.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Mono.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Mono.Build.0 = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|x86.ActiveCfg = Release|Any CPU
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|x86.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
@@ -2519,6 +2367,166 @@ Global
 		{E1582370-37B3-403C-917F-8209551B1634}.Release|Mono.Build.0 = Release|Any CPU
 		{E1582370-37B3-403C-917F-8209551B1634}.Release|x86.ActiveCfg = Release|Any CPU
 		{E1582370-37B3-403C-917F-8209551B1634}.Release|x86.Build.0 = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Mono.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Mono.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|x86.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|x86.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Mono.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|x86.Build.0 = Debug|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhone.Build.0 = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Mono.ActiveCfg = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Mono.Build.0 = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|x86.ActiveCfg = Release|Any CPU
+		{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|x86.Build.0 = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Mono.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Mono.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|x86.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|x86.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Mono.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|x86.Build.0 = Debug|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhone.Build.0 = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Mono.ActiveCfg = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Mono.Build.0 = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|x86.ActiveCfg = Release|Any CPU
+		{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|x86.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|x86.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Any CPU.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhone.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhone.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Mono.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Mono.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|x86.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|x86.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Mono.Build.0 = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|x86.Build.0 = Debug|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhone.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Mono.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Mono.Build.0 = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|x86.ActiveCfg = Release|Any CPU
+		{050CC912-FF49-4A8B-B534-9544017446DD}.Release|x86.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|x86.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Any CPU.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhone.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhone.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Mono.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Mono.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|x86.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|x86.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Mono.Build.0 = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|x86.Build.0 = Debug|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{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
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Mono.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Mono.Build.0 = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|x86.ActiveCfg = Release|Any CPU
+		{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|x86.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
@@ -2559,6 +2567,46 @@ Global
 		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Mono.Build.0 = Release|Any CPU
 		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|x86.ActiveCfg = Release|Any CPU
 		{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|x86.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}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|x86.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}.AppStore|Mono.ActiveCfg = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|Mono.Build.0 = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|x86.ActiveCfg = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|x86.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}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|Mono.Build.0 = Debug|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|x86.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
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|Mono.ActiveCfg = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|Mono.Build.0 = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|x86.ActiveCfg = Release|Any CPU
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -2576,11 +2624,8 @@ Global
 		{DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{AC18926A-E784-40FE-B09D-BB0FE2B599F0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
-		{E106CF37-4066-4615-B684-172A6D30B058} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
 		{3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C}
-		{54F237D5-A70A-4752-9656-0C70B1A7B047} = {B9894058-278A-46B5-B6ED-AD613FCC03B3}
-		{FB05AC90-89BA-4F2F-A924-F37875FB547C} = {B9894058-278A-46B5-B6ED-AD613FCC03B3}
 		{E4D9629C-F168-4224-3F51-A5E482FFBC42} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
 		{6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C}
 		{8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
@@ -2602,7 +2647,6 @@ Global
 		{FBCAF3D0-2808-4934-8E96-3F607594517B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{A0CC0258-D18C-4AB3-854F-7101680FC3F9} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{C7A69145-60B6-4882-97D6-A3921DD43978} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
-		{BD7F352C-6DC1-4740-BAF2-2D34A038728C} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{9DEFC6B7-845B-4D8F-AFC0-D32BF0032B8C} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
@@ -2616,7 +2660,10 @@ Global
 		{638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
 		{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
 		{E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
-		{CBFD5788-567D-401B-9DFA-74E4224025A0} = {A59C4C0A-64DF-4621-B450-2BA00D6F61E2}
+		{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}
+		{4ADA61C8-D191-428D-9066-EF4F0D86520F} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

+ 0 - 3
appveyor.yml

@@ -16,9 +16,7 @@ environment:
 init:
 - ps: if (Test-Path env:nuget_address) {[System.IO.File]::AppendAllText("C:\Windows\System32\drivers\etc\hosts", "`n$($env:nuget_address)`tapi.nuget.org")}
 install:
-  - if not exist gtk-sharp-2.12.26.msi appveyor DownloadFile http://download.xamarin.com/GTKforWindows/Windows/gtk-sharp-2.12.26.msi
   - if not exist dotnet-2.0.0.exe appveyor DownloadFile https://download.microsoft.com/download/0/F/D/0FD852A4-7EA1-4E2A-983A-0484AC19B92C/dotnet-sdk-2.0.0-win-x64.exe -FileName "dotnet-2.0.0.exe"
-  - ps: Start-Process -FilePath "msiexec" -ArgumentList "/i gtk-sharp-2.12.26.msi /quiet /qn /norestart" -Wait
   - ps: Start-Process -FilePath "dotnet-2.0.0.exe" -ArgumentList "/quiet" -Wait
   - cmd: set PATH=%programfiles(x86)%\GtkSharp\2.12\bin\;%PATH%
 before_build:
@@ -36,5 +34,4 @@ artifacts:
   - path: artifacts\zip\*.zip
   - path: artifacts\inspectcode.xml
 cache:
-  - gtk-sharp-2.12.26.msi
   - dotnet-2.0.0.exe

+ 0 - 2
build/NetCore.props

@@ -1,6 +1,4 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
-    <PackageReference Include="Microsoft.Extensions.DependencyModel" Version="1.1.0" />
   </ItemGroup>
 </Project>

+ 0 - 6
docs/guidelines/build.md

@@ -4,12 +4,6 @@
 
 Avalonia requires at least Visual Studio 2017 and .NET Core SDK 2.0 to build on Windows.
 
-### Install GTK Sharp
-
-For the moment under windows, you must have [gtk-sharp](http://www.mono-project.com/download/#download-win)
-installed. Note that after installing the package your machine may require a restart before GTK# is
-added to your path. We hope to remove or make this dependency optional at some point in the future.
-
 ### Clone the Avalonia repository
 
 ```

+ 32 - 47
packages.cake

@@ -223,6 +223,17 @@ public class Packages
             };
         });
 
+        var toolsContent = new[] {
+            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"
+            },
+            new NuSpecContent{
+                Source = ((FilePath)context.File("./src/tools/Avalonia.Designer.HostApp.NetFx/bin/" + parameters.DirSuffix + "/Avalonia.Designer.HostApp.exe")).FullPath, 
+                Target = "tools/net461/previewer"
+            }
+        };
+
         var nuspecNuGetSettingsCore = new []
         {
             ///////////////////////////////////////////////////////////////////////////////
@@ -237,6 +248,7 @@ public class Packages
                     new NuSpecDependency() { Id = "Splat", Version = SplatVersion },
                     new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion },
                     new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion },
+                    new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", Version = parameters.Version },
                     //.NET Core
                     new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp2.0", Version = "4.3.0" },
                     new NuSpecDependency() { Id = "Microsoft.Extensions.DependencyModel", TargetFramework = "netcoreapp2.0", Version = "1.1.0" },
@@ -245,6 +257,7 @@ public class Packages
                     new NuSpecDependency() { Id = "Serilog", TargetFramework = "netcoreapp2.0", Version = SerilogVersion },
                     new NuSpecDependency() { Id = "Sprache", TargetFramework = "netcoreapp2.0", Version = SpracheVersion },
                     new NuSpecDependency() { Id = "System.Reactive", TargetFramework = "netcoreapp2.0", Version = SystemReactiveVersion },
+                    new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", TargetFramework = "netcoreapp2.0", Version = parameters.Version },
                 }
                 .Deps(new string[]{null, "netcoreapp2.0"},
                     "System.ValueTuple", "System.ComponentModel.TypeConverter", "System.ComponentModel.Primitives",
@@ -253,6 +266,7 @@ public class Packages
                 Files = coreLibrariesNuSpecContent
                     .Concat(win32CoreLibrariesNuSpecContent).Concat(net45RuntimePlatform)
                     .Concat(netcoreappCoreLibrariesNuSpecContent).Concat(netCoreRuntimePlatform)
+                    .Concat(toolsContent)
                     .ToList(),
                 BasePath = context.Directory("./"),
                 OutputDirectory = parameters.NugetRoot
@@ -291,6 +305,19 @@ public class Packages
                 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 []
@@ -375,23 +402,6 @@ public class Packages
                 OutputDirectory = parameters.NugetRoot
             },
             ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Gtk
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Gtk",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
-                },
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.Gtk.dll", Target = "lib/net45" }
-                },
-                BasePath = context.Directory("./src/Gtk/Avalonia.Gtk/bin/" + parameters.DirSuffix),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
             // Avalonia.Gtk3
             ///////////////////////////////////////////////////////////////////////////////
             new NuGetPackSettings()
@@ -409,23 +419,6 @@ public class Packages
                 OutputDirectory = parameters.NugetRoot
             },
             ///////////////////////////////////////////////////////////////////////////////
-            // Avalonia.Cairo
-            ///////////////////////////////////////////////////////////////////////////////
-            new NuGetPackSettings()
-            {
-                Id = "Avalonia.Cairo",
-                Dependencies = new []
-                {
-                    new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
-                },
-                Files = new []
-                {
-                    new NuSpecContent { Source = "Avalonia.Cairo.dll", Target = "lib/net45" }
-                },
-                BasePath = context.Directory("./src/Gtk/Avalonia.Cairo/bin/" + parameters.DirSuffix),
-                OutputDirectory = parameters.NugetRoot
-            },
-            ///////////////////////////////////////////////////////////////////////////////
             // Avalonia.Skia
             ///////////////////////////////////////////////////////////////////////////////
             new NuGetPackSettings()
@@ -471,19 +464,11 @@ public class Packages
                 Id = "Avalonia.Desktop",
                 Dependencies = new []
                 {
-                    //Full .NET
-                    new NuSpecDependency() { Id = "Avalonia.Direct2D1", TargetFramework="net45", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Gtk", TargetFramework="net45", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Cairo", TargetFramework="net45", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="net45", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Skia", TargetFramework="net45", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="net45", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.MonoMac", TargetFramework="net45", Version = parameters.Version },
-                    //.NET Core
-                    new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="netcoreapp2.0", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Skia", TargetFramework="netcoreapp2.0", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="netcoreapp2.0", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.MonoMac", TargetFramework="netcoreapp2.0", Version = parameters.Version }
+                    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[]
                 {

+ 2 - 2
readme.md

@@ -7,7 +7,7 @@
 
 A multi-platform .NET UI framework. It can run on Windows, Linux, Mac OS X, iOS and Android.
 
-![](docs/images/screen.png)
+[![](docs/images/screen.png)](https://youtu.be/wHcB3sGLVYg)
 
 Desktop platforms:
 
@@ -36,7 +36,7 @@ Try out the ControlCatalog to give it a quick demo.
 
 Avalonia is a multi-platform windowing toolkit - somewhat like WPF - that is intended to be multi-
 platform. It supports XAML, lookless controls and a flexible styling system, and runs on Windows
-using Direct2D and other operating systems using Gtk & Cairo.
+using Direct2D and other operating systems using Skia and OS-specific windowing backend (GTK, Cocoa, etc).
 
 ## Current Status
 

+ 0 - 8
samples/BindingTest/BindingTest.csproj

@@ -148,14 +148,6 @@
       <Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project>
       <Name>Avalonia.Win32</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj">
-      <Project>{54F237D5-A70A-4752-9656-0C70B1A7B047}</Project>
-      <Name>Avalonia.Gtk</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj">
-      <Project>{FB05AC90-89BA-4F2F-A924-F37875FB547C}</Project>
-      <Name>Avalonia.Cairo</Name>
-    </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="..\..\build\Serilog.props" />

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

@@ -63,18 +63,10 @@
       <Project>{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}</Project>
       <Name>Avalonia.DotNetFrameworkRuntime</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj">
-      <Project>{FB05AC90-89BA-4F2F-A924-F37875FB547C}</Project>
-      <Name>Avalonia.Cairo</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\src\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj">
       <Project>{bb1f7bb5-6ad4-4776-94d9-c09d0a972658}</Project>
       <Name>Avalonia.Gtk3</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj">
-      <Project>{54F237D5-A70A-4752-9656-0C70B1A7B047}</Project>
-      <Name>Avalonia.Gtk</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
       <Project>{3E53A01A-B331-47F3-B828-4A5717E77A24}</Project>
       <Name>Avalonia.Markup.Xaml</Name>

+ 7 - 3
samples/ControlCatalog.Desktop/Program.cs

@@ -16,11 +16,15 @@ namespace ControlCatalog
 
             // TODO: Make this work with GTK/Skia/Cairo depending on command-line args
             // again.
-            AppBuilder.Configure<App>()
-                .UsePlatformDetect()
-                .Start<MainWindow>();
+            BuildAvaloniaApp().Start<MainWindow>();
         }
 
+        /// <summary>
+        /// This method is needed for IDE previewer infrastructure
+        /// </summary>
+        public static AppBuilder BuildAvaloniaApp()
+            => AppBuilder.Configure<App>().UsePlatformDetect();
+
         // This will be made into a runtime configuration extension soon!
         private static void InitializeLogging()
         {

+ 6 - 11
samples/ControlCatalog.NetCore/Program.cs

@@ -28,19 +28,14 @@ namespace ControlCatalog.NetCore
                     System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer());
                 });
             else
-                AppBuilder.Configure<App>()
-                    .CustomPlatformDetect()
-                    .UseReactiveUI()
-                    .Start<MainWindow>();
+                BuildAvaloniaApp().Start<MainWindow>();
         }
 
-        static AppBuilder CustomPlatformDetect(this AppBuilder builder)
-        {
-            //This is needed because we still aren't ready to have MonoMac backend as default one
-            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
-                return builder.UseSkia().UseMonoMac();
-            return builder.UsePlatformDetect();
-        }
+        /// <summary>
+        /// This method is needed for IDE previewer infrastructure
+        /// </summary>
+        public static AppBuilder BuildAvaloniaApp()
+            => AppBuilder.Configure<App>().UsePlatformDetect().UseReactiveUI();
 
         static void ConsoleSilencer()
         {

BIN
samples/ControlCatalog/Assets/test_icon.ico


+ 6 - 0
samples/ControlCatalog/ControlCatalog.csproj

@@ -69,6 +69,9 @@
     <EmbeddedResource Include="Pages\MenuPage.xaml">
       <SubType>Designer</SubType>
     </EmbeddedResource>
+    <EmbeddedResource Include="Pages\ProgressBarPage.xaml">
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
     <EmbeddedResource Include="Pages\RadioButtonPage.xaml">
       <SubType>Designer</SubType>
     </EmbeddedResource>
@@ -131,6 +134,9 @@
     <Compile Include="Pages\MenuPage.xaml.cs">
       <DependentUpon>MenuPage.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Pages\ProgressBarPage.xaml.cs">
+      <DependentUpon>ProgressBarPage.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Pages\RadioButtonPage.xaml.cs">
       <DependentUpon>RadioButtonPage.xaml</DependentUpon>
     </Compile>

+ 1 - 0
samples/ControlCatalog/MainView.xaml

@@ -16,6 +16,7 @@
     <TabItem Header="Image"><pages:ImagePage/></TabItem>
     <TabItem Header="LayoutTransformControl"><pages:LayoutTransformControlPage/></TabItem>
     <TabItem Header="Menu"><pages:MenuPage/></TabItem>
+    <TabItem Header="ProgressBar"><pages:ProgressBarPage/></TabItem>
     <TabItem Header="RadioButton"><pages:RadioButtonPage/></TabItem>
     <TabItem Header="Slider"><pages:SliderPage/></TabItem>
     <TabItem Header="TextBox"><pages:TextBoxPage/></TabItem>

+ 1 - 0
samples/ControlCatalog/MainWindow.xaml.cs

@@ -11,6 +11,7 @@ namespace ControlCatalog
         {
             this.InitializeComponent();
             this.AttachDevTools();
+            //Renderer.DrawFps = true;
             //Renderer.DrawDirtyRects = Renderer.DrawFps = true;
         }
 

+ 24 - 0
samples/ControlCatalog/Pages/ProgressBarPage.xaml

@@ -0,0 +1,24 @@
+<UserControl xmlns="https://github.com/avaloniaui">
+  <StackPanel Orientation="Vertical" Gap="4">
+    <TextBlock Classes="h1">ProgressBar</TextBlock>
+    <TextBlock Classes="h2">A progress bar control</TextBlock>
+
+    <StackPanel>
+      <StackPanel Orientation="Horizontal"
+                  Margin="0,16,0,0"
+                  HorizontalAlignment="Center"
+                  Gap="16">
+        <StackPanel Gap="16">
+          <ProgressBar Value="{Binding #hprogress.Value}" />
+          <ProgressBar IsIndeterminate="True"/>
+        </StackPanel>
+        <ProgressBar Value="{Binding #vprogress.Value}" Orientation="Vertical" />
+        <ProgressBar Orientation="Vertical" IsIndeterminate="True" />
+      </StackPanel>
+      <StackPanel Margin="16">
+        <Slider Name="hprogress" Maximum="100" Value="40"/>
+        <Slider Name="vprogress" Maximum="100" Value="60"/>
+      </StackPanel>
+    </StackPanel>
+  </StackPanel>
+</UserControl>

+ 18 - 0
samples/ControlCatalog/Pages/ProgressBarPage.xaml.cs

@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+    public class ProgressBarPage : UserControl
+    {
+        public ProgressBarPage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 2 - 2
samples/ControlCatalog/Pages/ToolTipPage.xaml

@@ -10,7 +10,7 @@
               HorizontalAlignment="Center">
             <Border Grid.Column="0"
                     Grid.Row="1"
-                    Background="{StyleResource ThemeAccentBrush}"
+                    Background="{DynamicResource ThemeAccentBrush}"
                     Margin="5"
                     Padding="50"
                     ToolTip.Tip="This is a ToolTip">
@@ -24,7 +24,7 @@
             <Border Name="Border"
                     Grid.Column="1"
                     Grid.Row="1"
-                    Background="{StyleResource ThemeAccentBrush}"
+                    Background="{DynamicResource ThemeAccentBrush}"
                     Margin="5"
                     Padding="50"
                     ToolTip.Placement="Bottom">

+ 0 - 126
samples/ControlCatalog/Program.cs

@@ -1,126 +0,0 @@
-using Avalonia.Logging.Serilog;
-using Serilog;
-using System;
-using System.Linq;
-using Avalonia;
-
-namespace ControlCatalog
-{
-    internal class Program
-    {
-        static void Main(string[] args)
-        {
-            InitializeLogging();
-
-            new App()
-                .ConfigureRenderSystem(args)
-                .LoadFromXaml()
-                .RunWithMainWindow<MainWindow>();
-        }
-
-        // This will be made into a runtime configuration extension soon!
-        private static void InitializeLogging()
-        {
-#if DEBUG
-            SerilogLogger.Initialize(new LoggerConfiguration()
-                .MinimumLevel.Warning()
-                .WriteTo.Trace(outputTemplate: "{Area}: {Message}")
-                .CreateLogger());
-#endif
-        }
-
-    }
-
-    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
-    // Experimental: Would like to move this into a shared location once I figure out the best place for it 
-    // considering all common libraries are PCL and do not have access to Environment.OSVersion.Platform
-    // nor do they have access to the platform specific render/subsystem extensions.
-    // 
-    // Perhaps via DI we register each system with a priority/rank
-    //
-    public static class RenderSystemExtensions
-    {
-        [Flags]
-        enum RenderSystem
-        {
-            None = 0,
-            GTK = 1,
-            Skia = 2,
-            Direct2D = 4
-        };
-
-        /// <summary>
-        /// Default (Optimal) render system for a particular platform
-        /// </summary>
-        /// <returns></returns>
-        private static RenderSystem DefaultRenderSystem()
-        {
-            switch (Environment.OSVersion.Platform)
-            {
-                case PlatformID.MacOSX:
-                    return RenderSystem.GTK;
-
-                case PlatformID.Unix:
-                    return RenderSystem.GTK;
-
-                case PlatformID.Win32Windows:
-                    return RenderSystem.Direct2D;
-            }
-
-            return RenderSystem.None;
-        }
-
-        /// <summary>
-        /// Returns an array of avalidable rendering systems in priority order
-        /// </summary>
-        /// <returns></returns>
-        private static RenderSystem[] AvailableRenderSystems()
-        {
-            switch (Environment.OSVersion.Platform)
-            {
-                case PlatformID.MacOSX:
-                    return new RenderSystem[] { RenderSystem.GTK, RenderSystem.Skia };
-
-                case PlatformID.Unix:
-                    return new RenderSystem[] { RenderSystem.GTK, RenderSystem.Skia };
-
-                case PlatformID.Win32Windows:
-                    return new RenderSystem[] { RenderSystem.Direct2D, RenderSystem.Skia, RenderSystem.GTK };
-            }
-
-            return new RenderSystem[0];
-        }
-
-        /// <summary>
-        /// Selects the optimal render system for desktop platforms. Supports cmd line overrides
-        /// </summary>
-        /// <param name="app"></param>
-        /// <param name="args"></param>
-        public static TApp ConfigureRenderSystem<TApp>(this TApp app, string[] args) where TApp : Application
-        {
-            // So this all works great under Windows where it can support
-            // ALL configurations. But on OSX/Unix we cannot use Direct2D
-            //
-            if (args.Contains("--gtk") || DefaultRenderSystem() == RenderSystem.GTK)
-            {
-                app.UseGtk();
-                app.UseCairo();
-            }
-            else
-            {
-                app.UseWin32();
-
-                if (args.Contains("--skia") || DefaultRenderSystem() == RenderSystem.Skia)
-                {
-                    app.UseSkia();
-                }
-                else
-                {
-                    app.UseDirect2D();
-                }
-            }
-
-            return app;
-        }
-    }
-}

+ 6 - 0
samples/Previewer/App.xaml

@@ -0,0 +1,6 @@
+<Application xmlns="https://github.com/avaloniaui">
+    <Application.Styles>
+        <StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/>
+        <StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
+    </Application.Styles>
+</Application>

+ 14 - 0
samples/Previewer/App.xaml.cs

@@ -0,0 +1,14 @@
+using Avalonia;
+using Avalonia.Markup.Xaml;
+
+namespace Previewer
+{
+    public class App : Application
+    {
+        public override void Initialize()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+
+}

+ 19 - 0
samples/Previewer/Center.cs

@@ -0,0 +1,19 @@
+using Avalonia;
+using Avalonia.Controls;
+
+namespace Previewer
+{
+    public class Center : Decorator
+    {
+        protected override Size ArrangeOverride(Size finalSize)
+        {
+            if (Child != null)
+            {
+                var desired = Child.DesiredSize;
+                Child.Arrange(new Rect((finalSize.Width - desired.Width) / 2, (finalSize.Height - desired.Height) / 2,
+                    desired.Width, desired.Height));
+            }
+            return finalSize;
+        }
+    }
+}

+ 12 - 0
samples/Previewer/MainWindow.xaml

@@ -0,0 +1,12 @@
+<Window xmlns="https://github.com/avaloniaui" Width="600" Height="500"
+        Title="Previewer">
+    <Grid RowDefinitions="0.5*,200">
+        <ScrollViewer Name="Remote"/>
+        
+        <ScrollViewer Name="ErrorsContainer" Background="#ffe0e0">
+            <TextBlock Name="Errors"/>
+        </ScrollViewer>
+        <TextBox Grid.Row="1" AcceptsReturn="True" Name="Xaml"/>
+    </Grid>
+    
+</Window>

+ 86 - 0
samples/Previewer/MainWindow.xaml.cs

@@ -0,0 +1,86 @@
+using System;
+using System.Net;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Remote;
+using Avalonia.Markup.Xaml;
+using Avalonia.Remote.Protocol;
+using Avalonia.Remote.Protocol.Designer;
+using Avalonia.Remote.Protocol.Viewport;
+using Avalonia.Threading;
+
+namespace Previewer
+{
+    public class MainWindow : Window
+    {
+        private const string InitialXaml = @"<Window xmlns=""https://github.com/avaloniaui"" Width=""600"" Height=""500"">
+        <TextBlock>Hello world!</TextBlock>
+    
+        </Window>";
+        private IAvaloniaRemoteTransportConnection _connection;
+        private Control _errorsContainer;
+        private TextBlock _errors;
+        private RemoteWidget _remote;
+
+
+        public MainWindow()
+        {
+            this.InitializeComponent();
+            var tb = this.FindControl<TextBox>("Xaml");
+            tb.Text = InitialXaml;
+            var scroll = this.FindControl<ScrollViewer>("Remote");
+            var rem = new Center();
+            scroll.Content = rem;
+            _errorsContainer = this.FindControl<Control>("ErrorsContainer");
+            _errors = this.FindControl<TextBlock>("Errors");
+            tb.GetObservable(TextBox.TextProperty).Subscribe(text => _connection?.Send(new UpdateXamlMessage
+            {
+                Xaml = text
+            }));
+            new BsonTcpTransport().Listen(IPAddress.Loopback, 25000, t =>
+            {
+                Dispatcher.UIThread.InvokeAsync(() =>
+                {
+                    if (_connection != null)
+                    {
+                        _connection.Dispose();
+                        _connection.OnMessage -= OnMessage;
+                    }
+                    _connection = t;
+                    rem.Child = _remote = new RemoteWidget(t);
+                    t.Send(new UpdateXamlMessage
+                    {
+                        Xaml = tb.Text
+                    });
+                    
+                    t.OnMessage += OnMessage;
+                });
+            });
+            Title = "Listening on 127.0.0.1:25000";
+        }
+
+        private void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
+        {
+            Dispatcher.UIThread.InvokeAsync(() =>
+            {
+                if (transport != _connection)
+                    return;
+                if (obj is UpdateXamlResultMessage result)
+                {
+                    _errorsContainer.IsVisible = result.Error != null;
+                    _errors.Text = result.Error ?? "";
+                }
+                if (obj is RequestViewportResizeMessage resize)
+                {
+                    _remote.Width = Math.Min(4096, Math.Max(resize.Width, 1));
+                    _remote.Height = Math.Min(4096, Math.Max(resize.Height, 1));
+                }
+            });
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 27 - 0
samples/Previewer/Previewer.csproj

@@ -0,0 +1,27 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Update="**\*.xaml.cs">
+      <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.HtmlRenderer\Avalonia.HtmlRenderer.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>

+ 13 - 0
samples/Previewer/Program.cs

@@ -0,0 +1,13 @@
+using System;
+using Avalonia;
+
+namespace Previewer
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            AppBuilder.Configure<App>().UsePlatformDetect().Start<MainWindow>();
+        }
+    }
+}

+ 53 - 0
samples/RemoteTest/Program.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Remote;
+using Avalonia.Remote.Protocol;
+using Avalonia.Threading;
+using ControlCatalog;
+
+namespace RemoteTest
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            AppBuilder.Configure<App>().UsePlatformDetect().SetupWithoutStarting();
+
+            var l = new TcpListener(IPAddress.Loopback, 0);
+            l.Start();
+            var port = ((IPEndPoint) l.LocalEndpoint).Port;
+            l.Stop();
+            
+            var transport = new BsonTcpTransport();
+            transport.Listen(IPAddress.Loopback, port, sc =>
+            {
+                Dispatcher.UIThread.InvokeAsync(() =>
+                {
+                    new RemoteServer(sc).Content = new MainView();
+                });
+            });
+
+            var cts = new CancellationTokenSource();
+            transport.Connect(IPAddress.Loopback, port).ContinueWith(t =>
+            {
+                Dispatcher.UIThread.InvokeAsync(() =>
+                {
+                    var window = new Window()
+                    {
+                        Content = new RemoteWidget(t.Result)
+                    };
+                    window.Closed += delegate { cts.Cancel(); };
+                    window.Show();
+                });
+            });
+            Dispatcher.UIThread.MainLoop(cts.Token);
+
+
+
+        }
+    }
+}

+ 25 - 0
samples/RemoteTest/RemoteTest.csproj

@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+  </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>
+
+</Project>

+ 0 - 8
samples/RenderTest/RenderTest.csproj

@@ -132,14 +132,6 @@
       <Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
       <Name>Avalonia.Themes.Default</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj">
-      <Project>{fb05ac90-89ba-4f2f-a924-f37875fb547c}</Project>
-      <Name>Avalonia.Cairo</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj">
-      <Project>{54f237d5-a70a-4752-9656-0c70b1a7b047}</Project>
-      <Name>Avalonia.Gtk</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
       <Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
       <Name>Avalonia.Markup.Xaml</Name>

+ 0 - 8
samples/VirtualizationTest/VirtualizationTest.csproj

@@ -134,14 +134,6 @@
       <Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project>
       <Name>Avalonia.Win32</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj">
-      <Project>{FB05AC90-89BA-4F2F-A924-F37875FB547C}</Project>
-      <Name>Avalonia.Cairo</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj">
-      <Project>{54F237D5-A70A-4752-9656-0C70B1A7B047}</Project>
-      <Name>Avalonia.Gtk</Name>
-    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="App.xaml">

+ 3 - 2
samples/interop/Direct3DInteropSample/MainWindow.cs

@@ -253,8 +253,9 @@ namespace Direct3DInteropSample
 
             public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
             {
-                return new DrawingContextImpl(visualBrushRenderer, _window._d2dRenderTarget,
-                    AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>());
+                return new DrawingContextImpl(visualBrushRenderer, null, _window._d2dRenderTarget,
+                    AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>(),
+                    AvaloniaLocator.Current.GetService<ImagingFactory>());
             }
         }
 

+ 0 - 6
samples/interop/GtkInteropDemo/App.config

@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
-    </startup>
-</configuration>

+ 0 - 154
samples/interop/GtkInteropDemo/GtkInteropDemo.csproj

@@ -1,154 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{BD7F352C-6DC1-4740-BAF2-2D34A038728C}</ProjectGuid>
-    <OutputType>WinExe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>GtkInteropDemo</RootNamespace>
-    <AssemblyName>GtkInteropDemo</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <UseVSHostingProcess>false</UseVSHostingProcess>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
-    <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
-    <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
-    <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Deployment" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="MainWindow.cs" />
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <EmbeddedResource Include="Properties\Resources.resx">
-      <Generator>ResXFileCodeGenerator</Generator>
-      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
-    <Compile Include="Properties\Resources.Designer.cs">
-      <AutoGen>True</AutoGen>
-      <DependentUpon>Resources.resx</DependentUpon>
-    </Compile>
-    <None Include="Properties\Settings.settings">
-      <Generator>SettingsSingleFileGenerator</Generator>
-      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
-    </None>
-    <Compile Include="Properties\Settings.Designer.cs">
-      <AutoGen>True</AutoGen>
-      <DependentUpon>Settings.settings</DependentUpon>
-      <DesignTimeSharedInput>True</DesignTimeSharedInput>
-    </Compile>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="App.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\..\src\Avalonia.Animation\Avalonia.Animation.csproj">
-      <Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
-      <Name>Avalonia.Animation</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.Base\Avalonia.Base.csproj">
-      <Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
-      <Name>Avalonia.Base</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.Controls\Avalonia.Controls.csproj">
-      <Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
-      <Name>Avalonia.Controls</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>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
-      <Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
-      <Name>Avalonia.Interactivity</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.Layout\Avalonia.Layout.csproj">
-      <Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
-      <Name>Avalonia.Layout</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj">
-      <Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
-      <Name>Avalonia.ReactiveUI</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj">
-      <Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
-      <Name>Avalonia.Visuals</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.Styling\Avalonia.Styling.csproj">
-      <Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
-      <Name>Avalonia.Styling</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj">
-      <Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
-      <Name>Avalonia.Themes.Default</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj">
-      <Project>{fb05ac90-89ba-4f2f-a924-f37875fb547c}</Project>
-      <Name>Avalonia.Cairo</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj">
-      <Project>{54f237d5-a70a-4752-9656-0c70b1a7b047}</Project>
-      <Name>Avalonia.Gtk</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
-      <Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
-      <Name>Avalonia.Markup.Xaml</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj">
-      <Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
-      <Name>Avalonia.Markup</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj">
-      <Project>{7d2d3083-71dd-4cc9-8907-39a0d86fb322}</Project>
-      <Name>Avalonia.Skia</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\ControlCatalog\ControlCatalog.csproj">
-      <Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project>
-      <Name>ControlCatalog</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="..\..\..\build\Rx.props" />
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-</Project>

+ 0 - 30
samples/interop/GtkInteropDemo/MainWindow.cs

@@ -1,30 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Diagnostics;
-using Avalonia.Gtk.Embedding;
-using ControlCatalog;
-using Gtk;
-
-namespace GtkInteropDemo
-{
-    class MainWindow : Window
-    {
-        public MainWindow() : base("Gtk Embedding Demo")
-        {
-            var root = new HBox();
-            var left  = new VBox();
-            left.Add(new Button("I'm GTK button"));
-            left.Add(new Calendar());
-            root.PackEnd(left, false, false, 0);
-            var host = new GtkAvaloniaControlHost() {Content = new MainView()};
-            host.SetSizeRequest(600, 600);
-            root.PackStart(host, true, true, 0);
-            Add(root);
-            
-            ShowAll();
-        }
-    }
-}

+ 0 - 24
samples/interop/GtkInteropDemo/Program.cs

@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Avalonia;
-using Avalonia.Controls;
-using ControlCatalog;
-
-namespace GtkInteropDemo
-{
-    static class Program
-    {
-        /// <summary>
-        /// The main entry point for the application.
-        /// </summary>
-        [STAThread]
-        static void Main()
-        {
-            AppBuilder.Configure<App>().UseGtk().UseCairo().SetupWithoutStarting();
-            new MainWindow().Show();
-            Gtk.Application.Run();
-        }
-    }
-}

+ 0 - 36
samples/interop/GtkInteropDemo/Properties/AssemblyInfo.cs

@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("GtkInteropDemo")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("GtkInteropDemo")]
-[assembly: AssemblyCopyright("Copyright ©  2016")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("bd7f352c-6dc1-4740-baf2-2d34a038728c")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 0 - 71
samples/interop/GtkInteropDemo/Properties/Resources.Designer.cs

@@ -1,71 +0,0 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-//     This code was generated by a tool.
-//     Runtime Version:4.0.30319.42000
-//
-//     Changes to this file may cause incorrect behavior and will be lost if
-//     the code is regenerated.
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-namespace GtkInteropDemo.Properties
-{
-
-
-    /// <summary>
-    ///   A strongly-typed resource class, for looking up localized strings, etc.
-    /// </summary>
-    // This class was auto-generated by the StronglyTypedResourceBuilder
-    // class via a tool like ResGen or Visual Studio.
-    // To add or remove a member, edit your .ResX file then rerun ResGen
-    // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    internal class Resources
-    {
-
-        private static global::System.Resources.ResourceManager resourceMan;
-
-        private static global::System.Globalization.CultureInfo resourceCulture;
-
-        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
-        internal Resources()
-        {
-        }
-
-        /// <summary>
-        ///   Returns the cached ResourceManager instance used by this class.
-        /// </summary>
-        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Resources.ResourceManager ResourceManager
-        {
-            get
-            {
-                if ((resourceMan == null))
-                {
-                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GtkInteropDemo.Properties.Resources", typeof(Resources).Assembly);
-                    resourceMan = temp;
-                }
-                return resourceMan;
-            }
-        }
-
-        /// <summary>
-        ///   Overrides the current thread's CurrentUICulture property for all
-        ///   resource lookups using this strongly typed resource class.
-        /// </summary>
-        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Globalization.CultureInfo Culture
-        {
-            get
-            {
-                return resourceCulture;
-            }
-            set
-            {
-                resourceCulture = value;
-            }
-        }
-    }
-}

+ 0 - 117
samples/interop/GtkInteropDemo/Properties/Resources.resx

@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-</root>

+ 0 - 30
samples/interop/GtkInteropDemo/Properties/Settings.Designer.cs

@@ -1,30 +0,0 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-//     This code was generated by a tool.
-//     Runtime Version:4.0.30319.42000
-//
-//     Changes to this file may cause incorrect behavior and will be lost if
-//     the code is regenerated.
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-namespace GtkInteropDemo.Properties
-{
-
-
-    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
-    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
-    {
-
-        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
-        public static Settings Default
-        {
-            get
-            {
-                return defaultInstance;
-            }
-        }
-    }
-}

+ 0 - 7
samples/interop/GtkInteropDemo/Properties/Settings.settings

@@ -1,7 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
-  <Profiles>
-    <Profile Name="(Default)" />
-  </Profiles>
-  <Settings />
-</SettingsFile>

+ 4 - 5
scripts/ReplaceNugetCache.ps1

@@ -1,5 +1,4 @@
-copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\
-copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.3\
-copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.3\
-copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\
-copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.3\
+copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp2.0\
+copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard2.0\
+copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard2.0\
+copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard2.0\

+ 3 - 4
scripts/ReplaceNugetCache.sh

@@ -1,7 +1,6 @@
  #!/usr/bin/env bash
  
- cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp1.0/
- cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard1.1/
- cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard1.1/
- cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.skia.desktop/$1/lib/netstandard1.3/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp2.0/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard2.0/
  

+ 4 - 5
scripts/ReplaceNugetCacheRelease.ps1

@@ -1,5 +1,4 @@
-copy ..\samples\ControlCatalog.NetCore\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\
-copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.3\
-copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.3\
-copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\
-copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.3\
+copy ..\samples\ControlCatalog.NetCore\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp2.0\
+copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard2.0\
+copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard2.0\
+copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard2.0\

+ 5 - 4
src/Android/Avalonia.Android/AndroidThreadingInterface.cs

@@ -12,6 +12,7 @@ using Android.Runtime;
 using Android.Views;
 using Android.Widget;
 using Avalonia.Platform;
+using Avalonia.Threading;
 
 namespace Avalonia.Android
 {
@@ -29,7 +30,7 @@ namespace Avalonia.Android
             return;
         }
 
-        public IDisposable StartTimer(TimeSpan interval, Action tick)
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
         {
             if (interval.TotalMilliseconds < 10)
                 interval = TimeSpan.FromMilliseconds(10);
@@ -78,13 +79,13 @@ namespace Avalonia.Android
 
         private void EnsureInvokeOnMainThread(Action action) => _handler.Post(action);
 
-        public void Signal()
+        public void Signal(DispatcherPriority prio)
         {
-            EnsureInvokeOnMainThread(() => Signaled?.Invoke());
+            EnsureInvokeOnMainThread(() => Signaled?.Invoke(null));
         }
 
         public bool CurrentThreadIsLoopThread => Looper.MainLooper.Thread.Equals(Java.Lang.Thread.CurrentThread());
-        public event Action Signaled;
+        public event Action<DispatcherPriority?> Signaled;
     }
 }
  

+ 2 - 1
src/Avalonia.Base/AvaloniaObject.cs

@@ -56,6 +56,7 @@ namespace Avalonia
         /// </summary>
         public AvaloniaObject()
         {
+            VerifyAccess();
             foreach (var property in AvaloniaPropertyRegistry.Instance.GetRegistered(this))
             {
                 object value = property.IsDirect ?
@@ -817,4 +818,4 @@ namespace Avalonia
             throw new ArgumentException($"Property '{p.Name} not registered on '{this.GetType()}");
         }
     }
-}
+}

+ 5 - 3
src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs

@@ -3,6 +3,7 @@
 
 using System;
 using System.Threading;
+using Avalonia.Threading;
 
 namespace Avalonia.Platform
 {
@@ -16,15 +17,16 @@ namespace Avalonia.Platform
         /// <summary>
         /// Starts a timer.
         /// </summary>
+        /// <param name="priority"></param>
         /// <param name="interval">The interval.</param>
         /// <param name="tick">The action to call on each tick.</param>
         /// <returns>An <see cref="IDisposable"/> used to stop the timer.</returns>
-        IDisposable StartTimer(TimeSpan interval, Action tick);
+        IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick);
 
-        void Signal();
+        void Signal(DispatcherPriority priority);
 
         bool CurrentThreadIsLoopThread { get; }
 
-        event Action Signaled;
+        event Action<DispatcherPriority?> Signaled;
     }
 }

+ 9 - 0
src/Avalonia.Base/Platform/IRuntimePlatform.cs

@@ -14,6 +14,15 @@ namespace Avalonia.Platform
         IDisposable StartSystemTimer(TimeSpan interval, Action tick);
         string GetStackTrace();
         RuntimePlatformInfo GetRuntimeInfo();
+        IUnmanagedBlob AllocBlob(int size);
+    }
+
+    public interface IUnmanagedBlob : IDisposable
+    {
+        IntPtr Address { get; }
+        int Size { get; }
+        bool IsDisposed { get; }
+        
     }
 
     public struct RuntimePlatformInfo

+ 2 - 2
src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs

@@ -36,7 +36,7 @@ namespace Avalonia.Threading
         /// <inheritdoc/>
         public override void Post(SendOrPostCallback d, object state)
         {
-           Dispatcher.UIThread.InvokeAsync(() => d(state));
+           Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send);
         }
 
         /// <inheritdoc/>
@@ -45,7 +45,7 @@ namespace Avalonia.Threading
             if (Dispatcher.UIThread.CheckAccess())
                 d(state);
             else
-                Dispatcher.UIThread.InvokeTaskAsync(() => d(state)).Wait();
+                Dispatcher.UIThread.InvokeTaskAsync(() => d(state), DispatcherPriority.Send).Wait();
         }
     }
 }

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

@@ -60,7 +60,7 @@ namespace Avalonia.Threading
         public void MainLoop(CancellationToken cancellationToken)
         {
             var platform = AvaloniaLocator.Current.GetService<IPlatformThreadingInterface>();
-            cancellationToken.Register(platform.Signal);
+            cancellationToken.Register(() => platform.Signal(DispatcherPriority.Send));
             platform.RunLoop(cancellationToken);
         }
 
@@ -69,7 +69,7 @@ namespace Avalonia.Threading
         /// </summary>
         public void RunJobs()
         {
-            _jobRunner?.RunJobs();
+            _jobRunner?.RunJobs(null);
         }
 
         /// <inheritdoc/>
@@ -84,6 +84,19 @@ namespace Avalonia.Threading
             _jobRunner?.Post(action, priority);
         }
 
+        /// <summary>
+        /// This is needed for platform backends that don't have internal priority system (e. g. win32)
+        /// To ensure that there are no jobs with higher priority
+        /// </summary>
+        /// <param name="currentPriority"></param>
+        internal void EnsurePriority(DispatcherPriority currentPriority)
+        {
+            if (currentPriority == DispatcherPriority.MaxValue)
+                return;
+            currentPriority += 1;
+            _jobRunner.RunJobs(currentPriority);
+        }
+
         /// <summary>
         /// Allows unit tests to change the platform threading interface.
         /// </summary>

+ 17 - 7
src/Avalonia.Base/Threading/DispatcherPriority.cs

@@ -10,10 +10,10 @@ namespace Avalonia.Threading
     public enum DispatcherPriority
     {
         /// <summary>
-        /// The job will not be processed.
+        /// Minimum possible priority
         /// </summary>
-        Inactive = 0,
-
+        MinValue = 1,
+        
         /// <summary>
         /// The job will be processed when the system is idle.
         /// </summary>
@@ -48,20 +48,30 @@ namespace Avalonia.Threading
         /// The job will be processed with the same priority as render.
         /// </summary>
         Render = 7,
-
+        
+        /// <summary>
+        /// The job will be processed with the same priority as render.
+        /// </summary>
+        Layout = 8,
+        
         /// <summary>
         /// The job will be processed with the same priority as data binding.
         /// </summary>
-        DataBind = 8,
+        DataBind = 9,
 
         /// <summary>
         /// The job will be processed with normal priority.
         /// </summary>
-        Normal = 9,
+        Normal = 10,
 
         /// <summary>
         /// The job will be processed before other asynchronous operations.
         /// </summary>
-        Send = 10,
+        Send = 11,
+        
+        /// <summary>
+        /// Maximum possible priority
+        /// </summary>
+        MaxValue = 11
     }
 }

+ 4 - 14
src/Avalonia.Base/Threading/DispatcherTimer.cs

@@ -17,13 +17,11 @@ namespace Avalonia.Threading
         private readonly DispatcherPriority _priority;
 
         private TimeSpan _interval;
-
-        private readonly Action _raiseTickAction;
-
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="DispatcherTimer"/> class.
         /// </summary>
-        public DispatcherTimer() : this(DispatcherPriority.Normal)
+        public DispatcherTimer() : this(DispatcherPriority.Background)
         {
         }
 
@@ -34,7 +32,6 @@ namespace Avalonia.Threading
         public DispatcherTimer(DispatcherPriority priority)
         {
             _priority = priority;
-            _raiseTickAction = RaiseTick;
         }
 
         /// <summary>
@@ -187,7 +184,7 @@ namespace Avalonia.Threading
                     throw new Exception("Could not start timer: IPlatformThreadingInterface is not registered.");
                 }
 
-                _timer = threading.StartTimer(Interval, InternalTick);
+                _timer = threading.StartTimer(_priority, Interval, InternalTick);
             }
         }
 
@@ -210,14 +207,7 @@ namespace Avalonia.Threading
         /// </summary>
         private void InternalTick()
         {
-            Dispatcher.UIThread.InvokeAsync(_raiseTickAction, _priority);
-        }
-
-        /// <summary>
-        /// Raises the <see cref="Tick"/> event.
-        /// </summary>
-        private void RaiseTick()
-        {
+            Dispatcher.UIThread.EnsurePriority(_priority);
             Tick?.Invoke(this, EventArgs.Empty);
         }
     }

+ 32 - 15
src/Avalonia.Base/Threading/JobRunner.cs

@@ -3,6 +3,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Threading.Tasks;
 using Avalonia.Platform;
 
@@ -13,29 +14,45 @@ namespace Avalonia.Threading
     /// </summary>
     internal class JobRunner
     {
-        private readonly Queue<Job> _queue = new Queue<Job>();
+
+
         private IPlatformThreadingInterface _platform;
 
+        private Queue<Job>[] _queues = Enumerable.Range(0, (int) DispatcherPriority.MaxValue + 1)
+            .Select(_ => new Queue<Job>()).ToArray();
+
         public JobRunner(IPlatformThreadingInterface platform)
         {
             _platform = platform;
         }
 
+        Job GetNextJob(DispatcherPriority minimumPriority)
+        {
+            for (int c = (int) DispatcherPriority.MaxValue; c >= (int) minimumPriority; c--)
+            {
+                var q = _queues[c];
+                lock (q)
+                {
+                    if (q.Count > 0)
+                        return q.Dequeue();
+                }
+            }
+            return null;
+        }
+
         /// <summary>
         /// Runs continuations pushed on the loop.
         /// </summary>
-        public void RunJobs()
+        /// <param name="priority">Priority to execute jobs for. Pass null if platform doesn't have internal priority system</param>
+        public void RunJobs(DispatcherPriority? priority)
         {
+            var minimumPriority = priority ?? DispatcherPriority.MinValue;
             while (true)
             {
-                Job job;
-
-                lock (_queue)
-                {
-                    if (_queue.Count == 0)
-                        return;
-                    job = _queue.Dequeue();
-                }
+                var job = GetNextJob(minimumPriority);
+                if (job == null)
+                    return;
+                
 
                 if (job.TaskCompletionSource == null)
                 {
@@ -77,7 +94,6 @@ namespace Avalonia.Threading
         /// <param name="priority">The priority with which to invoke the method.</param>
         internal void Post(Action action, DispatcherPriority priority)
         {
-            // TODO: Respect priority.
             AddJob(new Job(action, priority, true));
         }
 
@@ -92,13 +108,14 @@ namespace Avalonia.Threading
         private void AddJob(Job job)
         {
             var needWake = false;
-            lock (_queue)
+            var queue = _queues[(int) job.Priority];
+            lock (queue)
             {
-                needWake = _queue.Count == 0;
-                _queue.Enqueue(job);
+                needWake = queue.Count == 0;
+                queue.Enqueue(job);
             }
             if (needWake)
-                _platform?.Signal();
+                _platform?.Signal(job.Priority);
         }
 
         /// <summary>

+ 0 - 60
src/Avalonia.Base/Threading/SingleThreadDispatcher.cs

@@ -1,60 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Avalonia.Platform;
-
-namespace Avalonia.Threading
-{
-    public class SingleThreadDispatcher : Dispatcher
-    {
-        class ThreadingInterface : IPlatformThreadingInterface
-        {
-            private readonly AutoResetEvent _evnt = new AutoResetEvent(false);
-            private readonly JobRunner _timerJobRunner;
-
-            public ThreadingInterface()
-            {
-                _timerJobRunner = new JobRunner(this);
-            }
-
-            public void RunLoop(CancellationToken cancellationToken)
-            {
-                while (!cancellationToken.IsCancellationRequested)
-                {
-                    _evnt.WaitOne();
-                    if (cancellationToken.IsCancellationRequested)
-                        return;
-                    Signaled?.Invoke();
-                    _timerJobRunner.RunJobs();
-                }
-            }
-
-            public IDisposable StartTimer(TimeSpan interval, Action tick)
-                => AvaloniaLocator.Current.GetService<IRuntimePlatform>().StartSystemTimer(interval,
-                    () => _timerJobRunner.Post(tick, DispatcherPriority.Normal));
-
-            public void Signal() => _evnt.Set();
-            //TODO: Actually perform a check
-            public bool CurrentThreadIsLoopThread => true;
-
-            public event Action Signaled;
-        }
-
-        public SingleThreadDispatcher() : base(new ThreadingInterface())
-        {
-        }
-
-        public static Dispatcher StartNew(CancellationToken token)
-        {
-            var dispatcher = new SingleThreadDispatcher();
-            AvaloniaLocator.Current.GetService<IRuntimePlatform>().PostThreadPoolItem(() =>
-            {
-                dispatcher.MainLoop(token);
-            });
-            return dispatcher;
-        }
-    }
-}

+ 0 - 1
src/Avalonia.Base/Utilities/WeakTimer.cs

@@ -23,7 +23,6 @@ namespace Avalonia.Utilities
             _timer = new DispatcherTimer();
             
             _timer.Tick += delegate { OnTick(); };
-            _timer.Start();
         }
 
         private void OnTick()

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

@@ -12,7 +12,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Debug\Avalonia.Controls.XML</DocumentationFile>
-    <NoWarn>CS1591</NoWarn>
+    <NoWarn>CS1591;CS0067</NoWarn>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
     <DebugType>pdbonly</DebugType>
@@ -36,6 +36,7 @@
     <ProjectReference Include="..\Avalonia.Input\Avalonia.Input.csproj" />
     <ProjectReference Include="..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
     <ProjectReference Include="..\Avalonia.Layout\Avalonia.Layout.csproj" />
+    <ProjectReference Include="..\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj" />
     <ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
     <ProjectReference Include="..\Avalonia.Styling\Avalonia.Styling.csproj" />
   </ItemGroup>

+ 4 - 6
src/Avalonia.Controls/Control.cs

@@ -656,7 +656,6 @@ namespace Avalonia.Controls
         /// <param name="e">The event args.</param>
         protected virtual void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
         {
-            AttachedToLogicalTree?.Invoke(this, e);
         }
 
         /// <summary>
@@ -665,7 +664,6 @@ namespace Avalonia.Controls
         /// <param name="e">The event args.</param>
         protected virtual void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
         {
-            DetachedFromLogicalTree?.Invoke(this, e);
         }
 
         /// <inheritdoc/>
@@ -773,11 +771,9 @@ namespace Avalonia.Controls
         {
             while (e != null)
             {
-                var root = e as IStyleRoot;
-
-                if (root != null && root.StylingParent == null)
+                if (e is IRenderRoot root)
                 {
-                    return root;
+                    return root as IStyleRoot;
                 }
 
                 e = e.StylingParent;
@@ -844,6 +840,7 @@ namespace Avalonia.Controls
                 InitializeStylesIfNeeded(true);
 
                 OnAttachedToLogicalTree(e);
+                AttachedToLogicalTree?.Invoke(this, e);
             }
 
             foreach (var child in LogicalChildren.OfType<Control>())
@@ -864,6 +861,7 @@ namespace Avalonia.Controls
                 _isAttachedToLogicalTree = false;
                 _styleDetach.OnNext(this);
                 OnDetachedFromLogicalTree(e);
+                DetachedFromLogicalTree?.Invoke(this, e);
 
                 foreach (var child in LogicalChildren.OfType<Control>())
                 {

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

@@ -64,7 +64,7 @@ namespace Avalonia.Controls
             return rv;
         }
 
-        internal static void ApplyDesignerProperties(Control target, Control source)
+        public static void ApplyDesignModeProperties(Control target, Control source)
         {
             if (source.IsSet(WidthProperty))
                 target.Width = source.GetValue(WidthProperty);

+ 10 - 10
src/Avalonia.Controls/DropDown.cs

@@ -144,21 +144,21 @@ namespace Avalonia.Controls
         /// <inheritdoc/>
         protected override void OnPointerPressed(PointerPressedEventArgs e)
         {
-            if (!IsDropDownOpen && ((IVisual)e.Source).GetVisualRoot() is PopupRoot)
-            {
-                IsDropDownOpen = true;
-                e.Handled = true;
-            }
-
             if (!e.Handled)
             {
-                if (UpdateSelectionFromEventSource(e.Source))
+                if (((IVisual)e.Source).GetVisualRoot() is PopupRoot)
                 {
-                    _popup?.Close();
-                    e.Handled = true;
+                    if (UpdateSelectionFromEventSource(e.Source))
+                    {
+                        _popup?.Close();
+                        e.Handled = true;
+                    }
+                }
+                else
+                {
+                    IsDropDownOpen = !IsDropDownOpen;
                 }
             }
-
             base.OnPointerPressed(e);
         }
 

+ 63 - 0
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Layout;
+using Avalonia.Styling;
+
+namespace Avalonia.Controls.Embedding.Offscreen
+{
+    class OffscreenTopLevel : TopLevel, IStyleable
+    {
+        public OffscreenTopLevelImplBase Impl { get; }
+
+        public OffscreenTopLevel(OffscreenTopLevelImplBase impl) : base(impl)
+        {
+            Impl = impl;
+            Prepare();
+        }
+
+        public void Prepare()
+        {
+            EnsureInitialized();
+            ApplyTemplate();
+            LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+        }
+
+        private void EnsureInitialized()
+        {
+            if (!this.IsInitialized)
+            {
+                var init = (ISupportInitialize)this;
+                init.BeginInit();
+                init.EndInit();
+            }
+        }
+        
+        private readonly NameScope _nameScope = new NameScope();
+        public event EventHandler<NameScopeEventArgs> Registered
+        {
+            add { _nameScope.Registered += value; }
+            remove { _nameScope.Registered -= value; }
+        }
+
+        public event EventHandler<NameScopeEventArgs> Unregistered
+        {
+            add { _nameScope.Unregistered += value; }
+            remove { _nameScope.Unregistered -= value; }
+        }
+
+        public void Register(string name, object element) => _nameScope.Register(name, element);
+
+        public object Find(string name) => _nameScope.Find(name);
+
+        public void Unregister(string name) => _nameScope.Unregister(name);
+
+        Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
+        public void Dispose()
+        {
+            PlatformImpl.Dispose();
+        }
+    }
+}

+ 66 - 0
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+
+namespace Avalonia.Controls.Embedding.Offscreen
+{
+    public abstract class OffscreenTopLevelImplBase : ITopLevelImpl
+    {
+        private double _scaling = 1;
+        private Size _clientSize;
+        public IInputRoot InputRoot { get; private set; }
+
+        public virtual void Dispose()
+        {
+            //No-op
+        }
+
+        public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
+
+        public abstract void Invalidate(Rect rect);
+        public abstract IEnumerable<object> Surfaces { get; }
+
+        public Size ClientSize
+        {
+            get { return _clientSize; }
+            set
+            {
+                _clientSize = value;
+                Resized?.Invoke(value);
+            }
+        }
+
+        public double Scaling
+        {
+            get { return _scaling; }
+            set
+            {
+                _scaling = value;
+                ScalingChanged?.Invoke(value);
+            }
+        }
+        
+        public Action<RawInputEventArgs> Input { get; set; }
+        public Action<Rect> Paint { get; set; }
+        public Action<Size> Resized { get; set; }
+        public Action<double> ScalingChanged { get; set; }
+        public void SetInputRoot(IInputRoot inputRoot) => InputRoot = inputRoot;
+
+        public virtual Point PointToClient(Point point) => point;
+
+        public virtual Point PointToScreen(Point point) => point;
+
+        public virtual void SetCursor(IPlatformHandle cursor)
+        {
+        }
+
+        public Action Closed { get; set; }
+        public abstract IMouseDevice MouseDevice { get; }
+    }
+}

+ 15 - 0
src/Avalonia.Controls/MenuItem.cs

@@ -307,6 +307,21 @@ namespace Avalonia.Controls
                     () => IsSubMenuOpen = true,
                     TimeSpan.FromMilliseconds(400));
             }
+            else
+            {
+                var parentItem = Parent as MenuItem;
+                if (parentItem != null)
+                {
+                    foreach (var sibling in parentItem.Items
+                        .OfType<MenuItem>()
+                        .Where(x => x != this && x.IsSubMenuOpen))
+                    {
+                        sibling.CloseSubmenus();
+                        sibling.IsSubMenuOpen = false;
+                        sibling.IsSelected = false;
+                    }
+                }
+            }
         }
 
         /// <summary>

+ 21 - 0
src/Avalonia.Controls/Orientation.cs

@@ -0,0 +1,21 @@
+// 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.
+
+namespace Avalonia.Controls
+{
+    /// <summary>
+    /// Defines vertical or horizontal orientation.
+    /// </summary>
+    public enum Orientation
+    {
+        /// <summary>
+        /// Horizontal orientation.
+        /// </summary>
+        Horizontal,
+
+        /// <summary>
+        /// Vertical orientation.
+        /// </summary>
+        Vertical,
+    }
+}

+ 12 - 13
src/Linux/Avalonia.LinuxFramebuffer/PlatformThreadingInterface.cs → src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs

@@ -1,22 +1,20 @@
 using System;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
-using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using Avalonia.Platform;
 using Avalonia.Rendering;
+using Avalonia.Threading;
 
-namespace Avalonia.LinuxFramebuffer
+namespace Avalonia.Controls.Platform
 {
-    class PlatformThreadingInterface : IPlatformThreadingInterface, IRenderLoop
+    public class InternalPlatformThreadingInterface : IPlatformThreadingInterface, IRenderLoop
     {
-        public static PlatformThreadingInterface Instance { get; } = new PlatformThreadingInterface();
-
-        public PlatformThreadingInterface()
+        public InternalPlatformThreadingInterface()
         {
             TlsCurrentThreadIsLoopThread = true;
-            StartTimer(new TimeSpan(0, 0, 0, 0, 66), () => Tick?.Invoke(this, new EventArgs()));
+            StartTimer(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 0, 66), () => Tick?.Invoke(this, new EventArgs()));
         }
 
         private readonly AutoResetEvent _signaled = new AutoResetEvent(false);
@@ -30,13 +28,13 @@ namespace Avalonia.LinuxFramebuffer
             while (true)
             {
                 if (0 == WaitHandle.WaitAny(handles))
-                    Signaled?.Invoke();
+                    Signaled?.Invoke(null);
                 else
                 {
                     while (true)
                     {
                         Action item;
-                        lock(_actions)
+                        lock (_actions)
                             if (_actions.Count == 0)
                                 break;
                             else
@@ -66,6 +64,7 @@ namespace Avalonia.LinuxFramebuffer
                 _timer = timer;
                 _handle = GCHandle.Alloc(_timer);
             }
+
             public void Dispose()
             {
                 _handle.Free();
@@ -73,7 +72,7 @@ namespace Avalonia.LinuxFramebuffer
             }
         }
 
-        public IDisposable StartTimer(TimeSpan interval, Action tick)
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
         {
             return new WatTimer(new System.Threading.Timer(delegate
             {
@@ -97,7 +96,7 @@ namespace Avalonia.LinuxFramebuffer
 
         }
 
-        public void Signal()
+        public void Signal(DispatcherPriority prio)
         {
             _signaled.Set();
         }
@@ -105,8 +104,8 @@ namespace Avalonia.LinuxFramebuffer
         [ThreadStatic] private static bool TlsCurrentThreadIsLoopThread;
 
         public bool CurrentThreadIsLoopThread => TlsCurrentThreadIsLoopThread;
-        public event Action Signaled;
+        public event Action<DispatcherPriority?> Signaled;
         public event EventHandler<EventArgs> Tick;
 
     }
-}
+}

+ 1 - 1
src/Avalonia.Controls/Primitives/ScrollBar.cs

@@ -30,7 +30,7 @@ namespace Avalonia.Controls.Primitives
         /// Defines the <see cref="Orientation"/> property.
         /// </summary>
         public static readonly StyledProperty<Orientation> OrientationProperty =
-            AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation));
+            AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation), Orientation.Vertical);
 
         private Button _lineUpButton;
         private Button _lineDownButton;

+ 23 - 3
src/Avalonia.Controls/Primitives/Track.cs

@@ -128,7 +128,17 @@ namespace Avalonia.Controls.Primitives
 
             if (Orientation == Orientation.Horizontal)
             {
-                var thumbWidth = double.IsNaN(viewportSize) ? thumb?.DesiredSize.Width ?? 0 : finalSize.Width * viewportSize / extent;
+                double thumbWidth = 0;
+
+                if (double.IsNaN(viewportSize))
+                {
+                    thumbWidth = thumb?.DesiredSize.Width ?? 0;
+                }
+                else if (extent > 0)
+                {
+                    thumbWidth = finalSize.Width * viewportSize / extent;
+                }
+
                 var remaining = finalSize.Width - thumbWidth;
                 var firstWidth = range <= 0 ? 0 : remaining * offset / range;
 
@@ -149,7 +159,17 @@ namespace Avalonia.Controls.Primitives
             }
             else
             {
-                var thumbHeight = double.IsNaN(viewportSize) ? thumb?.DesiredSize.Height ?? 0 : finalSize.Height * viewportSize / extent;
+                double thumbHeight = 0;
+
+                if (double.IsNaN(viewportSize))
+                {
+                    thumbHeight = thumb?.DesiredSize.Height ?? 0;
+                }
+                else if (extent > 0)
+                {
+                    thumbHeight = finalSize.Height * viewportSize / extent;
+                }
+
                 var remaining = finalSize.Height - thumbHeight;
                 var firstHeight = range <= 0 ? 0 : remaining * offset / range;
 
@@ -165,7 +185,7 @@ namespace Avalonia.Controls.Primitives
 
                 if (increaseButton != null)
                 {
-                    increaseButton.Arrange(new Rect(0, firstHeight + thumbHeight, finalSize.Width, remaining - firstHeight));
+                    increaseButton.Arrange(new Rect(0, firstHeight + thumbHeight, finalSize.Width, Math.Max(remaining - firstHeight, 0)));
                 }
             }
 

+ 136 - 3
src/Avalonia.Controls/ProgressBar.cs

@@ -1,8 +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.
 
+using System;
+using System.Reactive.Linq;
+
+using Avalonia.Animation;
 using Avalonia.Controls.Primitives;
-using Avalonia.Controls.Templates;
+using Avalonia.Layout;
 
 namespace Avalonia.Controls
 {
@@ -11,11 +15,38 @@ namespace Avalonia.Controls
     /// </summary>
     public class ProgressBar : RangeBase
     {
+        public static readonly StyledProperty<bool> IsIndeterminateProperty =
+            AvaloniaProperty.Register<ProgressBar, bool>(nameof(IsIndeterminate));
+
+        public static readonly StyledProperty<Orientation> OrientationProperty =
+            AvaloniaProperty.Register<ProgressBar, Orientation>(nameof(Orientation), Orientation.Horizontal);
+
         private Border _indicator;
+        private IndeterminateAnimation _indeterminateAnimation;
 
         static ProgressBar()
         {
             ValueProperty.Changed.AddClassHandler<ProgressBar>(x => x.ValueChanged);
+
+            HorizontalAlignmentProperty.OverrideDefaultValue<ProgressBar>(HorizontalAlignment.Left);
+            VerticalAlignmentProperty.OverrideDefaultValue<ProgressBar>(VerticalAlignment.Top);
+
+            IsIndeterminateProperty.Changed.AddClassHandler<ProgressBar>(
+                (p, e) => { if (p._indicator != null) p.UpdateIsIndeterminate((bool)e.NewValue); });
+            OrientationProperty.Changed.AddClassHandler<ProgressBar>(
+                (p, e) => { if (p._indicator != null) p.UpdateOrientation((Orientation)e.NewValue); });
+        }
+
+        public bool IsIndeterminate
+        {
+            get => GetValue(IsIndeterminateProperty);
+            set => SetValue(IsIndeterminateProperty, value);
+        }
+
+        public Orientation Orientation
+        {
+            get => GetValue(OrientationProperty);
+            set => SetValue(OrientationProperty, value);
         }
 
         /// <inheritdoc/>
@@ -29,21 +60,123 @@ namespace Avalonia.Controls
         protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
         {
             _indicator = e.NameScope.Get<Border>("PART_Indicator");
+
             UpdateIndicator(Bounds.Size);
+            UpdateOrientation(Orientation);
+            UpdateIsIndeterminate(IsIndeterminate);
         }
 
         private void UpdateIndicator(Size bounds)
         {
             if (_indicator != null)
             {
-                double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum);
-                _indicator.Width = bounds.Width * percent;
+                if (IsIndeterminate)
+                {
+                    if (Orientation == Orientation.Horizontal)
+                        _indicator.Width = bounds.Width / 5.0;
+                    else
+                        _indicator.Height = bounds.Height / 5.0;
+                }
+                else
+                {
+                    double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum);
+
+                    if (Orientation == Orientation.Horizontal)
+                        _indicator.Width = bounds.Width * percent;
+                    else
+                        _indicator.Height = bounds.Height * percent;
+                }
+            }
+        }
+
+        private void UpdateOrientation(Orientation orientation)
+        {
+            if (orientation == Orientation.Horizontal)
+            {
+                MinHeight = 14;
+                MinWidth = 200;
+
+                _indicator.HorizontalAlignment = HorizontalAlignment.Left;
+                _indicator.VerticalAlignment = VerticalAlignment.Stretch;
+            }
+            else
+            {
+                MinHeight = 200;
+                MinWidth = 14;
+
+                _indicator.HorizontalAlignment = HorizontalAlignment.Stretch;
+                _indicator.VerticalAlignment = VerticalAlignment.Bottom;
             }
         }
 
+        private void UpdateIsIndeterminate(bool isIndeterminate)
+        {
+            if (isIndeterminate)
+                if (_indeterminateAnimation == null || _indeterminateAnimation.Disposed)
+                    _indeterminateAnimation = IndeterminateAnimation.StartAnimation(this);
+            else
+                _indeterminateAnimation?.Dispose();
+        }
+
         private void ValueChanged(AvaloniaPropertyChangedEventArgs e)
         {
             UpdateIndicator(Bounds.Size);
         }
+
+        private class IndeterminateAnimation : IDisposable
+        {
+            private WeakReference<ProgressBar> _progressBar;
+            private IDisposable _indeterminateBindSubscription;
+            private TimeSpan _startTime;
+            private bool _disposed;
+
+            public bool Disposed => _disposed;
+
+            private IndeterminateAnimation(ProgressBar progressBar)
+            {
+                _progressBar = new WeakReference<ProgressBar>(progressBar);
+                _startTime = Animate.Stopwatch.Elapsed;
+                _indeterminateBindSubscription = Animate.Timer.TakeWhile(x => (x - _startTime).TotalSeconds <= 4.0)
+                                                              .Select(GetAnimationRect)
+                                                              .Finally(() => _startTime = Animate.Stopwatch.Elapsed)
+                                                              .Repeat()
+                                                              .Subscribe(AnimationTick);
+            }
+
+            public static IndeterminateAnimation StartAnimation(ProgressBar progressBar)
+            {
+                return new IndeterminateAnimation(progressBar);
+            }
+
+            private Rect GetAnimationRect(TimeSpan time)
+            {
+                if (_progressBar.TryGetTarget(out var progressBar))
+                {
+                    if (progressBar.Orientation == Orientation.Horizontal)
+                        return new Rect(-progressBar._indicator.Width - 5 + (time - _startTime).TotalSeconds / 4.0 * (progressBar.Bounds.Width + progressBar._indicator.Width + 10), 0, progressBar._indicator.Bounds.Width, progressBar._indicator.Bounds.Height);
+                    else
+                        return new Rect(0, progressBar.Bounds.Height + 5 - (time - _startTime).TotalSeconds / 4.0 * (progressBar.Bounds.Height + progressBar._indicator.Height + 10), progressBar._indicator.Bounds.Width, progressBar._indicator.Bounds.Height);
+                }
+                else
+                {
+                    _indeterminateBindSubscription.Dispose();
+                    return Rect.Empty;
+                }
+            }
+
+            private void AnimationTick(Rect rect)
+            {
+                if (_progressBar.TryGetTarget(out var progressBar))
+                    progressBar._indicator.Arrange(rect);
+                else
+                    _indeterminateBindSubscription.Dispose();
+            }
+
+            public void Dispose()
+            {
+                _indeterminateBindSubscription?.Dispose();
+                _disposed = true;
+            }
+        }
     }
 }

+ 40 - 0
src/Avalonia.Controls/Remote/RemoteServer.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Controls.Embedding;
+using Avalonia.Controls.Remote.Server;
+using Avalonia.Platform;
+using Avalonia.Remote.Protocol;
+
+namespace Avalonia.Controls.Remote
+{
+    public class RemoteServer
+    {
+        private EmbeddableControlRoot _topLevel;
+
+        class EmbeddableRemoteServerTopLevelImpl : RemoteServerTopLevelImpl, IEmbeddableWindowImpl
+        {
+            public EmbeddableRemoteServerTopLevelImpl(IAvaloniaRemoteTransportConnection transport) : base(transport)
+            {
+            }
+#pragma warning disable 67
+            public event Action LostFocus;
+
+        }
+        
+        public RemoteServer(IAvaloniaRemoteTransportConnection transport)
+        {
+            _topLevel = new EmbeddableControlRoot(new EmbeddableRemoteServerTopLevelImpl(transport));
+            _topLevel.Prepare();
+            //TODO: Somehow react on closed connection?
+        }
+
+        public object Content
+        {
+            get => _topLevel.Content;
+            set => _topLevel.Content = value;
+        }
+    }
+}

+ 79 - 0
src/Avalonia.Controls/Remote/RemoteWidget.cs

@@ -0,0 +1,79 @@
+using System;
+using System.Runtime.InteropServices;
+using Avalonia.Input;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Remote.Protocol;
+using Avalonia.Remote.Protocol.Viewport;
+using Avalonia.Threading;
+using PixelFormat = Avalonia.Platform.PixelFormat;
+
+namespace Avalonia.Controls.Remote
+{
+    public class RemoteWidget : Control
+    {
+        private readonly IAvaloniaRemoteTransportConnection _connection;
+        private FrameMessage _lastFrame;
+        private WritableBitmap _bitmap;
+        public RemoteWidget(IAvaloniaRemoteTransportConnection connection)
+        {
+            _connection = connection;
+            _connection.OnMessage += (t, msg) => Dispatcher.UIThread.InvokeAsync(() => OnMessage(msg));
+            _connection.Send(new ClientSupportedPixelFormatsMessage
+            {
+                Formats = new[]
+                {
+                    Avalonia.Remote.Protocol.Viewport.PixelFormat.Bgra8888,
+                    Avalonia.Remote.Protocol.Viewport.PixelFormat.Rgba8888,
+                }
+            });
+        }
+
+        private void OnMessage(object msg)
+        {
+            if (msg is FrameMessage frame)
+            {
+                _connection.Send(new FrameReceivedMessage
+                {
+                    SequenceId = frame.SequenceId
+                });
+                _lastFrame = frame;
+                InvalidateVisual();
+            }
+            
+        }
+
+        protected override void ArrangeCore(Rect finalRect)
+        {
+            _connection.Send(new ClientViewportAllocatedMessage
+            {
+                Width = finalRect.Width,
+                Height = finalRect.Height,
+                DpiX = 96,
+                DpiY = 96 //TODO: Somehow detect the actual DPI
+            });
+            base.ArrangeCore(finalRect);
+        }
+
+        public override void Render(DrawingContext context)
+        {
+            if (_lastFrame != null)
+            {
+                var fmt = (PixelFormat) _lastFrame.Format;
+                if (_bitmap == null || _bitmap.PixelWidth != _lastFrame.Width ||
+                    _bitmap.PixelHeight != _lastFrame.Height)
+                    _bitmap = new WritableBitmap(_lastFrame.Width, _lastFrame.Height, fmt);
+                using (var l = _bitmap.Lock())
+                {
+                    var lineLen = (fmt == PixelFormat.Rgb565 ? 2 : 4) * _lastFrame.Width;
+                    for (var y = 0; y < _lastFrame.Height; y++)
+                        Marshal.Copy(_lastFrame.Data, y * _lastFrame.Stride,
+                            new IntPtr(l.Address.ToInt64() + l.RowBytes * y), lineLen);
+                }
+                context.DrawImage(_bitmap, 1, new Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight),
+                    new Rect(Bounds.Size));
+            }
+            base.Render(context);
+        }
+    }
+}

+ 176 - 0
src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs

@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Controls.Embedding.Offscreen;
+using Avalonia.Controls.Platform.Surfaces;
+using Avalonia.Input;
+using Avalonia.Layout;
+using Avalonia.Platform;
+using Avalonia.Remote.Protocol;
+using Avalonia.Remote.Protocol.Viewport;
+using Avalonia.Threading;
+using PixelFormat = Avalonia.Platform.PixelFormat;
+using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat;
+
+namespace Avalonia.Controls.Remote.Server
+{
+    public class RemoteServerTopLevelImpl : OffscreenTopLevelImplBase, IFramebufferPlatformSurface
+    {
+        private readonly IAvaloniaRemoteTransportConnection _transport;
+        private LockedFramebuffer _framebuffer;
+        private object _lock = new object();
+        private long _lastSentFrame = -1;
+        private long _lastReceivedFrame = -1;
+        private long _nextFrameNumber = 1;
+        private ClientViewportAllocatedMessage _pendingAllocation;
+        private bool _invalidated;
+        private Vector _dpi = new Vector(96, 96);
+        private ProtocolPixelFormat[] _supportedFormats;
+
+        public RemoteServerTopLevelImpl(IAvaloniaRemoteTransportConnection transport)
+        {
+            _transport = transport;
+            _transport.OnMessage += OnMessage;
+        }
+
+        protected virtual void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
+        {
+            lock (_lock)
+            {
+                if (obj is FrameReceivedMessage lastFrame)
+                {
+                    lock (_lock)
+                    {
+                        _lastReceivedFrame = lastFrame.SequenceId;
+                    }
+                    Dispatcher.UIThread.InvokeAsync(RenderIfNeeded);
+                }
+                if (obj is ClientSupportedPixelFormatsMessage supportedFormats)
+                {
+                    lock (_lock)
+                        _supportedFormats = supportedFormats.Formats;
+                    Dispatcher.UIThread.InvokeAsync(RenderIfNeeded);
+                }
+                if (obj is MeasureViewportMessage measure)
+                    Dispatcher.UIThread.InvokeAsync(() =>
+                    {
+                        var m = Measure(new Size(measure.Width, measure.Height));
+                        _transport.Send(new MeasureViewportMessage
+                        {
+                            Width = m.Width,
+                            Height = m.Height
+                        });
+                    });
+                if (obj is ClientViewportAllocatedMessage allocated)
+                {
+                    lock (_lock)
+                    {
+                        if (_pendingAllocation == null)
+                            Dispatcher.UIThread.InvokeAsync(() =>
+                            {
+                                ClientViewportAllocatedMessage allocation;
+                                lock (_lock)
+                                {
+                                    allocation = _pendingAllocation;
+                                    _pendingAllocation = null;
+                                }
+                                _dpi = new Vector(allocation.DpiX, allocation.DpiY);
+                                ClientSize = new Size(allocation.Width, allocation.Height);
+                                RenderIfNeeded();
+                            });
+
+                        _pendingAllocation = allocated;
+                    }
+                }
+            }
+        }
+
+        protected void SetDpi(Vector dpi)
+        {
+            _dpi = dpi;
+            RenderIfNeeded();
+        }
+
+        protected virtual Size Measure(Size constaint)
+        {
+            var l = (ILayoutable) InputRoot;
+            l.Measure(constaint);
+            return l.DesiredSize;
+        }
+
+        public override IEnumerable<object> Surfaces => new[] { this };
+        
+        FrameMessage RenderFrame(int width, int height, ProtocolPixelFormat? format)
+        {
+            var fmt = format ?? ProtocolPixelFormat.Rgba8888;
+            var bpp = fmt == ProtocolPixelFormat.Rgb565 ? 2 : 4;
+            var data = new byte[width * height * bpp];
+            var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
+            try
+            {
+                _framebuffer = new LockedFramebuffer(handle.AddrOfPinnedObject(), width, height, width * bpp, _dpi, (PixelFormat)fmt,
+                    null);
+                Paint?.Invoke(new Rect(0, 0, width, height));
+            }
+            finally
+            {
+                _framebuffer = null;
+                handle.Free();
+            }
+            return new FrameMessage
+            {
+                Data = data,
+                Format = (ProtocolPixelFormat) format,
+                Width = width,
+                Height = height,
+                Stride = width * bpp,
+            };
+        }
+
+        public ILockedFramebuffer Lock()
+        {
+            if (_framebuffer == null)
+                throw new InvalidOperationException("Paint was not requested, wait for Paint event");
+            return _framebuffer;
+        }
+
+        protected void RenderIfNeeded()
+        {
+            lock (_lock)
+            {
+                if (_lastReceivedFrame != _lastSentFrame || !_invalidated || _supportedFormats == null)
+                    return;
+
+            }
+            if (ClientSize.Width < 1 || ClientSize.Height < 1)
+                return;
+            var format = ProtocolPixelFormat.Rgba8888;
+            foreach(var fmt in _supportedFormats)
+                if (fmt <= ProtocolPixelFormat.MaxValue)
+                {
+                    format = fmt;
+                    break;
+                }
+            
+            var frame = RenderFrame((int) ClientSize.Width, (int) ClientSize.Height, format);
+            lock (_lock)
+            {
+                _lastSentFrame = _nextFrameNumber++;
+                frame.SequenceId = _lastSentFrame;
+                _invalidated = false;
+            }
+            _transport.Send(frame);
+        }
+
+        public override void Invalidate(Rect rect)
+        {
+            _invalidated = true;
+            Dispatcher.UIThread.InvokeAsync(RenderIfNeeded);
+        }
+
+        public override IMouseDevice MouseDevice { get; } = new MouseDevice();
+    }
+}

+ 10 - 17
src/Avalonia.Controls/StackPanel.cs

@@ -6,22 +6,6 @@ using Avalonia.Input;
 
 namespace Avalonia.Controls
 {
-    /// <summary>
-    /// Defines vertical or horizontal orientation.
-    /// </summary>
-    public enum Orientation
-    {
-        /// <summary>
-        /// Vertical orientation.
-        /// </summary>
-        Vertical,
-
-        /// <summary>
-        /// Horizontal orientation.
-        /// </summary>
-        Horizontal,
-    }
-
     /// <summary>
     /// A panel which lays out its children horizontally or vertically.
     /// </summary>
@@ -37,7 +21,7 @@ namespace Avalonia.Controls
         /// Defines the <see cref="Orientation"/> property.
         /// </summary>
         public static readonly StyledProperty<Orientation> OrientationProperty =
-            AvaloniaProperty.Register<StackPanel, Orientation>(nameof(Orientation));
+            AvaloniaProperty.Register<StackPanel, Orientation>(nameof(Orientation), Orientation.Vertical);
 
         /// <summary>
         /// Initializes static members of the <see cref="StackPanel"/> class.
@@ -186,6 +170,15 @@ namespace Avalonia.Controls
                 }
             }
 
+            if (Orientation == Orientation.Vertical)
+            {
+                measuredHeight -= gap;
+            }
+            else
+            {
+                measuredWidth -= gap;
+            }
+
             return new Size(measuredWidth, measuredHeight);
         }
 

+ 1 - 3
src/Avalonia.Controls/TreeView.cs

@@ -253,9 +253,7 @@ namespace Avalonia.Controls
 
                         if (AutoScrollToSelectedItem)
                         {
-                            DispatcherTimer.RunOnce(
-                                container.ContainerControl.BringIntoView,
-                                TimeSpan.Zero);
+                            Dispatcher.UIThread.InvokeAsync(container.ContainerControl.BringIntoView);
                         }
 
                         break;

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

@@ -12,7 +12,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Debug\Avalonia.DesignerSupport.xml</DocumentationFile>
-    <NoWarn>CS1591</NoWarn>
+    <NoWarn>CS1591;CS0067</NoWarn>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
     <DebugType>pdbonly</DebugType>

+ 76 - 0
src/Avalonia.DesignerSupport/DesignWindowLoader.cs

@@ -0,0 +1,76 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Markup.Xaml;
+using Avalonia.Styling;
+
+namespace Avalonia.DesignerSupport
+{
+    public class DesignWindowLoader
+    {
+        public static Window LoadDesignerWindow(string xaml, string assemblyPath)
+        {
+            Window window;
+            Control control;
+            using (PlatformManager.DesignerMode())
+            {
+                var loader = new AvaloniaXamlLoader();
+                var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml));
+
+
+                
+                Uri baseUri = null;
+                if (assemblyPath != null)
+                {
+                    //Fabricate fake Uri
+                    baseUri =
+                        new Uri("resm:Fake.xaml?assembly=" + Path.GetFileNameWithoutExtension(assemblyPath));
+                }
+
+                var loaded = loader.Load(stream, null, baseUri);
+                var styles = loaded as Styles;
+                if (styles != null)
+                {
+                    var substitute = Design.GetPreviewWith(styles) ??
+                                     styles.Select(Design.GetPreviewWith).FirstOrDefault(s => s != null);
+                    if (substitute != null)
+                    {
+                        substitute.Styles.AddRange(styles);
+                        control = substitute;
+                    }
+                    else
+                        control = new StackPanel
+                        {
+                            Children =
+                            {
+                                new TextBlock {Text = "Styles can't be previewed without Design.PreviewWith. Add"},
+                                new TextBlock {Text = "<Design.PreviewWith>"},
+                                new TextBlock {Text = "    <Border Padding=20><!-- YOUR CONTROL FOR PREVIEW HERE--></Border>"},
+                                new TextBlock {Text = "<Design.PreviewWith>"},
+                                new TextBlock {Text = "before setters in your first Style"}
+                            }
+                        };
+                }
+                if (loaded is Application)
+                    control = new TextBlock {Text = "Application can't be previewed in design view"};
+                else
+                    control = (Control) loaded;
+
+                window = control as Window;
+                if (window == null)
+                {
+                    window = new Window() {Content = (Control)control};
+                }
+
+                if (!window.IsSet(Window.SizeToContentProperty))
+                    window.SizeToContent = SizeToContent.WidthAndHeight;
+            }
+            window.Show();
+            Design.ApplyDesignModeProperties(window, control);
+            return window;
+        }
+    }
+}

+ 2 - 58
src/Avalonia.DesignerSupport/DesignerAssist.cs

@@ -86,67 +86,11 @@ namespace Avalonia.DesignerSupport
         private static void UpdateXaml2(Dictionary<string, object> dic)
         {
             var xamlInfo = new DesignerApiXamlFileInfo(dic);
-            Window window;
-            Control control;
-
-            using (PlatformManager.DesignerMode())
-            {
-                var loader = new AvaloniaXamlLoader();
-                var stream = new MemoryStream(Encoding.UTF8.GetBytes(xamlInfo.Xaml));
-
-
-                
-                Uri baseUri = null;
-                if (xamlInfo.AssemblyPath != null)
-                {
-                    //Fabricate fake Uri
-                    baseUri =
-                        new Uri("resm:Fake.xaml?assembly=" + Path.GetFileNameWithoutExtension(xamlInfo.AssemblyPath));
-                }
-
-                var loaded = loader.Load(stream, null, baseUri);
-                var styles = loaded as Styles;
-                if (styles != null)
-                {
-                    var substitute = Design.GetPreviewWith(styles) ??
-                                     styles.Select(Design.GetPreviewWith).FirstOrDefault(s => s != null);
-                    if (substitute != null)
-                    {
-                        substitute.Styles.AddRange(styles);
-                        control = substitute;
-                    }
-                    else
-                        control = new StackPanel
-                        {
-                            Children =
-                            {
-                                new TextBlock {Text = "Styles can't be previewed without Design.PreviewWith. Add"},
-                                new TextBlock {Text = "<Design.PreviewWith>"},
-                                new TextBlock {Text = "    <Border Padding=20><!-- YOUR CONTROL FOR PREVIEW HERE--></Border>"},
-                                new TextBlock {Text = "<Design.PreviewWith>"},
-                                new TextBlock {Text = "before setters in your first Style"}
-                            }
-                        };
-                }
-                if (loaded is Application)
-                    control = new TextBlock {Text = "Application can't be previewed in design view"};
-                else
-                    control = (Control) loaded;
-
-                window = control as Window;
-                if (window == null)
-                {
-                    window = new Window() {Content = (Control)control};
-                }
-
-                if (!window.IsSet(Window.SizeToContentProperty))
-                    window.SizeToContent = SizeToContent.WidthAndHeight;
-            }
+            Window window = DesignWindowLoader.LoadDesignerWindow(xamlInfo.Xaml, xamlInfo.AssemblyPath);
 
             s_currentWindow?.Close();
             s_currentWindow = window;
-            window.Show();
-            Design.ApplyDesignerProperties(window, control);
+            
             // ReSharper disable once PossibleNullReferenceException
             // Always not null at this point
             Api.OnWindowCreated?.Invoke(window.PlatformImpl.Handle.Handle);

+ 35 - 0
src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs

@@ -0,0 +1,35 @@
+using System;
+using System.Threading.Tasks;
+using Avalonia.Remote.Protocol;
+
+namespace Avalonia.DesignerSupport.Remote
+{
+    class DetachableTransportConnection : IAvaloniaRemoteTransportConnection
+    {
+        private IAvaloniaRemoteTransportConnection _inner;
+
+        public DetachableTransportConnection(IAvaloniaRemoteTransportConnection inner)
+        {
+            _inner = inner;
+            _inner.OnMessage += FireOnMessage;
+        }
+
+        public void Dispose()
+        {
+            if (_inner != null)
+                _inner.OnMessage -= FireOnMessage;
+            _inner = null;
+        }
+
+        public void FireOnMessage(IAvaloniaRemoteTransportConnection transport, object obj) => OnMessage?.Invoke(transport, obj);
+        
+        public Task Send(object data)
+        {
+            return _inner?.Send(data);
+        }
+
+        public event Action<IAvaloniaRemoteTransportConnection, object> OnMessage;
+
+        public event Action<IAvaloniaRemoteTransportConnection, Exception> OnException;
+    }
+}

+ 96 - 0
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@@ -0,0 +1,96 @@
+using System;
+using System.Reactive.Disposables;
+using Avalonia.Controls;
+using Avalonia.Controls.Remote.Server;
+using Avalonia.Platform;
+using Avalonia.Remote.Protocol;
+using Avalonia.Remote.Protocol.Viewport;
+using Avalonia.Threading;
+
+namespace Avalonia.DesignerSupport.Remote
+{
+    class PreviewerWindowImpl : RemoteServerTopLevelImpl, IWindowImpl, IEmbeddableWindowImpl
+    {
+        private readonly IAvaloniaRemoteTransportConnection _transport;
+
+        public PreviewerWindowImpl(IAvaloniaRemoteTransportConnection transport) : base(transport)
+        {
+            _transport = transport;
+            ClientSize = new Size(1, 1);
+        }
+
+        public void Show()
+        {
+        }
+
+        public void Hide()
+        {
+        }
+
+        public void BeginMoveDrag()
+        {
+        }
+
+        public void BeginResizeDrag(WindowEdge edge)
+        {
+        }
+
+        public Point Position { get; set; }
+        public Action<Point> PositionChanged { get; set; }
+        public Action Deactivated { get; set; }
+        public Action Activated { get; set; }
+        public IPlatformHandle Handle { get; }
+        public WindowState WindowState { get; set; }
+        public Size MaxClientSize { get; } = new Size(4096, 4096);
+        public event Action LostFocus;
+
+        protected override void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
+        {
+            // In previewer mode we completely ignore client-side viewport size
+            if (obj is ClientViewportAllocatedMessage alloc)
+            {
+                Dispatcher.UIThread.InvokeAsync(() => SetDpi(new Vector(alloc.DpiX, alloc.DpiY)));
+                return;
+            }
+            base.OnMessage(transport, obj);
+        }
+        
+        public void Resize(Size clientSize)
+        {
+            _transport.Send(new RequestViewportResizeMessage
+            {
+                Width = clientSize.Width,
+                Height = clientSize.Height
+            });
+            ClientSize = clientSize;
+            RenderIfNeeded();
+        }
+
+        public IScreenImpl Screen { get; } = new ScreenStub();
+
+        public void Activate()
+        {
+        }
+        
+        public void SetTitle(string title)
+        {
+        }
+
+        public IDisposable ShowDialog()
+        {
+            return Disposable.Empty;
+        }
+
+        public void SetSystemDecorations(bool enabled)
+        {
+        }
+
+        public void SetIcon(IWindowIconImpl icon)
+        {
+        }
+
+        public void ShowTaskbarIcon(bool value)
+        {
+        }
+    }
+}

+ 66 - 0
src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls.Platform;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Platform;
+using Avalonia.Remote.Protocol;
+using Avalonia.Rendering;
+
+namespace Avalonia.DesignerSupport.Remote
+{
+    class PreviewerWindowingPlatform : IWindowingPlatform, IPlatformSettings
+    {
+        static readonly IKeyboardDevice Keyboard = new KeyboardDevice();
+        private static IAvaloniaRemoteTransportConnection s_transport;
+        private static DetachableTransportConnection s_lastWindowTransport;
+        private static PreviewerWindowImpl s_lastWindow;
+        public static List<object> PreFlightMessages = new List<object>();
+        
+        public IWindowImpl CreateWindow() => new WindowStub();
+
+        public IEmbeddableWindowImpl CreateEmbeddableWindow()
+        {
+            if (s_lastWindow != null)
+            {
+                s_lastWindowTransport.Dispose();
+                try
+                {
+                    s_lastWindow.Dispose();
+                }
+                catch
+                {
+                    //Ignore
+                }
+            }
+            s_lastWindow =
+                new PreviewerWindowImpl(s_lastWindowTransport = new DetachableTransportConnection(s_transport));
+            foreach (var pf in PreFlightMessages)
+                s_lastWindowTransport.FireOnMessage(s_lastWindowTransport, pf);
+            return s_lastWindow;
+        }
+
+        public IPopupImpl CreatePopup() => new WindowStub();
+
+        public static void Initialize(IAvaloniaRemoteTransportConnection transport)
+        {
+            s_transport = transport;
+            var instance = new PreviewerWindowingPlatform();
+            var threading = new InternalPlatformThreadingInterface();
+            AvaloniaLocator.CurrentMutable
+                .Bind<IClipboard>().ToSingleton<ClipboardStub>()
+                .Bind<IStandardCursorFactory>().ToSingleton<CursorFactoryStub>()
+                .Bind<IKeyboardDevice>().ToConstant(Keyboard)
+                .Bind<IPlatformSettings>().ToConstant(instance)
+                .Bind<IPlatformThreadingInterface>().ToConstant(threading)
+                .Bind<IRenderLoop>().ToConstant(threading)
+                .Bind<ISystemDialogImpl>().ToSingleton<SystemDialogsStub>()
+                .Bind<IWindowingPlatform>().ToConstant(instance)
+                .Bind<IPlatformIconLoader>().ToSingleton<IconLoaderStub>();
+
+        }
+
+        public Size DoubleClickSize { get; } = new Size(2, 2);
+        public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500);
+    }
+}

+ 172 - 0
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@@ -0,0 +1,172 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Reflection;
+using Avalonia.Controls;
+using Avalonia.Controls.Shapes;
+using Avalonia.DesignerSupport;
+using Avalonia.Input;
+using Avalonia.Remote.Protocol;
+using Avalonia.Remote.Protocol.Designer;
+using Avalonia.Remote.Protocol.Viewport;
+using Avalonia.Threading;
+
+namespace Avalonia.DesignerSupport.Remote
+{
+    public class RemoteDesignerEntryPoint
+    {
+        private static ClientSupportedPixelFormatsMessage s_supportedPixelFormats;
+        private static ClientViewportAllocatedMessage s_viewportAllocatedMessage;
+        private static IAvaloniaRemoteTransportConnection s_transport;
+        class CommandLineArgs
+        {
+            public string AppPath { get; set; }
+            public Uri Transport { get; set; }
+        }
+
+        static Exception Die(string error)
+        {
+            if (error != null)
+            {
+                Console.Error.WriteLine(error);
+                Console.Error.Flush();
+            }
+            Environment.Exit(1);
+            return new Exception("APPEXIT");
+        }
+
+        static Exception PrintUsage()
+        {
+            Console.Error.WriteLine("Usage: --transport transport_spec app");
+            Console.Error.WriteLine();
+            Console.Error.WriteLine("Example: --transport tcp-bson://127.0.0.1:30243/ MyApp.exe");
+            Console.Error.Flush();
+            return Die(null);
+        }
+        
+        static CommandLineArgs ParseCommandLineArgs(string[] args)
+        {
+            var rv = new CommandLineArgs();
+            Action<string> next = null;
+            try
+            {
+                foreach (var arg in args)
+                {
+                    if (next != null)
+                    {
+                        next(arg);
+                        next = null;
+                    }
+                    else if (arg == "--transport")
+                        next = a => rv.Transport = new Uri(a, UriKind.Absolute);
+                    else if (rv.AppPath == null)
+                        rv.AppPath = arg;
+                    else
+                        PrintUsage();
+
+                }
+                if (rv.AppPath == null || rv.Transport == null)
+                    PrintUsage();
+            }
+            catch
+            {
+                PrintUsage();
+            }
+            return rv;
+        }
+
+        static IAvaloniaRemoteTransportConnection CreateTransport(Uri transport)
+        {
+            if (transport.Scheme == "tcp-bson")
+            {
+                return new BsonTcpTransport().Connect(IPAddress.Parse(transport.Host), transport.Port).Result;
+            }
+            PrintUsage();
+            return null;
+        }
+
+        interface IAppInitializer
+        {
+            Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport, object obj);
+        }
+        
+        class AppInitializer<T> : IAppInitializer where T : AppBuilderBase<T>, new()
+        {
+            public Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport, object obj)
+            {
+                var builder = (AppBuilderBase<T>) obj;
+                builder.UseWindowingSubsystem(() => PreviewerWindowingPlatform.Initialize(transport));
+                builder.SetupWithoutStarting();
+                return builder.Instance;
+            }
+        }
+
+        private const string BuilderMethodName = "BuildAvaloniaApp";
+
+        class NeverClose : ICloseable
+        {
+            public event EventHandler Closed;
+        }
+        
+        public static void Main(string[] cmdline)
+        {
+            var args = ParseCommandLineArgs(cmdline);
+            var transport = CreateTransport(args.Transport);
+            var asm = Assembly.LoadFile(System.IO.Path.GetFullPath(args.AppPath));
+            var entryPoint = asm.EntryPoint;
+            if (entryPoint == null)
+                throw Die($"Assembly {args.AppPath} doesn't have an entry point");
+            var builderMethod = entryPoint.DeclaringType.GetMethod(BuilderMethodName,
+                BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
+            if (builderMethod == null)
+                throw Die($"{entryPoint.DeclaringType.FullName} doesn't have a method named {BuilderMethodName}");
+
+            var appBuilder = builderMethod.Invoke(null, null);
+            var initializer =(IAppInitializer)Activator.CreateInstance(typeof(AppInitializer<>).MakeGenericType(appBuilder.GetType()));
+            var app = initializer.GetConfiguredApp(transport, appBuilder);
+            s_transport = transport;
+            transport.OnMessage += OnTransportMessage;
+            transport.OnException += (t, e) => Die(e.ToString());
+            app.Run(new NeverClose());
+        }
+
+
+        private static void RebuildPreFlight()
+        {
+            PreviewerWindowingPlatform.PreFlightMessages = new List<object>
+            {
+                s_supportedPixelFormats,
+                s_viewportAllocatedMessage
+            };
+        }
+        
+        private static void OnTransportMessage(IAvaloniaRemoteTransportConnection transport, object obj) => Dispatcher.UIThread.InvokeAsync(() =>
+        {
+            if (obj is ClientSupportedPixelFormatsMessage formats)
+            {
+                s_supportedPixelFormats = formats;
+                RebuildPreFlight();
+            }
+            if (obj is ClientViewportAllocatedMessage viewport)
+            {
+                s_viewportAllocatedMessage = viewport;
+                RebuildPreFlight();
+            }
+            if (obj is UpdateXamlMessage xaml)
+            {
+                try
+                {
+                    DesignWindowLoader.LoadDesignerWindow(xaml.Xaml, xaml.AssemblyPath);
+                    s_transport.Send(new UpdateXamlResultMessage());
+                }
+                catch (Exception e)
+                {
+                    s_transport.Send(new UpdateXamlResultMessage
+                    {
+                        Error = e.ToString()
+                    });
+                }
+            }
+        });
+    }
+}

+ 146 - 0
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reactive.Disposables;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Input.Raw;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+
+namespace Avalonia.DesignerSupport.Remote
+{
+    class WindowStub : IPopupImpl, IWindowImpl
+    {
+        public Action Deactivated { get; set; }
+        public Action Activated { get; set; }
+        public IPlatformHandle Handle { get; }
+        public Size MaxClientSize { get; }
+        public Size ClientSize { get; }
+        public double Scaling { get; }
+        public IEnumerable<object> Surfaces { get; }
+        public Action<RawInputEventArgs> Input { get; set; }
+        public Action<Rect> Paint { get; set; }
+        public Action<Size> Resized { get; set; }
+        public Action<double> ScalingChanged { get; set; }
+        public Action Closed { get; set; }
+        public IMouseDevice MouseDevice { get; } = new MouseDevice();
+        public Point Position { get; set; }
+        public Action<Point> PositionChanged { get; set; }
+        public WindowState WindowState { get; set; }
+        public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
+        public void Dispose()
+        {
+        }
+        public void Invalidate(Rect rect)
+        {
+        }
+
+        public void SetInputRoot(IInputRoot inputRoot)
+        {
+        }
+
+        public Point PointToClient(Point point) => point;
+
+        public Point PointToScreen(Point point) => point;
+
+        public void SetCursor(IPlatformHandle cursor)
+        {
+        }
+
+        public void Show()
+        {
+        }
+
+        public void Hide()
+        {
+        }
+
+        public void BeginMoveDrag()
+        {
+        }
+
+        public void BeginResizeDrag(WindowEdge edge)
+        {
+        }
+
+        public void Activate()
+        {
+        }
+
+        public void Resize(Size clientSize)
+        {
+        }
+
+        public IScreenImpl Screen { get; } = new ScreenStub();
+
+        public void SetTitle(string title)
+        {
+        }
+
+        public IDisposable ShowDialog() => Disposable.Empty;
+
+        public void SetSystemDecorations(bool enabled)
+        {
+        }
+
+        public void SetIcon(IWindowIconImpl icon)
+        {
+        }
+
+        public void ShowTaskbarIcon(bool value)
+        {
+        }
+    }
+
+    class ClipboardStub : IClipboard
+    {
+        public Task<string> GetTextAsync() => Task.FromResult("");
+
+        public Task SetTextAsync(string text) => Task.CompletedTask;
+
+        public Task ClearAsync() => Task.CompletedTask;
+    }
+
+    class CursorFactoryStub : IStandardCursorFactory
+    {
+        public IPlatformHandle GetCursor(StandardCursorType cursorType) => new PlatformHandle(IntPtr.Zero, "STUB");
+    }
+
+    class IconLoaderStub : IPlatformIconLoader
+    {
+        class IconStub : IWindowIconImpl
+        {
+            public void Save(Stream outputStream)
+            {
+                
+            }
+        }
+
+        public IWindowIconImpl LoadIcon(string fileName) => new IconStub();
+
+        public IWindowIconImpl LoadIcon(Stream stream) => new IconStub();
+
+        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) => new IconStub();
+    }
+
+    class SystemDialogsStub : ISystemDialogImpl
+    {
+        public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) =>
+            Task.FromResult((string[]) null);
+
+        public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) =>
+            Task.FromResult((string) null);
+    }
+
+    class ScreenStub : IScreenImpl
+    {
+        public int ScreenCount => 1;
+
+        public Screen[] AllScreens { get; } =
+            {new Screen(new Rect(0, 0, 4000, 4000), new Rect(0, 0, 4000, 4000), true)};
+    }
+}

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

@@ -2,6 +2,7 @@
   <PropertyGroup>
     <TargetFramework>netcoreapp2.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <DefineConstants>$(DefineConstants);DOTNETCORE</DefineConstants>
   </PropertyGroup>
   <PropertyGroup>
     <DocumentationFile>bin\$(Configuration)\Avalonia.DotNetCoreRuntime.XML</DocumentationFile>
@@ -21,5 +22,5 @@
     <ProjectReference Include="..\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj" />
   </ItemGroup>
   <Import Project="..\..\build\NetCore.props" />
-  <Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
+  <Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" />
 </Project>

+ 0 - 42
src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs

@@ -1,42 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.DotNet.PlatformAbstractions;
-using Microsoft.Extensions.DependencyModel;
-
-namespace Avalonia.Shared.PlatformSupport
-{
-    internal partial class StandardRuntimePlatform
-    {
-        private static readonly Lazy<Assembly[]> Assemblies = new Lazy<Assembly[]>(LoadAssemblies);
-        public Assembly[] GetLoadedAssemblies() => Assemblies.Value;
-
-        static Assembly[] LoadAssemblies()
-        {
-            var assemblies = new List<Assembly>();
-            // Mostly copy-pasted from (MIT):
-            // https://github.com/StefH/System.AppDomain.Core/blob/0b35e676c2721aa367b96e62eb52c97ee0b43a70/src/System.AppDomain.NetCoreApp/AppDomain.cs
-
-            foreach (var assemblyName in
-                DependencyContext.Default.GetRuntimeAssemblyNames(RuntimeEnvironment.GetRuntimeIdentifier()))
-            {
-                try
-                {
-                    var assembly = Assembly.Load(assemblyName);
-                    // just load all types and skip this assembly if one or more types cannot be resolved
-                    assembly.DefinedTypes.ToArray();
-                    assemblies.Add(assembly);
-                }
-                catch (Exception ex)
-                {
-                    Debug.Write(ex.Message);
-                }
-            }
-            return assemblies.ToArray();
-        }
-    }
-}

+ 0 - 1
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@@ -10,7 +10,6 @@
         <Compile Include="..\Shared\SharedAssemblyInfo.cs">
             <Link>Properties\SharedAssemblyInfo.cs</Link>
         </Compile>
-
         <ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
         <ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
         <ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />

+ 4 - 1
src/Avalonia.Input/Key.cs

@@ -1,7 +1,10 @@
 // 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.
-
+#if AVALONIA_REMOTE_PROTOCOL
+namespace Avalonia.Remote.Protocol.Input
+#else
 namespace Avalonia.Input
+#endif
 {
     /// <summary>
     /// Defines the keys available on a keyboard.

+ 20 - 2
src/Avalonia.Input/MouseDevice.cs

@@ -20,6 +20,8 @@ namespace Avalonia.Input
         private int _clickCount;
         private Rect _lastClickRect;
         private uint _lastClickTime;
+        private IInputElement _captured;
+        private IDisposable _capturedSubscription;
        
         /// <summary>
         /// Gets the control that is currently capturing by the mouse, if any.
@@ -31,8 +33,23 @@ namespace Avalonia.Input
         /// </remarks>
         public IInputElement Captured
         {
-            get;
-            protected set;
+            get => _captured;
+            protected set
+            {
+                _capturedSubscription?.Dispose();
+                _capturedSubscription = null;
+
+                if (value != null)
+                {
+                    _capturedSubscription = Observable.FromEventPattern<VisualTreeAttachmentEventArgs>(
+                        x => value.DetachedFromVisualTree += x,
+                        x => value.DetachedFromVisualTree -= x)
+                        .Take(1)
+                        .Subscribe(_ => Captured = null);
+                }
+
+                _captured = value;
+            }
         }
         
         /// <summary>
@@ -55,6 +72,7 @@ namespace Avalonia.Input
         /// </remarks>
         public virtual void Capture(IInputElement control)
         {
+            // TODO: Check visibility and enabled state before setting capture.
             Captured = control;
         }
 

+ 1 - 1
src/Avalonia.Layout/LayoutManager.cs

@@ -203,7 +203,7 @@ namespace Avalonia.Layout
         {
             if (!_queued && !_running)
             {
-                Dispatcher.UIThread.InvokeAsync(ExecuteLayoutPass, DispatcherPriority.Render);
+                Dispatcher.UIThread.InvokeAsync(ExecuteLayoutPass, DispatcherPriority.Layout);
                 _queued = true;
             }
         }

+ 9 - 0
src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj

@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <DefineConstants>AVALONIA_REMOTE_PROTOCOL;$(DefineConstants)</DefineConstants>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="..\Avalonia.Input\Key.cs" />
+  </ItemGroup>
+</Project>

+ 19 - 0
src/Avalonia.Remote.Protocol/AvaloniaRemoteMessageGuidAttribute.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Remote.Protocol
+{
+    [AttributeUsage(AttributeTargets.Class)]
+    public class AvaloniaRemoteMessageGuidAttribute : Attribute
+    {
+        public Guid Guid { get; }
+
+        public AvaloniaRemoteMessageGuidAttribute(string guid)
+        {
+            Guid = Guid.Parse(guid);
+        }
+    }
+}

+ 150 - 0
src/Avalonia.Remote.Protocol/BsonStreamTransport.cs

@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Metsys.Bson;
+
+namespace Avalonia.Remote.Protocol
+{
+    class BsonStreamTransportConnection : IAvaloniaRemoteTransportConnection
+    {
+        private readonly IMessageTypeResolver _resolver;
+        private readonly Stream _inputStream;
+        private readonly Stream _outputStream;
+        private readonly Action _disposeCallback;
+        private readonly CancellationToken _cancel;
+        private readonly CancellationTokenSource _cancelSource;
+        private readonly MemoryStream _outputBlock = new MemoryStream();
+        private readonly object _lock = new object();
+        private bool _writeOperationPending;
+        private bool _readingAlreadyStarted;
+        private bool _writerIsBroken;   
+        private static readonly byte[] ZeroLength = new byte[4];
+
+        public BsonStreamTransportConnection(IMessageTypeResolver resolver, Stream inputStream, Stream outputStream, Action disposeCallback)
+        {
+            _resolver = resolver;
+            _inputStream = inputStream;
+            _outputStream = outputStream;
+            _disposeCallback = disposeCallback;
+            _cancelSource = new CancellationTokenSource();
+            _cancel = _cancelSource.Token;
+        }
+
+        public void Dispose()
+        {
+            _cancelSource.Cancel();
+            _disposeCallback?.Invoke();
+        }
+        
+        public void StartReading()
+        {
+            lock (_lock)
+            {
+                if(_readingAlreadyStarted)
+                    throw new InvalidOperationException("Reading has already started");
+                _readingAlreadyStarted = true;
+                Task.Run(Reader, _cancel);
+            }
+        }
+
+        async Task ReadExact(byte[] buffer)
+        {
+            int read = 0;
+            while (read != buffer.Length)
+            {
+                var readNow = await _inputStream.ReadAsync(buffer, read, buffer.Length - read, _cancel)
+                    .ConfigureAwait(false);
+                if (readNow == 0)
+                    throw new EndOfStreamException();
+                read += readNow;
+            }
+        }
+
+        async Task Reader()
+        {
+            Task.Yield();
+            try
+            {
+                while (true)
+                {
+                    var infoBlock = new byte[20];
+                    await ReadExact(infoBlock).ConfigureAwait(false);
+                    var length = BitConverter.ToInt32(infoBlock, 0);
+                    var guidBytes = new byte[16];
+                    Buffer.BlockCopy(infoBlock, 4, guidBytes, 0, 16);
+                    var guid = new Guid(guidBytes);
+                    var buffer = new byte[length];
+                    await ReadExact(buffer).ConfigureAwait(false);
+                    var message = Deserializer.Deserialize(new BinaryReader(new MemoryStream(buffer)),
+                        _resolver.GetByGuid(guid));
+                    OnMessage?.Invoke(this, message);
+                }
+            }
+            catch (Exception e)
+            {
+                FireException(e);
+            }
+        }
+
+
+        public async Task Send(object data)
+        {
+            lock (_lock)
+            {
+                if(_writerIsBroken) //Ignore further calls, since there is no point of writing to "broken" stream
+                    return;
+                if (_writeOperationPending)
+                    throw new InvalidOperationException("Previous send operation was not finished");
+                _writeOperationPending = true;
+            }
+            try
+            {
+                var guid = _resolver.GetGuid(data.GetType()).ToByteArray();
+                _outputBlock.Seek(0, SeekOrigin.Begin);
+                _outputBlock.SetLength(0);
+                _outputBlock.Write(ZeroLength, 0, 4);
+                _outputBlock.Write(guid, 0, guid.Length);
+                var serialized = Serializer.Serialize(data);
+                _outputBlock.Write(serialized, 0, serialized.Length);
+                _outputBlock.Seek(0, SeekOrigin.Begin);
+                var length = BitConverter.GetBytes((int)_outputBlock.Length - 20);
+                _outputBlock.Write(length, 0, length.Length);
+                _outputBlock.Seek(0, SeekOrigin.Begin);
+
+                try
+                {
+                    await _outputBlock.CopyToAsync(_outputStream, 0x1000, _cancel).ConfigureAwait(false);
+                }
+                catch (Exception e) //We are only catching "network"-related exceptions here
+                {
+                    lock (_lock)
+                    {
+                        _writerIsBroken = true;
+                    }
+                    FireException(e);
+                }
+            }
+            finally
+            {
+                lock (_lock)
+                {
+                    _writeOperationPending = false;
+                }
+            }
+        }
+
+        void FireException(Exception e)
+        {
+            var cancel = e as OperationCanceledException;
+            if (cancel?.CancellationToken == _cancel)
+                return;
+            OnException?.Invoke(this, e);
+        }
+
+
+        public event Action<IAvaloniaRemoteTransportConnection, object> OnMessage;
+        public event Action<IAvaloniaRemoteTransportConnection, Exception> OnException;
+    }
+}

+ 27 - 0
src/Avalonia.Remote.Protocol/BsonTcpTransport.cs

@@ -0,0 +1,27 @@
+using System;
+using System.IO;
+using System.Reflection;
+
+namespace Avalonia.Remote.Protocol
+{
+    public class BsonTcpTransport : TcpTransportBase
+    {
+        public BsonTcpTransport(IMessageTypeResolver resolver) : base(resolver)
+        {
+        }
+
+        public BsonTcpTransport() : this(new DefaultMessageTypeResolver(typeof(BsonTcpTransport).GetTypeInfo().Assembly))
+        {
+            
+        }
+
+        protected override IAvaloniaRemoteTransportConnection CreateTransport(IMessageTypeResolver resolver,
+            Stream stream, Action dispose)
+        {
+            var t = new BsonStreamTransportConnection(resolver, stream, stream, dispose);
+            var wrap = new TransportConnectionWrapper(t);
+            t.StartReading();
+            return wrap;
+        }
+    }
+}

+ 35 - 0
src/Avalonia.Remote.Protocol/DefaultMessageTypeResolver.cs

@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Remote.Protocol
+{
+    public class DefaultMessageTypeResolver : IMessageTypeResolver
+    {
+        private readonly Dictionary<Guid, Type> _guidsToTypes = new Dictionary<Guid, Type>();
+        private readonly Dictionary<Type, Guid> _typesToGuids = new Dictionary<Type, Guid>();
+        public DefaultMessageTypeResolver(params Assembly[] assemblies)
+        {
+            foreach (var asm in
+                (assemblies ?? new Assembly[0]).Concat(new[]
+                    {typeof(AvaloniaRemoteMessageGuidAttribute).GetTypeInfo().Assembly}))
+            {
+                foreach (var t in asm.ExportedTypes)
+                {
+                    var attr = t.GetTypeInfo().GetCustomAttribute<AvaloniaRemoteMessageGuidAttribute>();
+                    if (attr != null)
+                    {
+                        _guidsToTypes[attr.Guid] = t;
+                        _typesToGuids[t] = attr.Guid;
+                    }
+                }
+            }
+        }
+
+        public Type GetByGuid(Guid id) => _guidsToTypes[id];
+        public Guid GetGuid(Type type) => _typesToGuids[type];
+    }
+}

+ 17 - 0
src/Avalonia.Remote.Protocol/DesignMessages.cs

@@ -0,0 +1,17 @@
+namespace Avalonia.Remote.Protocol.Designer
+{
+    [AvaloniaRemoteMessageGuid("9AEC9A2E-6315-4066-B4BA-E9A9EFD0F8CC")]
+    public class UpdateXamlMessage
+    {
+        public string Xaml { get; set; }
+        public string AssemblyPath { get; set; }
+    }
+
+    [AvaloniaRemoteMessageGuid("B7A70093-0C5D-47FD-9261-22086D43A2E2")]
+    public class UpdateXamlResultMessage
+    {
+        public string Error { get; set; }
+    }
+    
+    
+}

+ 74 - 0
src/Avalonia.Remote.Protocol/EventStash.cs

@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+
+namespace Avalonia.Remote.Protocol
+{
+    class EventStash<T>
+    {
+        private readonly IAvaloniaRemoteTransportConnection _transport;
+        private readonly Action<Exception> _exceptionHandler;
+        private List<T> _stash;
+        private Action<IAvaloniaRemoteTransportConnection, T> _delegate;
+
+        public EventStash(IAvaloniaRemoteTransportConnection transport, Action<Exception> exceptionHandler = null)
+        {
+            _transport = transport;
+            _exceptionHandler = exceptionHandler;
+        }
+        
+        public void Add(Action<IAvaloniaRemoteTransportConnection, T> handler)
+        {
+            List<T> stash;
+            lock (this)
+            {
+                var needsReplay = _delegate == null;
+                _delegate += handler;
+                if(!needsReplay)
+                    return;
+
+                lock (this)
+                {
+                    stash = _stash;
+                    if(_stash == null)
+                        return;
+                    _stash = null;
+                }
+            }
+            foreach (var m in stash)
+            {
+                if (_exceptionHandler != null)
+                    try
+                    {
+                        _delegate?.Invoke(_transport, m);
+                    }
+                    catch (Exception e)
+                    {
+                        _exceptionHandler(e);
+                    }
+                else
+                    _delegate?.Invoke(_transport, m);
+            }
+        }
+        
+        
+        public void Remove(Action<IAvaloniaRemoteTransportConnection, T> handler)
+        {
+            lock (this)
+                _delegate -= handler;
+        }
+
+        public void Fire(IAvaloniaRemoteTransportConnection transport, T ev)
+        {
+            if (_delegate == null)
+            {
+                lock (this)
+                {
+                    _stash = _stash ?? new List<T>();
+                    _stash.Add(ev);
+                }
+            }
+            else
+                _delegate?.Invoke(_transport, ev);
+        }
+    }
+}

+ 10 - 0
src/Avalonia.Remote.Protocol/IMessageTypeResolver.cs

@@ -0,0 +1,10 @@
+using System;
+
+namespace Avalonia.Remote.Protocol
+{
+    public interface IMessageTypeResolver
+    {
+        Type GetByGuid(Guid id);
+        Guid GetGuid(Type type);
+    }
+}

+ 15 - 0
src/Avalonia.Remote.Protocol/ITransport.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Remote.Protocol
+{
+    public interface IAvaloniaRemoteTransportConnection : IDisposable
+    {
+        Task Send(object data);
+        event Action<IAvaloniaRemoteTransportConnection, object> OnMessage;
+        event Action<IAvaloniaRemoteTransportConnection, Exception> OnException;
+    }
+}

+ 82 - 0
src/Avalonia.Remote.Protocol/InputMessages.cs

@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+/*
+ We are keeping copies of core events here, so they can be used 
+ without referencing Avalonia itself, e. g. from projects that
+ are using WPF, GTK#, etc
+ */
+namespace Avalonia.Remote.Protocol.Input
+{
+    /// <summary>
+    /// Keep this in sync with InputModifiers in the main library
+    /// </summary>
+    [Flags]
+    public enum InputModifiers
+    {
+        Alt,
+        Control,
+        Shift,
+        Windows,
+        LeftMouseButton,
+        RightMouseButton,
+        MiddleMouseButton
+    }
+
+    /// <summary>
+    /// Keep this in sync with InputModifiers in the main library
+    /// </summary>
+    public enum MouseButton
+    {
+        None,
+        Left,
+        Right,
+        Middle
+    }
+
+    public abstract class InputEventMessageBase
+    {
+        public InputModifiers[] Modifiers { get; set; }
+    }
+
+    public abstract class PointerEventMessageBase : InputEventMessageBase
+    {
+        public double X { get; set; }
+        public double Y { get; set; }
+    }
+
+    [AvaloniaRemoteMessageGuid("6228F0B9-99F2-4F62-A621-414DA2881648")]
+    public class PointerMovedEventMessage : PointerEventMessageBase
+    {
+        
+    }
+
+    [AvaloniaRemoteMessageGuid("7E9E2818-F93F-411A-800E-6B1AEB11DA46")]
+    public class PointerPressedEventMessage : PointerEventMessageBase
+    {
+        public MouseButton Button { get; set; }
+    }
+    
+    [AvaloniaRemoteMessageGuid("4ADC84EE-E7C8-4BCF-986C-DE3A2F78EDE4")]
+    public class PointerReleasedEventMessage : PointerEventMessageBase
+    {
+        public MouseButton Button { get; set; }
+    }
+
+    [AvaloniaRemoteMessageGuid("79301A05-F02D-4B90-BB39-472563B504AE")]
+    public class ScrollEventMessage : PointerEventMessageBase
+    {
+        public double DeltaX { get; set; }
+        public double DeltaY { get; set; }
+    }
+
+    [AvaloniaRemoteMessageGuid("1C3B691E-3D54-4237-BFB0-9FEA83BC1DB8")]
+    public class KeyEventMessage : InputEventMessageBase
+    {
+        public bool IsDown { get; set; }
+        public Key Key { get; set; }
+    }
+
+}

+ 1632 - 0
src/Avalonia.Remote.Protocol/MetsysBson.cs

@@ -0,0 +1,1632 @@
+/*
+Copyright (c) 2010, Karl Seguin - http://www.openmymind.net/
+All rights reserved.
+ 
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the <organization> nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+ 
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Code imported from https://github.com/elaberge/Metsys.Bson without any changes
+
+*/
+
+using System.Text;
+using System.Text.RegularExpressions;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Net;
+using System.Security.Cryptography;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System;
+using System.Runtime.Serialization;
+
+using Metsys.Bson.Configuration;
+// ReSharper disable All
+
+namespace Metsys.Bson
+{
+    internal enum Types
+    {
+        Double = 1,
+        String = 2,
+        Object = 3,
+        Array = 4,
+        Binary = 5,
+        Undefined = 6,
+        ObjectId = 7,
+        Boolean = 8,
+        DateTime = 9,
+        Null = 10,
+        Regex = 11,
+        Reference = 12,
+        Code = 13,
+        Symbol = 14,
+        ScopedCode = 15,
+        Int32 = 16,
+        Timestamp = 17,
+        Int64 = 18,
+    }
+}
+
+namespace Metsys.Bson
+{
+
+    internal class Serializer
+    {
+        private static readonly IDictionary<Type, Types> _typeMap = new Dictionary<Type, Types>
+                                                                            {
+                                                                                {typeof (int), Types.Int32},
+                                                                                {typeof (long), Types.Int64},
+                                                                                {typeof (bool), Types.Boolean},
+                                                                                {typeof (string), Types.String},
+                                                                                {typeof (double), Types.Double},
+                                                                                {typeof (Guid), Types.Binary},
+                                                                                {typeof (Regex), Types.Regex},
+                                                                                {typeof (DateTime), Types.DateTime},
+                                                                                {typeof (float), Types.Double},
+                                                                                {typeof (byte[]), Types.Binary},
+                                                                                {typeof (ObjectId), Types.ObjectId},
+                                                                                {typeof (ScopedCode), Types.ScopedCode}
+                                                                            };
+
+        private readonly BinaryWriter _writer;
+        private Document _current;
+
+        public static byte[] Serialize<T>(T document)
+        {
+            var type = document.GetType();
+            if (type.IsValueType ||
+                (typeof(IEnumerable).IsAssignableFrom(type) && typeof(IDictionary).IsAssignableFrom(type) == false)
+            )
+            {
+                throw new BsonException("Root type must be an object");
+            }
+            using (var ms = new MemoryStream(250))
+            using (var writer = new BinaryWriter(ms))
+            {
+                new Serializer(writer).WriteDocument(document);
+                return ms.ToArray();
+            }
+        }
+        public static byte[] Serialize(object document)
+        {
+            var type = document.GetType();
+            if (type.IsValueType ||
+                (typeof(IEnumerable).IsAssignableFrom(type) && typeof(IDictionary).IsAssignableFrom(type) == false)
+            )
+            {
+                throw new BsonException("Root type must be an object");
+            }
+            using (var ms = new MemoryStream(250))
+            using (var writer = new BinaryWriter(ms))
+            {
+                new Serializer(writer).WriteDocument(document);
+                return ms.ToArray();
+            }
+        }
+
+        private Serializer(BinaryWriter writer)
+        {
+            _writer = writer;
+        }
+
+        private void NewDocument()
+        {
+            var old = _current;
+            _current = new Document { Parent = old, Length = (int)_writer.BaseStream.Position, Digested = 4 };
+            _writer.Write(0); // length placeholder
+        }
+        private void EndDocument(bool includeEeo)
+        {
+            var old = _current;
+            if (includeEeo)
+            {
+                Written(1);
+                _writer.Write((byte)0);
+            }
+
+            _writer.Seek(_current.Length, SeekOrigin.Begin);
+            _writer.Write(_current.Digested); // override the document length placeholder
+            _writer.Seek(0, SeekOrigin.End); // back to the end
+            _current = _current.Parent;
+            if (_current != null)
+            {
+                Written(old.Digested);
+            }
+        }
+
+        private void Written(int length)
+        {
+            _current.Digested += length;
+        }
+
+        private void WriteDocument(object document)
+        {
+            NewDocument();
+            WriteObject(document);
+            EndDocument(true);
+        }
+
+        private void WriteObject(object document)
+        {
+            var asDictionary = document as IDictionary;
+            if (asDictionary != null)
+            {
+                Write(asDictionary);
+                return;
+            }
+
+            var typeHelper = TypeHelper.GetHelperForType(document.GetType());
+            foreach (var property in typeHelper.GetProperties())
+            {
+                if (property.Ignored) { continue; }
+                var name = property.Name;
+                var value = property.Getter(document);
+                if (value == null && property.IgnoredIfNull)
+                {
+                    continue;
+                }
+                SerializeMember(name, value);
+            }
+        }
+
+        private void SerializeMember(string name, object value)
+        {
+            if (value == null)
+            {
+                Write(Types.Null);
+                WriteName(name);
+                return;
+            }
+
+            var type = value.GetType();
+            if (type.IsEnum)
+            {
+                type = Enum.GetUnderlyingType(type);
+            }
+
+            Types storageType;
+            if (!_typeMap.TryGetValue(type, out storageType))
+            {
+                // this isn't a simple type;
+                Write(name, value);
+                return;
+            }
+
+            Write(storageType);
+            WriteName(name);
+            switch (storageType)
+            {
+                case Types.Int32:
+                    Written(4);
+                    _writer.Write((int)value);
+                    return;
+                case Types.Int64:
+                    Written(8);
+                    _writer.Write((long)value);
+                    return;
+                case Types.String:
+                    Write((string)value);
+                    return;
+                case Types.Double:
+                    Written(8);
+                    if (value is float)
+                    {
+                        _writer.Write(Convert.ToDouble((float)value));
+                    }
+                    else
+                    {
+                        _writer.Write((double)value);
+                    }
+
+                    return;
+                case Types.Boolean:
+                    Written(1);
+                    _writer.Write((bool)value ? (byte)1 : (byte)0);
+                    return;
+                case Types.DateTime:
+                    Written(8);
+                    _writer.Write((long)((DateTime)value).ToUniversalTime().Subtract(Helper.Epoch).TotalMilliseconds);
+                    return;
+                case Types.Binary:
+                    WriteBinnary(value);
+                    return;
+                case Types.ScopedCode:
+                    Write((ScopedCode)value);
+                    return;
+                case Types.ObjectId:
+                    Written(((ObjectId)value).Value.Length);
+                    _writer.Write(((ObjectId)value).Value);
+                    return;
+                case Types.Regex:
+                    Write((Regex)value);
+                    break;
+            }
+        }
+
+        private void Write(string name, object value)
+        {
+            if (value is IDictionary)
+            {
+                Write(Types.Object);
+                WriteName(name);
+                NewDocument();
+                Write((IDictionary)value);
+                EndDocument(true);
+            }
+            else if (value is IEnumerable)
+            {
+                Write(Types.Array);
+                WriteName(name);
+                NewDocument();
+                Write((IEnumerable)value);
+                EndDocument(true);
+            }
+            else
+            {
+                Write(Types.Object);
+                WriteName(name);
+                WriteDocument(value); // Write manages new/end document
+            }
+        }
+
+        private void Write(IEnumerable enumerable)
+        {
+            var index = 0;
+            foreach (var value in enumerable)
+            {
+                SerializeMember((index++).ToString(), value);
+            }
+        }
+
+        private void Write(IDictionary dictionary)
+        {
+            foreach (var key in dictionary.Keys)
+            {
+                SerializeMember((string)key, dictionary[key]);
+            }
+        }
+
+        private void WriteBinnary(object value)
+        {
+            if (value is byte[])
+            {
+                var bytes = (byte[])value;
+                var length = bytes.Length;
+                _writer.Write(length + 4);
+                _writer.Write((byte)2);
+                _writer.Write(length);
+                _writer.Write(bytes);
+                Written(9 + length);
+            }
+            else if (value is Guid)
+            {
+                var guid = (Guid)value;
+                var bytes = guid.ToByteArray();
+                _writer.Write(bytes.Length);
+                _writer.Write((byte)3);
+                _writer.Write(bytes);
+                Written(5 + bytes.Length);
+            }
+        }
+
+        private void Write(Types type)
+        {
+            _writer.Write((byte)type);
+            Written(1);
+        }
+
+        private void WriteName(string name)
+        {
+            var bytes = Encoding.UTF8.GetBytes(name);
+            _writer.Write(bytes);
+            _writer.Write((byte)0);
+            Written(bytes.Length + 1);
+        }
+
+        private void Write(string name)
+        {
+            var bytes = Encoding.UTF8.GetBytes(name);
+            _writer.Write(bytes.Length + 1);
+            _writer.Write(bytes);
+            _writer.Write((byte)0);
+            Written(bytes.Length + 5); // stringLength + length + null byte
+        }
+
+        private void Write(Regex regex)
+        {
+            WriteName(regex.ToString());
+
+            var options = string.Empty;
+            if ((regex.Options & RegexOptions.ECMAScript) == RegexOptions.ECMAScript)
+            {
+                options = string.Concat(options, 'e');
+            }
+
+            if ((regex.Options & RegexOptions.IgnoreCase) == RegexOptions.IgnoreCase)
+            {
+                options = string.Concat(options, 'i');
+            }
+
+            if ((regex.Options & RegexOptions.CultureInvariant) == RegexOptions.CultureInvariant)
+            {
+                options = string.Concat(options, 'l');
+            }
+
+            if ((regex.Options & RegexOptions.Multiline) == RegexOptions.Multiline)
+            {
+                options = string.Concat(options, 'm');
+            }
+
+            if ((regex.Options & RegexOptions.Singleline) == RegexOptions.Singleline)
+            {
+                options = string.Concat(options, 's');
+            }
+
+            options = string.Concat(options, 'u'); // all .net regex are unicode regex, therefore:
+            if ((regex.Options & RegexOptions.IgnorePatternWhitespace) == RegexOptions.IgnorePatternWhitespace)
+            {
+                options = string.Concat(options, 'w');
+            }
+
+            if ((regex.Options & RegexOptions.ExplicitCapture) == RegexOptions.ExplicitCapture)
+            {
+                options = string.Concat(options, 'x');
+            }
+
+            WriteName(options);
+        }
+
+        private void Write(ScopedCode value)
+        {
+            NewDocument();
+            Write(value.CodeString);
+            WriteDocument(value.Scope);
+            EndDocument(false);
+        }
+    }
+}
+namespace Metsys.Bson
+{
+    internal class ScopedCode
+    {
+        public string CodeString { get; set; }
+        public object Scope { get; set; }
+    }
+
+    internal class ScopedCode<T> : ScopedCode
+    {
+        public new T Scope { get; set; }
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal static class ObjectIdGenerator
+    {
+        private static readonly object _inclock = new object();
+
+        private static int _counter;
+        private static readonly byte[] _machineHash = GenerateHostHash();
+        private static readonly byte[] _processId = BitConverter.GetBytes(GenerateProcId());
+
+        public static byte[] Generate()
+        {
+            var oid = new byte[12];
+            var copyidx = 0;
+
+            Array.Copy(BitConverter.GetBytes(GenerateTime()), 0, oid, copyidx, 4);
+            copyidx += 4;
+
+            Array.Copy(_machineHash, 0, oid, copyidx, 3);
+            copyidx += 3;
+
+            Array.Copy(_processId, 0, oid, copyidx, 2);
+            copyidx += 2;
+
+            Array.Copy(BitConverter.GetBytes(GenerateInc()), 0, oid, copyidx, 3);
+            return oid;
+        }
+
+        private static int GenerateTime()
+        {
+            var now = DateTime.Now.ToUniversalTime();
+
+            var nowtime = new DateTime(Helper.Epoch.Year, Helper.Epoch.Month, Helper.Epoch.Day, now.Hour, now.Minute, now.Second, now.Millisecond);
+            var diff = nowtime - Helper.Epoch;
+            return Convert.ToInt32(Math.Floor(diff.TotalMilliseconds));
+        }
+
+        private static int GenerateInc()
+        {
+            lock (_inclock)
+            {
+                return _counter++;
+            }
+        }
+
+        private static byte[] GenerateHostHash()
+        {
+            using (var md5 = MD5.Create())
+            {
+                var host = Dns.GetHostName();
+                return md5.ComputeHash(Encoding.Default.GetBytes(host));
+            }
+        }
+        private static int GenerateProcId()
+        {
+            var proc = Process.GetCurrentProcess();
+            return proc.Id;
+        }
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal class ObjectId
+    {
+        private string _string;
+
+        public ObjectId()
+        {
+        }
+
+        public ObjectId(string value) : this(DecodeHex(value))
+        {
+        }
+
+        internal ObjectId(byte[] value)
+        {
+            Value = value;
+        }
+
+        public static ObjectId Empty
+        {
+            get { return new ObjectId("000000000000000000000000"); }
+        }
+
+        public byte[] Value { get; private set; }
+
+        public static ObjectId NewObjectId()
+        {
+            // TODO: generate random-ish bits.
+            return new ObjectId { Value = ObjectIdGenerator.Generate() };
+        }
+
+        public static bool TryParse(string value, out ObjectId id)
+        {
+            id = Empty;
+            if (value == null || value.Length != 24)
+            {
+                return false;
+            }
+
+            try
+            {
+                id = new ObjectId(value);
+                return true;
+            }
+            catch (FormatException)
+            {
+                return false;
+            }
+        }
+
+        public static bool operator ==(ObjectId a, ObjectId b)
+        {
+            if (ReferenceEquals(a, b))
+            {
+                return true;
+            }
+
+            if (((object)a == null) || ((object)b == null))
+            {
+                return false;
+            }
+
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(ObjectId a, ObjectId b)
+        {
+            return !(a == b);
+        }
+
+        public override int GetHashCode()
+        {
+            return Value != null ? ToString().GetHashCode() : 0;
+        }
+
+        public override string ToString()
+        {
+            if (_string == null && Value != null)
+            {
+                _string = BitConverter.ToString(Value).Replace("-", string.Empty).ToLower();
+            }
+
+            return _string;
+        }
+
+        public override bool Equals(object o)
+        {
+            var other = o as ObjectId;
+            return Equals(other);
+        }
+
+        public bool Equals(ObjectId other)
+        {
+            return other != null && ToString() == other.ToString();
+        }
+
+        protected static byte[] DecodeHex(string val)
+        {
+            var chars = val.ToCharArray();
+            var numberChars = chars.Length;
+            var bytes = new byte[numberChars / 2];
+
+            for (var i = 0; i < numberChars; i += 2)
+            {
+                bytes[i / 2] = Convert.ToByte(new string(chars, i, 2), 16);
+            }
+
+            return bytes;
+        }
+
+        public static implicit operator string(ObjectId oid)
+        {
+            return oid == null ? null : oid.ToString();
+        }
+        public static implicit operator ObjectId(string oidString)
+        {
+            return new ObjectId(oidString);
+        }
+    }
+}
+
+namespace Metsys.Bson
+{
+    public interface IExpando
+    {
+        IDictionary<string, object> Expando { get; }
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal class MagicProperty
+    {
+        private readonly PropertyInfo _property;
+        private readonly string _name;
+        private readonly bool _ignored;
+        public readonly bool _ignoredIfNull;
+
+        public Type Type
+        {
+            get { return _property.PropertyType; }
+        }
+        public string Name
+        {
+            get { return _name; }
+        }
+        public bool Ignored
+        {
+            get { return _ignored; }
+        }
+        public bool IgnoredIfNull
+        {
+            get { return _ignoredIfNull; }
+        }
+
+        public Action<object, object> Setter { get; private set; }
+
+        public Func<object, object> Getter { get; private set; }
+
+        public MagicProperty(PropertyInfo property, string name, bool ignored, bool ignoredIfNull)
+        {
+            _property = property;
+            _name = name;
+            _ignored = ignored;
+            _ignoredIfNull = ignoredIfNull;
+            Getter = CreateGetterMethod(property);
+            Setter = CreateSetterMethod(property);
+        }
+
+        private static Action<object, object> CreateSetterMethod(PropertyInfo property)
+        {
+            var genericHelper = typeof(MagicProperty).GetMethod("SetterMethod", BindingFlags.Static | BindingFlags.NonPublic);
+            var constructedHelper = genericHelper.MakeGenericMethod(property.DeclaringType, property.PropertyType);
+            return (Action<object, object>)constructedHelper.Invoke(null, new object[] { property });
+        }
+
+        private static Func<object, object> CreateGetterMethod(PropertyInfo property)
+        {
+            var genericHelper = typeof(MagicProperty).GetMethod("GetterMethod", BindingFlags.Static | BindingFlags.NonPublic);
+            var constructedHelper = genericHelper.MakeGenericMethod(property.DeclaringType, property.PropertyType);
+            return (Func<object, object>)constructedHelper.Invoke(null, new object[] { property });
+        }
+
+        //called via reflection       
+        private static Action<object, object> SetterMethod<TTarget, TParam>(PropertyInfo method) where TTarget : class
+        {
+            var m = method.GetSetMethod(true);
+            if (m == null) { return null; } //no setter
+            var func = (Action<TTarget, TParam>)Delegate.CreateDelegate(typeof(Action<TTarget, TParam>), m);
+            return (target, param) => func((TTarget)target, (TParam)param);
+        }
+
+        //called via reflection
+        private static Func<object, object> GetterMethod<TTarget, TParam>(PropertyInfo method) where TTarget : class
+        {
+            var m = method.GetGetMethod(true);
+            var func = (Func<TTarget, TParam>)Delegate.CreateDelegate(typeof(Func<TTarget, TParam>), m);
+            return target => func((TTarget)target);
+        }
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal class TypeHelper
+    {
+        private static readonly IDictionary<Type, TypeHelper> _cachedTypeLookup = new Dictionary<Type, TypeHelper>();
+        private static readonly BsonConfiguration _configuration = BsonConfiguration.Instance;
+
+        private readonly IDictionary<string, MagicProperty> _properties;
+
+        private TypeHelper(Type type)
+        {
+            var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
+            _properties = LoadMagicProperties(type, properties);
+            if (typeof(IExpando).IsAssignableFrom(type))
+            {
+                Expando = _properties["Expando"];
+            }
+        }
+
+        public MagicProperty Expando { get; private set; }
+
+        public ICollection<MagicProperty> GetProperties()
+        {
+            return _properties.Values;
+        }
+
+        public MagicProperty FindProperty(string name)
+        {
+            return _properties.ContainsKey(name) ? _properties[name] : null;
+        }
+
+        public static TypeHelper GetHelperForType(Type type)
+        {
+            TypeHelper helper;
+            if (!_cachedTypeLookup.TryGetValue(type, out helper))
+            {
+                helper = new TypeHelper(type);
+                _cachedTypeLookup[type] = helper;
+            }
+            return helper;
+        }
+
+        public static string FindProperty(LambdaExpression lambdaExpression)
+        {
+            Expression expressionToCheck = lambdaExpression;
+
+            var done = false;
+            while (!done)
+            {
+                switch (expressionToCheck.NodeType)
+                {
+                    case ExpressionType.Convert:
+                        expressionToCheck = ((UnaryExpression)expressionToCheck).Operand;
+                        break;
+
+                    case ExpressionType.Lambda:
+                        expressionToCheck = ((LambdaExpression)expressionToCheck).Body;
+                        break;
+
+                    case ExpressionType.MemberAccess:
+                        var memberExpression = (MemberExpression)expressionToCheck;
+
+                        if (memberExpression.Expression.NodeType != ExpressionType.Parameter && memberExpression.Expression.NodeType != ExpressionType.Convert)
+                        {
+                            throw new ArgumentException(string.Format("Expression '{0}' must resolve to top-level member.", lambdaExpression), "lambdaExpression");
+                        }
+                        return memberExpression.Member.Name;
+                    default:
+                        done = true;
+                        break;
+                }
+            }
+
+            return null;
+        }
+
+        public static PropertyInfo FindProperty(Type type, string name)
+        {
+            return type.GetProperties().Where(p => p.Name == name).First();
+        }
+
+        private static IDictionary<string, MagicProperty> LoadMagicProperties(Type type, IEnumerable<PropertyInfo> properties)
+        {
+            var magic = new Dictionary<string, MagicProperty>(StringComparer.CurrentCultureIgnoreCase);
+            foreach (var property in properties)
+            {
+                if (property.GetIndexParameters().Length > 0)
+                {
+                    continue;
+                }
+                var name = _configuration.AliasFor(type, property.Name);
+                var ignored = _configuration.IsIgnored(type, property.Name);
+                var ignoredIfNull = _configuration.IsIgnoredIfNull(type, property.Name);
+                magic.Add(name, new MagicProperty(property, name, ignored, ignoredIfNull));
+            }
+            return magic;
+        }
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal class ListWrapper : BaseWrapper
+    {
+        private IList _list;
+
+        public override object Collection
+        {
+            get { return _list; }
+        }
+        public override void Add(object value)
+        {
+            _list.Add(value);
+        }
+
+        protected override object CreateContainer(Type type, Type itemType)
+        {
+            if (type.IsInterface)
+            {
+                return Activator.CreateInstance(typeof(List<>).MakeGenericType(itemType));
+            }
+            if (type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null) != null)
+            {
+                return Activator.CreateInstance(type);
+            }
+            return null;
+        }
+        protected override void SetContainer(object container)
+        {
+            _list = container == null ? new ArrayList() : (IList)container;
+        }
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal static class ListHelper
+    {
+        public static Type GetListItemType(Type enumerableType)
+        {
+            if (enumerableType.IsArray)
+            {
+                return enumerableType.GetElementType();
+            }
+            return enumerableType.IsGenericType ? enumerableType.GetGenericArguments()[0] : typeof(object);
+        }
+
+        public static Type GetDictionarKeyType(Type enumerableType)
+        {
+            return enumerableType.IsGenericType
+                ? enumerableType.GetGenericArguments()[0]
+                : typeof(object);
+        }
+
+        public static Type GetDictionarValueType(Type enumerableType)
+        {
+            return enumerableType.IsGenericType
+                ? enumerableType.GetGenericArguments()[1]
+                : typeof(object);
+        }
+
+        public static IDictionary CreateDictionary(Type dictionaryType, Type keyType, Type valueType)
+        {
+            if (dictionaryType.IsInterface)
+            {
+                return (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(keyType, valueType));
+            }
+
+            if (dictionaryType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null) != null)
+            {
+                return (IDictionary)Activator.CreateInstance(dictionaryType);
+            }
+
+            return new Dictionary<object, object>();
+        }
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal class CollectionWrapper<T> : BaseWrapper
+    {
+        private ICollection<T> _list;
+
+        public override object Collection
+        {
+            get { return _list; }
+        }
+
+        public override void Add(object value)
+        {
+            _list.Add((T)value);
+        }
+
+        protected override object CreateContainer(Type type, Type itemType)
+        {
+            return Activator.CreateInstance(type);
+        }
+        protected override void SetContainer(object container)
+        {
+            _list = (ICollection<T>)container;
+        }
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal abstract class BaseWrapper
+    {
+        public static BaseWrapper Create(Type type, Type itemType, object existingContainer)
+        {
+            var instance = CreateWrapperFromType(existingContainer == null ? type : existingContainer.GetType(), itemType);
+            instance.SetContainer(existingContainer ?? instance.CreateContainer(type, itemType));
+            return instance;
+        }
+
+        private static BaseWrapper CreateWrapperFromType(Type type, Type itemType)
+        {
+            if (type.IsArray)
+            {
+                return (BaseWrapper)Activator.CreateInstance(typeof(ArrayWrapper<>).MakeGenericType(itemType));
+            }
+
+            var isCollection = false;
+            var types = new List<Type>(type.GetInterfaces().Select(h => h.IsGenericType ? h.GetGenericTypeDefinition() : h));
+            types.Insert(0, type.IsGenericType ? type.GetGenericTypeDefinition() : type);
+            foreach (var @interface in types)
+            {
+                if (typeof(IList<>).IsAssignableFrom(@interface) || typeof(IList).IsAssignableFrom(@interface))
+                {
+                    return new ListWrapper();
+                }
+                if (typeof(ICollection<>).IsAssignableFrom(@interface))
+                {
+                    isCollection = true;
+                }
+            }
+            if (isCollection)
+            {
+                return (BaseWrapper)Activator.CreateInstance(typeof(CollectionWrapper<>).MakeGenericType(itemType));
+            }
+
+            //a last-ditch pass
+            foreach (var @interface in types)
+            {
+                if (typeof(IEnumerable<>).IsAssignableFrom(@interface) || typeof(IEnumerable).IsAssignableFrom(@interface))
+                {
+                    return new ListWrapper();
+                }
+            }
+            throw new BsonException(string.Format("Collection of type {0} cannot be deserialized", type.FullName));
+        }
+
+        public abstract void Add(object value);
+        public abstract object Collection { get; }
+
+        protected abstract object CreateContainer(Type type, Type itemType);
+        protected abstract void SetContainer(object container);
+    }
+}
+
+namespace Metsys.Bson
+{
+
+    internal class ArrayWrapper<T> : BaseWrapper
+    {
+        private readonly List<T> _list = new List<T>();
+
+        public override void Add(object value)
+        {
+            _list.Add((T)value);
+        }
+
+        protected override object CreateContainer(Type type, Type itemType)
+        {
+            return null;
+        }
+
+        protected override void SetContainer(object container)
+        {
+            if (container != null)
+            {
+                throw new BsonException("An container cannot exist when trying to deserialize an array");
+            }
+        }
+
+        public override object Collection
+        {
+            get
+            {
+                return _list.ToArray();
+            }
+        }
+    }
+}
+
+namespace Metsys.Bson
+{
+    public static class Helper
+    {
+        public static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+    }
+}
+namespace Metsys.Bson
+{
+    internal class Document
+    {
+        public int Length;
+        public Document Parent;
+        public int Digested;
+    }
+}
+
+namespace Metsys.Bson
+{
+    internal class Deserializer
+    {
+        internal class Options
+        {
+            public bool LongIntegers { get; set; }
+            public bool StringDates { get; set; }
+        }
+
+        private readonly static IDictionary<Types, Type> _typeMap = new Dictionary<Types, Type>
+        {
+            {Types.Int32, typeof(int)},
+            {Types.Int64, typeof (long)},
+            {Types.Boolean, typeof (bool)},
+            {Types.String, typeof (string)},
+            {Types.Double, typeof(double)},
+            {Types.Binary, typeof (byte[])},
+            {Types.Regex, typeof (Regex)},
+            {Types.DateTime, typeof (DateTime)},
+            {Types.ObjectId, typeof(ObjectId)},
+            {Types.Array, typeof(List<object>)},
+            {Types.Object, typeof(Dictionary<string, object>)},
+            {Types.Null, null},
+        };
+        private readonly BinaryReader _reader;
+        private Document _current;
+
+        private Deserializer(BinaryReader reader)
+        {
+            _reader = reader;
+        }
+
+        public static T Deserialize<T>(byte[] objectData, Options options = null) where T : class
+        {
+            using (var ms = new MemoryStream())
+            {
+                ms.Write(objectData, 0, objectData.Length);
+                ms.Position = 0;
+                return Deserialize<T>(new BinaryReader(ms), options ?? new Options());
+            }
+        }
+
+        private static T Deserialize<T>(BinaryReader stream, Options options)
+        {
+            return new Deserializer(stream).Read<T>(options);
+        }
+
+        private T Read<T>(Options options)
+        {
+            NewDocument(_reader.ReadInt32());
+            var @object = (T)DeserializeValue(typeof(T), Types.Object, options);
+            return @object;
+        }
+
+        public static object Deserialize(BinaryReader stream, Type t, Options options = null)
+        {
+            return new Deserializer(stream).Read(t, options ?? new Options());
+        }
+
+        object Read(Type t, Options options)
+        {
+            NewDocument(_reader.ReadInt32());
+            return DeserializeValue(t, Types.Object, options);
+        }
+
+        private void Read(int read)
+        {
+            _current.Digested += read;
+        }
+
+        private bool IsDone()
+        {
+            var isDone = _current.Digested + 1 == _current.Length;
+            if (isDone)
+            {
+                _reader.ReadByte(); // EOO
+                var old = _current;
+                _current = old.Parent;
+                if (_current != null) { Read(old.Length); }
+            }
+            return isDone;
+        }
+
+        private void NewDocument(int length)
+        {
+            var old = _current;
+            _current = new Document { Length = length, Parent = old, Digested = 4 };
+        }
+
+        private object DeserializeValue(Type type, Types storedType, Options options)
+        {
+            return DeserializeValue(type, storedType, null, options);
+        }
+
+        private object DeserializeValue(Type type, Types storedType, object container, Options options)
+        {
+            if (storedType == Types.Null)
+            {
+                return null;
+            }
+            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
+            {
+                type = Nullable.GetUnderlyingType(type);
+            }
+            if (type == typeof(string))
+            {
+                return ReadString();
+            }
+            if (type == typeof(int))
+            {
+                var val = ReadInt(storedType);
+                return options.LongIntegers ? (object)(long)val : (object)val;
+            }
+            if (type.IsEnum)
+            {
+                return ReadEnum(type, storedType);
+            }
+            if (type == typeof(float))
+            {
+                Read(8);
+                return (float)_reader.ReadDouble();
+            }
+            if (storedType == Types.Binary)
+            {
+                return ReadBinary();
+            }
+            if (typeof(IEnumerable).IsAssignableFrom(type))
+            {
+                return ReadList(type, container, options);
+            }
+            if (type == typeof(bool))
+            {
+                Read(1);
+                return _reader.ReadBoolean();
+            }
+            if (type == typeof(DateTime))
+            {
+                var value = Helper.Epoch.AddMilliseconds(ReadLong(Types.Int64));
+                return options.StringDates ? value.ToString("s", System.Globalization.CultureInfo.InvariantCulture) : (object)value;
+            }
+            if (type == typeof(ObjectId))
+            {
+                Read(12);
+                return new ObjectId(_reader.ReadBytes(12));
+            }
+            if (type == typeof(long))
+            {
+                return ReadLong(storedType);
+            }
+            if (type == typeof(double))
+            {
+                Read(8);
+                return _reader.ReadDouble();
+            }
+            if (type == typeof(Regex))
+            {
+                return ReadRegularExpression();
+            }
+            if (type == typeof(ScopedCode))
+            {
+                return ReadScopedCode(options);
+            }
+            return ReadObject(type, options);
+        }
+
+        private object ReadObject(Type type, Options options)
+        {
+            var instance = Activator.CreateInstance(type, true);
+            var typeHelper = TypeHelper.GetHelperForType(type);
+            while (true)
+            {
+                var storageType = ReadType();
+                var name = ReadName();
+                var isNull = false;
+                if (storageType == Types.Object)
+                {
+                    var length = _reader.ReadInt32();
+                    if (length == 5)
+                    {
+                        _reader.ReadByte(); //eoo
+                        Read(5);
+                        isNull = true;
+                    }
+                    else
+                    {
+                        NewDocument(length);
+                    }
+                }
+                object container = null;
+                var property = typeHelper.FindProperty(name);
+                var propertyType = property != null ? property.Type : _typeMap.ContainsKey(storageType) ? _typeMap[storageType] : typeof(object);
+                if (property == null && typeHelper.Expando == null)
+                {
+                    throw new BsonException(string.Format("Deserialization failed: type {0} does not have a property named {1}", type.FullName, name));
+                }
+                if (property != null && property.Setter == null)
+                {
+                    container = property.Getter(instance);
+                }
+                var value = isNull ? null : DeserializeValue(propertyType, storageType, container, options);
+                if (property == null)
+                {
+                    ((IDictionary<string, object>)typeHelper.Expando.Getter(instance))[name] = value;
+                }
+                else if (container == null && value != null && !property.Ignored)
+                {
+                    property.Setter(instance, value);
+                }
+                if (IsDone())
+                {
+                    break;
+                }
+            }
+            return instance;
+        }
+
+        private object ReadList(Type listType, object existingContainer, Options options)
+        {
+            if (IsDictionary(listType))
+            {
+                return ReadDictionary(listType, existingContainer, options);
+            }
+
+            NewDocument(_reader.ReadInt32());
+            var itemType = ListHelper.GetListItemType(listType);
+            var isObject = typeof(object) == itemType;
+            var wrapper = BaseWrapper.Create(listType, itemType, existingContainer);
+
+            while (!IsDone())
+            {
+                var storageType = ReadType();
+                ReadName();
+                if (storageType == Types.Object)
+                {
+                    NewDocument(_reader.ReadInt32());
+                }
+                var specificItemType = isObject ? _typeMap[storageType] : itemType;
+                var value = DeserializeValue(specificItemType, storageType, options);
+                wrapper.Add(value);
+            }
+            return wrapper.Collection;
+        }
+
+        private static bool IsDictionary(Type type)
+        {
+            var types = new List<Type>(type.GetInterfaces());
+            types.Insert(0, type);
+            foreach (var interfaceType in types)
+            {
+                if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private object ReadDictionary(Type listType, object existingContainer, Options options)
+        {
+            var valueType = ListHelper.GetDictionarValueType(listType);
+            var isObject = typeof(object) == valueType;
+            var container = existingContainer == null ? ListHelper.CreateDictionary(listType, ListHelper.GetDictionarKeyType(listType), valueType) : (IDictionary)existingContainer;
+
+            while (!IsDone())
+            {
+                var storageType = ReadType();
+
+                var key = ReadName();
+                if (storageType == Types.Object)
+                {
+                    NewDocument(_reader.ReadInt32());
+                }
+                var specificItemType = isObject ? _typeMap[storageType] : valueType;
+                var value = DeserializeValue(specificItemType, storageType, options);
+                container.Add(key, value);
+            }
+            return container;
+        }
+
+        private object ReadBinary()
+        {
+            var length = _reader.ReadInt32();
+            var subType = _reader.ReadByte();
+            Read(5 + length);
+            if (subType == 2)
+            {
+                return _reader.ReadBytes(_reader.ReadInt32());
+            }
+            if (subType == 3)
+            {
+                return new Guid(_reader.ReadBytes(length));
+            }
+            throw new BsonException("No support for binary type: " + subType);
+        }
+
+        private string ReadName()
+        {
+            var buffer = new List<byte>(128); //todo: use a pool to prevent fragmentation
+            byte b;
+            while ((b = _reader.ReadByte()) > 0)
+            {
+                buffer.Add(b);
+            }
+            Read(buffer.Count + 1);
+            return Encoding.UTF8.GetString(buffer.ToArray());
+        }
+
+        private string ReadString()
+        {
+            var length = _reader.ReadInt32();
+            var buffer = _reader.ReadBytes(length - 1); //todo: again, look at fragementation prevention
+            _reader.ReadByte(); //null;
+            Read(4 + length);
+
+            return Encoding.UTF8.GetString(buffer);
+        }
+
+        private int ReadInt(Types storedType)
+        {
+            switch (storedType)
+            {
+                case Types.Int32:
+                    Read(4);
+                    return _reader.ReadInt32();
+                case Types.Int64:
+                    Read(8);
+                    return (int)_reader.ReadInt64();
+                case Types.Double:
+                    Read(8);
+                    return (int)_reader.ReadDouble();
+                default:
+                    throw new BsonException("Could not create an int from " + storedType);
+            }
+        }
+
+        private long ReadLong(Types storedType)
+        {
+            switch (storedType)
+            {
+                case Types.Int32:
+                    Read(4);
+                    return _reader.ReadInt32();
+                case Types.Int64:
+                    Read(8);
+                    return _reader.ReadInt64();
+                case Types.Double:
+                    Read(8);
+                    return (long)_reader.ReadDouble();
+                default:
+                    throw new BsonException("Could not create an int64 from " + storedType);
+            }
+        }
+
+        private object ReadEnum(Type type, Types storedType)
+        {
+            if (storedType == Types.Int64)
+            {
+                return Enum.Parse(type, ReadLong(storedType).ToString(), false);
+            }
+            return Enum.Parse(type, ReadInt(storedType).ToString(), false);
+        }
+
+        private object ReadRegularExpression()
+        {
+            var pattern = ReadName();
+            var optionsString = ReadName();
+
+            var options = RegexOptions.None;
+            if (optionsString.Contains("e")) options = options | RegexOptions.ECMAScript;
+            if (optionsString.Contains("i")) options = options | RegexOptions.IgnoreCase;
+            if (optionsString.Contains("l")) options = options | RegexOptions.CultureInvariant;
+            if (optionsString.Contains("m")) options = options | RegexOptions.Multiline;
+            if (optionsString.Contains("s")) options = options | RegexOptions.Singleline;
+            if (optionsString.Contains("w")) options = options | RegexOptions.IgnorePatternWhitespace;
+            if (optionsString.Contains("x")) options = options | RegexOptions.ExplicitCapture;
+
+            return new Regex(pattern, options);
+        }
+
+        private Types ReadType()
+        {
+            Read(1);
+            return (Types)_reader.ReadByte();
+        }
+
+        private ScopedCode ReadScopedCode(Options options)
+        {
+            _reader.ReadInt32(); //length
+            Read(4);
+            var name = ReadString();
+            NewDocument(_reader.ReadInt32());
+            return new ScopedCode { CodeString = name, Scope = DeserializeValue(typeof(object), Types.Object, options) };
+        }
+    }
+}
+
+namespace Metsys.Bson.Configuration
+{
+    public interface ITypeConfiguration<T>
+    {
+        ITypeConfiguration<T> UseAlias(Expression<Func<T, object>> expression, string alias);
+        ITypeConfiguration<T> Ignore(Expression<Func<T, object>> expression);
+        ITypeConfiguration<T> Ignore(string name);
+        ITypeConfiguration<T> IgnoreIfNull(Expression<Func<T, object>> expression);
+    }
+
+    internal class TypeConfiguration<T> : ITypeConfiguration<T>
+    {
+        private readonly BsonConfiguration _configuration;
+
+        internal TypeConfiguration(BsonConfiguration configuration)
+        {
+            _configuration = configuration;
+        }
+
+        public ITypeConfiguration<T> UseAlias(Expression<Func<T, object>> expression, string alias)
+        {
+            var member = expression.GetMemberExpression();
+            _configuration.AddMap<T>(member.GetName(), alias);
+            return this;
+        }
+
+        public ITypeConfiguration<T> Ignore(Expression<Func<T, object>> expression)
+        {
+            var member = expression.GetMemberExpression();
+            return Ignore(member.GetName());
+        }
+
+        public ITypeConfiguration<T> Ignore(string name)
+        {
+            _configuration.AddIgnore<T>(name);
+            return this;
+        }
+
+        public ITypeConfiguration<T> IgnoreIfNull(Expression<Func<T, object>> expression)
+        {
+            var member = expression.GetMemberExpression();
+            _configuration.AddIgnoreIfNull<T>(member.GetName());
+            return this;
+        }
+    }
+}
+
+namespace Metsys.Bson.Configuration
+{
+    public static class ExpressionHelper
+    {
+        public static string GetName(this MemberExpression expression)
+        {
+            return new ExpressionNameVisitor().Visit(expression);
+        }
+
+        public static MemberExpression GetMemberExpression<T, TValue>(this Expression<Func<T, TValue>> expression)
+        {
+            if (expression == null)
+            {
+                return null;
+            }
+            if (expression.Body is MemberExpression)
+            {
+                return (MemberExpression)expression.Body;
+            }
+            if (expression.Body is UnaryExpression)
+            {
+                var operand = ((UnaryExpression)expression.Body).Operand;
+                if (operand is MemberExpression)
+                {
+                    return (MemberExpression)operand;
+                }
+                if (operand is MethodCallExpression)
+                {
+                    return ((MethodCallExpression)operand).Object as MemberExpression;
+                }
+            }
+            return null;
+        }
+
+        private class ExpressionNameVisitor
+        {
+            public string Visit(Expression expression)
+            {
+                if (expression is UnaryExpression)
+                {
+                    expression = ((UnaryExpression)expression).Operand;
+                }
+                if (expression is MethodCallExpression)
+                {
+                    return Visit((MethodCallExpression)expression);
+                }
+                if (expression is MemberExpression)
+                {
+                    return Visit((MemberExpression)expression);
+                }
+                if (expression is BinaryExpression && expression.NodeType == ExpressionType.ArrayIndex)
+                {
+                    return Visit((BinaryExpression)expression);
+                }
+                return null;
+            }
+
+            private string Visit(BinaryExpression expression)
+            {
+                string result = null;
+                if (expression.Left is MemberExpression)
+                {
+                    result = Visit((MemberExpression)expression.Left);
+                }
+                var index = Expression.Lambda(expression.Right).Compile().DynamicInvoke();
+                return result + string.Format("[{0}]", index);
+            }
+
+            private string Visit(MemberExpression expression)
+            {
+                var name = expression.Member.Name;
+                var ancestorName = Visit(expression.Expression);
+                if (ancestorName != null)
+                {
+                    name = ancestorName + "." + name;
+                }
+                return name;
+            }
+
+            private string Visit(MethodCallExpression expression)
+            {
+                string name = null;
+                if (expression.Object is MemberExpression)
+                {
+                    name = Visit((MemberExpression)expression.Object);
+                }
+
+                //TODO: Is there a more certain way to determine if this is an indexed property?
+                if (expression.Method.Name == "get_Item" && expression.Arguments.Count == 1)
+                {
+                    var index = Expression.Lambda(expression.Arguments[0]).Compile().DynamicInvoke();
+                    name += string.Format("[{0}]", index);
+                }
+                return name;
+            }
+        }
+    }
+}
+
+namespace Metsys.Bson.Configuration
+{
+
+    internal class BsonConfiguration
+    {
+        private readonly IDictionary<Type, IDictionary<string, string>> _aliasMap = new Dictionary<Type, IDictionary<string, string>>();
+        private readonly IDictionary<Type, HashSet<string>> _ignored = new Dictionary<Type, HashSet<string>>();
+        private readonly IDictionary<Type, HashSet<string>> _ignoredIfNull = new Dictionary<Type, HashSet<string>>();
+
+        //not thread safe
+        private static BsonConfiguration _instance;
+        internal static BsonConfiguration Instance
+        {
+            get
+            {
+                if (_instance == null) { _instance = new BsonConfiguration(); }
+                return _instance;
+            }
+        }
+
+        private BsonConfiguration() { }
+
+        public static void ForType<T>(Action<ITypeConfiguration<T>> action)
+        {
+            action(new TypeConfiguration<T>(Instance));
+        }
+
+        internal void AddMap<T>(string property, string alias)
+        {
+            var type = typeof(T);
+            if (!_aliasMap.ContainsKey(type))
+            {
+                _aliasMap[type] = new Dictionary<string, string>();
+            }
+            _aliasMap[type][property] = alias;
+        }
+        internal string AliasFor(Type type, string property)
+        {
+            IDictionary<string, string> map;
+            if (!_aliasMap.TryGetValue(type, out map))
+            {
+                return property;
+            }
+            return map.ContainsKey(property) ? map[property] : property;
+        }
+
+        public void AddIgnore<T>(string name)
+        {
+            var type = typeof(T);
+            if (!_ignored.ContainsKey(type))
+            {
+                _ignored[type] = new HashSet<string>();
+            }
+            _ignored[type].Add(name);
+        }
+        public bool IsIgnored(Type type, string name)
+        {
+            HashSet<string> list;
+            return _ignored.TryGetValue(type, out list) && list.Contains(name);
+        }
+
+        public void AddIgnoreIfNull<T>(string name)
+        {
+            var type = typeof(T);
+            if (!_ignoredIfNull.ContainsKey(type))
+            {
+                _ignoredIfNull[type] = new HashSet<string>();
+            }
+            _ignoredIfNull[type].Add(name);
+        }
+        public bool IsIgnoredIfNull(Type type, string name)
+        {
+            HashSet<string> list;
+            return _ignoredIfNull.TryGetValue(type, out list) && list.Contains(name);
+        }
+    }
+}
+namespace Metsys.Bson
+{
+
+    internal class BsonException : Exception
+    {
+        public BsonException() { }
+        public BsonException(string message) : base(message) { }
+        public BsonException(string message, Exception innerException) : base(message, innerException) { }
+        protected BsonException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+    }
+}

+ 78 - 0
src/Avalonia.Remote.Protocol/TcpTransportBase.cs

@@ -0,0 +1,78 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading.Tasks;
+
+namespace Avalonia.Remote.Protocol
+{
+    public abstract class TcpTransportBase
+    {
+        private readonly IMessageTypeResolver _resolver;
+
+        public TcpTransportBase(IMessageTypeResolver resolver)
+        {
+            _resolver = resolver;
+        }
+        
+        protected abstract IAvaloniaRemoteTransportConnection CreateTransport(IMessageTypeResolver resolver,
+            Stream stream, Action disposeCallback);
+
+        class DisposableServer : IDisposable
+        {
+            private readonly TcpListener _l;
+
+            public DisposableServer(TcpListener l)
+            {
+                _l = l;
+            }
+            public void Dispose()
+            {
+                try
+                {
+                    _l.Stop();
+                }
+                catch
+                {
+                    //Ignore
+                }
+            }
+        }
+        
+        public IDisposable Listen(IPAddress address, int port, Action<IAvaloniaRemoteTransportConnection> cb)
+        {
+            var server = new TcpListener(address, port);
+            async void AcceptNew()
+            {
+                try
+                {
+                    var cl = await server.AcceptTcpClientAsync();
+                    AcceptNew();
+                    Task.Run(async () =>
+                    {
+                        var tcs = new TaskCompletionSource<int>();
+                        var t = CreateTransport(_resolver, cl.GetStream(), () => tcs.TrySetResult(0));
+                        cb(t);
+                        await tcs.Task;
+
+
+                    });
+                }
+                catch
+                {
+                    //Ignore and stop
+                }
+            }
+            server.Start();
+            AcceptNew();
+            return new DisposableServer(server);
+        }
+
+        public async Task<IAvaloniaRemoteTransportConnection> Connect(IPAddress address, int port)
+        {
+            var c = new TcpClient();
+            await c.ConnectAsync(address, port);
+            return CreateTransport(_resolver, c.GetStream(), c.Dispose);
+        }
+    }
+}

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