浏览代码

Merge branch 'master' into bindingoperations-donothing

Steven Kirk 6 年之前
父节点
当前提交
d1f071ef08
共有 96 个文件被更改,包括 2187 次插入5935 次删除
  1. 0 29
      Avalonia.sln
  2. 23 5
      nukebuild/Build.cs
  3. 2 1
      nukebuild/_build.csproj
  4. 5 7
      readme.md
  5. 9 13
      samples/ControlCatalog.NetCore/Program.cs
  6. 11 0
      samples/ControlCatalog/App.xaml.cs
  7. 13 0
      samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
  8. 14 0
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  9. 6 1
      samples/ControlCatalog/ViewModels/ContextMenuPageViewModel.cs
  10. 6 1
      samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
  11. 46 0
      src/Avalonia.Base/Data/Converters/StringFormatMultiValueConverter.cs
  12. 19 54
      src/Avalonia.Controls/AppBuilderBase.cs
  13. 14 202
      src/Avalonia.Controls/Application.cs
  14. 133 0
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  15. 8 3
      src/Avalonia.Controls/ApplicationLifetimes/ControlledApplicationLifetimeExitEventArgs.cs
  16. 7 0
      src/Avalonia.Controls/ApplicationLifetimes/IApplicationLifetime.cs
  17. 31 0
      src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
  18. 5 8
      src/Avalonia.Controls/ApplicationLifetimes/IControlledApplicationLifetime.cs
  19. 7 0
      src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs
  20. 22 0
      src/Avalonia.Controls/ApplicationLifetimes/StartupEventArgs.cs
  21. 27 6
      src/Avalonia.Controls/ColumnDefinition.cs
  22. 67 0
      src/Avalonia.Controls/DesktopApplicationExtensions.cs
  23. 104 69
      src/Avalonia.Controls/DockPanel.cs
  24. 4 1
      src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
  25. 12 2
      src/Avalonia.Controls/ItemsControl.cs
  26. 12 1
      src/Avalonia.Controls/ListBox.cs
  27. 1 1
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  28. 43 22
      src/Avalonia.Controls/Primitives/RangeBase.cs
  29. 409 235
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  30. 31 10
      src/Avalonia.Controls/RowDefinition.cs
  31. 3 2
      src/Avalonia.Controls/Screens.cs
  32. 0 36
      src/Avalonia.Controls/StartupEventArgs.cs
  33. 0 20
      src/Avalonia.Controls/TopLevel.cs
  34. 24 2
      src/Avalonia.Controls/TreeView.cs
  35. 18 45
      src/Avalonia.Controls/Window.cs
  36. 3 0
      src/Avalonia.Controls/WindowBase.cs
  37. 0 134
      src/Avalonia.Controls/WindowCollection.cs
  38. 4 6
      src/Avalonia.Controls/WrapPanel.cs
  39. 2 10
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs
  40. 9 1
      src/Avalonia.Styling/StyledElement.cs
  41. 3 7
      src/Avalonia.X11/X11KeyTransform.cs
  42. 13 2
      src/Avalonia.X11/X11Window.cs
  43. 0 11
      src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj
  44. 0 51
      src/Gtk/Avalonia.Gtk3/ClipboardImpl.cs
  45. 0 84
      src/Gtk/Avalonia.Gtk3/CursorFactory.cs
  46. 0 62
      src/Gtk/Avalonia.Gtk3/FramebufferManager.cs
  47. 0 86
      src/Gtk/Avalonia.Gtk3/GdkCursor.cs
  48. 0 1341
      src/Gtk/Avalonia.Gtk3/GdkKey.cs
  49. 0 115
      src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs
  50. 0 168
      src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs
  51. 0 24
      src/Gtk/Avalonia.Gtk3/GtkScreen.cs
  52. 0 9
      src/Gtk/Avalonia.Gtk3/IDeferredRenderOperation.cs
  53. 0 144
      src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs
  54. 0 20
      src/Gtk/Avalonia.Gtk3/Interop/CairoSurface.cs
  55. 0 30
      src/Gtk/Avalonia.Gtk3/Interop/GException.cs
  56. 0 87
      src/Gtk/Avalonia.Gtk3/Interop/GObject.cs
  57. 0 46
      src/Gtk/Avalonia.Gtk3/Interop/GlibPriority.cs
  58. 0 58
      src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs
  59. 0 12
      src/Gtk/Avalonia.Gtk3/Interop/ICustomGtk3NativeLibraryResolver.cs
  60. 0 37
      src/Gtk/Avalonia.Gtk3/Interop/ManagedCairoSurface.cs
  61. 0 790
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  62. 0 20
      src/Gtk/Avalonia.Gtk3/Interop/NativeException.cs
  63. 0 65
      src/Gtk/Avalonia.Gtk3/Interop/Pixbuf.cs
  64. 0 156
      src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs
  65. 0 47
      src/Gtk/Avalonia.Gtk3/Interop/Signal.cs
  66. 0 230
      src/Gtk/Avalonia.Gtk3/KeyTransform.cs
  67. 0 20
      src/Gtk/Avalonia.Gtk3/PlatformIconLoader.cs
  68. 0 19
      src/Gtk/Avalonia.Gtk3/PopupImpl.cs
  69. 0 10
      src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs
  70. 0 8
      src/Gtk/Avalonia.Gtk3/README.md
  71. 0 56
      src/Gtk/Avalonia.Gtk3/ScreenImpl.cs
  72. 0 110
      src/Gtk/Avalonia.Gtk3/SystemDialogs.cs
  73. 0 527
      src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
  74. 0 102
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs
  75. 0 78
      src/Gtk/Avalonia.Gtk3/X11.cs
  76. 0 55
      src/Gtk/Avalonia.Gtk3/X11Framebuffer.cs
  77. 1 1
      src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
  78. 1 3
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebuffer.cs
  79. 55 19
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  80. 7 5
      src/Linux/Avalonia.LinuxFramebuffer/Mice.cs
  81. 0 8
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  82. 1 1
      src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
  83. 12 16
      src/Markup/Avalonia.Markup/Data/MultiBinding.cs
  84. 0 120
      tests/Avalonia.Controls.UnitTests/ApplicationTests.cs
  85. 1 3
      tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
  86. 213 0
      tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs
  87. 38 1
      tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs
  88. 113 2
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
  89. 493 30
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
  90. 0 19
      tests/Avalonia.Controls.UnitTests/TopLevelTests.cs
  91. 0 6
      tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
  92. 0 76
      tests/Avalonia.Controls.UnitTests/WindowTests.cs
  93. 31 9
      tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs
  94. 19 0
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
  95. 31 0
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs
  96. 1 2
      tests/Avalonia.UnitTests/UnitTestApplication.cs

+ 0 - 29
Avalonia.sln

@@ -63,8 +63,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DE
 		src\Shared\SharedAssemblyInfo.cs = src\Shared\SharedAssemblyInfo.cs
 	EndProjectSection
 EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gtk", "Gtk", "{B9894058-278A-46B5-B6ED-AD613FCC03B3}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"
 EndProject
 Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlatformSupport", "src\Shared\PlatformSupport\PlatformSupport.shproj", "{E4D9629C-F168-4224-3F51-A5E482FFBC42}"
@@ -123,8 +121,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Android", "s
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia", "src\Skia\Avalonia.Skia\Avalonia.Skia.csproj", "{7D2D3083-71DD-4CC9-8907-39A0D86FB322}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Gtk3", "src\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj", "{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.NetCore", "samples\ControlCatalog.NetCore\ControlCatalog.NetCore.csproj", "{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}"
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
@@ -1318,30 +1314,6 @@ Global
 		{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|iPhone.Build.0 = Release|Any CPU
 		{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|Any CPU.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|iPhone.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|iPhone.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|iPhone.Build.0 = Debug|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|iPhone.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|iPhone.Build.0 = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 		{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
 		{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
 		{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
@@ -1911,7 +1883,6 @@ Global
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
-		{BB1F7BB5-6AD4-4776-94D9-C09D0A972658} = {B9894058-278A-46B5-B6ED-AD613FCC03B3}
 		{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
 		{638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}

+ 23 - 5
nukebuild/Build.cs

@@ -19,7 +19,7 @@ using static Nuke.Common.IO.PathConstruction;
 using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
 using static Nuke.Common.Tools.DotNet.DotNetTasks;
 using static Nuke.Common.Tools.Xunit.XunitTasks;
-
+using static Nuke.Common.Tools.VSWhere.VSWhereTasks;
 
 /*
  Before editing this file, install support plugin for your IDE,
@@ -30,7 +30,26 @@ using static Nuke.Common.Tools.Xunit.XunitTasks;
  */
 
 partial class Build : NukeBuild
-{   
+{
+    static Lazy<string> MsBuildExe = new Lazy<string>(() =>
+    {
+        if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            return null;
+
+        var msBuildDirectory = VSWhere("-latest -nologo -property installationPath -format value -prerelease").FirstOrDefault().Text;
+
+        if (!string.IsNullOrWhiteSpace(msBuildDirectory))
+        {
+            string msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\Current\Bin\MSBuild.exe");
+            if (!System.IO.File.Exists(msBuildExe))
+                msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\15.0\Bin\MSBuild.exe");
+
+            return msBuildExe;
+        }
+
+        return null;
+    }, false);
+
     BuildParameters Parameters { get; set; }
     protected override void OnBuildInitialized()
     {
@@ -85,7 +104,6 @@ partial class Build : NukeBuild
         .DependsOn(Clean)
         .Executes(() =>
         {
-
             if (Parameters.IsRunningOnWindows)
                 MSBuild(Parameters.MSBuildSolution, c => c
                     .SetArgumentConfigurator(a => a.Add("/r"))
@@ -93,7 +111,7 @@ partial class Build : NukeBuild
                     .SetVerbosity(MSBuildVerbosity.Minimal)
                     .AddProperty("PackageVersion", Parameters.Version)
                     .AddProperty("iOSRoslynPathHackRequired", "true")
-                    .SetToolsVersion(MSBuildToolsVersion._15_0)
+                    .SetToolPath(MsBuildExe.Value)
                     .AddTargets("Build")
                 );
 
@@ -224,7 +242,7 @@ partial class Build : NukeBuild
                     .SetVerbosity(MSBuildVerbosity.Minimal)
                     .AddProperty("PackageVersion", Parameters.Version)
                     .AddProperty("iOSRoslynPathHackRequired", "true")
-                    .SetToolsVersion(MSBuildToolsVersion._15_0)
+                    .SetToolPath(MsBuildExe.Value)
                     .AddTargets("Pack"));
             else
                 DotNetPack(Parameters.MSBuildSolution, c =>

+ 2 - 1
nukebuild/_build.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
@@ -13,6 +13,7 @@
     <PackageReference Include="Nuke.Common" Version="0.12.3" />
     <PackageReference Include="xunit.runner.console" Version="2.3.1" />
     <PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" />
+    <PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
   </ItemGroup>
 
   <ItemGroup>

+ 5 - 7
readme.md

@@ -8,9 +8,9 @@
 
 ## About
 
-Avalonia is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of OSs: Windows (.NET Framework, .NET Core), Linux (libX11), MacOS, Android (experimental) and iOS (exprerimental).
+**Avalonia** is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), MacOS and with experimental support for Android and iOS.
 
-**Avalonia is currently in beta** which means that the framework is generally usable for writing applications, but there may be some bugs and breaking changes as we continue development, for more details about the status see https://github.com/AvaloniaUI/Avalonia/issues/2239
+**Avalonia** is ready for **General-Purpose Desktop App Development**. However there may be some bugs and breaking changes as we continue along into this project's development. To see the status for some of our features, please see our [Roadmap here](https://github.com/AvaloniaUI/Avalonia/issues/2239).
 
 | Control catalog | Desktop platforms | Mobile platforms |
 |---|---|---|
@@ -40,11 +40,11 @@ https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed
 
 ## Documentation
 
-As mentioned above, Avalonia is still in beta and as such there's not much documentation yet. You can take a look at the [getting started page](http://avaloniaui.net/docs/quickstart/) for an overview of how to get started but probably the best thing to do for now is to already know a little bit about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/AvaloniaUI/Avalonia).
+You can take a look at the [getting started page](http://avaloniaui.net/docs/quickstart/) for an overview of how to get started but probably the best thing to do for now is to already know a little bit about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/AvaloniaUI/Avalonia). 
 
 There's also a high-level [architecture document](http://avaloniaui.net/architecture/project-structure) that is currently a little bit out of date, and I've also started writing blog posts on Avalonia at http://grokys.github.io/.
 
-Contributions are always welcome!
+Contributions for our docs are always welcome!
 
 ## Building and Using
 
@@ -80,6 +80,4 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
 <a href="https://opencollective.com/Avalonia/sponsor/6/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/6/avatar.svg"></a>
 <a href="https://opencollective.com/Avalonia/sponsor/7/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/7/avatar.svg"></a>
 <a href="https://opencollective.com/Avalonia/sponsor/8/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/8/avatar.svg"></a>
-<a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a>
-
-
+<a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a> 

+ 9 - 13
samples/ControlCatalog.NetCore/Program.cs

@@ -3,6 +3,7 @@ using System.Diagnostics;
 using System.Linq;
 using System.Threading;
 using Avalonia;
+using Avalonia.Controls;
 using Avalonia.Skia;
 using Avalonia.ReactiveUI;
 
@@ -11,7 +12,7 @@ namespace ControlCatalog.NetCore
     static class Program
     {
 
-        static void Main(string[] args)
+        static int Main(string[] args)
         {
             Thread.CurrentThread.TrySetApartmentState(ApartmentState.STA);
             if (args.Contains("--wait-for-attach"))
@@ -25,21 +26,16 @@ namespace ControlCatalog.NetCore
                 }
             }
 
+            var builder = BuildAvaloniaApp();
             if (args.Contains("--fbdev"))
-                AppBuilder.Configure<App>().InitializeWithLinuxFramebuffer(tl =>
-                {
-                    tl.Content = new MainView();
-                    System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer());
-                });
+            {
+                System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer());
+                return builder.StartLinuxFramebuffer(args);
+            }
             else
-                BuildAvaloniaApp().Start(AppMain, args);
+                return builder.StartWithClassicDesktopLifetime(args);
         }
-
-        static void AppMain(Application app, string[] args)
-        {
-            app.Run(new MainWindow());
-        }
-
+        
         /// <summary>
         /// This method is needed for IDE previewer infrastructure
         /// </summary>

+ 11 - 0
samples/ControlCatalog/App.xaml.cs

@@ -1,4 +1,5 @@
 using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Markup.Xaml;
 
 namespace ControlCatalog
@@ -9,5 +10,15 @@ namespace ControlCatalog
         {
             AvaloniaXamlLoader.Load(this);
         }
+
+        public override void OnFrameworkInitializationCompleted()
+        {
+            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
+                desktopLifetime.MainWindow = new MainWindow();
+            else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime)
+                singleViewLifetime.MainView = new MainView();
+            
+            base.OnFrameworkInitializationCompleted();
+        }
     }
 }

+ 13 - 0
samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
 using ControlCatalog.ViewModels;
@@ -12,6 +13,18 @@ namespace ControlCatalog.Pages
             DataContext = new ContextMenuPageViewModel();
         }
 
+        private ContextMenuPageViewModel _model;
+        protected override void OnDataContextChanged(EventArgs e)
+        {
+            if (_model != null)
+                _model.View = null;
+            _model  = DataContext as ContextMenuPageViewModel;
+            if (_model != null)
+                _model.View = this;
+
+            base.OnDataContextChanged(e);
+        }
+
         private void InitializeComponent()
         {
             AvaloniaXamlLoader.Load(this);

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

@@ -1,3 +1,4 @@
+using System;
 using System.Collections.Generic;
 using System.Reactive;
 using System.Threading.Tasks;
@@ -21,5 +22,18 @@ namespace ControlCatalog.Pages
         {
             AvaloniaXamlLoader.Load(this);
         }
+        
+        private MenuPageViewModel _model;
+        protected override void OnDataContextChanged(EventArgs e)
+        {
+            if (_model != null)
+                _model.View = null;
+            _model  = DataContext as MenuPageViewModel;
+            if (_model != null)
+                _model.View = this;
+
+            base.OnDataContextChanged(e);
+        }
+        
     }
 }

+ 6 - 1
samples/ControlCatalog/ViewModels/ContextMenuPageViewModel.cs

@@ -2,12 +2,14 @@
 using System.Reactive;
 using System.Threading.Tasks;
 using Avalonia.Controls;
+using Avalonia.VisualTree;
 using ReactiveUI;
 
 namespace ControlCatalog.ViewModels
 {
     public class ContextMenuPageViewModel
     {
+        public Control View { get; set; }
         public ContextMenuPageViewModel()
         {
             OpenCommand = ReactiveCommand.CreateFromTask(Open);
@@ -48,8 +50,11 @@ namespace ControlCatalog.ViewModels
 
         public async Task Open()
         {
+            var window = View?.GetVisualRoot() as Window;
+            if (window == null)
+                return;
             var dialog = new OpenFileDialog();
-            var result = await dialog.ShowAsync(App.Current.MainWindow);
+            var result = await dialog.ShowAsync(window);
 
             if (result != null)
             {

+ 6 - 1
samples/ControlCatalog/ViewModels/MenuPageViewModel.cs

@@ -3,12 +3,14 @@ using System.Reactive;
 using System.Reactive.Linq;
 using System.Threading.Tasks;
 using Avalonia.Controls;
+using Avalonia.VisualTree;
 using ReactiveUI;
 
 namespace ControlCatalog.ViewModels
 {
     public class MenuPageViewModel
     {
+        public Control View { get; set; }
         public MenuPageViewModel()
         {
             OpenCommand = ReactiveCommand.CreateFromTask(Open);
@@ -65,8 +67,11 @@ namespace ControlCatalog.ViewModels
 
         public async Task Open()
         {
+            var window = View?.GetVisualRoot() as Window;
+            if (window == null)
+                return;
             var dialog = new OpenFileDialog();
-            var result = await dialog.ShowAsync(App.Current.MainWindow);
+            var result = await dialog.ShowAsync(window);
 
             if (result != null)
             {

+ 46 - 0
src/Avalonia.Base/Data/Converters/StringFormatMultiValueConverter.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace Avalonia.Data.Converters
+{
+    /// <summary>
+    /// A multi-value converter which calls <see cref="string.Format(string, object)"/>
+    /// </summary>
+    public class StringFormatMultiValueConverter : IMultiValueConverter
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StringFormatMultiValueConverter"/> class.
+        /// </summary>
+        /// <param name="format">The format string.</param>
+        /// <param name="inner">
+        /// An optional inner converter to be called before the format takes place.
+        /// </param>
+        public StringFormatMultiValueConverter(string format, IMultiValueConverter inner)
+        {
+            Contract.Requires<ArgumentNullException>(format != null);
+
+            Format = format;
+            Inner = inner;
+        }
+
+        /// <summary>
+        /// Gets an inner value converter which will be called before the string format takes place.
+        /// </summary>
+        public IMultiValueConverter Inner { get; }
+
+        /// <summary>
+        /// Gets the format string.
+        /// </summary>
+        public string Format { get; }
+
+        /// <inheritdoc/>
+        public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
+        {
+            return Inner == null
+                       ? string.Format(culture, Format, values.ToArray())
+                       : string.Format(culture, Format, Inner.Convert(values, targetType, parameter, culture));
+        }
+    }
+}

+ 19 - 54
src/Avalonia.Controls/AppBuilderBase.cs

@@ -4,6 +4,7 @@
 using System;
 using System.Reflection;
 using System.Linq;
+using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Platform;
 
 namespace Avalonia.Controls
@@ -57,10 +58,6 @@ namespace Avalonia.Controls
         /// </summary>
         public Action<TAppBuilder> AfterSetupCallback { get; private set; } = builder => { };
 
-        /// <summary>
-        /// Gets or sets a method to call before Start is called on the <see cref="Application"/>.
-        /// </summary>
-        public Action<TAppBuilder> BeforeStartCallback { get; private set; } = builder => { };
 
         protected AppBuilderBase(IRuntimePlatform platform, Action<TAppBuilder> platformServices)
         {
@@ -95,17 +92,6 @@ namespace Avalonia.Controls
 
         protected TAppBuilder Self => (TAppBuilder)this;
 
-        /// <summary>
-        /// Registers a callback to call before Start is called on the <see cref="Application"/>.
-        /// </summary>
-        /// <param name="callback">The callback.</param>
-        /// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
-        public TAppBuilder BeforeStarting(Action<TAppBuilder> callback)
-        {
-            BeforeStartCallback = (Action<TAppBuilder>)Delegate.Combine(BeforeStartCallback, callback);
-            return Self;
-        }
-
         public TAppBuilder AfterSetup(Action<TAppBuilder> callback)
         {
             AfterSetupCallback = (Action<TAppBuilder>)Delegate.Combine(AfterSetupCallback, callback);
@@ -117,48 +103,37 @@ namespace Avalonia.Controls
         /// </summary>
         /// <typeparam name="TMainWindow">The window type.</typeparam>
         /// <param name="dataContextProvider">A delegate that will be called to create a data context for the window (optional).</param>
+        [Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details")]
         public void Start<TMainWindow>(Func<object> dataContextProvider = null)
             where TMainWindow : Window, new()
         {
-            Setup();
-            BeforeStartCallback(Self);
-
-            var window = new TMainWindow();
-            if (dataContextProvider != null)
-                window.DataContext = dataContextProvider();
-            Instance.Run(window);
-        }
-
-        /// <summary>
-        /// Starts the application with the provided instance of <typeparamref name="TMainWindow"/>.
-        /// </summary>
-        /// <typeparam name="TMainWindow">The window type.</typeparam>
-        /// <param name="mainWindow">Instance of type TMainWindow to use when starting the app</param>
-        /// <param name="dataContextProvider">A delegate that will be called to create a data context for the window (optional).</param>
-        public void Start<TMainWindow>(TMainWindow mainWindow, Func<object> dataContextProvider = null)
-            where TMainWindow : Window
-        {
-            Setup();
-            BeforeStartCallback(Self);
-
-            if (dataContextProvider != null)
-                mainWindow.DataContext = dataContextProvider();
-            Instance.Run(mainWindow);
+            AfterSetup(builder =>
+            {
+                var window = new TMainWindow();
+                if (dataContextProvider != null)
+                    window.DataContext = dataContextProvider();
+                ((IClassicDesktopStyleApplicationLifetime)builder.Instance.ApplicationLifetime)
+                    .MainWindow = window;
+            });
+            
+            // Copy-pasted because we can't call extension methods due to generic constraints
+            var lifetime = new ClassicDesktopStyleApplicationLifetime(Instance) {ShutdownMode = ShutdownMode.OnMainWindowClose};
+            Instance.ApplicationLifetime = lifetime;
+            SetupWithoutStarting();
+            lifetime.Start(Array.Empty<string>());
         }
 
         public delegate void AppMainDelegate(Application app, string[] args);
 
+        [Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details", true)]
         public void Start()
         {
-            Setup();
-            BeforeStartCallback(Self);
-            Instance.Run();
+            throw new NotSupportedException();
         }
 
         public void Start(AppMainDelegate main, string[] args)
         {
             Setup();
-            BeforeStartCallback(Self);
             main(Instance, args);
         }
 
@@ -224,17 +199,6 @@ namespace Avalonia.Controls
 
         public TAppBuilder UseAvaloniaModules() => AfterSetup(builder => SetupAvaloniaModules());
 
-        /// <summary>
-        /// Sets the shutdown mode of the application.
-        /// </summary>
-        /// <param name="shutdownMode">The shutdown mode.</param>
-        /// <returns></returns>
-        public TAppBuilder SetShutdownMode(ShutdownMode shutdownMode)
-        {
-            Instance.ShutdownMode = shutdownMode;
-            return Self;
-        }
-
         protected virtual bool CheckSetup => true;
 
         private void SetupAvaloniaModules()
@@ -313,6 +277,7 @@ namespace Avalonia.Controls
             Instance.RegisterServices();
             Instance.Initialize();
             AfterSetupCallback(Self);
+            Instance.OnFrameworkInitializationCompleted();
         }
     }
 }

+ 14 - 202
src/Avalonia.Controls/Application.cs

@@ -6,6 +6,7 @@ using System.Reactive.Concurrency;
 using System.Threading;
 using Avalonia.Animation;
 using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Controls.Templates;
 using Avalonia.Input;
 using Avalonia.Input.Platform;
@@ -31,7 +32,7 @@ namespace Avalonia
     /// method.
     /// - Tracks the lifetime of the application.
     /// </remarks>
-    public class Application : IApplicationLifecycle, IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IResourceNode
+    public class Application : IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IResourceNode
     {
         /// <summary>
         /// The application-global data templates.
@@ -43,22 +44,6 @@ namespace Avalonia
         private readonly Styler _styler = new Styler();
         private Styles _styles;
         private IResourceDictionary _resources;
-        private CancellationTokenSource _mainLoopCancellationTokenSource;
-        private int _exitCode;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="Application"/> class.
-        /// </summary>
-        public Application()
-        {
-            Windows = new WindowCollection(this);
-        }
-
-        /// <inheritdoc/>
-        public event EventHandler<StartupEventArgs> Startup;
-
-        /// <inheritdoc/>
-        public event EventHandler<ExitEventArgs> Exit;
 
         /// <inheritdoc/>
         public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
@@ -166,198 +151,21 @@ namespace Avalonia
 
         /// <inheritdoc/>
         IResourceNode IResourceNode.ResourceParent => null;
-
-        /// <summary>
-        /// Gets or sets the <see cref="ShutdownMode"/>. This property indicates whether the application is shutdown explicitly or implicitly. 
-        /// If <see cref="ShutdownMode"/> is set to OnExplicitShutdown the application is only closes if Shutdown is called.
-        /// The default is OnLastWindowClose
-        /// </summary>
-        /// <value>
-        /// The shutdown mode.
-        /// </value>
-        public ShutdownMode ShutdownMode { get; set; }
-
-        /// <summary>
-        /// Gets or sets the main window of the application.
-        /// </summary>
-        /// <value>
-        /// The main window.
-        /// </value>
-        public Window MainWindow { get; set; }
-
-        /// <summary>
-        /// Gets the open windows of the application.
-        /// </summary>
-        /// <value>
-        /// The windows.
-        /// </value>
-        public WindowCollection Windows { get; }
-
+        
         /// <summary>
-        /// Gets or sets a value indicating whether this instance is shutting down.
+        /// Application lifetime, use it for things like setting the main window and exiting the app from code
+        /// Currently supported lifetimes are:
+        /// - <see cref="IClassicDesktopStyleApplicationLifetime"/>
+        /// - <see cref="ISingleViewApplicationLifetime"/>
+        /// - <see cref="IControlledApplicationLifetime"/> 
         /// </summary>
-        /// <value>
-        ///   <c>true</c> if this instance is shutting down; otherwise, <c>false</c>.
-        /// </value>
-        internal bool IsShuttingDown { get; private set; }
+        public IApplicationLifetime ApplicationLifetime { get; set; }
 
         /// <summary>
         /// Initializes the application by loading XAML etc.
         /// </summary>
         public virtual void Initialize() { }
 
-        /// <summary>
-        /// Runs the application's main loop.
-        /// </summary>
-        /// <remarks>
-        /// This will return when the <see cref="Avalonia.Controls.ShutdownMode"/> condition is met
-        /// or <see cref="Shutdown(int)"/> was called. 
-        /// </remarks>
-        /// <returns>The application's exit code that is returned to the operating system on termination.</returns>
-        public int Run()
-        {
-            return Run(new CancellationTokenSource());
-        }
-
-        /// <summary>
-        /// Runs the application's main loop.
-        /// </summary>
-        /// <remarks>
-        /// This will return when the <see cref="Avalonia.Controls.ShutdownMode"/> condition is met
-        /// or <see cref="Shutdown(int)"/> was called.
-        /// This also returns when <see cref="ICloseable"/> is closed.
-        /// </remarks>
-        /// <param name="closable">The closable to track.</param>
-        /// <returns>The application's exit code that is returned to the operating system on termination.</returns>
-        public int Run(ICloseable closable)
-        {
-            closable.Closed += (s, e) => _mainLoopCancellationTokenSource?.Cancel();
-
-            return Run(new CancellationTokenSource());
-        }
-
-        /// <summary>
-        /// Runs the application's main loop.
-        /// </summary>
-        /// <remarks>
-        /// This will return when the <see cref="Avalonia.Controls.ShutdownMode"/> condition is met
-        /// or <see cref="Shutdown(int)"/> was called.
-        /// </remarks>
-        /// <param name="mainWindow">The window that is used as <see cref="MainWindow"/>
-        /// when the <see cref="MainWindow"/> isn't already set.</param>
-        /// <returns>The application's exit code that is returned to the operating system on termination.</returns>
-        public int Run(Window mainWindow)
-        {
-            if (mainWindow == null)
-            {
-                throw new ArgumentNullException(nameof(mainWindow));
-            }
-
-            if (MainWindow == null)
-            {
-                if (!mainWindow.IsVisible)
-                {
-                    mainWindow.Show();
-                }
-
-                MainWindow = mainWindow;
-            }
-
-            return Run(new CancellationTokenSource());
-        }
-        /// <summary>
-        /// Runs the application's main loop.
-        /// </summary>
-        /// <remarks>
-        /// This will return when the <see cref="Avalonia.Controls.ShutdownMode"/> condition is met
-        /// or <see cref="Shutdown(int)"/> was called.
-        /// This also returns when the <see cref="CancellationToken"/> is canceled.
-        /// </remarks>
-        /// <returns>The application's exit code that is returned to the operating system on termination.</returns>
-        /// <param name="token">The token to track.</param>
-        public int Run(CancellationToken token)
-        {
-            return Run(CancellationTokenSource.CreateLinkedTokenSource(token));
-        }
-
-        private int Run(CancellationTokenSource tokenSource)
-        {
-            if (IsShuttingDown)
-            {
-                throw new InvalidOperationException("Application is shutting down.");
-            }
-
-            if (_mainLoopCancellationTokenSource != null)
-            {
-                throw new InvalidOperationException("Application is already running.");
-            }
-
-            _mainLoopCancellationTokenSource = tokenSource;
-
-            Dispatcher.UIThread.Post(() => OnStartup(new StartupEventArgs()), DispatcherPriority.Send);
-
-            Dispatcher.UIThread.MainLoop(_mainLoopCancellationTokenSource.Token);
-
-            if (!IsShuttingDown)
-            {
-                Shutdown(_exitCode);
-            }
-
-            return _exitCode;
-        }
-
-        /// <summary>
-        /// Raises the <see cref="Startup"/> event.
-        /// </summary>
-        /// <param name="e">A <see cref="StartupEventArgs"/> that contains the event data.</param>
-        protected virtual void OnStartup(StartupEventArgs e)
-        {
-            Startup?.Invoke(this, e);
-        }
-
-        /// <summary>
-        /// Raises the <see cref="Exit"/> event.
-        /// </summary>
-        /// <param name="e">A <see cref="ExitEventArgs"/> that contains the event data.</param>
-        protected virtual void OnExit(ExitEventArgs e)
-        {
-            Exit?.Invoke(this, e);
-        }
-
-        /// <inheritdoc/>
-        public void Shutdown(int exitCode = 0)
-        {
-            if (IsShuttingDown)
-            {
-                throw new InvalidOperationException("Application is already shutting down.");
-            }
-
-            _exitCode = exitCode;
-
-            IsShuttingDown = true;         
-
-            Windows.Clear();
-
-            try
-            {
-                var e = new ExitEventArgs { ApplicationExitCode = _exitCode };
-
-                OnExit(e);
-
-                _exitCode = e.ApplicationExitCode;                
-            }
-            finally
-            {
-                _mainLoopCancellationTokenSource?.Cancel();
-
-                _mainLoopCancellationTokenSource = null;
-
-                IsShuttingDown = false;
-
-                Environment.ExitCode = _exitCode;
-            }
-        }
-
         /// <inheritdoc/>
         bool IResourceProvider.TryGetResource(object key, out object value)
         {
@@ -383,7 +191,6 @@ namespace Avalonia
                 .Bind<IInputManager>().ToConstant(InputManager)
                 .Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()
                 .Bind<IStyler>().ToConstant(_styler)
-                .Bind<IApplicationLifecycle>().ToConstant(this)
                 .Bind<IScheduler>().ToConstant(AvaloniaScheduler.Instance)
                 .Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance)
                 .Bind<IPlatformDragSource>().ToTransient<InProcessDragSource>();
@@ -394,6 +201,11 @@ namespace Avalonia
                 .GetService<IRenderLoop>()?.Add(clock);
         }
 
+        public virtual void OnFrameworkInitializationCompleted()
+        {
+            
+        }
+
         private void ThisResourcesChanged(object sender, ResourcesChangedEventArgs e)
         {
             ResourcesChanged?.Invoke(this, e);

+ 133 - 0
src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs

@@ -0,0 +1,133 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Interactivity;
+
+namespace Avalonia.Controls.ApplicationLifetimes
+{
+    public class ClassicDesktopStyleApplicationLifetime : IClassicDesktopStyleApplicationLifetime, IDisposable
+    {
+        private readonly Application _app;
+        private int _exitCode;
+        private CancellationTokenSource _cts;
+        private bool _isShuttingDown;
+        private HashSet<Window> _windows = new HashSet<Window>();
+
+        private static ClassicDesktopStyleApplicationLifetime _activeLifetime;
+        static ClassicDesktopStyleApplicationLifetime()
+        {
+            Window.WindowOpenedEvent.AddClassHandler(typeof(Window), OnWindowOpened);
+            Window.WindowClosedEvent.AddClassHandler(typeof(Window), WindowClosedEvent);
+        }
+
+        private static void WindowClosedEvent(object sender, RoutedEventArgs e)
+        {
+            _activeLifetime?._windows.Remove((Window)sender);
+            _activeLifetime?.HandleWindowClosed((Window)sender);
+        }
+
+        private static void OnWindowOpened(object sender, RoutedEventArgs e)
+        {
+            _activeLifetime?._windows.Add((Window)sender);
+        }
+
+        public ClassicDesktopStyleApplicationLifetime(Application app)
+        {
+            if (_activeLifetime != null)
+                throw new InvalidOperationException(
+                    "Can not have multiple active ClassicDesktopStyleApplicationLifetime instances and the previously created one was not disposed");
+            _app = app;
+            _activeLifetime = this;
+        }
+        
+        /// <inheritdoc/>
+        public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
+        /// <inheritdoc/>
+        public event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit;
+
+        /// <inheritdoc/>
+        public ShutdownMode ShutdownMode { get; set; }
+        
+        /// <inheritdoc/>
+        public Window MainWindow { get; set; }
+
+        public IReadOnlyList<Window> Windows => _windows.ToList();
+
+        private void HandleWindowClosed(Window window)
+        {
+            if (window == null)
+                return;
+            
+            if (_isShuttingDown)
+                return;
+
+            if (ShutdownMode == ShutdownMode.OnLastWindowClose && _windows.Count == 0)
+                Shutdown();
+            else if (ShutdownMode == ShutdownMode.OnMainWindowClose && window == MainWindow)
+                Shutdown();
+        }
+        
+        
+
+
+        public void Shutdown(int exitCode = 0)
+        {
+            if (_isShuttingDown)
+                throw new InvalidOperationException("Application is already shutting down.");
+            
+            _exitCode = exitCode;
+            _isShuttingDown = true;
+
+            try
+            {
+                foreach (var w in Windows)
+                    w.Close();
+                var e = new ControlledApplicationLifetimeExitEventArgs(exitCode);
+                Exit?.Invoke(this, e);
+                _exitCode = e.ApplicationExitCode;                
+            }
+            finally
+            {
+                _cts?.Cancel();
+                _cts = null;
+                _isShuttingDown = false;
+            }
+        }
+        
+        
+        public int Start(string[] args)
+        {
+            Startup?.Invoke(this, new ControlledApplicationLifetimeStartupEventArgs(args));
+            _cts = new CancellationTokenSource();
+            MainWindow?.Show();
+            _app.Run(_cts.Token);
+            Environment.ExitCode = _exitCode;
+            return _exitCode;
+        }
+
+        public void Dispose()
+        {
+            if (_activeLifetime == this)
+                _activeLifetime = null;
+        }
+    }
+}
+
+namespace Avalonia
+{
+    public static class ClassicDesktopStyleApplicationLifetimeExtensions
+    {
+        public static int StartWithClassicDesktopLifetime<T>(
+            this T builder, string[] args, ShutdownMode shutdownMode = ShutdownMode.OnLastWindowClose)
+            where T : AppBuilderBase<T>, new()
+        {
+            var lifetime = new ClassicDesktopStyleApplicationLifetime(builder.Instance) {ShutdownMode = shutdownMode};
+            builder.Instance.ApplicationLifetime = lifetime;
+            builder.SetupWithoutStarting();
+            return lifetime.Start(args);
+        }
+    }
+}

+ 8 - 3
src/Avalonia.Controls/ExitEventArgs.cs → src/Avalonia.Controls/ApplicationLifetimes/ControlledApplicationLifetimeExitEventArgs.cs

@@ -3,13 +3,18 @@
 
 using System;
 
-namespace Avalonia.Controls
+namespace Avalonia.Controls.ApplicationLifetimes
 {
     /// <summary>
-    /// Contains the arguments for the <see cref="IApplicationLifecycle.Exit"/> event.
+    /// Contains the arguments for the <see cref="IClassicDesktopStyleApplicationLifetime.Exit"/> event.
     /// </summary>
-    public class ExitEventArgs : EventArgs
+    public class ControlledApplicationLifetimeExitEventArgs : EventArgs
     {
+        public ControlledApplicationLifetimeExitEventArgs(int applicationExitCode)
+        {
+            ApplicationExitCode = applicationExitCode;
+        }
+
         /// <summary>
         /// Gets or sets the exit code that an application returns to the operating system when the application exits.
         /// </summary>

+ 7 - 0
src/Avalonia.Controls/ApplicationLifetimes/IApplicationLifetime.cs

@@ -0,0 +1,7 @@
+namespace Avalonia.Controls.ApplicationLifetimes
+{
+    public interface IApplicationLifetime
+    {
+        
+    }
+}

+ 31 - 0
src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+
+namespace Avalonia.Controls.ApplicationLifetimes
+{
+    /// <summary>
+    /// Controls application lifetime in classic desktop style
+    /// </summary>
+    public interface IClassicDesktopStyleApplicationLifetime : IControlledApplicationLifetime
+    {
+        /// <summary>
+        /// Gets or sets the <see cref="ShutdownMode"/>. This property indicates whether the application is shutdown explicitly or implicitly. 
+        /// If <see cref="ShutdownMode"/> is set to OnExplicitShutdown the application is only closes if Shutdown is called.
+        /// The default is OnLastWindowClose
+        /// </summary>
+        /// <value>
+        /// The shutdown mode.
+        /// </value>
+        ShutdownMode ShutdownMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets the main window of the application.
+        /// </summary>
+        /// <value>
+        /// The main window.
+        /// </value>
+        Window MainWindow { get; set; }
+        
+        IReadOnlyList<Window> Windows { get; }
+    }
+}

+ 5 - 8
src/Avalonia.Controls/IApplicationLifecycle.cs → src/Avalonia.Controls/ApplicationLifetimes/IControlledApplicationLifetime.cs

@@ -1,22 +1,19 @@
 using System;
 
-namespace Avalonia.Controls
+namespace Avalonia.Controls.ApplicationLifetimes
 {
-    /// <summary>
-    /// Sends events about the application lifecycle.
-    /// </summary>
-    public interface IApplicationLifecycle
+    public interface IControlledApplicationLifetime : IApplicationLifetime
     {
         /// <summary>
         /// Sent when the application is starting up.
         /// </summary>
-        event EventHandler<StartupEventArgs> Startup;
+        event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
 
         /// <summary>
         /// Sent when the application is exiting.
         /// </summary>
-        event EventHandler<ExitEventArgs> Exit;
-
+        event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit;
+        
         /// <summary>
         /// Shuts down the application and sets the exit code that is returned to the operating system when the application exits.
         /// </summary>

+ 7 - 0
src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs

@@ -0,0 +1,7 @@
+namespace Avalonia.Controls.ApplicationLifetimes
+{
+    public interface ISingleViewApplicationLifetime : IApplicationLifetime
+    {
+        Control MainView { get; set; }
+    }
+}

+ 22 - 0
src/Avalonia.Controls/ApplicationLifetimes/StartupEventArgs.cs

@@ -0,0 +1,22 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Avalonia.Controls.ApplicationLifetimes
+{
+    /// <summary>
+    /// Contains the arguments for the <see cref="IClassicDesktopStyleApplicationLifetime.Startup"/> event.
+    /// </summary>
+    public class ControlledApplicationLifetimeStartupEventArgs : EventArgs
+    {
+        public ControlledApplicationLifetimeStartupEventArgs(IEnumerable<string> args)
+        {
+            Args = args?.ToArray() ?? Array.Empty<string>();
+        }
+
+        public string[] Args { get;  }
+    }
+}

+ 27 - 6
src/Avalonia.Controls/ColumnDefinition.cs

@@ -62,8 +62,15 @@ namespace Avalonia.Controls
         /// </summary>
         public double MaxWidth
         {
-            get { return GetValue(MaxWidthProperty); }
-            set { SetValue(MaxWidthProperty, value); }
+            get
+            {
+                return GetValue(MaxWidthProperty);
+            }
+            set
+            {
+                Parent?.InvalidateMeasure();
+                SetValue(MaxWidthProperty, value);
+            }
         }
 
         /// <summary>
@@ -71,8 +78,15 @@ namespace Avalonia.Controls
         /// </summary>
         public double MinWidth
         {
-            get { return GetValue(MinWidthProperty); }
-            set { SetValue(MinWidthProperty, value); }
+            get
+            {
+                return GetValue(MinWidthProperty);
+            }
+            set
+            {
+                Parent?.InvalidateMeasure();
+                SetValue(MinWidthProperty, value);
+            }
         }
 
         /// <summary>
@@ -80,8 +94,15 @@ namespace Avalonia.Controls
         /// </summary>
         public GridLength Width
         {
-            get { return GetValue(WidthProperty); }
-            set { SetValue(WidthProperty, value); }
+            get
+            {
+                return GetValue(WidthProperty);
+            }
+            set
+            {
+                Parent?.InvalidateMeasure();
+                SetValue(WidthProperty, value);
+            }
         }
 
         internal override GridLength UserSizeValueCache => this.Width;

+ 67 - 0
src/Avalonia.Controls/DesktopApplicationExtensions.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Threading;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Threading;
+
+namespace Avalonia.Controls
+{
+    public static class DesktopApplicationExtensions
+    {
+        [Obsolete("Running application without a cancellation token and a lifetime is no longer supported, see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details", true)]
+        public static void Run(this Application app) => throw new NotSupportedException();
+
+        /// <summary>
+        /// On desktop-style platforms runs the application's main loop until closable is closed
+        /// </summary>
+        /// <remarks>
+        /// Consider using StartWithDesktopStyleLifetime instead, see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details
+        /// </remarks>
+        public static void Run(this Application app, ICloseable closable)
+        {
+            var cts = new CancellationTokenSource();
+            closable.Closed += (s, e) => cts.Cancel();
+
+            app.Run(cts.Token);
+        }
+
+        /// <summary>
+        /// On desktop-style platforms runs the application's main loop until main window is closed
+        /// </summary>
+        /// <remarks>
+        /// Consider using StartWithDesktopStyleLifetime instead, see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details
+        /// </remarks>
+        public static void Run(this Application app, Window mainWindow)
+        {
+            if (mainWindow == null)
+            {
+                throw new ArgumentNullException(nameof(mainWindow));
+            }
+            var cts = new CancellationTokenSource();
+            mainWindow.Closed += (_, __) => cts.Cancel();
+            if (!mainWindow.IsVisible)
+            {
+                mainWindow.Show();
+            }
+            app.Run(cts.Token);
+        }
+        
+        /// <summary>
+        /// On desktop-style platforms runs the application's main loop with custom CancellationToken
+        /// without setting a lifetime.
+        /// </summary>
+        /// <param name="token">The token to track.</param>
+        public static void Run(this Application app, CancellationToken token)
+        {
+            Dispatcher.UIThread.MainLoop(token);
+        }
+
+        public static void RunWithMainWindow<TWindow>(this Application app)
+            where TWindow : Avalonia.Controls.Window, new()
+        {
+            var window = new TWindow();
+            window.Show();
+            app.Run(window);
+        }
+    }
+}

+ 104 - 69
src/Avalonia.Controls/DockPanel.cs

@@ -1,7 +1,12 @@
+// This source file is adapted from the Windows Presentation Foundation project. 
+// (https://github.com/dotnet/wpf/) 
+// 
+// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
+
+using System;
+
 namespace Avalonia.Controls
 {
-    using System;
-
     /// <summary>
     /// Defines the available docking modes for a control in a <see cref="DockPanel"/>.
     /// </summary>
@@ -70,107 +75,137 @@ namespace Avalonia.Controls
             set { SetValue(LastChildFillProperty, value); }
         }
 
-        /// <inheritdoc/>
+        /// <summary>
+        /// Updates DesiredSize of the DockPanel.  Called by parent Control.  This is the first pass of layout.
+        /// </summary>
+        /// <remarks>
+        /// Children are measured based on their sizing properties and <see cref="Dock" />.  
+        /// Each child is allowed to consume all of the space on the side on which it is docked; Left/Right docked
+        /// children are granted all vertical space for their entire width, and Top/Bottom docked children are
+        /// granted all horizontal space for their entire height.
+        /// </remarks>
+        /// <param name="constraint">Constraint size is an "upper limit" that the return value should not exceed.</param>
+        /// <returns>The Panel's desired size.</returns>
         protected override Size MeasureOverride(Size constraint)
         {
-            double usedWidth = 0.0;
-            double usedHeight = 0.0;
-            double maximumWidth = 0.0;
-            double maximumHeight = 0.0;
+            var children = Children;
+
+            double parentWidth = 0;   // Our current required width due to children thus far.
+            double parentHeight = 0;   // Our current required height due to children thus far.
+            double accumulatedWidth = 0;   // Total width consumed by children.
+            double accumulatedHeight = 0;   // Total height consumed by children.
 
-            // Measure each of the Children
-            foreach (Control element in Children)
+            for (int i = 0, count = children.Count; i < count; ++i)
             {
-                // Get the child's desired size
-                Size remainingSize = new Size(
-                    Math.Max(0.0, constraint.Width - usedWidth),
-                    Math.Max(0.0, constraint.Height - usedHeight));
-                element.Measure(remainingSize);
-                Size desiredSize = element.DesiredSize;
-
-                // Decrease the remaining space for the rest of the children
-                switch (GetDock(element))
+                var child = children[i];
+                Size childConstraint;             // Contains the suggested input constraint for this child.
+                Size childDesiredSize;            // Contains the return size from child measure.
+
+                if (child == null)
+                { continue; }
+
+                // Child constraint is the remaining size; this is total size minus size consumed by previous children.
+                childConstraint = new Size(Math.Max(0.0, constraint.Width - accumulatedWidth),
+                                           Math.Max(0.0, constraint.Height - accumulatedHeight));
+
+                // Measure child.
+                child.Measure(childConstraint);
+                childDesiredSize = child.DesiredSize;
+
+                // Now, we adjust:
+                // 1. Size consumed by children (accumulatedSize).  This will be used when computing subsequent
+                //    children to determine how much space is remaining for them.
+                // 2. Parent size implied by this child (parentSize) when added to the current children (accumulatedSize).
+                //    This is different from the size above in one respect: A Dock.Left child implies a height, but does
+                //    not actually consume any height for subsequent children.
+                // If we accumulate size in a given dimension, the next child (or the end conditions after the child loop)
+                // will deal with computing our minimum size (parentSize) due to that accumulation.
+                // Therefore, we only need to compute our minimum size (parentSize) in dimensions that this child does
+                //   not accumulate: Width for Top/Bottom, Height for Left/Right.
+                switch (DockPanel.GetDock((Control)child))
                 {
                     case Dock.Left:
                     case Dock.Right:
-                        maximumHeight = Math.Max(maximumHeight, usedHeight + desiredSize.Height);
-                        usedWidth += desiredSize.Width;
+                        parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height);
+                        accumulatedWidth += childDesiredSize.Width;
                         break;
+
                     case Dock.Top:
                     case Dock.Bottom:
-                        maximumWidth = Math.Max(maximumWidth, usedWidth + desiredSize.Width);
-                        usedHeight += desiredSize.Height;
+                        parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width);
+                        accumulatedHeight += childDesiredSize.Height;
                         break;
                 }
             }
 
-            maximumWidth = Math.Max(maximumWidth, usedWidth);
-            maximumHeight = Math.Max(maximumHeight, usedHeight);
-            return new Size(maximumWidth, maximumHeight);
+            // Make sure the final accumulated size is reflected in parentSize.
+            parentWidth = Math.Max(parentWidth, accumulatedWidth);
+            parentHeight = Math.Max(parentHeight, accumulatedHeight);
+
+            return (new Size(parentWidth, parentHeight));
         }
 
-        /// <inheritdoc/>
+        /// <summary>
+        /// DockPanel computes a position and final size for each of its children based upon their
+        /// <see cref="Dock" /> enum and sizing properties.
+        /// </summary>
+        /// <param name="arrangeSize">Size that DockPanel will assume to position children.</param>
         protected override Size ArrangeOverride(Size arrangeSize)
         {
-            double left = 0.0;
-            double top = 0.0;
-            double right = 0.0;
-            double bottom = 0.0;
-
-            // Arrange each of the Children
             var children = Children;
-            int dockedCount = children.Count - (LastChildFill ? 1 : 0);
-            int index = 0;
+            int totalChildrenCount = children.Count;
+            int nonFillChildrenCount = totalChildrenCount - (LastChildFill ? 1 : 0);
+
+            double accumulatedLeft = 0;
+            double accumulatedTop = 0;
+            double accumulatedRight = 0;
+            double accumulatedBottom = 0;
 
-            foreach (Control element in children)
+            for (int i = 0; i < totalChildrenCount; ++i)
             {
-                // Determine the remaining space left to arrange the element
-                Rect remainingRect = new Rect(
-                    left,
-                    top,
-                    Math.Max(0.0, arrangeSize.Width - left - right),
-                    Math.Max(0.0, arrangeSize.Height - top - bottom));
-
-                // Trim the remaining Rect to the docked size of the element
-                // (unless the element should fill the remaining space because
-                // of LastChildFill)
-                if (index < dockedCount)
+                var child = children[i];
+                if (child == null)
+                { continue; }
+
+                Size childDesiredSize = child.DesiredSize;
+                Rect rcChild = new Rect(
+                    accumulatedLeft,
+                    accumulatedTop,
+                    Math.Max(0.0, arrangeSize.Width - (accumulatedLeft + accumulatedRight)),
+                    Math.Max(0.0, arrangeSize.Height - (accumulatedTop + accumulatedBottom)));
+
+                if (i < nonFillChildrenCount)
                 {
-                    Size desiredSize = element.DesiredSize;
-                    switch (GetDock(element))
+                    switch (DockPanel.GetDock((Control)child))
                     {
                         case Dock.Left:
-                            left += desiredSize.Width;
-                            remainingRect = remainingRect.WithWidth(desiredSize.Width);
-                            break;
-                        case Dock.Top:
-                            top += desiredSize.Height;
-                            remainingRect = remainingRect.WithHeight(desiredSize.Height);
+                            accumulatedLeft += childDesiredSize.Width;
+                            rcChild = rcChild.WithWidth(childDesiredSize.Width);
                             break;
+
                         case Dock.Right:
-                            right += desiredSize.Width;
-                            remainingRect = new Rect(
-                                Math.Max(0.0, arrangeSize.Width - right),
-                                remainingRect.Y,
-                                desiredSize.Width,
-                                remainingRect.Height);
+                            accumulatedRight += childDesiredSize.Width;
+                            rcChild = rcChild.WithX(Math.Max(0.0, arrangeSize.Width - accumulatedRight));
+                            rcChild = rcChild.WithWidth(childDesiredSize.Width);
                             break;
+
+                        case Dock.Top:
+                            accumulatedTop += childDesiredSize.Height;
+                            rcChild = rcChild.WithHeight(childDesiredSize.Height);
+                            break;
+
                         case Dock.Bottom:
-                            bottom += desiredSize.Height;
-                            remainingRect = new Rect(
-                                remainingRect.X,
-                                Math.Max(0.0, arrangeSize.Height - bottom),
-                                remainingRect.Width,
-                                desiredSize.Height);
+                            accumulatedBottom += childDesiredSize.Height;
+                            rcChild = rcChild.WithY(Math.Max(0.0, arrangeSize.Height - accumulatedBottom));
+                            rcChild = rcChild.WithHeight(childDesiredSize.Height);
                             break;
                     }
                 }
 
-                element.Arrange(remainingRect);
-                index++;
+                child.Arrange(rcChild);
             }
 
-            return arrangeSize;
+            return (arrangeSize);
         }
     }
 }

+ 4 - 1
src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs

@@ -45,7 +45,10 @@ namespace Avalonia.Controls.Embedding
         {
             if (EnforceClientSize)
                 availableSize = PlatformImpl?.ClientSize ?? default(Size);
-            return base.MeasureOverride(availableSize);
+            var rv = base.MeasureOverride(availableSize);
+            if (EnforceClientSize)
+                return availableSize;
+            return rv;
         }
 
         private readonly NameScope _nameScope = new NameScope();

+ 12 - 2
src/Avalonia.Controls/ItemsControl.cs

@@ -36,6 +36,12 @@ namespace Avalonia.Controls
         public static readonly DirectProperty<ItemsControl, IEnumerable> ItemsProperty =
             AvaloniaProperty.RegisterDirect<ItemsControl, IEnumerable>(nameof(Items), o => o.Items, (o, v) => o.Items = v);
 
+        /// <summary>
+        /// Defines the <see cref="ItemCount"/> property.
+        /// </summary>
+        public static readonly DirectProperty<ItemsControl, int> ItemCountProperty =
+            AvaloniaProperty.RegisterDirect<ItemsControl, int>(nameof(ItemCount), o => o.ItemCount);
+
         /// <summary>
         /// Defines the <see cref="ItemsPanel"/> property.
         /// </summary>
@@ -55,6 +61,7 @@ namespace Avalonia.Controls
             AvaloniaProperty.Register<ItemsControl, IMemberSelector>(nameof(MemberSelector));
 
         private IEnumerable _items = new AvaloniaList<object>();
+        private int _itemCount;
         private IItemContainerGenerator _itemContainerGenerator;
         private IDisposable _itemsCollectionChangedSubscription;
 
@@ -110,10 +117,13 @@ namespace Avalonia.Controls
             set { SetAndRaise(ItemsProperty, ref _items, value); }
         }
 
+        /// <summary>
+        /// Gets the number of items in <see cref="Items"/>.
+        /// </summary>
         public int ItemCount
         {
-            get;
-            private set;
+            get => _itemCount;
+            private set => SetAndRaise(ItemCountProperty, ref _itemCount, value);
         }
 
         /// <summary>

+ 12 - 1
src/Avalonia.Controls/ListBox.cs

@@ -84,6 +84,16 @@ namespace Avalonia.Controls
             set { SetValue(VirtualizationModeProperty, value); }
         }
 
+        /// <summary>
+        /// Selects all items in the <see cref="ListBox"/>.
+        /// </summary>
+        public new void SelectAll() => base.SelectAll();
+
+        /// <summary>
+        /// Deselects all items in the <see cref="ListBox"/>.
+        /// </summary>
+        public new void UnselectAll() => base.UnselectAll();
+
         /// <inheritdoc/>
         protected override IItemContainerGenerator CreateItemContainerGenerator()
         {
@@ -118,7 +128,8 @@ namespace Avalonia.Controls
                     e.Source,
                     true,
                     (e.InputModifiers & InputModifiers.Shift) != 0,
-                    (e.InputModifiers & InputModifiers.Control) != 0);
+                    (e.InputModifiers & InputModifiers.Control) != 0,
+                    e.MouseButton == MouseButton.Right);
             }
         }
 

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

@@ -80,7 +80,7 @@ namespace Avalonia.Controls.Primitives
         /// </summary>
         public void SnapInsideScreenEdges()
         {
-            var screen = Application.Current.MainWindow?.Screens.ScreenFromPoint(Position);
+            var screen = (VisualRoot as WindowBase)?.Screens?.ScreenFromPoint(Position);
 
             if (screen != null)
             {

+ 43 - 22
src/Avalonia.Controls/Primitives/RangeBase.cs

@@ -75,10 +75,18 @@ namespace Avalonia.Controls.Primitives
 
             set
             {
-                value = ValidateMinimum(value);
-                SetAndRaise(MinimumProperty, ref _minimum, value);
-                Maximum = ValidateMaximum(Maximum);
-                Value = ValidateValue(Value);
+                ValidateDouble(value, "Minimum");
+
+                if (IsInitialized)
+                {
+                    SetAndRaise(MinimumProperty, ref _minimum, value);
+                    Maximum = ValidateMaximum(Maximum);
+                    Value = ValidateValue(Value);
+                }
+                else
+                {
+                    SetAndRaise(MinimumProperty, ref _minimum, value);
+                }
             }
         }
 
@@ -94,9 +102,18 @@ namespace Avalonia.Controls.Primitives
 
             set
             {
-                value = ValidateMaximum(value);
-                SetAndRaise(MaximumProperty, ref _maximum, value);
-                Value = ValidateValue(Value);
+                ValidateDouble(value, "Maximum");
+
+                if (IsInitialized)
+                {
+                    value = ValidateMaximum(value);
+                    SetAndRaise(MaximumProperty, ref _maximum, value);
+                    Value = ValidateValue(Value);
+                }
+                else
+                {
+                    SetAndRaise(MaximumProperty, ref _maximum, value);
+                }
             }
         }
 
@@ -112,8 +129,17 @@ namespace Avalonia.Controls.Primitives
 
             set
             {
-                value = ValidateValue(value);
-                SetAndRaise(ValueProperty, ref _value, value);
+                ValidateDouble(value, "Value");
+
+                if (IsInitialized)
+                {
+                    value = ValidateValue(value);
+                    SetAndRaise(ValueProperty, ref _value, value);
+                }
+                else
+                {
+                    SetAndRaise(ValueProperty, ref _value, value);
+                }
             }
         }
 
@@ -129,6 +155,14 @@ namespace Avalonia.Controls.Primitives
             set => SetValue(LargeChangeProperty, value);
         }
 
+        protected override void OnInitialized()
+        {
+            base.OnInitialized();
+
+            Maximum = ValidateMaximum(Maximum);
+            Value = ValidateValue(Value);
+        }
+
         /// <summary>
         /// Throws an exception if the double value is NaN or Inf.
         /// </summary>
@@ -142,17 +176,6 @@ namespace Avalonia.Controls.Primitives
             }
         }
 
-        /// <summary>
-        /// Validates the <see cref="Minimum"/> property.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <returns>The coerced value.</returns>
-        private double ValidateMinimum(double value)
-        {
-            ValidateDouble(value, "Minimum");
-            return value;
-        }
-
         /// <summary>
         /// Validates/coerces the <see cref="Maximum"/> property.
         /// </summary>
@@ -160,7 +183,6 @@ namespace Avalonia.Controls.Primitives
         /// <returns>The coerced value.</returns>
         private double ValidateMaximum(double value)
         {
-            ValidateDouble(value, "Maximum");
             return Math.Max(value, Minimum);
         }
 
@@ -171,7 +193,6 @@ namespace Avalonia.Controls.Primitives
         /// <returns>The coerced value.</returns>
         private double ValidateValue(double value)
         {
-            ValidateDouble(value, "Value");
             return MathUtilities.Clamp(value, Minimum, Maximum);
         }
     }

+ 409 - 235
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@@ -12,6 +12,7 @@ using Avalonia.Data;
 using Avalonia.Input;
 using Avalonia.Input.Platform;
 using Avalonia.Interactivity;
+using Avalonia.Logging;
 using Avalonia.Styling;
 using Avalonia.VisualTree;
 
@@ -103,6 +104,7 @@ namespace Avalonia.Controls.Primitives
 
         private static readonly IList Empty = Array.Empty<object>();
 
+        private readonly Selection _selection = new Selection();
         private int _selectedIndex = -1;
         private object _selectedItem;
         private IList _selectedItems;
@@ -152,23 +154,8 @@ namespace Avalonia.Controls.Primitives
             {
                 if (_updateCount == 0)
                 {
-                    SetAndRaise(SelectedIndexProperty, ref _selectedIndex, (int val, ref int backing, Action<Action> notifyWrapper) =>
-                    {
-                        var old = backing;
-                        var effective = (val >= 0 && val < Items?.Cast<object>().Count()) ? val : -1;
-
-                        if (old != effective)
-                        {
-                            backing = effective;
-                            notifyWrapper(() =>
-                                RaisePropertyChanged(
-                                    SelectedIndexProperty,
-                                    old,
-                                    effective,
-                                    BindingPriority.LocalValue));
-                            SelectedItem = ElementAt(Items, effective);
-                        }
-                    }, value);
+                    var effective = (value >= 0 && value < ItemCount) ? value : -1;
+                    UpdateSelectedItem(effective);
                 }
                 else
                 {
@@ -192,41 +179,7 @@ namespace Avalonia.Controls.Primitives
             {
                 if (_updateCount == 0)
                 {
-                    SetAndRaise(SelectedItemProperty, ref _selectedItem, (object val, ref object backing, Action<Action> notifyWrapper) =>
-                    {
-                        var old = backing;
-                        var index = IndexOf(Items, val);
-                        var effective = index != -1 ? val : null;
-
-                        if (!object.Equals(effective, old))
-                        {
-                            backing = effective;
-
-                            notifyWrapper(() =>
-                                RaisePropertyChanged(
-                                    SelectedItemProperty,
-                                    old,
-                                    effective,
-                                    BindingPriority.LocalValue));
-
-                            SelectedIndex = index;
-
-                            if (effective != null)
-                            {
-                                if (SelectedItems.Count != 1 || SelectedItems[0] != effective)
-                                {
-                                    _syncingSelectedItems = true;
-                                    SelectedItems.Clear();
-                                    SelectedItems.Add(effective);
-                                    _syncingSelectedItems = false;
-                                }
-                            }
-                            else if (SelectedItems.Count > 0)
-                            {
-                                SelectedItems.Clear();
-                            }
-                        }
-                    }, value);
+                    UpdateSelectedItem(IndexOf(Items, value));
                 }
                 else
                 {
@@ -354,31 +307,23 @@ namespace Avalonia.Controls.Primitives
                     {
                         SelectedIndex = 0;
                     }
+                    else
+                    {
+                        _selection.ItemsInserted(e.NewStartingIndex, e.NewItems.Count);
+                        UpdateSelectedItem(_selection.First(), false);
+                    }
 
                     break;
 
                 case NotifyCollectionChangedAction.Remove:
-                case NotifyCollectionChangedAction.Replace:
-                    var selectedIndex = SelectedIndex;
-
-                    if (selectedIndex >= e.OldStartingIndex &&
-                        selectedIndex < e.OldStartingIndex + e.OldItems.Count)
-                    {
-                        if (!AlwaysSelected)
-                        {
-                            selectedIndex = SelectedIndex = -1;
-                        }
-                        else
-                        {
-                            LostSelection();
-                        }
-                    }
+                    _selection.ItemsRemoved(e.OldStartingIndex, e.OldItems.Count);
+                    UpdateSelectedItem(_selection.First(), false);
+                    ResetSelectedItems();
+                    break;
 
-                    var items = Items?.Cast<object>();
-                    if (selectedIndex >= items.Count())
-                    {
-                        selectedIndex = SelectedIndex = items.Count() - 1;
-                    }
+                case NotifyCollectionChangedAction.Replace:
+                    UpdateSelectedItem(SelectedIndex, false);
+                    ResetSelectedItems();
                     break;
 
                 case NotifyCollectionChangedAction.Move:
@@ -439,11 +384,7 @@ namespace Avalonia.Controls.Primitives
             {
                 if (i.ContainerControl != null && i.Item != null)
                 {
-                    var ms = MemberSelector;
-                    bool selected = ms == null ? 
-                        SelectedItems.Contains(i.Item) : 
-                        SelectedItems.OfType<object>().Any(v => Equals(ms.Select(v), i.Item));
-
+                    bool selected = _selection.Contains(i.Index);
                     MarkContainerSelected(i.ContainerControl, selected);
                 }
             }
@@ -476,9 +417,12 @@ namespace Avalonia.Controls.Primitives
                 var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>();
                 bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e));
 
-                if (this.SelectionMode == SelectionMode.Multiple && Match(keymap.SelectAll))
+                if (ItemCount > 0 &&
+                    Match(keymap.SelectAll) &&
+                    (((SelectionMode & SelectionMode.Multiple) != 0) ||
+                      (SelectionMode & SelectionMode.Toggle) != 0))
                 {
-                    SynchronizeItems(SelectedItems, Items?.Cast<object>());
+                    SelectAll();
                     e.Handled = true;
                 }
             }
@@ -520,6 +464,41 @@ namespace Avalonia.Controls.Primitives
             return false;
         }
 
+        /// <summary>
+        /// Selects all items in the control.
+        /// </summary>
+        protected void SelectAll()
+        {
+            if ((SelectionMode & (SelectionMode.Multiple | SelectionMode.Toggle)) == 0)
+            {
+                throw new NotSupportedException("Multiple selection is not enabled on this control.");
+            }
+
+            UpdateSelectedItems(() =>
+            {
+                _selection.Clear();
+
+                for (var i = 0; i < ItemCount; ++i)
+                {
+                    _selection.Add(i);
+                }
+
+                UpdateSelectedItem(0, false);
+
+                foreach (var container in ItemContainerGenerator.Containers)
+                {
+                    MarkItemSelected(container.Index, true);
+                }
+
+                ResetSelectedItems();
+            });
+        }
+
+        /// <summary>
+        /// Deselects all items in the control.
+        /// </summary>
+        protected void UnselectAll() => UpdateSelectedItem(-1);
+
         /// <summary>
         /// Updates the selection for an item based on user interaction.
         /// </summary>
@@ -527,51 +506,83 @@ namespace Avalonia.Controls.Primitives
         /// <param name="select">Whether the item should be selected or unselected.</param>
         /// <param name="rangeModifier">Whether the range modifier is enabled (i.e. shift key).</param>
         /// <param name="toggleModifier">Whether the toggle modifier is enabled (i.e. ctrl key).</param>
+        /// <param name="rightButton">Whether the event is a right-click.</param>
         protected void UpdateSelection(
             int index,
             bool select = true,
             bool rangeModifier = false,
-            bool toggleModifier = false)
+            bool toggleModifier = false,
+            bool rightButton = false)
         {
             if (index != -1)
             {
                 if (select)
                 {
                     var mode = SelectionMode;
-                    var toggle = toggleModifier || (mode & SelectionMode.Toggle) != 0;
                     var multi = (mode & SelectionMode.Multiple) != 0;
-                    var range = multi && SelectedIndex != -1 && rangeModifier;
+                    var toggle = (toggleModifier || (mode & SelectionMode.Toggle) != 0);
+                    var range = multi && rangeModifier;
 
-                    if (!toggle && !range)
+                    if (range)
                     {
-                        SelectedIndex = index;
-                    }
-                    else if (multi && range)
-                    {
-                        SynchronizeItems(
-                            SelectedItems,
-                            GetRange(Items, SelectedIndex, index));
+                        UpdateSelectedItems(() =>
+                        {
+                            var start = SelectedIndex != -1 ? SelectedIndex : 0;
+                            var step = start < index ? 1 : -1;
+
+                            _selection.Clear();
+
+                            for (var i = start; i != index; i += step)
+                            {
+                                _selection.Add(i);
+                            }
+
+                            _selection.Add(index);
+
+                            var first = Math.Min(start, index);
+                            var last = Math.Max(start, index);
+
+                            foreach (var container in ItemContainerGenerator.Containers)
+                            {
+                                MarkItemSelected(
+                                    container.Index,
+                                    container.Index >= first && container.Index <= last);
+                            }
+
+                            ResetSelectedItems();
+                        });
                     }
-                    else
+                    else if (multi && toggle)
                     {
-                        var item = ElementAt(Items, index);
-                        var i = SelectedItems.IndexOf(item);
-
-                        if (i != -1 && (!AlwaysSelected || SelectedItems.Count > 1))
-                        {
-                            SelectedItems.Remove(item);
-                        }
-                        else
+                        UpdateSelectedItems(() =>
                         {
-                            if (multi)
+                            if (!_selection.Contains(index))
                             {
-                                SelectedItems.Add(item);
+                                _selection.Add(index);
+                                MarkItemSelected(index, true);
+                                SelectedItems.Add(ElementAt(Items, index));
                             }
                             else
                             {
-                                SelectedIndex = index;
+                                _selection.Remove(index);
+                                MarkItemSelected(index, false);
+
+                                if (index == _selectedIndex)
+                                {
+                                    UpdateSelectedItem(_selection.First(), false);
+                                }
+
+                                SelectedItems.Remove(ElementAt(Items, index));
                             }
-                        }
+                        });
+                    }
+                    else if (toggle)
+                    {
+                        SelectedIndex = (SelectedIndex == index) ? -1 : index;
+                    }
+                    else
+                    {
+                        UpdateSelectedItem(index, !(rightButton && _selection.Contains(index)));
                     }
 
                     if (Presenter?.Panel != null)
@@ -596,17 +607,19 @@ namespace Avalonia.Controls.Primitives
         /// <param name="select">Whether the container should be selected or unselected.</param>
         /// <param name="rangeModifier">Whether the range modifier is enabled (i.e. shift key).</param>
         /// <param name="toggleModifier">Whether the toggle modifier is enabled (i.e. ctrl key).</param>
+        /// <param name="rightButton">Whether the event is a right-click.</param>
         protected void UpdateSelection(
             IControl container,
             bool select = true,
             bool rangeModifier = false,
-            bool toggleModifier = false)
+            bool toggleModifier = false,
+            bool rightButton = false)
         {
             var index = ItemContainerGenerator?.IndexFromContainer(container) ?? -1;
 
             if (index != -1)
             {
-                UpdateSelection(index, select, rangeModifier, toggleModifier);
+                UpdateSelection(index, select, rangeModifier, toggleModifier, rightButton);
             }
         }
 
@@ -618,6 +631,7 @@ namespace Avalonia.Controls.Primitives
         /// <param name="select">Whether the container should be selected or unselected.</param>
         /// <param name="rangeModifier">Whether the range modifier is enabled (i.e. shift key).</param>
         /// <param name="toggleModifier">Whether the toggle modifier is enabled (i.e. ctrl key).</param>
+        /// <param name="rightButton">Whether the event is a right-click.</param>
         /// <returns>
         /// True if the event originated from a container that belongs to the control; otherwise
         /// false.
@@ -626,51 +640,20 @@ namespace Avalonia.Controls.Primitives
             IInteractive eventSource,
             bool select = true,
             bool rangeModifier = false,
-            bool toggleModifier = false)
+            bool toggleModifier = false,
+            bool rightButton = false)
         {
             var container = GetContainerFromEventSource(eventSource);
 
             if (container != null)
             {
-                UpdateSelection(container, select, rangeModifier, toggleModifier);
+                UpdateSelection(container, select, rangeModifier, toggleModifier, rightButton);
                 return true;
             }
 
             return false;
         }
 
-        /// <summary>
-        /// Makes a list of objects equal another.
-        /// </summary>
-        /// <param name="items">The items collection.</param>
-        /// <param name="desired">The desired items.</param>
-        internal static void SynchronizeItems(IList items, IEnumerable<object> desired)
-        {
-            var index = 0;
-
-            foreach (object item in desired)
-            {
-                int itemIndex = items.IndexOf(item);
-
-                if (itemIndex == -1)
-                {
-                    items.Insert(index, item);
-                }
-                else if(itemIndex != index)
-                {
-                    items.RemoveAt(itemIndex);
-                    items.Insert(index, item);
-                }
-
-                ++index;
-            }
-
-            while (index < items.Count)
-            {
-                items.RemoveAt(items.Count - 1);
-            }
-        }
-
         /// <summary>
         /// Gets a range of items from an IEnumerable.
         /// </summary>
@@ -678,17 +661,19 @@ namespace Avalonia.Controls.Primitives
         /// <param name="first">The index of the first item.</param>
         /// <param name="last">The index of the last item.</param>
         /// <returns>The items.</returns>
-        private static IEnumerable<object> GetRange(IEnumerable items, int first, int last)
+        private static List<object> GetRange(IEnumerable items, int first, int last)
         {
             var list = (items as IList) ?? items.Cast<object>().ToList();
-            int step = first > last ? -1 : 1;
+            var step = first > last ? -1 : 1;
+            var result = new List<object>();
 
             for (int i = first; i != last; i += step)
             {
-                yield return list[i];
+                result.Add(list[i]);
             }
 
-            yield return list[last];
+            result.Add(list[last]);
+            return result;
         }
 
         /// <summary>
@@ -724,19 +709,14 @@ namespace Avalonia.Controls.Primitives
         private void LostSelection()
         {
             var items = Items?.Cast<object>();
+            var index = -1;
 
             if (items != null && AlwaysSelected)
             {
-                var index = Math.Min(SelectedIndex, items.Count() - 1);
-
-                if (index > -1)
-                {
-                    SelectedItem = items.ElementAt(index);
-                    return;
-                }
+                index = Math.Min(SelectedIndex, items.Count() - 1);
             }
 
-            SelectedIndex = -1;
+            SelectedIndex = index;
         }
 
         /// <summary>
@@ -793,7 +773,7 @@ namespace Avalonia.Controls.Primitives
         /// </summary>
         /// <param name="item">The item.</param>
         /// <param name="selected">Whether the item should be selected or deselected.</param>
-        private void MarkItemSelected(object item, bool selected)
+        private int MarkItemSelected(object item, bool selected)
         {
             var index = IndexOf(Items, item);
 
@@ -801,6 +781,21 @@ namespace Avalonia.Controls.Primitives
             {
                 MarkItemSelected(index, selected);
             }
+
+            return index;
+        }
+
+        private void ResetSelectedItems()
+        {
+            UpdateSelectedItems(() =>
+            {
+                SelectedItems.Clear();
+
+                foreach (var i in _selection)
+                {
+                    SelectedItems.Add(ElementAt(Items, i));
+                }
+            });
         }
 
         /// <summary>
@@ -810,95 +805,97 @@ namespace Avalonia.Controls.Primitives
         /// <param name="e">The event args.</param>
         private void SelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
         {
-            var generator = ItemContainerGenerator;
+            if (_syncingSelectedItems)
+            {
+                return;
+            }
+
+            void Add(IList newItems, IList addedItems = null)
+            {
+                foreach (var item in newItems)
+                {
+                    var index = MarkItemSelected(item, true);
+
+                    if (index != -1 && _selection.Add(index) && addedItems != null)
+                    {
+                        addedItems.Add(item);
+                    }
+                }
+            }
+
+            void UpdateSelection()
+            {
+                if ((SelectedIndex != -1 && !_selection.Contains(SelectedIndex)) ||
+                    (SelectedIndex == -1 && _selection.HasItems))
+                {
+                    _selectedIndex = _selection.First();
+                    _selectedItem = ElementAt(Items, _selectedIndex);
+                    RaisePropertyChanged(SelectedIndexProperty, -1, _selectedIndex, BindingPriority.LocalValue);
+                    RaisePropertyChanged(SelectedItemProperty, null, _selectedItem, BindingPriority.LocalValue);
+
+                    if (AutoScrollToSelectedItem)
+                    {
+                        ScrollIntoView(_selectedIndex);
+                    }
+                }
+            }
+
             IList added = null;
             IList removed = null;
 
             switch (e.Action)
             {
                 case NotifyCollectionChangedAction.Add:
-                    SelectedItemsAdded(e.NewItems.Cast<object>().ToList());
-
-                    if (AutoScrollToSelectedItem)
                     {
-                        ScrollIntoView(e.NewItems[0]);
+                        Add(e.NewItems);
+                        UpdateSelection();
+                        added = e.NewItems;
                     }
 
-                    added = e.NewItems;
                     break;
 
                 case NotifyCollectionChangedAction.Remove:
                     if (SelectedItems.Count == 0)
                     {
-                        if (!_syncingSelectedItems)
-                        {
-                            SelectedIndex = -1;
-                        }
+                        SelectedIndex = -1;
                     }
 
                     foreach (var item in e.OldItems)
                     {
-                        MarkItemSelected(item, false);
+                        var index = MarkItemSelected(item, false);
+                        _selection.Remove(index);
                     }
 
                     removed = e.OldItems;
                     break;
 
+                case NotifyCollectionChangedAction.Replace:
+                    throw new NotSupportedException("Replacing items in a SelectedItems collection is not supported.");
+
+                case NotifyCollectionChangedAction.Move:
+                    throw new NotSupportedException("Moving items in a SelectedItems collection is not supported.");
+
                 case NotifyCollectionChangedAction.Reset:
-                    if (generator != null)
                     {
                         removed = new List<object>();
+                        added = new List<object>();
 
-                        foreach (var item in generator.Containers)
+                        foreach (var index in _selection.ToList())
                         {
-                            if (item?.ContainerControl != null)
+                            var item = ElementAt(Items, index);
+
+                            if (!SelectedItems.Contains(item))
                             {
-                                if (MarkContainerSelected(item.ContainerControl, false))
-                                {
-                                    removed.Add(item.Item);
-                                }
+                                MarkItemSelected(index, false);
+                                removed.Add(item);
+                                _selection.Remove(index);
                             }
                         }
-                    }
 
-                    if (SelectedItems.Count > 0)
-                    {
-                        _selectedItem = null;
-                        SelectedItemsAdded(SelectedItems);
-                        added = SelectedItems;
-                    }
-                    else if (!_syncingSelectedItems)
-                    {
-                        SelectedIndex = -1;
-                    }
-
-                    break;
-
-                case NotifyCollectionChangedAction.Replace:
-                    foreach (var item in e.OldItems)
-                    {
-                        MarkItemSelected(item, false);
-                    }
-
-                    foreach (var item in e.NewItems)
-                    {
-                        MarkItemSelected(item, true);
+                        Add(SelectedItems, added);
+                        UpdateSelection();
                     }
 
-                    if (SelectedItem != SelectedItems[0] && !_syncingSelectedItems)
-                    {
-                        var oldItem = SelectedItem;
-                        var oldIndex = SelectedIndex;
-                        var item = SelectedItems[0];
-                        var index = IndexOf(Items, item);
-                        _selectedIndex = index;
-                        _selectedItem = item;
-                        RaisePropertyChanged(SelectedIndexProperty, oldIndex, index, BindingPriority.LocalValue);
-                        RaisePropertyChanged(SelectedItemProperty, oldItem, item, BindingPriority.LocalValue);
-                    }
-
-                    added = e.NewItems;
-                    removed = e.OldItems;
                     break;
             }
 
@@ -912,34 +909,6 @@ namespace Avalonia.Controls.Primitives
             }
         }
 
-        /// <summary>
-        /// Called when items are added to the <see cref="SelectedItems"/> collection.
-        /// </summary>
-        /// <param name="items">The added items.</param>
-        private void SelectedItemsAdded(IList items)
-        {
-            if (items.Count > 0)
-            {
-                foreach (var item in items)
-                {
-                    MarkItemSelected(item, true);
-                }
-
-                if (SelectedItem == null && !_syncingSelectedItems)
-                {
-                    var index = IndexOf(Items, items[0]);
-
-                    if (index != -1)
-                    {
-                        _selectedItem = items[0];
-                        _selectedIndex = index;
-                        RaisePropertyChanged(SelectedIndexProperty, -1, index, BindingPriority.LocalValue);
-                        RaisePropertyChanged(SelectedItemProperty, null, items[0], BindingPriority.LocalValue);
-                    }
-                }
-            }
-        }
-
         /// <summary>
         /// Subscribes to the <see cref="SelectedItems"/> CollectionChanged event, if any.
         /// </summary>
@@ -970,6 +939,112 @@ namespace Avalonia.Controls.Primitives
             }
         }
 
+        /// <summary>
+        /// Updates the selection due to a change to <see cref="SelectedIndex"/> or
+        /// <see cref="SelectedItem"/>.
+        /// </summary>
+        /// <param name="index">The new selected index.</param>
+        /// <param name="clear">Whether to clear existing selection.</param>
+        private void UpdateSelectedItem(int index, bool clear = true)
+        {
+            var oldIndex = _selectedIndex;
+            var oldItem = _selectedItem;
+
+            if (index == -1 && AlwaysSelected)
+            {
+                index = Math.Min(SelectedIndex, ItemCount - 1);
+            }
+
+            var item = ElementAt(Items, index);
+            var added = -1;
+            HashSet<int> removed = null;
+
+            _selectedIndex = index;
+            _selectedItem = item;
+
+            if (oldIndex != index || _selection.HasMultiple)
+            {
+                if (clear)
+                {
+                    removed = _selection.Clear();
+                }
+
+                if (index != -1)
+                {
+                    if (_selection.Add(index))
+                    {
+                        added = index;
+                    }
+
+                    if (removed?.Contains(index) == true)
+                    {
+                        removed.Remove(index);
+                        added = -1;
+                    }
+                }
+
+                if (removed != null)
+                {
+                    foreach (var i in removed)
+                    {
+                        MarkItemSelected(i, false);
+                    }
+                }
+
+                MarkItemSelected(index, true);
+
+                RaisePropertyChanged(
+                    SelectedIndexProperty,
+                    oldIndex,
+                    index);
+            }
+
+            if (!Equals(item, oldItem))
+            {
+                RaisePropertyChanged(
+                    SelectedItemProperty,
+                    oldItem,
+                    item);
+            }
+
+            if (removed != null && index != -1)
+            {
+                removed.Remove(index);
+            }
+
+            if (added != -1 || removed?.Count > 0)
+            {
+                ResetSelectedItems();
+
+                var e = new SelectionChangedEventArgs(
+                    SelectionChangedEvent,
+                    added != -1 ? new[] { ElementAt(Items, added) } : Array.Empty<object>(),
+                    removed?.Select(x => ElementAt(Items, x)).ToArray() ?? Array.Empty<object>());
+                RaiseEvent(e);
+            }
+        }
+
+        private void UpdateSelectedItems(Action action)
+        {
+            try
+            {
+                _syncingSelectedItems = true;
+                action();
+            }
+            catch (Exception ex)
+            {
+                Logger.Error(
+                    LogArea.Property,
+                    this,
+                    "Error thrown updating SelectedItems: {Error}",
+                    ex);
+            }
+            finally
+            {
+                _syncingSelectedItems = false;
+            }
+        }
+
         private void UpdateFinished()
         {
             if (_updateSelectedIndex != int.MinValue)
@@ -981,5 +1056,104 @@ namespace Avalonia.Controls.Primitives
                 SelectedItems = _updateSelectedItems;
             }
         }
+
+        private class Selection : IEnumerable<int>
+        {
+            private readonly List<int> _list = new List<int>();
+            private HashSet<int> _set = new HashSet<int>();
+
+            public bool HasItems => _set.Count > 0;
+            public bool HasMultiple => _set.Count > 1;
+
+            public bool Add(int index)
+            {
+                if (index == -1)
+                {
+                    throw new ArgumentException("Invalid index", "index");
+                }
+
+                if (_set.Add(index))
+                {
+                    _list.Add(index);
+                    return true;
+                }
+
+                return false;
+            }
+
+            public bool Remove(int index)
+            {
+                if (_set.Remove(index))
+                {
+                    _list.RemoveAll(x => x == index);
+                    return true;
+                }
+
+                return false;
+            }
+
+            public HashSet<int> Clear()
+            {
+                var result = _set;
+                _list.Clear();
+                _set = new HashSet<int>();
+                return result;
+            }
+
+            public void ItemsInserted(int index, int count)
+            {
+                _set = new HashSet<int>();
+
+                for (var i = 0; i < _list.Count; ++i)
+                {
+                    var ix = _list[i];
+
+                    if (ix >= index)
+                    {
+                        var newIndex = ix + count;
+                        _list[i] = newIndex;
+                        _set.Add(newIndex);
+                    }
+                    else
+                    {
+                        _set.Add(ix);
+                    }
+                }
+            }
+
+            public void ItemsRemoved(int index, int count)
+            {
+                var last = (index + count) - 1;
+
+                _set = new HashSet<int>();
+
+                for (var i = 0; i < _list.Count; ++i)
+                {
+                    var ix = _list[i];
+
+                    if (ix >= index && ix <= last)
+                    {
+                        _list.RemoveAt(i--);
+                    }
+                    else if (ix > last)
+                    {
+                        var newIndex = ix - count;
+                        _list[i] = newIndex;
+                        _set.Add(newIndex);
+                    }
+                    else
+                    {
+                        _set.Add(ix);
+                    }
+                }
+            }
+
+            public bool Contains(int index) => _set.Contains(index);
+
+            public int First() => HasItems ? _list[0] : -1;
+
+            public IEnumerator<int> GetEnumerator() => _set.GetEnumerator();
+            IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+        }
     }
 }

+ 31 - 10
src/Avalonia.Controls/RowDefinition.cs

@@ -29,7 +29,7 @@ namespace Avalonia.Controls
         /// <summary>
         /// Initializes a new instance of the <see cref="RowDefinition"/> class.
         /// </summary>
-        public RowDefinition() 
+        public RowDefinition()
         {
         }
 
@@ -38,7 +38,7 @@ namespace Avalonia.Controls
         /// </summary>
         /// <param name="value">The height of the row.</param>
         /// <param name="type">The height unit of the column.</param>
-        public RowDefinition(double value, GridUnitType type) 
+        public RowDefinition(double value, GridUnitType type)
         {
             Height = new GridLength(value, type);
         }
@@ -47,7 +47,7 @@ namespace Avalonia.Controls
         /// Initializes a new instance of the <see cref="RowDefinition"/> class.
         /// </summary>
         /// <param name="height">The height of the column.</param>
-        public RowDefinition(GridLength height) 
+        public RowDefinition(GridLength height)
         {
             Height = height;
         }
@@ -62,8 +62,15 @@ namespace Avalonia.Controls
         /// </summary>
         public double MaxHeight
         {
-            get { return GetValue(MaxHeightProperty); }
-            set { SetValue(MaxHeightProperty, value); }
+            get
+            {
+                return GetValue(MaxHeightProperty);
+            }
+            set
+            {
+                Parent?.InvalidateMeasure();
+                SetValue(MaxHeightProperty, value);
+            }
         }
 
         /// <summary>
@@ -71,8 +78,15 @@ namespace Avalonia.Controls
         /// </summary>
         public double MinHeight
         {
-            get { return GetValue(MinHeightProperty); }
-            set { SetValue(MinHeightProperty, value); }
+            get
+            {
+                return GetValue(MinHeightProperty);
+            }
+            set
+            {
+                Parent?.InvalidateMeasure();
+                SetValue(MinHeightProperty, value);
+            }
         }
 
         /// <summary>
@@ -80,12 +94,19 @@ namespace Avalonia.Controls
         /// </summary>
         public GridLength Height
         {
-            get { return GetValue(HeightProperty); }
-            set { SetValue(HeightProperty, value); }
+            get
+            {
+                return GetValue(HeightProperty);
+            }
+            set
+            {
+                Parent?.InvalidateMeasure();
+                SetValue(HeightProperty, value);
+            }
         }
 
         internal override GridLength UserSizeValueCache => this.Height;
         internal override double UserMinSizeValueCache => this.MinHeight;
         internal override double UserMaxSizeValueCache => this.MaxHeight;
     }
-}
+}

+ 3 - 2
src/Avalonia.Controls/Screens.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Platform;
 using Avalonia.Utilities;
@@ -11,7 +12,7 @@ namespace Avalonia.Controls
         private readonly IScreenImpl _iScreenImpl;
 
         public int ScreenCount => _iScreenImpl.ScreenCount;
-        public IReadOnlyList<Screen> All => _iScreenImpl?.AllScreens;
+        public IReadOnlyList<Screen> All => _iScreenImpl?.AllScreens ?? Array.Empty<Screen>();
         public Screen Primary => All.FirstOrDefault(x => x.Primary);
 
         public Screens(IScreenImpl iScreenImpl)

+ 0 - 36
src/Avalonia.Controls/StartupEventArgs.cs

@@ -1,36 +0,0 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Avalonia.Controls
-{
-    /// <summary>
-    /// Contains the arguments for the <see cref="IApplicationLifecycle.Startup"/> event.
-    /// </summary>
-    public class StartupEventArgs : EventArgs
-    {
-        private string[] _args;
-
-        /// <summary>
-        /// Gets the command line arguments that were passed to the application.
-        /// </summary>
-        public IReadOnlyList<string> Args => _args ?? (_args = GetArgs());
-
-        private static string[] GetArgs()
-        {
-            try
-            {
-                var args = Environment.GetCommandLineArgs();
-
-                return args.Length > 1 ? args.Skip(1).ToArray() : new string[0];
-            }
-            catch (NotSupportedException)
-            {
-                return new string[0];
-            }
-        }
-    }
-}

+ 0 - 20
src/Avalonia.Controls/TopLevel.cs

@@ -51,7 +51,6 @@ namespace Avalonia.Controls
         private readonly IInputManager _inputManager;
         private readonly IAccessKeyHandler _accessKeyHandler;
         private readonly IKeyboardNavigationHandler _keyboardNavigationHandler;
-        private readonly IApplicationLifecycle _applicationLifecycle;
         private readonly IPlatformRenderInterface _renderInterface;
         private Size _clientSize;
         private ILayoutManager _layoutManager;
@@ -96,7 +95,6 @@ namespace Avalonia.Controls
             _accessKeyHandler = TryGetService<IAccessKeyHandler>(dependencyResolver);
             _inputManager = TryGetService<IInputManager>(dependencyResolver);
             _keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver);
-            _applicationLifecycle = TryGetService<IApplicationLifecycle>(dependencyResolver);
             _renderInterface = TryGetService<IPlatformRenderInterface>(dependencyResolver);
 
             Renderer = impl.CreateRenderer(this);
@@ -125,11 +123,6 @@ namespace Avalonia.Controls
                     x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty<Cursor>())
                 .Switch().Subscribe(cursor => PlatformImpl?.SetCursor(cursor?.PlatformCursor));
 
-            if (_applicationLifecycle != null)
-            {
-                _applicationLifecycle.Exit += OnApplicationExiting;
-            }
-
             if (((IStyleHost)this).StylingParent is IResourceProvider applicationResources)
             {
                 WeakSubscriptionManager.Subscribe(
@@ -281,7 +274,6 @@ namespace Avalonia.Controls
             Closed?.Invoke(this, EventArgs.Empty);
             Renderer?.Dispose();
             Renderer = null;
-            _applicationLifecycle.Exit -= OnApplicationExiting;
         }
 
         /// <summary>
@@ -348,18 +340,6 @@ namespace Avalonia.Controls
             return result;
         }
 
-        private void OnApplicationExiting(object sender, EventArgs args)
-        {
-            HandleApplicationExiting();
-        }
-
-        /// <summary>
-        /// Handles the application exiting, either from the last window closing, or a call to <see cref="IApplicationLifecycle.Exit"/>.
-        /// </summary>
-        protected virtual void HandleApplicationExiting()
-        {
-        }
-
         /// <summary>
         /// Handles input from <see cref="ITopLevelImpl.Input"/>.
         /// </summary>

+ 24 - 2
src/Avalonia.Controls/TreeView.cs

@@ -409,7 +409,7 @@ namespace Avalonia.Controls
 
                 if (this.SelectionMode == SelectionMode.Multiple && Match(keymap.SelectAll))
                 {
-                    SelectingItemsControl.SynchronizeItems(SelectedItems, ItemContainerGenerator.Index.Items);
+                    SynchronizeItems(SelectedItems, ItemContainerGenerator.Index.Items);
                     e.Handled = true;
                 }
             }
@@ -521,7 +521,7 @@ namespace Avalonia.Controls
             }
             else if (multi && range)
             {
-                SelectingItemsControl.SynchronizeItems(
+                SynchronizeItems(
                     SelectedItems,
                     GetItemsInRange(selectedContainer as TreeViewItem, container as TreeViewItem));
             }
@@ -778,5 +778,27 @@ namespace Avalonia.Controls
                 container.Classes.Set(":selected", selected);
             }
         }
+
+        /// <summary>
+        /// Makes a list of objects equal another (though doesn't preserve order).
+        /// </summary>
+        /// <param name="items">The items collection.</param>
+        /// <param name="desired">The desired items.</param>
+        private static void SynchronizeItems(IList items, IEnumerable<object> desired)
+        {
+            var list = items.Cast<object>().ToList();
+            var toRemove = list.Except(desired).ToList();
+            var toAdd = desired.Except(list).ToList();
+
+            foreach (var i in toRemove)
+            {
+                items.Remove(i);
+            }
+
+            foreach (var i in toAdd)
+            {
+                items.Add(i);
+            }
+        }
     }
 }

+ 18 - 45
src/Avalonia.Controls/Window.cs

@@ -14,6 +14,7 @@ using System.Collections.Generic;
 using System.Linq;
 using JetBrains.Annotations;
 using System.ComponentModel;
+using Avalonia.Interactivity;
 
 namespace Avalonia.Controls
 {
@@ -97,6 +98,20 @@ namespace Avalonia.Controls
         public static readonly StyledProperty<bool> CanResizeProperty =
             AvaloniaProperty.Register<Window, bool>(nameof(CanResize), true);
 
+        /// <summary>
+        /// Routed event that can be used for global tracking of window destruction
+        /// </summary>
+        public static readonly RoutedEvent WindowClosedEvent =
+            RoutedEvent.Register<Window, RoutedEventArgs>("WindowClosed", RoutingStrategies.Direct);
+        
+        /// <summary>
+        /// Routed event that can be used for global tracking of opening windows
+        /// </summary>
+        public static readonly RoutedEvent WindowOpenedEvent =
+            RoutedEvent.Register<Window, RoutedEventArgs>("WindowOpened", RoutingStrategies.Direct);
+
+
+
         private readonly NameScope _nameScope = new NameScope();
         private object _dialogResult;
         private readonly Size _maxPlatformClientSize;
@@ -140,7 +155,6 @@ namespace Avalonia.Controls
             impl.Closing = HandleClosing;
             impl.WindowStateChanged = HandleWindowStateChanged;
             _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
-            Screens = new Screens(PlatformImpl?.Screen);
         }
 
         /// <inheritdoc/>
@@ -157,8 +171,6 @@ namespace Avalonia.Controls
             remove { _nameScope.Unregistered -= value; }
         }
 
-        public Screens Screens { get; private set; }
-
         /// <summary>
         /// Gets the platform-specific window implementation.
         /// </summary>
@@ -252,26 +264,6 @@ namespace Avalonia.Controls
         /// </summary>
         public event EventHandler<CancelEventArgs> Closing;      
 
-        private static void AddWindow(Window window)
-        {
-            if (Application.Current == null)
-            {
-                return;
-            }
-
-            Application.Current.Windows.Add(window);
-        }
-
-        private static void RemoveWindow(Window window)
-        {
-            if (Application.Current == null)
-            {
-                return;
-            }
-
-            Application.Current.Windows.Remove(window);
-        }
-
         /// <summary>
         /// Closes the window.
         /// </summary>
@@ -280,12 +272,6 @@ namespace Avalonia.Controls
             Close(false);
         }
 
-        protected override void HandleApplicationExiting()
-        {
-            base.HandleApplicationExiting();
-            Close(true);
-        }
-
         /// <summary>
         /// Closes a dialog window with the specified result.
         /// </summary>
@@ -385,7 +371,7 @@ namespace Avalonia.Controls
                 return;
             }
 
-            AddWindow(this);
+            this.RaiseEvent(new RoutedEventArgs(WindowOpenedEvent));
 
             EnsureInitialized();
             IsVisible = true;
@@ -447,7 +433,7 @@ namespace Avalonia.Controls
                 throw new InvalidOperationException("The window is already being shown.");
             }
 
-            AddWindow(this);
+            RaiseEvent(new RoutedEventArgs(WindowOpenedEvent));
 
             EnsureInitialized();
             IsVisible = true;
@@ -560,7 +546,7 @@ namespace Avalonia.Controls
 
         protected override void HandleClosed()
         {
-            RemoveWindow(this);
+            RaiseEvent(new RoutedEventArgs(WindowClosedEvent));
 
             base.HandleClosed();
         }
@@ -588,16 +574,3 @@ namespace Avalonia.Controls
         protected virtual void OnClosing(CancelEventArgs e) => Closing?.Invoke(this, e);
     }
 }
-
-namespace Avalonia
-{
-    public static class WindowApplicationExtensions
-    {
-        public static void RunWithMainWindow<TWindow>(this Application app) where TWindow : Avalonia.Controls.Window, new()
-        {
-            var window = new TWindow();
-            window.Show();
-            app.Run(window);
-        }
-    }
-}

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

@@ -63,6 +63,7 @@ namespace Avalonia.Controls
 
         public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver) : base(impl, dependencyResolver)
         {
+            Screens = new Screens(PlatformImpl?.Screen);
             impl.Activated = HandleActivated;
             impl.Deactivated = HandleDeactivated;
             impl.PositionChanged = HandlePositionChanged;
@@ -108,6 +109,8 @@ namespace Avalonia.Controls
                     impl.Position = value;
             }
         }
+        
+        public Screens Screens { get; private set; }
 
         /// <summary>
         /// Whether an auto-size operation is in progress.

+ 0 - 134
src/Avalonia.Controls/WindowCollection.cs

@@ -1,134 +0,0 @@
-// 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.Collections;
-using System.Collections.Generic;
-
-using Avalonia.Controls;
-
-namespace Avalonia
-{
-    public class WindowCollection : IReadOnlyList<Window>
-    {
-        private readonly Application _application;
-        private readonly List<Window> _windows = new List<Window>();
-
-        public WindowCollection(Application application)
-        {
-            _application = application;
-        }
-
-        /// <inheritdoc />
-        /// <summary>
-        /// Gets the number of elements in the collection.
-        /// </summary>
-        public int Count => _windows.Count;
-
-        /// <inheritdoc />
-        /// <summary>
-        /// Gets the <see cref="T:Avalonia.Controls.Window" /> at the specified index.
-        /// </summary>
-        /// <value>
-        /// The <see cref="T:Avalonia.Controls.Window" />.
-        /// </value>
-        /// <param name="index">The index.</param>
-        /// <returns></returns>
-        public Window this[int index] => _windows[index];
-
-        /// <inheritdoc />
-        /// <summary>
-        /// Returns an enumerator that iterates through the collection.
-        /// </summary>
-        /// <returns>
-        /// An enumerator that can be used to iterate through the collection.
-        /// </returns>
-        public IEnumerator<Window> GetEnumerator()
-        {
-            return _windows.GetEnumerator();
-        }
-
-        /// <inheritdoc />
-        /// <summary>
-        /// Returns an enumerator that iterates through a collection.
-        /// </summary>
-        /// <returns>
-        /// An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
-        /// </returns>
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return GetEnumerator();
-        }
-
-        /// <summary>
-        /// Adds the specified window.
-        /// </summary>
-        /// <param name="window">The window.</param>
-        internal void Add(Window window)
-        {
-            if (window == null)
-            {
-                return;
-            }
-
-            _windows.Add(window);
-        }
-
-        /// <summary>
-        /// Removes the specified window.
-        /// </summary>
-        /// <param name="window">The window.</param>
-        internal void Remove(Window window)
-        {
-            if (window == null)
-            {
-                return;
-            }
-
-            _windows.Remove(window);
-
-            OnRemoveWindow(window);
-        }
-
-        /// <summary>
-        /// Closes all windows and removes them from the underlying collection.
-        /// </summary>
-        internal void Clear()
-        {
-            while (_windows.Count > 0)
-            {
-                _windows[0].Close(true);
-            }
-        }
-
-        private void OnRemoveWindow(Window window)
-        {
-            if (window == null)
-            {
-                return;
-            }
-
-            if (_application.IsShuttingDown)
-            {
-                return;
-            }
-
-            switch (_application.ShutdownMode)
-            {
-                case ShutdownMode.OnLastWindowClose:
-                    if (Count == 0)
-                    {
-                        _application.Shutdown();
-                    }
-
-                    break;
-                case ShutdownMode.OnMainWindowClose:
-                    if (window == _application.MainWindow)
-                    {
-                        _application.Shutdown();
-                    }
-
-                    break;                   
-            }
-        }
-    }
-}

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

@@ -1,9 +1,7 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
+// This source file is adapted from the Windows Presentation Foundation project. 
+// (https://github.com/dotnet/wpf/) 
+// 
+// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
 
 using Avalonia.Input;
 using Avalonia.Utilities;

+ 2 - 10
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Net;
 using System.Reflection;
+using System.Threading;
 using System.Xml;
 using Avalonia.Controls;
 using Avalonia.Input;
@@ -122,15 +123,6 @@ namespace Avalonia.DesignerSupport.Remote
         }
 
         private const string BuilderMethodName = "BuildAvaloniaApp";
-
-        class NeverClose : ICloseable
-        {
-            public event EventHandler Closed
-            {
-                add {}
-                remove {}
-            }
-        }
         
         public static void Main(string[] cmdline)
         {
@@ -155,7 +147,7 @@ namespace Avalonia.DesignerSupport.Remote
             transport.OnException += (t, e) => Die(e.ToString());
             Log("Sending StartDesignerSessionMessage");
             transport.Send(new StartDesignerSessionMessage {SessionId = args.SessionId});
-            app.Run(new NeverClose());
+            Dispatcher.UIThread.MainLoop(CancellationToken.None);
         }
 
 

+ 9 - 1
src/Avalonia.Styling/StyledElement.cs

@@ -392,6 +392,7 @@ namespace Avalonia
             if (_initCount == 0 && !IsInitialized)
             {
                 IsInitialized = true;
+                OnInitialized();
                 Initialized?.Invoke(this, EventArgs.Empty);
             }
         }
@@ -608,7 +609,14 @@ namespace Avalonia
         protected virtual void OnDataContextEndUpdate()
         {
         }
-        
+
+        /// <summary>
+        /// Called when the control finishes initialization.
+        /// </summary>
+        protected virtual void OnInitialized()
+        {
+        }
+
         private static void DataContextNotifying(IAvaloniaObject o, bool updateStarted)
         {
             if (o is StyledElement element)

+ 3 - 7
src/Avalonia.X11/X11KeyTransform.cs

@@ -221,12 +221,8 @@ namespace Avalonia.X11
             //{ X11Key.?, Key.DeadCharProcessed }
         };
 
-        public static Key ConvertKey(IntPtr key)
-        {
-            var ikey = key.ToInt32();
-            Key result;
-            return KeyDic.TryGetValue((X11Key)ikey, out result) ? result : Key.None;
-        }
-}
+        public static Key ConvertKey(X11Key key) 
+            => KeyDic.TryGetValue(key, out var result) ? result : Key.None;
+    }
     
 }

+ 13 - 2
src/Avalonia.X11/X11Window.cs

@@ -419,10 +419,21 @@ namespace Avalonia.X11
                     return;
                 var buffer = stackalloc byte[40];
 
-                var latinKeysym = XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, 0);
+                var index = ev.KeyEvent.state.HasFlag(XModifierMask.ShiftMask);
+                
+                // We need the latin key, since it's mainly used for hotkeys, we use a different API for text anyway
+                var key = (X11Key)XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, index ? 1 : 0).ToInt32();
+                
+                // Manually switch the Shift index for the keypad,
+                // there should be a proper way to do this
+                if (ev.KeyEvent.state.HasFlag(XModifierMask.Mod2Mask)
+                    && key > X11Key.Num_Lock && key <= X11Key.KP_9)
+                    key = (X11Key)XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, index ? 0 : 1).ToInt32();
+                
+                
                 ScheduleInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(),
                     ev.type == XEventName.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
-                    X11KeyTransform.ConvertKey(latinKeysym), TranslateModifiers(ev.KeyEvent.state)), ref ev);
+                    X11KeyTransform.ConvertKey(key), TranslateModifiers(ev.KeyEvent.state)), ref ev);
 
                 if (ev.type == XEventName.KeyPress)
                 {

+ 0 - 11
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj

@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <TargetFramework>netstandard2.0</TargetFramework>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <DefineConstants>$(DefineConstants);GTK3_PINVOKE</DefineConstants>
-    <PackageId>Avalonia.Gtk3</PackageId>
-  </PropertyGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
-  </ItemGroup>
-</Project>

+ 0 - 51
src/Gtk/Avalonia.Gtk3/ClipboardImpl.cs

@@ -1,51 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Input.Platform;
-using Avalonia.Platform.Interop;
-
-namespace Avalonia.Gtk3
-{
-    class ClipboardImpl : IClipboard
-    {
-
-        IntPtr GetClipboard() => Native.GtkClipboardGetForDisplay(Native.GdkGetDefaultDisplay(), IntPtr.Zero);
-
-        static void OnText(IntPtr clipboard, IntPtr utf8string, IntPtr userdata)
-        {
-            var handle = GCHandle.FromIntPtr(userdata);
-
-            ((TaskCompletionSource<string>) handle.Target)
-                .TrySetResult(Utf8Buffer.StringFromPtr(utf8string));
-            handle.Free();
-        }
-
-        private static readonly Native.D.GtkClipboardTextReceivedFunc OnTextDelegate = OnText;
-
-        static ClipboardImpl()
-        {
-            GCHandle.Alloc(OnTextDelegate);
-        }
-
-        public Task<string> GetTextAsync()
-        {
-            var tcs = new TaskCompletionSource<string>();
-            Native.GtkClipboardRequestText(GetClipboard(), OnTextDelegate, GCHandle.ToIntPtr(GCHandle.Alloc(tcs)));
-            return tcs.Task;
-        }
-
-        public Task SetTextAsync(string text)
-        {
-            using (var buf = new Utf8Buffer(text))
-                Native.GtkClipboardSetText(GetClipboard(), buf, buf.ByteLen);
-            return Task.FromResult(0);
-        }
-
-        public Task ClearAsync()
-        {
-            Native.GtkClipboardRequestClear(GetClipboard());
-            return Task.FromResult(0);
-        }
-    }
-}

+ 0 - 84
src/Gtk/Avalonia.Gtk3/CursorFactory.cs

@@ -1,84 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Input;
-using Avalonia.Platform;
-using Avalonia.Platform.Interop;
-using CursorType = Avalonia.Gtk3.GdkCursorType;
-namespace Avalonia.Gtk3
-{
-    class CursorFactory :  IStandardCursorFactory
-    {
-        private static readonly Dictionary<StandardCursorType, object> CursorTypeMapping = new Dictionary
-    <StandardCursorType, object>
-        {
-            {StandardCursorType.None, CursorType.Blank},
-            {StandardCursorType.AppStarting, CursorType.Watch},
-            {StandardCursorType.Arrow, CursorType.LeftPtr},
-            {StandardCursorType.Cross, CursorType.Cross},
-            {StandardCursorType.Hand, CursorType.Hand1},
-            {StandardCursorType.Ibeam, CursorType.Xterm},
-            {StandardCursorType.No, "gtk-cancel"},
-            {StandardCursorType.SizeAll, CursorType.Sizing},
-            //{ StandardCursorType.SizeNorthEastSouthWest, 32643 },
-            {StandardCursorType.SizeNorthSouth, CursorType.SbVDoubleArrow},
-            //{ StandardCursorType.SizeNorthWestSouthEast, 32642 },
-            {StandardCursorType.SizeWestEast, CursorType.SbHDoubleArrow},
-            {StandardCursorType.UpArrow, CursorType.BasedArrowUp},
-            {StandardCursorType.Wait, CursorType.Watch},
-            {StandardCursorType.Help, "gtk-help"},
-            {StandardCursorType.TopSide, CursorType.TopSide},
-            {StandardCursorType.BottomSize, CursorType.BottomSide},
-            {StandardCursorType.LeftSide, CursorType.LeftSide},
-            {StandardCursorType.RightSide, CursorType.RightSide},
-            {StandardCursorType.TopLeftCorner, CursorType.TopLeftCorner},
-            {StandardCursorType.TopRightCorner, CursorType.TopRightCorner},
-            {StandardCursorType.BottomLeftCorner, CursorType.BottomLeftCorner},
-            {StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner},
-            {StandardCursorType.DragCopy, CursorType.CenterPtr},
-            {StandardCursorType.DragMove, CursorType.Fleur},
-            {StandardCursorType.DragLink, CursorType.Cross},
-        };
-
-        private static readonly Dictionary<StandardCursorType, IPlatformHandle> Cache =
-            new Dictionary<StandardCursorType, IPlatformHandle>();
-
-        private IntPtr GetCursor(object desc)
-        {
-            IntPtr rv;
-            var name = desc as string;
-            if (name != null)
-            {
-                var theme = Native.GtkIconThemeGetDefault();
-                IntPtr icon, error;
-                using (var u = new Utf8Buffer(name))
-                    icon = Native.GtkIconThemeLoadIcon(theme, u, 32, 0, out error);
-                rv = icon == IntPtr.Zero
-                    ? Native.GdkCursorNew(GdkCursorType.XCursor)
-                    : Native.GdkCursorNewFromPixbuf(Native.GdkGetDefaultDisplay(), icon, 0, 0);
-            }
-            else
-            {
-                rv = Native.GdkCursorNew((CursorType)desc);
-            }
-
-            
-            return rv;
-        }
-
-        public IPlatformHandle GetCursor(StandardCursorType cursorType)
-        {
-            IPlatformHandle rv;
-            if (!Cache.TryGetValue(cursorType, out rv))
-            {
-                Cache[cursorType] =
-                    rv =
-                        new PlatformHandle(
-                            GetCursor(CursorTypeMapping[cursorType]),
-                            "GTKCURSOR");
-            }
-
-            return rv;
-        }
-    }
-}

+ 0 - 62
src/Gtk/Avalonia.Gtk3/FramebufferManager.cs

@@ -1,62 +0,0 @@
-using System;
-using Avalonia.Controls.Platform.Surfaces;
-using Avalonia.Platform;
-using Avalonia.Threading;
-
-namespace Avalonia.Gtk3
-{
-    class FramebufferManager : IFramebufferPlatformSurface, IDisposable
-    {
-        private readonly WindowBaseImpl _window;
-        public FramebufferManager(WindowBaseImpl window)
-        {
-            _window = window;
-        }
-
-        public void Dispose()
-        {
-            //
-        }
-
-        public ILockedFramebuffer Lock()
-        {
-            // This method may be called from non-UI thread, don't touch anything that calls back to GTK/GDK
-            var s = _window.ClientSize;
-            var width = Math.Max(1, (int) s.Width);
-            var height = Math.Max(1, (int) s.Height);
-            
-            
-            if (!Dispatcher.UIThread.CheckAccess() && Gtk3Platform.DisplayClassName.ToLower().Contains("x11"))
-            {
-                var x11 = LockX11Framebuffer(width, height);
-                if (x11 != null)
-                    return x11;
-            }
-            
-
-            return new ImageSurfaceFramebuffer(_window, width, height, _window.LastKnownScaleFactor);
-        }
-
-        private static int X11ErrorHandler(IntPtr d, ref X11.XErrorEvent e)
-        {
-            return 0;
-        }
-
-        private static X11.XErrorHandler X11ErrorHandlerDelegate = X11ErrorHandler;
-        
-        private static IntPtr X11Display;
-        private ILockedFramebuffer LockX11Framebuffer(int width, int height)
-        {
-            if (!_window.GdkWindowHandle.HasValue)
-                return null;
-            if (X11Display == IntPtr.Zero)
-            {
-                X11Display = X11.XOpenDisplay(IntPtr.Zero);
-                if (X11Display == IntPtr.Zero)
-                    return null;
-                X11.XSetErrorHandler(X11ErrorHandlerDelegate);
-            }
-            return new X11Framebuffer(X11Display, _window.GdkWindowHandle.Value, width, height, _window.LastKnownScaleFactor);
-        }
-    }
-}

+ 0 - 86
src/Gtk/Avalonia.Gtk3/GdkCursor.cs

@@ -1,86 +0,0 @@
-namespace Avalonia.Gtk3
-{
-    enum GdkCursorType
-    {
-        Blank = -2,
-        CursorIsPixmap = -1,
-        XCursor = 0,
-        Arrow = 2,
-        BasedArrowDown = 4,
-        BasedArrowUp = 6,
-        Boat = 8,
-        Bogosity = 10,
-        BottomLeftCorner = 12,
-        BottomRightCorner = 14,
-        BottomSide = 16,
-        BottomTee = 18,
-        BoxSpiral = 20,
-        CenterPtr = 22,
-        Circle = 24,
-        Clock = 26,
-        CoffeeMug = 28,
-        Cross = 30,
-        CrossReverse = 32,
-        Crosshair = 34,
-        DiamondCross = 36,
-        Dot = 38,
-        Dotbox = 40,
-        DoubleArrow = 42,
-        DraftLarge = 44,
-        DraftSmall = 46,
-        DrapedBox = 48,
-        Exchange = 50,
-        Fleur = 52,
-        Gobbler = 54,
-        Gumby = 56,
-        Hand1 = 58,
-        Hand2 = 60,
-        Heart = 62,
-        Icon = 64,
-        IronCross = 66,
-        LeftPtr = 68,
-        LeftSide = 70,
-        LeftTee = 72,
-        Leftbutton = 74,
-        LlAngle = 76,
-        LrAngle = 78,
-        Man = 80,
-        Middlebutton = 82,
-        Mouse = 84,
-        Pencil = 86,
-        Pirate = 88,
-        Plus = 90,
-        QuestionArrow = 92,
-        RightPtr = 94,
-        RightSide = 96,
-        RightTee = 98,
-        Rightbutton = 100,
-        RtlLogo = 102,
-        Sailboat = 104,
-        SbDownArrow = 106,
-        SbHDoubleArrow = 108,
-        SbLeftArrow = 110,
-        SbRightArrow = 112,
-        SbUpArrow = 114,
-        SbVDoubleArrow = 116,
-        Shuttle = 118,
-        Sizing = 120,
-        Spider = 122,
-        Spraycan = 124,
-        Star = 126,
-        Target = 128,
-        Tcross = 130,
-        TopLeftArrow = 132,
-        TopLeftCorner = 134,
-        TopRightCorner = 136,
-        TopSide = 138,
-        TopTee = 140,
-        Trek = 142,
-        UlAngle = 144,
-        Umbrella = 146,
-        UrAngle = 148,
-        Watch = 150,
-        Xterm = 152,
-        LastCursor = 153,
-    }
-}

+ 0 - 1341
src/Gtk/Avalonia.Gtk3/GdkKey.cs

@@ -1,1341 +0,0 @@
-namespace Avalonia.Gtk3
-{
-    enum GdkKey
-    {
-        space = 32,
-        exclam = 33,
-        quotedbl = 34,
-        numbersign = 35,
-        dollar = 36,
-        percent = 37,
-        ampersand = 38,
-        apostrophe = 39,
-        quoteright = 39,
-        parenleft = 40,
-        parenright = 41,
-        asterisk = 42,
-        plus = 43,
-        comma = 44,
-        minus = 45,
-        period = 46,
-        slash = 47,
-        Key_0 = 48,
-        Key_1 = 49,
-        Key_2 = 50,
-        Key_3 = 51,
-        Key_4 = 52,
-        Key_5 = 53,
-        Key_6 = 54,
-        Key_7 = 55,
-        Key_8 = 56,
-        Key_9 = 57,
-        colon = 58,
-        semicolon = 59,
-        less = 60,
-        equal = 61,
-        greater = 62,
-        question = 63,
-        at = 64,
-        A = 65,
-        B = 66,
-        C = 67,
-        D = 68,
-        E = 69,
-        F = 70,
-        G = 71,
-        H = 72,
-        I = 73,
-        J = 74,
-        K = 75,
-        L = 76,
-        M = 77,
-        N = 78,
-        O = 79,
-        P = 80,
-        Q = 81,
-        R = 82,
-        S = 83,
-        T = 84,
-        U = 85,
-        V = 86,
-        W = 87,
-        X = 88,
-        Y = 89,
-        Z = 90,
-        bracketleft = 91,
-        backslash = 92,
-        bracketright = 93,
-        asciicircum = 94,
-        underscore = 95,
-        grave = 96,
-        quoteleft = 96,
-        a = 97,
-        b = 98,
-        c = 99,
-        d = 100,
-        e = 101,
-        f = 102,
-        g = 103,
-        h = 104,
-        i = 105,
-        j = 106,
-        k = 107,
-        l = 108,
-        m = 109,
-        n = 110,
-        o = 111,
-        p = 112,
-        q = 113,
-        r = 114,
-        s = 115,
-        t = 116,
-        u = 117,
-        v = 118,
-        w = 119,
-        x = 120,
-        y = 121,
-        z = 122,
-        braceleft = 123,
-        bar = 124,
-        braceright = 125,
-        asciitilde = 126,
-        nobreakspace = 160,
-        exclamdown = 161,
-        cent = 162,
-        sterling = 163,
-        currency = 164,
-        yen = 165,
-        brokenbar = 166,
-        section = 167,
-        diaeresis = 168,
-        copyright = 169,
-        ordfeminine = 170,
-        guillemotleft = 171,
-        notsign = 172,
-        hyphen = 173,
-        registered = 174,
-        macron = 175,
-        degree = 176,
-        plusminus = 177,
-        twosuperior = 178,
-        threesuperior = 179,
-        acute = 180,
-        mu = 181,
-        paragraph = 182,
-        periodcentered = 183,
-        cedilla = 184,
-        onesuperior = 185,
-        masculine = 186,
-        guillemotright = 187,
-        onequarter = 188,
-        onehalf = 189,
-        threequarters = 190,
-        questiondown = 191,
-        Agrave = 192,
-        Aacute = 193,
-        Acircumflex = 194,
-        Atilde = 195,
-        Adiaeresis = 196,
-        Aring = 197,
-        AE = 198,
-        Ccedilla = 199,
-        Egrave = 200,
-        Eacute = 201,
-        Ecircumflex = 202,
-        Ediaeresis = 203,
-        Igrave = 204,
-        Iacute = 205,
-        Icircumflex = 206,
-        Idiaeresis = 207,
-        ETH = 208,
-        Eth = 208,
-        Ntilde = 209,
-        Ograve = 210,
-        Oacute = 211,
-        Ocircumflex = 212,
-        Otilde = 213,
-        Odiaeresis = 214,
-        multiply = 215,
-        Ooblique = 216,
-        Ugrave = 217,
-        Uacute = 218,
-        Ucircumflex = 219,
-        Udiaeresis = 220,
-        Yacute = 221,
-        THORN = 222,
-        Thorn = 222,
-        ssharp = 223,
-        agrave = 224,
-        aacute = 225,
-        acircumflex = 226,
-        atilde = 227,
-        adiaeresis = 228,
-        aring = 229,
-        ae = 230,
-        ccedilla = 231,
-        egrave = 232,
-        eacute = 233,
-        ecircumflex = 234,
-        ediaeresis = 235,
-        igrave = 236,
-        iacute = 237,
-        icircumflex = 238,
-        idiaeresis = 239,
-        eth = 240,
-        ntilde = 241,
-        ograve = 242,
-        oacute = 243,
-        ocircumflex = 244,
-        otilde = 245,
-        odiaeresis = 246,
-        division = 247,
-        oslash = 248,
-        ugrave = 249,
-        uacute = 250,
-        ucircumflex = 251,
-        udiaeresis = 252,
-        yacute = 253,
-        thorn = 254,
-        ydiaeresis = 255,
-        Aogonek = 417,
-        breve = 418,
-        Lstroke = 419,
-        Lcaron = 421,
-        Sacute = 422,
-        Scaron = 425,
-        Scedilla = 426,
-        Tcaron = 427,
-        Zacute = 428,
-        Zcaron = 430,
-        Zabovedot = 431,
-        aogonek = 433,
-        ogonek = 434,
-        lstroke = 435,
-        lcaron = 437,
-        sacute = 438,
-        caron = 439,
-        scaron = 441,
-        scedilla = 442,
-        tcaron = 443,
-        zacute = 444,
-        doubleacute = 445,
-        zcaron = 446,
-        zabovedot = 447,
-        Racute = 448,
-        Abreve = 451,
-        Lacute = 453,
-        Cacute = 454,
-        Ccaron = 456,
-        Eogonek = 458,
-        Ecaron = 460,
-        Dcaron = 463,
-        Dstroke = 464,
-        Nacute = 465,
-        Ncaron = 466,
-        Odoubleacute = 469,
-        Rcaron = 472,
-        Uring = 473,
-        Udoubleacute = 475,
-        Tcedilla = 478,
-        racute = 480,
-        abreve = 483,
-        lacute = 485,
-        cacute = 486,
-        ccaron = 488,
-        eogonek = 490,
-        ecaron = 492,
-        dcaron = 495,
-        dstroke = 496,
-        nacute = 497,
-        ncaron = 498,
-        odoubleacute = 501,
-        rcaron = 504,
-        uring = 505,
-        udoubleacute = 507,
-        tcedilla = 510,
-        abovedot = 511,
-        Hstroke = 673,
-        Hcircumflex = 678,
-        Iabovedot = 681,
-        Gbreve = 683,
-        Jcircumflex = 684,
-        hstroke = 689,
-        hcircumflex = 694,
-        idotless = 697,
-        gbreve = 699,
-        jcircumflex = 700,
-        Cabovedot = 709,
-        Ccircumflex = 710,
-        Gabovedot = 725,
-        Gcircumflex = 728,
-        Ubreve = 733,
-        Scircumflex = 734,
-        cabovedot = 741,
-        ccircumflex = 742,
-        gabovedot = 757,
-        gcircumflex = 760,
-        ubreve = 765,
-        scircumflex = 766,
-        kappa = 930,
-        kra = 930,
-        Rcedilla = 931,
-        Itilde = 933,
-        Lcedilla = 934,
-        Emacron = 938,
-        Gcedilla = 939,
-        Tslash = 940,
-        rcedilla = 947,
-        itilde = 949,
-        lcedilla = 950,
-        emacron = 954,
-        gcedilla = 955,
-        tslash = 956,
-        ENG = 957,
-        eng = 959,
-        Amacron = 960,
-        Iogonek = 967,
-        Eabovedot = 972,
-        Imacron = 975,
-        Ncedilla = 977,
-        Omacron = 978,
-        Kcedilla = 979,
-        Uogonek = 985,
-        Utilde = 989,
-        Umacron = 990,
-        amacron = 992,
-        iogonek = 999,
-        eabovedot = 1004,
-        imacron = 1007,
-        ncedilla = 1009,
-        omacron = 1010,
-        kcedilla = 1011,
-        uogonek = 1017,
-        utilde = 1021,
-        umacron = 1022,
-        overline = 1150,
-        kana_fullstop = 1185,
-        kana_openingbracket = 1186,
-        kana_closingbracket = 1187,
-        kana_comma = 1188,
-        kana_conjunctive = 1189,
-        kana_middledot = 1189,
-        kana_WO = 1190,
-        kana_a = 1191,
-        kana_i = 1192,
-        kana_u = 1193,
-        kana_e = 1194,
-        kana_o = 1195,
-        kana_ya = 1196,
-        kana_yu = 1197,
-        kana_yo = 1198,
-        kana_tsu = 1199,
-        kana_tu = 1199,
-        prolongedsound = 1200,
-        kana_A = 1201,
-        kana_I = 1202,
-        kana_U = 1203,
-        kana_E = 1204,
-        kana_O = 1205,
-        kana_KA = 1206,
-        kana_KI = 1207,
-        kana_KU = 1208,
-        kana_KE = 1209,
-        kana_KO = 1210,
-        kana_SA = 1211,
-        kana_SHI = 1212,
-        kana_SU = 1213,
-        kana_SE = 1214,
-        kana_SO = 1215,
-        kana_TA = 1216,
-        kana_CHI = 1217,
-        kana_TI = 1217,
-        kana_TSU = 1218,
-        kana_TU = 1218,
-        kana_TE = 1219,
-        kana_TO = 1220,
-        kana_NA = 1221,
-        kana_NI = 1222,
-        kana_NU = 1223,
-        kana_NE = 1224,
-        kana_NO = 1225,
-        kana_HA = 1226,
-        kana_HI = 1227,
-        kana_FU = 1228,
-        kana_HU = 1228,
-        kana_HE = 1229,
-        kana_HO = 1230,
-        kana_MA = 1231,
-        kana_MI = 1232,
-        kana_MU = 1233,
-        kana_ME = 1234,
-        kana_MO = 1235,
-        kana_YA = 1236,
-        kana_YU = 1237,
-        kana_YO = 1238,
-        kana_RA = 1239,
-        kana_RI = 1240,
-        kana_RU = 1241,
-        kana_RE = 1242,
-        kana_RO = 1243,
-        kana_WA = 1244,
-        kana_N = 1245,
-        voicedsound = 1246,
-        semivoicedsound = 1247,
-        Arabic_comma = 1452,
-        Arabic_semicolon = 1467,
-        Arabic_question_mark = 1471,
-        Arabic_hamza = 1473,
-        Arabic_maddaonalef = 1474,
-        Arabic_hamzaonalef = 1475,
-        Arabic_hamzaonwaw = 1476,
-        Arabic_hamzaunderalef = 1477,
-        Arabic_hamzaonyeh = 1478,
-        Arabic_alef = 1479,
-        Arabic_beh = 1480,
-        Arabic_tehmarbuta = 1481,
-        Arabic_teh = 1482,
-        Arabic_theh = 1483,
-        Arabic_jeem = 1484,
-        Arabic_hah = 1485,
-        Arabic_khah = 1486,
-        Arabic_dal = 1487,
-        Arabic_thal = 1488,
-        Arabic_ra = 1489,
-        Arabic_zain = 1490,
-        Arabic_seen = 1491,
-        Arabic_sheen = 1492,
-        Arabic_sad = 1493,
-        Arabic_dad = 1494,
-        Arabic_tah = 1495,
-        Arabic_zah = 1496,
-        Arabic_ain = 1497,
-        Arabic_ghain = 1498,
-        Arabic_tatweel = 1504,
-        Arabic_feh = 1505,
-        Arabic_qaf = 1506,
-        Arabic_kaf = 1507,
-        Arabic_lam = 1508,
-        Arabic_meem = 1509,
-        Arabic_noon = 1510,
-        Arabic_ha = 1511,
-        Arabic_heh = 1511,
-        Arabic_waw = 1512,
-        Arabic_alefmaksura = 1513,
-        Arabic_yeh = 1514,
-        Arabic_fathatan = 1515,
-        Arabic_dammatan = 1516,
-        Arabic_kasratan = 1517,
-        Arabic_fatha = 1518,
-        Arabic_damma = 1519,
-        Arabic_kasra = 1520,
-        Arabic_shadda = 1521,
-        Arabic_sukun = 1522,
-        Serbian_dje = 1697,
-        Macedonia_gje = 1698,
-        Cyrillic_io = 1699,
-        Ukrainian_ie = 1700,
-        Ukranian_je = 1700,
-        Macedonia_dse = 1701,
-        Ukrainian_i = 1702,
-        Ukranian_i = 1702,
-        Ukrainian_yi = 1703,
-        Ukranian_yi = 1703,
-        Cyrillic_je = 1704,
-        Serbian_je = 1704,
-        Cyrillic_lje = 1705,
-        Serbian_lje = 1705,
-        Cyrillic_nje = 1706,
-        Serbian_nje = 1706,
-        Serbian_tshe = 1707,
-        Macedonia_kje = 1708,
-        Byelorussian_shortu = 1710,
-        Cyrillic_dzhe = 1711,
-        Serbian_dze = 1711,
-        numerosign = 1712,
-        Serbian_DJE = 1713,
-        Macedonia_GJE = 1714,
-        Cyrillic_IO = 1715,
-        Ukrainian_IE = 1716,
-        Ukranian_JE = 1716,
-        Macedonia_DSE = 1717,
-        Ukrainian_I = 1718,
-        Ukranian_I = 1718,
-        Ukrainian_YI = 1719,
-        Ukranian_YI = 1719,
-        Cyrillic_JE = 1720,
-        Serbian_JE = 1720,
-        Cyrillic_LJE = 1721,
-        Serbian_LJE = 1721,
-        Cyrillic_NJE = 1722,
-        Serbian_NJE = 1722,
-        Serbian_TSHE = 1723,
-        Macedonia_KJE = 1724,
-        Byelorussian_SHORTU = 1726,
-        Cyrillic_DZHE = 1727,
-        Serbian_DZE = 1727,
-        Cyrillic_yu = 1728,
-        Cyrillic_a = 1729,
-        Cyrillic_be = 1730,
-        Cyrillic_tse = 1731,
-        Cyrillic_de = 1732,
-        Cyrillic_ie = 1733,
-        Cyrillic_ef = 1734,
-        Cyrillic_ghe = 1735,
-        Cyrillic_ha = 1736,
-        Cyrillic_i = 1737,
-        Cyrillic_shorti = 1738,
-        Cyrillic_ka = 1739,
-        Cyrillic_el = 1740,
-        Cyrillic_em = 1741,
-        Cyrillic_en = 1742,
-        Cyrillic_o = 1743,
-        Cyrillic_pe = 1744,
-        Cyrillic_ya = 1745,
-        Cyrillic_er = 1746,
-        Cyrillic_es = 1747,
-        Cyrillic_te = 1748,
-        Cyrillic_u = 1749,
-        Cyrillic_zhe = 1750,
-        Cyrillic_ve = 1751,
-        Cyrillic_softsign = 1752,
-        Cyrillic_yeru = 1753,
-        Cyrillic_ze = 1754,
-        Cyrillic_sha = 1755,
-        Cyrillic_e = 1756,
-        Cyrillic_shcha = 1757,
-        Cyrillic_che = 1758,
-        Cyrillic_hardsign = 1759,
-        Cyrillic_YU = 1760,
-        Cyrillic_A = 1761,
-        Cyrillic_BE = 1762,
-        Cyrillic_TSE = 1763,
-        Cyrillic_DE = 1764,
-        Cyrillic_IE = 1765,
-        Cyrillic_EF = 1766,
-        Cyrillic_GHE = 1767,
-        Cyrillic_HA = 1768,
-        Cyrillic_I = 1769,
-        Cyrillic_SHORTI = 1770,
-        Cyrillic_KA = 1771,
-        Cyrillic_EL = 1772,
-        Cyrillic_EM = 1773,
-        Cyrillic_EN = 1774,
-        Cyrillic_O = 1775,
-        Cyrillic_PE = 1776,
-        Cyrillic_YA = 1777,
-        Cyrillic_ER = 1778,
-        Cyrillic_ES = 1779,
-        Cyrillic_TE = 1780,
-        Cyrillic_U = 1781,
-        Cyrillic_ZHE = 1782,
-        Cyrillic_VE = 1783,
-        Cyrillic_SOFTSIGN = 1784,
-        Cyrillic_YERU = 1785,
-        Cyrillic_ZE = 1786,
-        Cyrillic_SHA = 1787,
-        Cyrillic_E = 1788,
-        Cyrillic_SHCHA = 1789,
-        Cyrillic_CHE = 1790,
-        Cyrillic_HARDSIGN = 1791,
-        Greek_ALPHAaccent = 1953,
-        Greek_EPSILONaccent = 1954,
-        Greek_ETAaccent = 1955,
-        Greek_IOTAaccent = 1956,
-        Greek_IOTAdiaeresis = 1957,
-        Greek_OMICRONaccent = 1959,
-        Greek_UPSILONaccent = 1960,
-        Greek_UPSILONdieresis = 1961,
-        Greek_OMEGAaccent = 1963,
-        Greek_accentdieresis = 1966,
-        Greek_horizbar = 1967,
-        Greek_alphaaccent = 1969,
-        Greek_epsilonaccent = 1970,
-        Greek_etaaccent = 1971,
-        Greek_iotaaccent = 1972,
-        Greek_iotadieresis = 1973,
-        Greek_iotaaccentdieresis = 1974,
-        Greek_omicronaccent = 1975,
-        Greek_upsilonaccent = 1976,
-        Greek_upsilondieresis = 1977,
-        Greek_upsilonaccentdieresis = 1978,
-        Greek_omegaaccent = 1979,
-        Greek_ALPHA = 1985,
-        Greek_BETA = 1986,
-        Greek_GAMMA = 1987,
-        Greek_DELTA = 1988,
-        Greek_EPSILON = 1989,
-        Greek_ZETA = 1990,
-        Greek_ETA = 1991,
-        Greek_THETA = 1992,
-        Greek_IOTA = 1993,
-        Greek_KAPPA = 1994,
-        Greek_LAMBDA = 1995,
-        Greek_LAMDA = 1995,
-        Greek_MU = 1996,
-        Greek_NU = 1997,
-        Greek_XI = 1998,
-        Greek_OMICRON = 1999,
-        Greek_PI = 2000,
-        Greek_RHO = 2001,
-        Greek_SIGMA = 2002,
-        Greek_TAU = 2004,
-        Greek_UPSILON = 2005,
-        Greek_PHI = 2006,
-        Greek_CHI = 2007,
-        Greek_PSI = 2008,
-        Greek_OMEGA = 2009,
-        Greek_alpha = 2017,
-        Greek_beta = 2018,
-        Greek_gamma = 2019,
-        Greek_delta = 2020,
-        Greek_epsilon = 2021,
-        Greek_zeta = 2022,
-        Greek_eta = 2023,
-        Greek_theta = 2024,
-        Greek_iota = 2025,
-        Greek_kappa = 2026,
-        Greek_lambda = 2027,
-        Greek_lamda = 2027,
-        Greek_mu = 2028,
-        Greek_nu = 2029,
-        Greek_xi = 2030,
-        Greek_omicron = 2031,
-        Greek_pi = 2032,
-        Greek_rho = 2033,
-        Greek_sigma = 2034,
-        Greek_finalsmallsigma = 2035,
-        Greek_tau = 2036,
-        Greek_upsilon = 2037,
-        Greek_phi = 2038,
-        Greek_chi = 2039,
-        Greek_psi = 2040,
-        Greek_omega = 2041,
-        leftradical = 2209,
-        topleftradical = 2210,
-        horizconnector = 2211,
-        topintegral = 2212,
-        botintegral = 2213,
-        vertconnector = 2214,
-        topleftsqbracket = 2215,
-        botleftsqbracket = 2216,
-        toprightsqbracket = 2217,
-        botrightsqbracket = 2218,
-        topleftparens = 2219,
-        botleftparens = 2220,
-        toprightparens = 2221,
-        botrightparens = 2222,
-        leftmiddlecurlybrace = 2223,
-        rightmiddlecurlybrace = 2224,
-        topleftsummation = 2225,
-        botleftsummation = 2226,
-        topvertsummationconnector = 2227,
-        botvertsummationconnector = 2228,
-        toprightsummation = 2229,
-        botrightsummation = 2230,
-        rightmiddlesummation = 2231,
-        lessthanequal = 2236,
-        notequal = 2237,
-        greaterthanequal = 2238,
-        integral = 2239,
-        therefore = 2240,
-        variation = 2241,
-        infinity = 2242,
-        nabla = 2245,
-        approximate = 2248,
-        similarequal = 2249,
-        ifonlyif = 2253,
-        implies = 2254,
-        identical = 2255,
-        radical = 2262,
-        includedin = 2266,
-        includes = 2267,
-        intersection = 2268,
-        union = 2269,
-        logicaland = 2270,
-        logicalor = 2271,
-        partialderivative = 2287,
-        function = 2294,
-        leftarrow = 2299,
-        uparrow = 2300,
-        rightarrow = 2301,
-        downarrow = 2302,
-        blank = 2527,
-        soliddiamond = 2528,
-        checkerboard = 2529,
-        ht = 2530,
-        ff = 2531,
-        cr = 2532,
-        lf = 2533,
-        nl = 2536,
-        vt = 2537,
-        lowrightcorner = 2538,
-        uprightcorner = 2539,
-        upleftcorner = 2540,
-        lowleftcorner = 2541,
-        crossinglines = 2542,
-        horizlinescan1 = 2543,
-        horizlinescan3 = 2544,
-        horizlinescan5 = 2545,
-        horizlinescan7 = 2546,
-        horizlinescan9 = 2547,
-        leftt = 2548,
-        rightt = 2549,
-        bott = 2550,
-        topt = 2551,
-        vertbar = 2552,
-        emspace = 2721,
-        enspace = 2722,
-        em3space = 2723,
-        em4space = 2724,
-        digitspace = 2725,
-        punctspace = 2726,
-        thinspace = 2727,
-        hairspace = 2728,
-        emdash = 2729,
-        endash = 2730,
-        signifblank = 2732,
-        ellipsis = 2734,
-        doubbaselinedot = 2735,
-        onethird = 2736,
-        twothirds = 2737,
-        onefifth = 2738,
-        twofifths = 2739,
-        threefifths = 2740,
-        fourfifths = 2741,
-        onesixth = 2742,
-        fivesixths = 2743,
-        careof = 2744,
-        figdash = 2747,
-        leftanglebracket = 2748,
-        decimalpoint = 2749,
-        rightanglebracket = 2750,
-        marker = 2751,
-        oneeighth = 2755,
-        threeeighths = 2756,
-        fiveeighths = 2757,
-        seveneighths = 2758,
-        trademark = 2761,
-        signaturemark = 2762,
-        trademarkincircle = 2763,
-        leftopentriangle = 2764,
-        rightopentriangle = 2765,
-        emopencircle = 2766,
-        emopenrectangle = 2767,
-        leftsinglequotemark = 2768,
-        rightsinglequotemark = 2769,
-        leftdoublequotemark = 2770,
-        rightdoublequotemark = 2771,
-        prescription = 2772,
-        minutes = 2774,
-        seconds = 2775,
-        latincross = 2777,
-        hexagram = 2778,
-        filledrectbullet = 2779,
-        filledlefttribullet = 2780,
-        filledrighttribullet = 2781,
-        emfilledcircle = 2782,
-        emfilledrect = 2783,
-        enopencircbullet = 2784,
-        enopensquarebullet = 2785,
-        openrectbullet = 2786,
-        opentribulletup = 2787,
-        opentribulletdown = 2788,
-        openstar = 2789,
-        enfilledcircbullet = 2790,
-        enfilledsqbullet = 2791,
-        filledtribulletup = 2792,
-        filledtribulletdown = 2793,
-        leftpointer = 2794,
-        rightpointer = 2795,
-        club = 2796,
-        diamond = 2797,
-        heart = 2798,
-        maltesecross = 2800,
-        dagger = 2801,
-        doubledagger = 2802,
-        checkmark = 2803,
-        ballotcross = 2804,
-        musicalsharp = 2805,
-        musicalflat = 2806,
-        malesymbol = 2807,
-        femalesymbol = 2808,
-        telephone = 2809,
-        telephonerecorder = 2810,
-        phonographcopyright = 2811,
-        caret = 2812,
-        singlelowquotemark = 2813,
-        doublelowquotemark = 2814,
-        cursor = 2815,
-        leftcaret = 2979,
-        rightcaret = 2982,
-        downcaret = 2984,
-        upcaret = 2985,
-        overbar = 3008,
-        downtack = 3010,
-        upshoe = 3011,
-        downstile = 3012,
-        underbar = 3014,
-        jot = 3018,
-        quad = 3020,
-        uptack = 3022,
-        circle = 3023,
-        upstile = 3027,
-        downshoe = 3030,
-        rightshoe = 3032,
-        leftshoe = 3034,
-        lefttack = 3036,
-        righttack = 3068,
-        hebrew_doublelowline = 3295,
-        hebrew_aleph = 3296,
-        hebrew_bet = 3297,
-        hebrew_beth = 3297,
-        hebrew_gimel = 3298,
-        hebrew_gimmel = 3298,
-        hebrew_dalet = 3299,
-        hebrew_daleth = 3299,
-        hebrew_he = 3300,
-        hebrew_waw = 3301,
-        hebrew_zain = 3302,
-        hebrew_zayin = 3302,
-        hebrew_chet = 3303,
-        hebrew_het = 3303,
-        hebrew_tet = 3304,
-        hebrew_teth = 3304,
-        hebrew_yod = 3305,
-        hebrew_finalkaph = 3306,
-        hebrew_kaph = 3307,
-        hebrew_lamed = 3308,
-        hebrew_finalmem = 3309,
-        hebrew_mem = 3310,
-        hebrew_finalnun = 3311,
-        hebrew_nun = 3312,
-        hebrew_samech = 3313,
-        hebrew_samekh = 3313,
-        hebrew_ayin = 3314,
-        hebrew_finalpe = 3315,
-        hebrew_pe = 3316,
-        hebrew_finalzade = 3317,
-        hebrew_finalzadi = 3317,
-        hebrew_zade = 3318,
-        hebrew_zadi = 3318,
-        hebrew_kuf = 3319,
-        hebrew_qoph = 3319,
-        hebrew_resh = 3320,
-        hebrew_shin = 3321,
-        hebrew_taf = 3322,
-        hebrew_taw = 3322,
-        Thai_kokai = 3489,
-        Thai_khokhai = 3490,
-        Thai_khokhuat = 3491,
-        Thai_khokhwai = 3492,
-        Thai_khokhon = 3493,
-        Thai_khorakhang = 3494,
-        Thai_ngongu = 3495,
-        Thai_chochan = 3496,
-        Thai_choching = 3497,
-        Thai_chochang = 3498,
-        Thai_soso = 3499,
-        Thai_chochoe = 3500,
-        Thai_yoying = 3501,
-        Thai_dochada = 3502,
-        Thai_topatak = 3503,
-        Thai_thothan = 3504,
-        Thai_thonangmontho = 3505,
-        Thai_thophuthao = 3506,
-        Thai_nonen = 3507,
-        Thai_dodek = 3508,
-        Thai_totao = 3509,
-        Thai_thothung = 3510,
-        Thai_thothahan = 3511,
-        Thai_thothong = 3512,
-        Thai_nonu = 3513,
-        Thai_bobaimai = 3514,
-        Thai_popla = 3515,
-        Thai_phophung = 3516,
-        Thai_fofa = 3517,
-        Thai_phophan = 3518,
-        Thai_fofan = 3519,
-        Thai_phosamphao = 3520,
-        Thai_moma = 3521,
-        Thai_yoyak = 3522,
-        Thai_rorua = 3523,
-        Thai_ru = 3524,
-        Thai_loling = 3525,
-        Thai_lu = 3526,
-        Thai_wowaen = 3527,
-        Thai_sosala = 3528,
-        Thai_sorusi = 3529,
-        Thai_sosua = 3530,
-        Thai_hohip = 3531,
-        Thai_lochula = 3532,
-        Thai_oang = 3533,
-        Thai_honokhuk = 3534,
-        Thai_paiyannoi = 3535,
-        Thai_saraa = 3536,
-        Thai_maihanakat = 3537,
-        Thai_saraaa = 3538,
-        Thai_saraam = 3539,
-        Thai_sarai = 3540,
-        Thai_saraii = 3541,
-        Thai_saraue = 3542,
-        Thai_sarauee = 3543,
-        Thai_sarau = 3544,
-        Thai_sarauu = 3545,
-        Thai_phinthu = 3546,
-        Thai_maihanakat_maitho = 3550,
-        Thai_baht = 3551,
-        Thai_sarae = 3552,
-        Thai_saraae = 3553,
-        Thai_sarao = 3554,
-        Thai_saraaimaimuan = 3555,
-        Thai_saraaimaimalai = 3556,
-        Thai_lakkhangyao = 3557,
-        Thai_maiyamok = 3558,
-        Thai_maitaikhu = 3559,
-        Thai_maiek = 3560,
-        Thai_maitho = 3561,
-        Thai_maitri = 3562,
-        Thai_maichattawa = 3563,
-        Thai_thanthakhat = 3564,
-        Thai_nikhahit = 3565,
-        Thai_leksun = 3568,
-        Thai_leknung = 3569,
-        Thai_leksong = 3570,
-        Thai_leksam = 3571,
-        Thai_leksi = 3572,
-        Thai_lekha = 3573,
-        Thai_lekhok = 3574,
-        Thai_lekchet = 3575,
-        Thai_lekpaet = 3576,
-        Thai_lekkao = 3577,
-        Hangul_Kiyeog = 3745,
-        Hangul_SsangKiyeog = 3746,
-        Hangul_KiyeogSios = 3747,
-        Hangul_Nieun = 3748,
-        Hangul_NieunJieuj = 3749,
-        Hangul_NieunHieuh = 3750,
-        Hangul_Dikeud = 3751,
-        Hangul_SsangDikeud = 3752,
-        Hangul_Rieul = 3753,
-        Hangul_RieulKiyeog = 3754,
-        Hangul_RieulMieum = 3755,
-        Hangul_RieulPieub = 3756,
-        Hangul_RieulSios = 3757,
-        Hangul_RieulTieut = 3758,
-        Hangul_RieulPhieuf = 3759,
-        Hangul_RieulHieuh = 3760,
-        Hangul_Mieum = 3761,
-        Hangul_Pieub = 3762,
-        Hangul_SsangPieub = 3763,
-        Hangul_PieubSios = 3764,
-        Hangul_Sios = 3765,
-        Hangul_SsangSios = 3766,
-        Hangul_Ieung = 3767,
-        Hangul_Jieuj = 3768,
-        Hangul_SsangJieuj = 3769,
-        Hangul_Cieuc = 3770,
-        Hangul_Khieuq = 3771,
-        Hangul_Tieut = 3772,
-        Hangul_Phieuf = 3773,
-        Hangul_Hieuh = 3774,
-        Hangul_A = 3775,
-        Hangul_AE = 3776,
-        Hangul_YA = 3777,
-        Hangul_YAE = 3778,
-        Hangul_EO = 3779,
-        Hangul_E = 3780,
-        Hangul_YEO = 3781,
-        Hangul_YE = 3782,
-        Hangul_O = 3783,
-        Hangul_WA = 3784,
-        Hangul_WAE = 3785,
-        Hangul_OE = 3786,
-        Hangul_YO = 3787,
-        Hangul_U = 3788,
-        Hangul_WEO = 3789,
-        Hangul_WE = 3790,
-        Hangul_WI = 3791,
-        Hangul_YU = 3792,
-        Hangul_EU = 3793,
-        Hangul_YI = 3794,
-        Hangul_I = 3795,
-        Hangul_J_Kiyeog = 3796,
-        Hangul_J_SsangKiyeog = 3797,
-        Hangul_J_KiyeogSios = 3798,
-        Hangul_J_Nieun = 3799,
-        Hangul_J_NieunJieuj = 3800,
-        Hangul_J_NieunHieuh = 3801,
-        Hangul_J_Dikeud = 3802,
-        Hangul_J_Rieul = 3803,
-        Hangul_J_RieulKiyeog = 3804,
-        Hangul_J_RieulMieum = 3805,
-        Hangul_J_RieulPieub = 3806,
-        Hangul_J_RieulSios = 3807,
-        Hangul_J_RieulTieut = 3808,
-        Hangul_J_RieulPhieuf = 3809,
-        Hangul_J_RieulHieuh = 3810,
-        Hangul_J_Mieum = 3811,
-        Hangul_J_Pieub = 3812,
-        Hangul_J_PieubSios = 3813,
-        Hangul_J_Sios = 3814,
-        Hangul_J_SsangSios = 3815,
-        Hangul_J_Ieung = 3816,
-        Hangul_J_Jieuj = 3817,
-        Hangul_J_Cieuc = 3818,
-        Hangul_J_Khieuq = 3819,
-        Hangul_J_Tieut = 3820,
-        Hangul_J_Phieuf = 3821,
-        Hangul_J_Hieuh = 3822,
-        Hangul_RieulYeorinHieuh = 3823,
-        Hangul_SunkyeongeumMieum = 3824,
-        Hangul_SunkyeongeumPieub = 3825,
-        Hangul_PanSios = 3826,
-        Hangul_KkogjiDalrinIeung = 3827,
-        Hangul_SunkyeongeumPhieuf = 3828,
-        Hangul_YeorinHieuh = 3829,
-        Hangul_AraeA = 3830,
-        Hangul_AraeAE = 3831,
-        Hangul_J_PanSios = 3832,
-        Hangul_J_KkogjiDalrinIeung = 3833,
-        Hangul_J_YeorinHieuh = 3834,
-        Korean_Won = 3839,
-        OE = 5052,
-        oe = 5053,
-        Ydiaeresis = 5054,
-        EcuSign = 8352,
-        ColonSign = 8353,
-        CruzeiroSign = 8354,
-        FFrancSign = 8355,
-        LiraSign = 8356,
-        MillSign = 8357,
-        NairaSign = 8358,
-        PesetaSign = 8359,
-        RupeeSign = 8360,
-        WonSign = 8361,
-        NewSheqelSign = 8362,
-        DongSign = 8363,
-        EuroSign = 8364,
-        Key_3270_Duplicate = 64769,
-        Key_3270_FieldMark = 64770,
-        Key_3270_Right2 = 64771,
-        Key_3270_Left2 = 64772,
-        Key_3270_BackTab = 64773,
-        Key_3270_EraseEOF = 64774,
-        Key_3270_EraseInput = 64775,
-        Key_3270_Reset = 64776,
-        Key_3270_Quit = 64777,
-        Key_3270_PA1 = 64778,
-        Key_3270_PA2 = 64779,
-        Key_3270_PA3 = 64780,
-        Key_3270_Test = 64781,
-        Key_3270_Attn = 64782,
-        Key_3270_CursorBlink = 64783,
-        Key_3270_AltCursor = 64784,
-        Key_3270_KeyClick = 64785,
-        Key_3270_Jump = 64786,
-        Key_3270_Ident = 64787,
-        Key_3270_Rule = 64788,
-        Key_3270_Copy = 64789,
-        Key_3270_Play = 64790,
-        Key_3270_Setup = 64791,
-        Key_3270_Record = 64792,
-        Key_3270_ChangeScreen = 64793,
-        Key_3270_DeleteWord = 64794,
-        Key_3270_ExSelect = 64795,
-        Key_3270_CursorSelect = 64796,
-        Key_3270_PrintScreen = 64797,
-        Key_3270_Enter = 64798,
-        ISO_Lock = 65025,
-        ISO_Level2_Latch = 65026,
-        ISO_Level3_Shift = 65027,
-        ISO_Level3_Latch = 65028,
-        ISO_Level3_Lock = 65029,
-        ISO_Group_Latch = 65030,
-        ISO_Group_Lock = 65031,
-        ISO_Next_Group = 65032,
-        ISO_Next_Group_Lock = 65033,
-        ISO_Prev_Group = 65034,
-        ISO_Prev_Group_Lock = 65035,
-        ISO_First_Group = 65036,
-        ISO_First_Group_Lock = 65037,
-        ISO_Last_Group = 65038,
-        ISO_Last_Group_Lock = 65039,
-        ISO_Left_Tab = 65056,
-        ISO_Move_Line_Up = 65057,
-        ISO_Move_Line_Down = 65058,
-        ISO_Partial_Line_Up = 65059,
-        ISO_Partial_Line_Down = 65060,
-        ISO_Partial_Space_Left = 65061,
-        ISO_Partial_Space_Right = 65062,
-        ISO_Set_Margin_Left = 65063,
-        ISO_Set_Margin_Right = 65064,
-        ISO_Release_Margin_Left = 65065,
-        ISO_Release_Margin_Right = 65066,
-        ISO_Release_Both_Margins = 65067,
-        ISO_Fast_Cursor_Left = 65068,
-        ISO_Fast_Cursor_Right = 65069,
-        ISO_Fast_Cursor_Up = 65070,
-        ISO_Fast_Cursor_Down = 65071,
-        ISO_Continuous_Underline = 65072,
-        ISO_Discontinuous_Underline = 65073,
-        ISO_Emphasize = 65074,
-        ISO_Center_Object = 65075,
-        ISO_Enter = 65076,
-        dead_grave = 65104,
-        dead_acute = 65105,
-        dead_circumflex = 65106,
-        dead_tilde = 65107,
-        dead_macron = 65108,
-        dead_breve = 65109,
-        dead_abovedot = 65110,
-        dead_diaeresis = 65111,
-        dead_abovering = 65112,
-        dead_doubleacute = 65113,
-        dead_caron = 65114,
-        dead_cedilla = 65115,
-        dead_ogonek = 65116,
-        dead_iota = 65117,
-        dead_voiced_sound = 65118,
-        dead_semivoiced_sound = 65119,
-        dead_belowdot = 65120,
-        AccessX_Enable = 65136,
-        AccessX_Feedback_Enable = 65137,
-        RepeatKeys_Enable = 65138,
-        SlowKeys_Enable = 65139,
-        BounceKeys_Enable = 65140,
-        StickyKeys_Enable = 65141,
-        MouseKeys_Enable = 65142,
-        MouseKeys_Accel_Enable = 65143,
-        Overlay1_Enable = 65144,
-        Overlay2_Enable = 65145,
-        AudibleBell_Enable = 65146,
-        First_Virtual_Screen = 65232,
-        Prev_Virtual_Screen = 65233,
-        Next_Virtual_Screen = 65234,
-        Last_Virtual_Screen = 65236,
-        Terminate_Server = 65237,
-        Pointer_Left = 65248,
-        Pointer_Right = 65249,
-        Pointer_Up = 65250,
-        Pointer_Down = 65251,
-        Pointer_UpLeft = 65252,
-        Pointer_UpRight = 65253,
-        Pointer_DownLeft = 65254,
-        Pointer_DownRight = 65255,
-        Pointer_Button_Dflt = 65256,
-        Pointer_Button1 = 65257,
-        Pointer_Button2 = 65258,
-        Pointer_Button3 = 65259,
-        Pointer_Button4 = 65260,
-        Pointer_Button5 = 65261,
-        Pointer_DblClick_Dflt = 65262,
-        Pointer_DblClick1 = 65263,
-        Pointer_DblClick2 = 65264,
-        Pointer_DblClick3 = 65265,
-        Pointer_DblClick4 = 65266,
-        Pointer_DblClick5 = 65267,
-        Pointer_Drag_Dflt = 65268,
-        Pointer_Drag1 = 65269,
-        Pointer_Drag2 = 65270,
-        Pointer_Drag3 = 65271,
-        Pointer_Drag4 = 65272,
-        Pointer_EnableKeys = 65273,
-        Pointer_Accelerate = 65274,
-        Pointer_DfltBtnNext = 65275,
-        Pointer_DfltBtnPrev = 65276,
-        Pointer_Drag5 = 65277,
-        BackSpace = 65288,
-        Tab = 65289,
-        Linefeed = 65290,
-        Clear = 65291,
-        Return = 65293,
-        Pause = 65299,
-        Scroll_Lock = 65300,
-        Sys_Req = 65301,
-        Escape = 65307,
-        Multi_key = 65312,
-        Kanji = 65313,
-        Muhenkan = 65314,
-        Henkan = 65315,
-        Henkan_Mode = 65315,
-        Romaji = 65316,
-        Hiragana = 65317,
-        Katakana = 65318,
-        Hiragana_Katakana = 65319,
-        Zenkaku = 65320,
-        Hankaku = 65321,
-        Zenkaku_Hankaku = 65322,
-        Touroku = 65323,
-        Massyo = 65324,
-        Kana_Lock = 65325,
-        Kana_Shift = 65326,
-        Eisu_Shift = 65327,
-        Eisu_toggle = 65328,
-        Hangul = 65329,
-        Hangul_Start = 65330,
-        Hangul_End = 65331,
-        Hangul_Hanja = 65332,
-        Hangul_Jamo = 65333,
-        Hangul_Romaja = 65334,
-        Codeinput = 65335,
-        Hangul_Codeinput = 65335,
-        Kanji_Bangou = 65335,
-        Hangul_Jeonja = 65336,
-        Hangul_Banja = 65337,
-        Hangul_PreHanja = 65338,
-        Hangul_PostHanja = 65339,
-        Hangul_SingleCandidate = 65340,
-        SingleCandidate = 65340,
-        Hangul_MultipleCandidate = 65341,
-        MultipleCandidate = 65341,
-        Zen_Koho = 65341,
-        Hangul_PreviousCandidate = 65342,
-        Mae_Koho = 65342,
-        PreviousCandidate = 65342,
-        Hangul_Special = 65343,
-        Home = 65360,
-        Left = 65361,
-        Up = 65362,
-        Right = 65363,
-        Down = 65364,
-        Page_Up = 65365,
-        Prior = 65365,
-        Next = 65366,
-        Page_Down = 65366,
-        End = 65367,
-        Begin = 65368,
-        Select = 65376,
-        Print = 65377,
-        Execute = 65378,
-        Insert = 65379,
-        Undo = 65381,
-        Redo = 65382,
-        Menu = 65383,
-        Find = 65384,
-        Cancel = 65385,
-        Help = 65386,
-        Break = 65387,
-        Arabic_switch = 65406,
-        Greek_switch = 65406,
-        Hangul_switch = 65406,
-        Hebrew_switch = 65406,
-        ISO_Group_Shift = 65406,
-        Mode_switch = 65406,
-        kana_switch = 65406,
-        script_switch = 65406,
-        Num_Lock = 65407,
-        KP_Space = 65408,
-        KP_Tab = 65417,
-        KP_Enter = 65421,
-        KP_F1 = 65425,
-        KP_F2 = 65426,
-        KP_F3 = 65427,
-        KP_F4 = 65428,
-        KP_Home = 65429,
-        KP_Left = 65430,
-        KP_Up = 65431,
-        KP_Right = 65432,
-        KP_Down = 65433,
-        KP_Page_Up = 65434,
-        KP_Prior = 65434,
-        KP_Next = 65435,
-        KP_Page_Down = 65435,
-        KP_End = 65436,
-        KP_Begin = 65437,
-        KP_Insert = 65438,
-        KP_Delete = 65439,
-        KP_Multiply = 65450,
-        KP_Add = 65451,
-        KP_Separator = 65452,
-        KP_Subtract = 65453,
-        KP_Decimal = 65454,
-        KP_Divide = 65455,
-        KP_0 = 65456,
-        KP_1 = 65457,
-        KP_2 = 65458,
-        KP_3 = 65459,
-        KP_4 = 65460,
-        KP_5 = 65461,
-        KP_6 = 65462,
-        KP_7 = 65463,
-        KP_8 = 65464,
-        KP_9 = 65465,
-        KP_Equal = 65469,
-        F1 = 65470,
-        F2 = 65471,
-        F3 = 65472,
-        F4 = 65473,
-        F5 = 65474,
-        F6 = 65475,
-        F7 = 65476,
-        F8 = 65477,
-        F9 = 65478,
-        F10 = 65479,
-        F11 = 65480,
-        L1 = 65480,
-        F12 = 65481,
-        L2 = 65481,
-        F13 = 65482,
-        L3 = 65482,
-        F14 = 65483,
-        L4 = 65483,
-        F15 = 65484,
-        L5 = 65484,
-        F16 = 65485,
-        L6 = 65485,
-        F17 = 65486,
-        L7 = 65486,
-        F18 = 65487,
-        L8 = 65487,
-        F19 = 65488,
-        L9 = 65488,
-        F20 = 65489,
-        L10 = 65489,
-        F21 = 65490,
-        R1 = 65490,
-        F22 = 65491,
-        R2 = 65491,
-        F23 = 65492,
-        R3 = 65492,
-        F24 = 65493,
-        R4 = 65493,
-        F25 = 65494,
-        R5 = 65494,
-        F26 = 65495,
-        R6 = 65495,
-        F27 = 65496,
-        R7 = 65496,
-        F28 = 65497,
-        R8 = 65497,
-        F29 = 65498,
-        R9 = 65498,
-        F30 = 65499,
-        R10 = 65499,
-        F31 = 65500,
-        R11 = 65500,
-        F32 = 65501,
-        R12 = 65501,
-        F33 = 65502,
-        R13 = 65502,
-        F34 = 65503,
-        R14 = 65503,
-        F35 = 65504,
-        R15 = 65504,
-        Shift_L = 65505,
-        Shift_R = 65506,
-        Control_L = 65507,
-        Control_R = 65508,
-        Caps_Lock = 65509,
-        Shift_Lock = 65510,
-        Meta_L = 65511,
-        Meta_R = 65512,
-        Alt_L = 65513,
-        Alt_R = 65514,
-        Super_L = 65515,
-        Super_R = 65516,
-        Hyper_L = 65517,
-        Hyper_R = 65518,
-        Delete = 65535,
-        VoidSymbol = 16777215,
-    }
-}

+ 0 - 115
src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs

@@ -1,115 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Avalonia.Controls;
-using Avalonia.Controls.Platform;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Platform;
-using Avalonia.Platform.Interop;
-
-namespace Avalonia.Gtk3
-{
-    public class Gtk3ForeignX11SystemDialog : ISystemDialogImpl
-    {
-        private Task<bool> _initialized;
-        private SystemDialogBase _inner = new SystemDialogBase();
-
-
-        public async Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
-        {
-            await EnsureInitialized();
-            var xid = parent.Handle.Handle;
-            return await await RunOnGtkThread(
-                () => _inner.ShowFileDialogAsync(dialog, GtkWindow.Null, chooser => UpdateParent(chooser, xid)));
-        }
-
-        public async Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
-        {
-            await EnsureInitialized();
-            var xid = parent.Handle.Handle;
-            return await await RunOnGtkThread(
-                () => _inner.ShowFolderDialogAsync(dialog, GtkWindow.Null, chooser => UpdateParent(chooser, xid)));
-        }
-
-        void UpdateParent(GtkFileChooser chooser, IntPtr xid)
-        {
-            Native.GtkWidgetRealize(chooser);
-            var window = Native.GtkWidgetGetWindow(chooser);
-            var parent = Native.GdkWindowForeignNewForDisplay(GdkDisplay, xid);
-            if (window != IntPtr.Zero && parent != IntPtr.Zero)
-                Native.GdkWindowSetTransientFor(window, parent);
-        }
-        
-        async Task EnsureInitialized()
-        {
-            if (_initialized == null)
-            {
-                var tcs = new TaskCompletionSource<bool>();
-                _initialized = tcs.Task;
-                new Thread(() => GtkThread(tcs))
-                {
-                    IsBackground = true
-                }.Start();
-            }
-
-            if (!(await _initialized))
-                throw new Exception("Unable to initialize GTK on separate thread");
-
-        }
-        
-        Task<T> RunOnGtkThread<T>(Func<T> action)
-        {
-            var tcs = new TaskCompletionSource<T>();
-            GlibTimeout.Add(0, 0, () =>
-            {
-
-                try
-                {
-                    tcs.SetResult(action());
-                }
-                catch (Exception e)
-                {
-                    tcs.TrySetException(e);
-                }
-
-                return false;
-            });
-            return tcs.Task;
-        }
-        
-
-        void GtkThread(TaskCompletionSource<bool> tcs)
-        {
-            try
-            {
-                X11.XInitThreads();
-            }catch{}
-            Resolver.Resolve();
-            if (Native.GdkWindowForeignNewForDisplay == null)
-                throw new Exception("gdk_x11_window_foreign_new_for_display is not found in your libgdk-3.so");
-            using (var backends = new Utf8Buffer("x11"))
-                Native.GdkSetAllowedBackends?.Invoke(backends);
-            if (!Native.GtkInitCheck(0, IntPtr.Zero))
-            {
-                tcs.SetResult(false);
-                return;
-            }
-
-            using (var utf = new Utf8Buffer($"avalonia.app.a{Guid.NewGuid().ToString("N")}"))
-                App = Native.GtkApplicationNew(utf, 0);
-            if (App == IntPtr.Zero)
-            {
-                tcs.SetResult(false);
-                return;
-            }
-            GdkDisplay = Native.GdkGetDefaultDisplay();
-            tcs.SetResult(true);
-            while (true)
-                Native.GtkMainIteration();
-        }
-
-        private IntPtr GdkDisplay { get; set; }
-        private IntPtr App { get; set; }
-    }
-}

+ 0 - 168
src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs

@@ -1,168 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using System.Threading;
-using Avalonia.Controls;
-using Avalonia.Controls.Platform;
-using Avalonia.Gtk3;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Input;
-using Avalonia.Input.Platform;
-using Avalonia.OpenGL;
-using Avalonia.Platform;
-using Avalonia.Platform.Interop;
-using Avalonia.Rendering;
-using Avalonia.Threading;
-
-namespace Avalonia.Gtk3
-{
-    public class Gtk3Platform : IWindowingPlatform, IPlatformSettings, IPlatformThreadingInterface
-    {
-        internal static readonly Gtk3Platform Instance = new Gtk3Platform();
-        internal static readonly MouseDevice Mouse = new MouseDevice();
-        internal static readonly KeyboardDevice Keyboard = new KeyboardDevice();
-        internal static IntPtr App { get; set; }
-        internal static string DisplayClassName;
-        public static bool UseDeferredRendering = true;
-        private static bool s_gtkInitialized;
-
-        static bool EnvOption(string option, bool def, bool? specified)
-        {
-            bool? Parse(string env)
-            {
-                var v = Environment.GetEnvironmentVariable("AVALONIA_GTK3_" + env);
-                if (v == null)
-                    return null;
-                if (v.ToLowerInvariant() == "false" || v == "0")
-                    return false;
-                return true;
-            }
-
-            var overridden = Parse(option + "_OVERRIDE");
-            if (overridden.HasValue)
-                return overridden.Value;
-            if (specified.HasValue)
-                return specified.Value;
-            var envValue = Parse(option);
-            return envValue ?? def;
-        }
-        
-        public static void Initialize(Gtk3PlatformOptions options)
-        {
-            Resolver.Custom = options.CustomResolver;
-            UseDeferredRendering = EnvOption("USE_DEFERRED_RENDERING", true, options.UseDeferredRendering);
-            var useGpu = EnvOption("USE_GPU", true, options.UseGpuAcceleration);
-            if (!s_gtkInitialized)
-            {
-                try
-                {
-                    X11.XInitThreads();
-                }catch{}
-                Resolver.Resolve();
-                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
-                    using (var backends = new Utf8Buffer("x11"))
-                        Native.GdkSetAllowedBackends?.Invoke(backends);
-                Native.GtkInit(0, IntPtr.Zero);
-                var disp = Native.GdkGetDefaultDisplay();
-                DisplayClassName =
-                    Utf8Buffer.StringFromPtr(Native.GTypeName(Marshal.ReadIntPtr(Marshal.ReadIntPtr(disp))));
-
-                using (var utf = new Utf8Buffer($"avalonia.app.a{Guid.NewGuid().ToString("N")}"))
-                    App = Native.GtkApplicationNew(utf, 0);
-                //Mark current thread as UI thread
-                s_tlsMarker = true;
-                s_gtkInitialized = true;
-            }
-            AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatform>().ToConstant(Instance)
-                .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
-                .Bind<IStandardCursorFactory>().ToConstant(new CursorFactory())
-                .Bind<IKeyboardDevice>().ToConstant(Keyboard)
-                .Bind<IPlatformSettings>().ToConstant(Instance)
-                .Bind<IPlatformThreadingInterface>().ToConstant(Instance)
-                .Bind<ISystemDialogImpl>().ToSingleton<SystemDialog>()
-                .Bind<IRenderLoop>().ToConstant(new RenderLoop())
-                .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
-                .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
-                .Bind<IPlatformIconLoader>().ToConstant(new PlatformIconLoader());
-            if (useGpu)
-                EglGlPlatformFeature.TryInitialize();
-        }
-
-        public IWindowImpl CreateWindow() => new WindowImpl();
-
-        public IEmbeddableWindowImpl CreateEmbeddableWindow()
-        {
-            throw new NotImplementedException();
-        }
-
-        public IPopupImpl CreatePopup() => new PopupImpl();
-
-        public Size DoubleClickSize => new Size(4, 4);
-
-        public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(100); //STUB
-        public double RenderScalingFactor { get; } = 1;
-        public double LayoutScalingFactor { get; } = 1;
-
-        public void RunLoop(CancellationToken cancellationToken)
-        {
-            while (!cancellationToken.IsCancellationRequested)
-                Native.GtkMainIteration();
-        }
-
-        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
-        {
-            var msec = interval.TotalMilliseconds;
-            var imsec = (uint) msec;
-            if (imsec == 0)
-                imsec = 1;
-            return GlibTimeout.StartTimer(GlibPriority.FromDispatcherPriority(priority), imsec, tick);
-        }
-
-        private bool[] _signaled = new bool[(int) DispatcherPriority.MaxValue + 1];
-        object _lock = new object();
-        public void Signal(DispatcherPriority prio)
-        {
-            var idx = (int) prio;
-            lock(_lock)
-                if (!_signaled[idx])
-                {
-                    _signaled[idx] = true;
-                    GlibTimeout.Add(GlibPriority.FromDispatcherPriority(prio), 0, () =>
-                    {
-                        lock (_lock)
-                        {
-                            _signaled[idx] = false;
-                        }
-                        Signaled?.Invoke(prio);
-                        return false;
-                    });
-                }
-        }
-        public event Action<DispatcherPriority?> Signaled;
-
-
-        [ThreadStatic]
-        private static bool s_tlsMarker;
-
-        public bool CurrentThreadIsLoopThread => s_tlsMarker;
-    }
-
-    public class Gtk3PlatformOptions
-    {
-        public bool? UseDeferredRendering { get; set; }
-        public bool? UseGpuAcceleration { get; set; }
-        public ICustomGtk3NativeLibraryResolver CustomResolver { get; set; }
-    }
-}
-
-namespace Avalonia
-{
-    public static class Gtk3AppBuilderExtensions
-    {
-        public static T UseGtk3<T>(this AppBuilderBase<T> builder, Gtk3PlatformOptions options = null) 
-            where T : AppBuilderBase<T>, new()
-        {
-            return builder.UseWindowingSubsystem(() => Gtk3Platform.Initialize(options ?? new Gtk3PlatformOptions()),
-                "GTK3");
-        }
-    }
-}

+ 0 - 24
src/Gtk/Avalonia.Gtk3/GtkScreen.cs

@@ -1,24 +0,0 @@
-using Avalonia.Platform;
-
-namespace Avalonia.Gtk3
-{
-    public class GtkScreen : Screen
-    {
-        private readonly int _screenId;
-        
-        public GtkScreen(PixelRect bounds, PixelRect workingArea, bool primary, int screenId) : base(bounds, workingArea, primary)
-        {
-            this._screenId = screenId;
-        }
-
-        public override int GetHashCode()
-        {
-            return _screenId;
-        }
-
-        public override bool Equals(object obj)
-        {
-            return (obj is GtkScreen screen) ? this._screenId == screen._screenId : base.Equals(obj);
-        }
-    }
-}

+ 0 - 9
src/Gtk/Avalonia.Gtk3/IDeferredRenderOperation.cs

@@ -1,9 +0,0 @@
-using System;
-
-namespace Avalonia.Gtk3
-{
-    public interface IDeferredRenderOperation : IDisposable
-    {
-        void RenderNow(IntPtr? ctx);
-    }
-}

+ 0 - 144
src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs

@@ -1,144 +0,0 @@
-using System;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Platform;
-using Avalonia.Threading;
-
-
-namespace Avalonia.Gtk3
-{
-    class ImageSurfaceFramebuffer : ILockedFramebuffer
-    {
-        private readonly WindowBaseImpl _impl;
-        private readonly GtkWidget _widget;
-        private ManagedCairoSurface _surface;
-        private int _factor;
-        private object _lock = new object();
-        public ImageSurfaceFramebuffer(WindowBaseImpl impl, int width, int height, int factor)
-        {
-            _impl = impl;
-            _widget = impl.GtkWidget;
-            _factor = factor;
-            width *= _factor;
-            height *= _factor;
-            _surface = new ManagedCairoSurface(width, height);
-            
-            Size = new PixelSize(width, height);
-            Address = _surface.Buffer;
-            RowBytes = _surface.Stride;
-            Native.CairoSurfaceFlush(_surface.Surface);
-        }
-
-        static void Draw(IntPtr context, CairoSurface surface, double factor)
-        {
-            
-            Native.CairoSurfaceMarkDirty(surface);
-            Native.CairoScale(context, 1d / factor, 1d / factor);
-            Native.CairoSetSourceSurface(context, surface, 0, 0);
-            Native.CairoPaint(context);
-
-        }
-        /*
-        static Stopwatch St =Stopwatch.StartNew();
-        private static int _frames;
-        private static int _fps;*/
-        static void DrawToWidget(GtkWidget widget, CairoSurface surface, int width, int height, double factor)
-        {
-            if(surface == null || widget.IsClosed)
-                return;
-            var window = Native.GtkWidgetGetWindow(widget);
-            if(window == IntPtr.Zero)
-                return;
-            var rc = new GdkRectangle {Width = width, Height = height};
-            Native.GdkWindowBeginPaintRect(window, ref rc);
-            var context = Native.GdkCairoCreate(window);
-            Draw(context, surface, factor);
-            /*
-            _frames++;
-            var el = St.Elapsed;
-            if (el.TotalSeconds > 1)
-            {
-                _fps = (int) (_frames / el.TotalSeconds);
-                _frames = 0;
-                St = Stopwatch.StartNew();
-            }
-            
-            Native.CairoSetSourceRgba(context, 1, 0, 0, 1);
-            Native.CairoMoveTo(context, 20, 20);
-            Native.CairoSetFontSize(context, 30);
-            using (var txt = new Utf8Buffer("FPS: " + _fps))
-                Native.CairoShowText(context, txt);
-            */
-            
-            Native.CairoDestroy(context);
-            Native.GdkWindowEndPaint(window);
-        }
-        
-        class RenderOp : IDeferredRenderOperation
-        {
-            private readonly GtkWidget _widget;
-            private ManagedCairoSurface _surface;
-            private readonly double _factor;
-            private readonly int _width;
-            private readonly int _height;
-
-            public RenderOp(GtkWidget widget, ManagedCairoSurface surface, double factor, int width, int height)
-            {
-                _widget = widget;
-                _surface = surface ?? throw new ArgumentNullException(nameof(surface));
-                _factor = factor;
-                _width = width;
-                _height = height;
-            }
-
-            public void Dispose()
-            {
-                _surface?.Dispose();
-                _surface = null;
-            }
-
-            public void RenderNow(IntPtr? ctx)
-            {
-                if(ctx.HasValue)
-                    Draw(ctx.Value, _surface.Surface, _factor);
-                else
-                    DrawToWidget(_widget, _surface.Surface, _width, _height, _factor);
-            }
-        }
-        
-        public void Dispose()
-        {
-            lock (_lock)
-            {
-                if (Dispatcher.UIThread.CheckAccess())
-                {
-                    if (_impl.CurrentCairoContext != IntPtr.Zero)
-                        Draw(_impl.CurrentCairoContext, _surface.Surface, _factor);
-                    else
-                        DrawToWidget(_widget, _surface.Surface, Size.Width, Size.Height, _factor);
-                    _surface.Dispose();
-                }
-                else
-                    _impl.SetNextRenderOperation(new RenderOp(_widget, _surface, _factor, Size.Width, Size.Height));
-                _surface = null;
-            }
-        }
-
-        public IntPtr Address { get; }
-        public PixelSize Size { get; }
-        public int RowBytes { get; }
-
-        
-        public Vector Dpi
-        {
-            get
-            {
-                return new Vector(96, 96) * _factor;
-            }
-        }
-
-        public PixelFormat Format => PixelFormat.Bgra8888;
-    }
-}
-
-
-

+ 0 - 20
src/Gtk/Avalonia.Gtk3/Interop/CairoSurface.cs

@@ -1,20 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Avalonia.Gtk3.Interop
-{
-    class CairoSurface : SafeHandle
-    {
-        public CairoSurface() : base(IntPtr.Zero, true)
-        {
-        }
-
-        protected override bool ReleaseHandle()
-        {
-            Native.CairoSurfaceDestroy(handle);
-            return true;
-        }
-
-        public override bool IsInvalid => handle == IntPtr.Zero;
-    }
-}

+ 0 - 30
src/Gtk/Avalonia.Gtk3/Interop/GException.cs

@@ -1,30 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using Avalonia.Platform.Interop;
-
-namespace Avalonia.Gtk3.Interop
-{
-    public class GException : Exception
-    {
-        [StructLayout(LayoutKind.Sequential)]
-        struct GError
-        {
-            UInt32 domain;
-            int code;
-            public IntPtr message;
-        };
-
-        static unsafe string GetError(IntPtr error)
-        {
-            if (error == IntPtr.Zero)
-                return "Unknown error";
-            return Utf8Buffer.StringFromPtr(((GError*) error)->message);
-        }
-
-        public GException(IntPtr error) : base(GetError(error))
-        {
-            
-        }
-
-    }
-}

+ 0 - 87
src/Gtk/Avalonia.Gtk3/Interop/GObject.cs

@@ -1,87 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace Avalonia.Gtk3.Interop
-{
-    class GObject : SafeHandle
-    {
-        public GObject() : base(IntPtr.Zero, true)
-        {
-        }
-
-        public GObject(IntPtr handle, bool owned = true) : base(IntPtr.Zero, owned)
-        {
-            this.handle = handle;
-        }
-
-        protected override bool ReleaseHandle()
-        {
-            if (handle != IntPtr.Zero)
-            {
-                Debug.Assert(Native.GTypeCheckInstanceIsFundamentallyA(handle, new IntPtr(Native.G_TYPE_OBJECT)),
-                    "Handle is not a GObject");
-                Native.GObjectUnref(handle);
-            }
-
-            handle = IntPtr.Zero;
-            return true;
-        }
-
-        public override bool IsInvalid => handle == IntPtr.Zero;
-    }
-
-    class GInputStream : GObject
-    {
-        
-    }
-
-    class GtkWidget : GObject
-    {
-        
-    }
-
-    class GtkWindow : GtkWidget
-    {
-        public static GtkWindow Null { get; } = new GtkWindow();
-    }
-
-    class GtkImContext : GObject
-    {
-    }
-
-    class GdkScreen : GObject
-    {
-        public GdkScreen() : base(IntPtr.Zero, false)
-        {
-        }
-
-        public GdkScreen(IntPtr handle, bool owned = true) : base(handle, owned)
-        {
-            this.handle = handle;
-        }
-    }
-
-    class UnownedGdkScreen : GdkScreen
-    {
-        public UnownedGdkScreen() : base(IntPtr.Zero, false)
-        {
-        }
-
-        public UnownedGdkScreen(IntPtr handle, bool owned = true) : base(IntPtr.Zero, false)
-        {
-            this.handle = handle;
-        }
-    }
-
-    class GtkDialog : GtkWindow
-    {
-        
-    }
-
-    class GtkFileChooser : GtkDialog
-    {
-        
-    }
-}
-

+ 0 - 46
src/Gtk/Avalonia.Gtk3/Interop/GlibPriority.cs

@@ -1,46 +0,0 @@
-using System;
-using Avalonia.Threading;
-
-namespace Avalonia.Gtk3.Interop
-{
-    static class GlibPriority
-    {
-        public static int High = -100;
-        public static int Default = 0;
-        public static int HighIdle = 100;
-        public static int GtkResize = HighIdle + 10;
-        public static int GtkPaint = HighIdle + 20;
-        public static int DefaultIdle = 200;
-        public static int Low = 300;
-        public static int GdkEvents = Default;
-        public static int GdkRedraw = HighIdle + 20;
-
-        public static int FromDispatcherPriority(DispatcherPriority prio)
-        {
-            if (prio == DispatcherPriority.Send)
-                return High;
-            if (prio == DispatcherPriority.Normal)
-                return Default;
-            if (prio == DispatcherPriority.DataBind)
-                return Default + 1;
-            if (prio == DispatcherPriority.Layout)
-                return Default + 2;
-            if (prio == DispatcherPriority.Render)
-                return Default + 3;
-            if (prio == DispatcherPriority.Loaded)
-                return GtkPaint + 20;
-            if (prio == DispatcherPriority.Input)
-                return GtkPaint + 21;
-            if (prio == DispatcherPriority.Background)
-                return DefaultIdle + 1;
-            if (prio == DispatcherPriority.ContextIdle)
-                return DefaultIdle + 2;
-            if (prio == DispatcherPriority.ApplicationIdle)
-                return DefaultIdle + 3;
-            if (prio == DispatcherPriority.SystemIdle)
-                return DefaultIdle + 4;
-            throw new ArgumentException("Unknown priority");
-
-        }
-    }
-}

+ 0 - 58
src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs

@@ -1,58 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Avalonia.Gtk3.Interop
-{
-    static class GlibTimeout
-    {
-        static bool Handler(IntPtr data)
-        {
-            var handle = GCHandle.FromIntPtr(data);
-            var cb = (Func<bool>) handle.Target;
-            if (!cb())
-            {
-                handle.Free();
-                return false;
-            }
-            return true;
-        }
-        
-        private static readonly Native.D.timeout_callback PinnedHandler;
-        static GlibTimeout()
-        {
-            PinnedHandler = Handler;
-        }
-
-
-        public static void Add(int priority, uint interval, Func<bool> callback)
-        {
-            var handle = GCHandle.Alloc(callback);
-            Native.GTimeoutAddFull(priority, interval, PinnedHandler, GCHandle.ToIntPtr(handle), IntPtr.Zero);
-        }
-
-        class Timer : IDisposable
-        {
-            public bool Stopped;
-            public void Dispose()
-            {
-
-                Stopped = true;
-            }
-        }
-
-        public static IDisposable StartTimer(int priority, uint interval, Action tick)
-        {
-            var timer = new Timer ();
-            GlibTimeout.Add(priority, interval,
-                () =>
-                {
-                    if (timer.Stopped)
-                        return false;
-                    tick();
-                    return !timer.Stopped;
-                });
-
-            return timer;
-        }
-    }
-}

+ 0 - 12
src/Gtk/Avalonia.Gtk3/Interop/ICustomGtk3NativeLibraryResolver.cs

@@ -1,12 +0,0 @@
-using Avalonia.Gtk3.Interop;
-
-namespace Avalonia.Gtk3
-{
-    public interface ICustomGtk3NativeLibraryResolver
-    {
-        string GetName(GtkDll dll);
-        string BasePath { get; }
-        bool TrySystemFirst { get; }
-        string Lookup(GtkDll dll);
-    }
-}

+ 0 - 37
src/Gtk/Avalonia.Gtk3/Interop/ManagedCairoSurface.cs

@@ -1,37 +0,0 @@
-using System;
-using Avalonia.Platform;
-
-namespace Avalonia.Gtk3.Interop
-{
-    class ManagedCairoSurface : IDisposable
-    {
-        public IntPtr Buffer { get; private set; }
-        public CairoSurface Surface { get; private set; }
-        public int Stride { get; private set; }
-        private int _size;
-        private IRuntimePlatform _plat;
-        private IUnmanagedBlob _blob;
-
-        public ManagedCairoSurface(int width, int height)
-        {
-            _plat = AvaloniaLocator.Current.GetService<IRuntimePlatform>();
-            Stride = width * 4;
-            _size = height * Stride;
-            _blob = _plat.AllocBlob(_size * 2);
-            Buffer = _blob.Address;
-            Surface = Native.CairoImageSurfaceCreateForData(Buffer, 1, width, height, Stride);
-        }
-        
-        public void Dispose()
-        {
-            
-            if (Buffer != IntPtr.Zero)
-            {
-                Surface.Dispose();
-                _blob.Dispose();
-                Buffer = IntPtr.Zero;
-            }
-        }
-
-    }
-}

+ 0 - 790
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@@ -1,790 +0,0 @@
-#pragma warning disable 649
-using System;
-using System.Runtime.InteropServices;
-using Avalonia.Controls;
-using Avalonia.Platform.Interop;
-using gdouble = System.Double;
-using gint = System.Int32;
-using gint16 = System.Int16;
-using gint8 = System.Byte;
-using guint = System.UInt32;
-using guint16 = System.UInt16;
-using guint32 = System.UInt32;
-
-namespace Avalonia.Gtk3.Interop
-{
-    static class Native
-    {
-        public static class D
-        {
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate gint16 gdk_display_get_n_screens(IntPtr display);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate UnownedGdkScreen gdk_display_get_screen(IntPtr display, gint16 num);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate UnownedGdkScreen gdk_display_get_default_screen (IntPtr display);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate gint16 gdk_screen_get_n_monitors(GdkScreen screen);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate gint16 gdk_screen_get_primary_monitor(GdkScreen screen);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_screen_get_monitor_geometry(GdkScreen screen, gint16 num, ref GdkRectangle rect);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_screen_get_monitor_workarea(GdkScreen screen, gint16 num, ref GdkRectangle rect);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_application_new(Utf8Buffer appId, int flags);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_main_iteration();
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate GtkWindow gtk_window_new(GtkWindowType windowType);           
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_init(int argc, IntPtr argv);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate bool gtk_init_check(int argc, IntPtr argv);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk, optional: true)]
-            public delegate IntPtr gdk_set_allowed_backends (Utf8Buffer backends);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_present(GtkWindow gtkWindow);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_widget_hide(GtkWidget gtkWidget);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_widget_show(GtkWidget gtkWidget);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_icon(GtkWindow window, Pixbuf pixbuf);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_modal(GtkWindow window, bool modal);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_transient_for(GtkWindow window, IntPtr parent);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)] //No manual import
-            public delegate IntPtr gdk_get_native_handle(IntPtr gdkWindow);
-
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_widget_get_window(GtkWidget gtkWidget);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk, optional: true)]
-            public delegate uint gtk_widget_get_scale_factor(GtkWidget gtkWidget);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_widget_get_screen(GtkWidget gtkWidget);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_widget_set_double_buffered(GtkWidget gtkWidget, bool value);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_widget_set_events(GtkWidget gtkWidget, uint flags);
-
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate int gdk_screen_get_height(IntPtr screen);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate int gdk_screen_get_width(IntPtr screen);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate IntPtr gdk_display_get_default();
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate int gdk_window_get_origin(IntPtr gdkWindow, out int x, out int y);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_resize(IntPtr gtkWindow, int width, int height);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_set_override_redirect(IntPtr gdkWindow, bool value);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_widget_realize(GtkWidget gtkWidget);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_title(GtkWindow gtkWindow, Utf8Buffer title);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_resizable(GtkWindow gtkWindow, bool resizable);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_decorated(GtkWindow gtkWindow, bool decorated);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_skip_taskbar_hint(GtkWindow gtkWindow, bool setting); 
-            
-             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate bool gtk_window_get_skip_taskbar_hint(GtkWindow gtkWindow);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_skip_pager_hint(GtkWindow gtkWindow, bool setting); 
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate bool gtk_window_get_skip_pager_hint(GtkWindow gtkWindow); 
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_get_size(GtkWindow gtkWindow, out int width, out int height);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_resize(GtkWindow gtkWindow, int width, int height);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_widget_set_size_request(GtkWidget widget, int width, int height);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_default_size(GtkWindow gtkWindow, int width, int height);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_get_position(GtkWindow gtkWindow, out int x, out int y);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_move(GtkWindow gtkWindow, int x, int y);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate GtkFileChooser gtk_file_chooser_dialog_new(Utf8Buffer title, GtkWindow parent, GtkFileChooserAction action, IntPtr ignore);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public unsafe delegate GSList* gtk_file_chooser_get_filenames(GtkFileChooser chooser);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_file_chooser_set_select_multiple(GtkFileChooser chooser, bool allow);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_file_chooser_set_filename(GtkFileChooser chooser, Utf8Buffer file);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_dialog_add_button(GtkDialog raw, Utf8Buffer button_text, GtkResponseType response_id);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate CairoSurface cairo_image_surface_create(int format, int width, int height);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate CairoSurface cairo_image_surface_create_for_data(IntPtr data, int format, int width, int height, int stride);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate IntPtr cairo_image_surface_get_data(CairoSurface surface);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate int cairo_image_surface_get_stride(CairoSurface surface);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_surface_mark_dirty(CairoSurface surface);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_surface_write_to_png(CairoSurface surface, Utf8Buffer path);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_surface_flush(CairoSurface surface);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_surface_destroy(IntPtr surface);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_set_source_surface(IntPtr cr, CairoSurface surface, double x, double y);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_set_source_rgba(IntPtr cr, double r, double g, double b, double a);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_scale(IntPtr context, double sx, double sy);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_paint(IntPtr context);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_show_text(IntPtr context, Utf8Buffer text);   
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_set_font_size(IntPtr context, double size);  
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_select_font_face(IntPtr context, Utf8Buffer face, int slant, int weight);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_move_to(IntPtr context, double x, double y);   
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_destroy(IntPtr context);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_widget_queue_draw_area(GtkWidget widget, int x, int y, int width, int height);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate uint gtk_widget_add_tick_callback(GtkWidget widget, TickCallback callback, IntPtr userData, IntPtr destroy);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate uint gtk_widget_remove_tick_callback(GtkWidget widget, uint id);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate GtkImContext gtk_im_multicontext_new();
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_im_context_set_client_window(GtkImContext context, IntPtr window);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate bool gtk_im_context_filter_keypress(GtkImContext context, IntPtr ev);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_widget_activate(GtkWidget widget);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate IntPtr gdk_screen_get_root_window(IntPtr screen);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate IntPtr gdk_cursor_new(GdkCursorType type);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate IntPtr gdk_window_get_pointer(IntPtr raw, out int x, out int y, out int mask);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate GdkWindowState gdk_window_get_state(IntPtr window);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_iconify(GtkWindow window);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_deiconify(GtkWindow window);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_maximize(GtkWindow window);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_unmaximize(GtkWindow window);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_close(GtkWindow window);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_keep_above(GtkWindow gtkWindow, bool setting);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_window_set_geometry_hints(GtkWindow window, IntPtr geometry_widget, ref GdkGeometry geometry, GdkWindowHints geom_mask);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_invalidate_rect(IntPtr window, ref GdkRectangle rect, bool invalidate_children);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_begin_move_drag(IntPtr window, gint button, gint root_x, gint root_y, guint32 timestamp);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_begin_resize_drag(IntPtr window, WindowEdge edge, gint button, gint root_x, gint root_y, guint32 timestamp);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_process_updates(IntPtr window, bool updateChildren);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_begin_paint_rect(IntPtr window, ref GdkRectangle rect);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_end_paint(IntPtr window);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk, optional: true)]
-            public delegate IntPtr gdk_x11_window_foreign_new_for_display(IntPtr display, IntPtr xid);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_window_set_transient_for(IntPtr window, IntPtr parent);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate void gdk_event_request_motions(IntPtr ev);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_clipboard_get_for_display(IntPtr display, IntPtr atom);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_clipboard_request_text(IntPtr clipboard, GtkClipboardTextReceivedFunc callback, IntPtr user_data);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_clipboard_set_text(IntPtr clipboard, Utf8Buffer text, int len);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate void gtk_clipboard_clear(IntPtr clipboard);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.GdkPixBuf)]
-            public delegate IntPtr gdk_pixbuf_new_from_file(Utf8Buffer filename, out IntPtr error);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_icon_theme_get_default();
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
-            public delegate IntPtr gtk_icon_theme_load_icon(IntPtr icon_theme, Utf8Buffer icon_name, gint size, int flags,out IntPtr error);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate IntPtr gdk_cursor_new_from_pixbuf(IntPtr disp, IntPtr pixbuf, int x, int y);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate IntPtr gdk_window_set_cursor(IntPtr window, IntPtr cursor);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.GdkPixBuf)]
-            public delegate IntPtr gdk_pixbuf_new_from_stream(GInputStream stream, IntPtr cancel, out IntPtr error);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.GdkPixBuf)]
-            public delegate bool gdk_pixbuf_save_to_bufferv(Pixbuf pixbuf, out IntPtr buffer, out IntPtr buffer_size,
-                            Utf8Buffer type, IntPtr option_keys, IntPtr option_values, out IntPtr error);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
-            public delegate IntPtr gdk_cairo_create(IntPtr window);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
-            public delegate void g_object_unref(IntPtr instance);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
-            public delegate void g_object_ref(GObject instance);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
-            public delegate IntPtr g_type_name(IntPtr instance);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
-            public delegate ulong g_signal_connect_object(GObject instance, Utf8Buffer signal, IntPtr handler, IntPtr userData, int flags);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
-            public delegate ulong g_signal_handler_disconnect(GObject instance, ulong connectionId);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
-            public delegate ulong g_timeout_add(uint interval, timeout_callback callback, IntPtr data);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
-            public delegate ulong g_timeout_add_full(int prio, uint interval, timeout_callback callback, IntPtr data, IntPtr destroy);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
-            public delegate ulong g_free(IntPtr data);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
-            public delegate bool g_type_check_instance_is_fundamentally_a(IntPtr instance, IntPtr type);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
-            public unsafe delegate void g_slist_free(GSList* data);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gio)]
-            public delegate GInputStream g_memory_input_stream_new_from_data(IntPtr ptr, IntPtr len, IntPtr destroyCallback);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate bool signal_widget_draw(IntPtr gtkWidget, IntPtr cairoContext, IntPtr userData);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate bool signal_generic(IntPtr gtkWidget, IntPtr userData);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate bool signal_dialog_response(IntPtr gtkWidget, GtkResponseType response, IntPtr userData);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate bool signal_onevent(IntPtr gtkWidget, IntPtr ev, IntPtr userData);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate void monitors_changed(IntPtr screen, IntPtr userData);
-            
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate bool signal_commit(IntPtr gtkWidget, IntPtr utf8string, IntPtr userData);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate bool timeout_callback(IntPtr data);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate void GtkClipboardTextReceivedFunc(IntPtr clipboard, IntPtr utf8string, IntPtr userdata);
-
-            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-            public delegate bool TickCallback(IntPtr widget, IntPtr clock, IntPtr userdata);
-
-
-        }
-
-        public static D.gdk_display_get_n_screens GdkDisplayGetNScreens;
-        public static D.gdk_display_get_screen GdkDisplayGetScreen;
-        public static D.gdk_display_get_default_screen GdkDisplayGetDefaultScreen;
-        public static D.gdk_screen_get_n_monitors GdkScreenGetNMonitors;
-        public static D.gdk_screen_get_primary_monitor GdkScreenGetPrimaryMonitor;
-        public static D.gdk_screen_get_monitor_geometry GdkScreenGetMonitorGeometry;
-        public static D.gdk_screen_get_monitor_workarea GdkScreenGetMonitorWorkarea;
-        public static D.gtk_window_set_decorated GtkWindowSetDecorated;
-        public static D.gtk_window_set_resizable GtkWindowSetResizable;
-        public static D.gtk_window_set_skip_taskbar_hint GtkWindowSetSkipTaskbarHint;
-        public static D.gtk_window_get_skip_taskbar_hint GtkWindowGetSkipTaskbarHint;
-        public static D.gtk_window_set_skip_pager_hint GtkWindowSetSkipPagerHint;
-        public static D.gtk_window_get_skip_pager_hint GtkWindowGetSkipPagerHint;
-        public static D.gtk_window_set_title GtkWindowSetTitle;
-        public static D.gtk_application_new GtkApplicationNew;
-        public static D.gtk_main_iteration GtkMainIteration;
-        public static D.gtk_window_new GtkWindowNew;
-        public static D.gtk_window_set_icon GtkWindowSetIcon;
-        public static D.gtk_window_set_modal GtkWindowSetModal;
-        public static D.gtk_window_set_transient_for GtkWindowSetTransientFor;
-        public static D.gdk_set_allowed_backends GdkSetAllowedBackends;
-        public static D.gtk_init GtkInit;
-        public static D.gtk_init_check GtkInitCheck;
-        public static D.gtk_window_present GtkWindowPresent;
-        public static D.gtk_widget_hide GtkWidgetHide;
-        public static D.gtk_widget_show GtkWidgetShow;
-        public static D.gdk_get_native_handle GetNativeGdkWindowHandle;
-        public static D.gtk_widget_get_window GtkWidgetGetWindow;
-        public static D.gtk_widget_get_scale_factor GtkWidgetGetScaleFactor;
-        public static D.gtk_widget_get_screen GtkWidgetGetScreen;
-        public static D.gtk_widget_realize GtkWidgetRealize;
-        public static D.gtk_window_get_size GtkWindowGetSize;
-        public static D.gtk_window_resize GtkWindowResize;
-        public static D.gdk_window_resize GdkWindowResize;
-        public static D.gdk_window_set_override_redirect GdkWindowSetOverrideRedirect;
-        public static D.gtk_widget_set_size_request GtkWindowSetSizeRequest;
-        public static D.gtk_window_set_default_size GtkWindowSetDefaultSize;
-        public static D.gtk_window_set_geometry_hints GtkWindowSetGeometryHints;
-        public static D.gtk_window_get_position GtkWindowGetPosition;
-        public static D.gtk_window_move GtkWindowMove;
-        public static D.gtk_file_chooser_dialog_new GtkFileChooserDialogNew;
-        public static D.gtk_file_chooser_set_select_multiple GtkFileChooserSetSelectMultiple;
-        public static D.gtk_file_chooser_set_filename GtkFileChooserSetFilename;
-        public static D.gtk_file_chooser_get_filenames GtkFileChooserGetFilenames;
-        public static D.gtk_dialog_add_button GtkDialogAddButton;
-        public static D.g_object_unref GObjectUnref;
-        public static D.g_object_ref GObjectRef;
-        public static D.g_type_name GTypeName;
-        public static D.g_signal_connect_object GSignalConnectObject;
-        public static D.g_signal_handler_disconnect GSignalHandlerDisconnect;
-        public static D.g_timeout_add GTimeoutAdd;
-        public static D.g_timeout_add_full GTimeoutAddFull;
-        public static D.g_free GFree;
-        public static D.g_type_check_instance_is_fundamentally_a GTypeCheckInstanceIsFundamentallyA;
-        public static D.g_slist_free GSlistFree;
-        public static D.g_memory_input_stream_new_from_data GMemoryInputStreamNewFromData;
-        public static D.gtk_widget_set_double_buffered GtkWidgetSetDoubleBuffered;
-        public static D.gtk_widget_set_events GtkWidgetSetEvents;
-        public static D.gdk_window_invalidate_rect GdkWindowInvalidateRect;
-        public static D.gtk_widget_queue_draw_area GtkWidgetQueueDrawArea;
-        public static D.gtk_widget_add_tick_callback GtkWidgetAddTickCallback;
-        public static D.gtk_widget_remove_tick_callback GtkWidgetRemoveTickCallback;
-        public static D.gtk_widget_activate GtkWidgetActivate;
-        public static D.gtk_clipboard_get_for_display GtkClipboardGetForDisplay;
-        public static D.gtk_clipboard_request_text GtkClipboardRequestText;
-        public static D.gtk_clipboard_set_text GtkClipboardSetText;
-        public static D.gtk_clipboard_clear GtkClipboardRequestClear;
-        
-        public static D.gtk_im_multicontext_new GtkImMulticontextNew;
-        public static D.gtk_im_context_filter_keypress GtkImContextFilterKeypress;
-        public static D.gtk_im_context_set_client_window GtkImContextSetClientWindow;
-
-        public static D.gdk_screen_get_height GdkScreenGetHeight;
-        public static D.gdk_display_get_default GdkGetDefaultDisplay;
-        public static D.gdk_screen_get_width GdkScreenGetWidth;
-        public static D.gdk_screen_get_root_window GdkScreenGetRootWindow;
-        public static D.gdk_cursor_new GdkCursorNew;
-        public static D.gdk_window_get_origin GdkWindowGetOrigin;
-        public static D.gdk_window_get_pointer GdkWindowGetPointer;
-        public static D.gdk_window_get_state GdkWindowGetState;
-        public static D.gtk_window_iconify GtkWindowIconify;
-        public static D.gtk_window_deiconify GtkWindowDeiconify;
-        public static D.gtk_window_maximize GtkWindowMaximize;
-        public static D.gtk_window_unmaximize GtkWindowUnmaximize;
-        public static D.gtk_window_close GtkWindowClose;
-        public static D.gtk_window_set_keep_above GtkWindowSetKeepAbove;
-        public static D.gdk_window_begin_move_drag GdkWindowBeginMoveDrag;
-        public static D.gdk_window_begin_resize_drag GdkWindowBeginResizeDrag;
-        public static D.gdk_event_request_motions GdkEventRequestMotions;
-        public static D.gdk_window_process_updates GdkWindowProcessUpdates;
-        public static D.gdk_window_begin_paint_rect GdkWindowBeginPaintRect;
-        public static D.gdk_window_end_paint GdkWindowEndPaint;
-        public static D.gdk_x11_window_foreign_new_for_display GdkWindowForeignNewForDisplay;
-        public static D.gdk_window_set_transient_for GdkWindowSetTransientFor;
-        
-        public static D.gdk_pixbuf_new_from_file GdkPixbufNewFromFile;
-        public static D.gtk_icon_theme_get_default GtkIconThemeGetDefault;
-        public static D.gtk_icon_theme_load_icon GtkIconThemeLoadIcon;
-        public static D.gdk_cursor_new_from_pixbuf GdkCursorNewFromPixbuf;
-        public static D.gdk_window_set_cursor GdkWindowSetCursor;
-        public static D.gdk_pixbuf_new_from_stream GdkPixbufNewFromStream;
-        public static D.gdk_pixbuf_save_to_bufferv GdkPixbufSaveToBufferv;
-        public static D.gdk_cairo_create GdkCairoCreate;
-        
-        public static D.cairo_image_surface_create CairoImageSurfaceCreate;
-        public static D.cairo_image_surface_create_for_data CairoImageSurfaceCreateForData;
-        public static D.cairo_image_surface_get_data CairoImageSurfaceGetData;
-        public static D.cairo_image_surface_get_stride CairoImageSurfaceGetStride;
-        public static D.cairo_surface_mark_dirty CairoSurfaceMarkDirty;
-        public static D.cairo_surface_write_to_png CairoSurfaceWriteToPng;
-        public static D.cairo_surface_flush CairoSurfaceFlush;
-        public static D.cairo_surface_destroy CairoSurfaceDestroy;
-        public static D.cairo_set_source_surface CairoSetSourceSurface;
-        public static D.cairo_set_source_rgba CairoSetSourceRgba;
-        public static D.cairo_scale CairoScale;
-        public static D.cairo_paint CairoPaint;
-        public static D.cairo_show_text CairoShowText;
-        public static D.cairo_select_font_face CairoSelectFontFace;
-        public static D.cairo_set_font_size CairoSetFontSize;
-        public static D.cairo_move_to CairoMoveTo;
-        public static D.cairo_destroy CairoDestroy;
-
-        public const int G_TYPE_OBJECT = 80;
-    }
-
-    public enum GtkWindowType
-    {
-        TopLevel,
-        Popup
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public struct GdkRectangle
-    {
-        public int X, Y, Width, Height;
-
-        public static GdkRectangle FromRect(Rect rect)
-        {
-            return new GdkRectangle
-            {
-                X = (int) rect.X,
-                Y = (int) rect.Y,
-                Width = (int) rect.Width,
-                Height = (int) rect.Height
-            };
-        }
-    }
-
-    enum GdkEventType
-    {
-        Nothing = -1,
-        Delete = 0,
-        Destroy = 1,
-        Expose = 2,
-        MotionNotify = 3,
-        ButtonPress = 4,
-        TwoButtonPress = 5,
-        ThreeButtonPress = 6,
-        ButtonRelease = 7,
-        KeyPress = 8,
-        KeyRelease = 9,
-        EnterNotify = 10,
-        LeaveNotify = 11,
-        FocusChange = 12,
-        Configure = 13,
-        Map = 14,
-        Unmap = 15,
-        PropertyNotify = 16,
-        SelectionClear = 17,
-        SelectionRequest = 18,
-        SelectionNotify = 19,
-        ProximityIn = 20,
-        ProximityOut = 21,
-        DragEnter = 22,
-        DragLeave = 23,
-        DragMotion = 24,
-        DragStatus = 25,
-        DropStart = 26,
-        DropFinished = 27,
-        ClientEvent = 28,
-        VisibilityNotify = 29,
-        NoExpose = 30,
-        Scroll = 31,
-        WindowState = 32,
-        Setting = 33,
-        OwnerChange = 34,
-        GrabBroken = 35,
-    }
-
-    enum GdkModifierType
-    {
-        ShiftMask = 1,
-        LockMask = 2,
-        ControlMask = 4,
-        Mod1Mask = 8,
-        Mod2Mask = 16,
-        Mod3Mask = 32,
-        Mod4Mask = 64,
-        Mod5Mask = 128,
-        Button1Mask = 256,
-        Button2Mask = 512,
-        Button3Mask = 1024,
-        Button4Mask = 2048,
-        Button5Mask = 4096,
-        SuperMask = 67108864,
-        HyperMask = 134217728,
-        MetaMask = 268435456,
-        ReleaseMask = 1073741824,
-        ModifierMask = ReleaseMask | Button5Mask | Button4Mask | Button3Mask | Button2Mask | Button1Mask | Mod5Mask | Mod4Mask | Mod3Mask | Mod2Mask | Mod1Mask | ControlMask | LockMask | ShiftMask,
-        None = 0,
-    }
-
-    enum GdkScrollDirection
-    {
-        Up,
-        Down,
-        Left,
-        Right,
-        Smooth
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    unsafe struct GdkEventButton
-    {
-        public GdkEventType type;
-        public IntPtr window;
-        public gint8 send_event;
-        public guint32 time;
-        public gdouble x;
-        public gdouble y;
-        public gdouble* axes;
-        public GdkModifierType state;
-        public guint button;
-        public IntPtr device;
-        public gdouble x_root, y_root;
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    unsafe struct GdkEventMotion
-    {
-        public GdkEventType type;
-        public IntPtr window;
-        public gint8 send_event;
-        public guint32 time;
-        public gdouble x;
-        public gdouble y;
-        public gdouble* axes;
-        public GdkModifierType state;
-        public gint16 is_hint;
-        public IntPtr device;
-        public gdouble x_root, y_root;
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    unsafe  struct GdkEventScroll
-    {
-        public GdkEventType type;
-        public IntPtr window;
-        public gint8 send_event;
-        public guint32 time;
-        public gdouble x;
-        public gdouble y;
-        public GdkModifierType state;
-        public GdkScrollDirection direction;
-        public IntPtr device;
-        public gdouble x_root, y_root;
-        public gdouble delta_x;
-        public gdouble delta_y;
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    unsafe  struct GdkEventCrossing 
-    {
-        public GdkEventType type;
-        public IntPtr window;
-        public gint8 send_event;
-        public IntPtr subwindow;
-        public guint32 time;
-        public gdouble x;
-        public gdouble y;
-        public gdouble x_root;
-        public gdouble y_root;
-        public int mode;
-        public int detail;
-        public bool focus;
-        public GdkModifierType state;
-    };
-    
-    [StructLayout(LayoutKind.Sequential)]
-    unsafe struct GdkEventWindowState
-    {
-        public GdkEventType type;
-        public IntPtr window;
-        gint8 send_event;
-        public GdkWindowState changed_mask;
-        public GdkWindowState new_window_state;
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    unsafe struct GdkEventKey
-    {
-        public GdkEventType type;
-        public IntPtr window;
-        public gint8 send_event;
-        public guint32 time;
-        public guint state;
-        public guint keyval;
-        public gint length;
-        public IntPtr pstring;
-        public guint16 hardware_keycode;
-        public byte group;
-        public guint is_modifier;
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    unsafe struct GSList
-    {
-        public IntPtr Data;
-        public GSList* Next;
-    }
-
-    [Flags]
-    public enum GdkWindowState
-    {
-        Withdrawn = 1,
-        Iconified = 2,
-        Maximized = 4,
-        Sticky = 8,
-        Fullscreen = 16,
-        Above = 32,
-        Below = 64,
-        Focused = 128,
-        Ttiled = 256
-    }
-
-    public enum GtkResponseType
-    {
-        Help = -11,
-        Apply = -10,
-        No = -9,
-        Yes = -8,
-        Close = -7,
-        Cancel = -6,
-        Ok = -5,
-        DeleteEvent = -4,
-        Accept = -3,
-        Reject = -2,
-        None = -1,
-    }
-
-    public enum GtkFileChooserAction
-    {
-        Open,
-        Save,
-        SelectFolder,
-        CreateFolder,
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public struct GdkGeometry
-    {
-        public gint min_width;
-        public gint min_height;
-        public gint max_width;
-        public gint max_height;
-        public gint base_width;
-        public gint base_height;
-        public gint width_inc;
-        public gint height_inc;
-        public gdouble min_aspect;
-        public gdouble max_aspect;
-        public gint win_gravity;
-    }
-
-    enum GdkWindowHints
-    {
-        GDK_HINT_POS = 1 << 0,
-        GDK_HINT_MIN_SIZE = 1 << 1,
-        GDK_HINT_MAX_SIZE = 1 << 2,
-        GDK_HINT_BASE_SIZE = 1 << 3,
-        GDK_HINT_ASPECT = 1 << 4,
-        GDK_HINT_RESIZE_INC = 1 << 5,
-        GDK_HINT_WIN_GRAVITY = 1 << 6,
-        GDK_HINT_USER_POS = 1 << 7,
-        GDK_HINT_USER_SIZE = 1 << 8
-    }
-}

+ 0 - 20
src/Gtk/Avalonia.Gtk3/Interop/NativeException.cs

@@ -1,20 +0,0 @@
-using System;
-
-namespace Avalonia.Gtk3.Interop
-{
-    public class NativeException : Exception
-    {
-        public NativeException()
-        {
-        }
-
-        public NativeException(string message) : base(message)
-        {
-        }
-
-        public NativeException(string message, Exception inner) : base(message, inner)
-        {
-        }
-        
-    }
-}

+ 0 - 65
src/Gtk/Avalonia.Gtk3/Interop/Pixbuf.cs

@@ -1,65 +0,0 @@
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using Avalonia.Platform;
-using Avalonia.Platform.Interop;
-
-namespace Avalonia.Gtk3.Interop
-{
-    internal class Pixbuf : GObject, IWindowIconImpl
-    {
-        Pixbuf(IntPtr handle) : base(handle)
-        {
-            
-        }
-
-        public static Pixbuf NewFromFile(string filename)
-        {
-            using (var ub = new Utf8Buffer(filename))
-            {
-                IntPtr err;
-                var rv = Native.GdkPixbufNewFromFile(ub, out err);
-                if(rv != IntPtr.Zero)
-                    return new Pixbuf(rv);
-                throw new GException(err);
-            }
-        }
-
-        public static unsafe Pixbuf NewFromBytes(byte[] data)
-        {
-            fixed (void* bytes = data)
-            {
-                using (var stream = Native.GMemoryInputStreamNewFromData(new IntPtr(bytes), new IntPtr(data.Length), IntPtr.Zero))
-                {
-                    IntPtr err;
-                    var rv = Native.GdkPixbufNewFromStream(stream, IntPtr.Zero, out err);
-                    if (rv != IntPtr.Zero)
-                        return new Pixbuf(rv);
-                    throw new GException(err);
-                }
-            }
-        }
-
-        public static Pixbuf NewFromStream(Stream s)
-        {
-            if (s is MemoryStream)
-                return NewFromBytes(((MemoryStream) s).ToArray());
-            var ms = new MemoryStream();
-            s.CopyTo(ms);
-            return NewFromBytes(ms.ToArray());
-        }
-
-        public void Save(Stream outputStream)
-        {
-            IntPtr buffer, bufferLen, error;
-            using (var png = new Utf8Buffer("png"))
-                if (!Native.GdkPixbufSaveToBufferv(this, out buffer, out bufferLen, png,
-                    IntPtr.Zero, IntPtr.Zero, out error))
-                    throw new GException(error);
-            var data = new byte[bufferLen.ToInt32()];
-            Marshal.Copy(buffer, data, 0, bufferLen.ToInt32());
-            Native.GFree(buffer);
-            outputStream.Write(data, 0, data.Length);
-        }
-    }
-}

+ 0 - 156
src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs

@@ -1,156 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using Avalonia.Platform;
-using Avalonia.Platform.Interop;
-
-namespace Avalonia.Gtk3.Interop
-{
-    internal class GtkImportAttribute : Attribute
-    {
-        public GtkDll Dll { get; set; }
-        public string Name { get; set; }
-        public bool Optional { get; set; }
-
-        public GtkImportAttribute(GtkDll dll, string name = null, bool optional = false)
-        {
-            Dll = dll;
-            Name = name;
-            Optional = optional;
-        }
-    }
-
-    public enum GtkDll
-    {
-        Gdk,
-        Gtk,
-        Glib,
-        Gio,
-        Gobject,
-        Cairo,
-        GdkPixBuf
-    }
-
-    static class Resolver
-    {
-        private static Lazy<OperatingSystemType> Platform =
-            new Lazy<OperatingSystemType>(
-                () => AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem);
-
-        public static ICustomGtk3NativeLibraryResolver Custom { get; set; }
-
-
-        static string FormatName(string name, int version = 0)
-        {
-            if (Platform.Value == OperatingSystemType.WinNT)
-                return "lib" + name + "-" + version + ".dll";
-            if (Platform.Value == OperatingSystemType.Linux)
-                return "lib" + name + ".so" + "." + version;
-            if (Platform.Value == OperatingSystemType.OSX)
-                return "lib" + name + "." + version + ".dylib";
-            throw new Exception("Unknown platform, use custom name resolver");
-        }
-
-        
-
-        static string GetDllName(GtkDll dll)
-        {
-            var name = Custom?.GetName(dll);
-            if (name != null)
-                return name;
-
-            switch (dll)
-            {
-                case GtkDll.Cairo:
-                    return FormatName("cairo", 2);
-                case GtkDll.Gdk:
-                    return FormatName("gdk-3");
-                case GtkDll.Glib:
-                    return FormatName("glib-2.0");
-                case GtkDll.Gio:
-                    return FormatName("gio-2.0");
-                case GtkDll.Gtk:
-                    return FormatName("gtk-3");
-                case GtkDll.Gobject:
-                    return FormatName("gobject-2.0");
-                case GtkDll.GdkPixBuf:
-                    return FormatName("gdk_pixbuf-2.0");
-                default:
-                    throw new ArgumentException("Unknown lib: " + dll);
-            }
-        }
-
-        static IntPtr LoadDll(IDynamicLibraryLoader  loader, GtkDll dll)
-        {
-            
-            var exceptions = new List<Exception>();
-
-            var name = GetDllName(dll);
-            if (Custom?.TrySystemFirst != false)
-            {
-                try
-                {
-                    return loader.LoadLibrary(name);
-                }
-                catch (Exception e)
-                {
-                    exceptions.Add(e);
-                }
-            }
-            var path = Custom?.Lookup(dll);
-            if (path == null && Custom?.BasePath != null)
-                path = Path.Combine(Custom.BasePath, name);
-            if (path != null)
-            {
-                try
-                {
-                    return loader.LoadLibrary(path);
-                }
-                catch (Exception e)
-                {
-                    exceptions.Add(e);
-                }
-            }
-            throw new AggregateException("Unable to load " + dll, exceptions);
-        }
-
-        public static void Resolve(string basePath = null)
-        {
-            var loader = AvaloniaLocator.Current.GetService<IDynamicLibraryLoader>();
-
-            var dlls = Enum.GetValues(typeof(GtkDll)).Cast<GtkDll>().ToDictionary(x => x, x => LoadDll(loader, x));
-            
-            foreach (var fieldInfo in typeof(Native).GetTypeInfo().DeclaredFields)
-            {
-                var import = fieldInfo.FieldType.GetTypeInfo().GetCustomAttributes(typeof(GtkImportAttribute), true).Cast<GtkImportAttribute>().FirstOrDefault();
-                if(import == null)
-                    continue;
-                IntPtr lib = dlls[import.Dll];
-
-                var funcPtr =  loader.GetProcAddress(lib, import.Name ?? fieldInfo.FieldType.Name, import.Optional);
-
-                if (funcPtr != IntPtr.Zero)
-                    fieldInfo.SetValue(null, Marshal.GetDelegateForFunctionPointer(funcPtr, fieldInfo.FieldType));
-            }
-
-            var nativeHandleNames = new[] { "gdk_win32_window_get_handle", "gdk_x11_window_get_xid", "gdk_quartz_window_get_nswindow" };
-            foreach (var name in nativeHandleNames)
-            {
-                var ptr = loader.GetProcAddress(dlls[GtkDll.Gdk], name, true);
-                if (ptr == IntPtr.Zero)
-                    continue;
-                Native.GetNativeGdkWindowHandle = (Native.D.gdk_get_native_handle) Marshal
-                    .GetDelegateForFunctionPointer(ptr, typeof(Native.D.gdk_get_native_handle));
-            }
-            if (Native.GetNativeGdkWindowHandle == null)
-                throw new Exception($"Unable to locate any of [{string.Join(", ", nativeHandleNames)}] in libgdk");
-
-        }
-
-
-    }
-}
-

+ 0 - 47
src/Gtk/Avalonia.Gtk3/Interop/Signal.cs

@@ -1,47 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using Avalonia.Platform.Interop;
-
-namespace Avalonia.Gtk3.Interop
-{
-    class Signal
-    {
-        class ConnectedSignal : IDisposable
-        {
-            private readonly GObject _instance;
-            private GCHandle _handle;
-            private readonly ulong _id;
-
-            public ConnectedSignal(GObject instance, GCHandle handle, ulong id)
-            {
-                _instance = instance;
-                Native.GObjectRef(instance);
-                _handle = handle;
-                _id = id;
-            }
-
-            public void Dispose()
-            {
-                if (_handle.IsAllocated)
-                {
-                    Native.GObjectUnref(_instance.DangerousGetHandle());
-                    Native.GSignalHandlerDisconnect(_instance, _id);
-                    _handle.Free();
-                }
-            }
-        }
-
-        public static IDisposable Connect<T>(GObject obj, string name, T handler) 
-        {
-            var handle = GCHandle.Alloc(handler);
-            var ptr = Marshal.GetFunctionPointerForDelegate((Delegate)(object)handler);
-            using (var utf = new Utf8Buffer(name))
-            {
-                var id = Native.GSignalConnectObject(obj, utf, ptr, IntPtr.Zero, 0);
-                if (id == 0)
-                    throw new ArgumentException("Unable to connect to signal " + name);
-                return new ConnectedSignal(obj, handle, id);
-            }
-        }
-    }
-}

+ 0 - 230
src/Gtk/Avalonia.Gtk3/KeyTransform.cs

@@ -1,230 +0,0 @@
-using System.Collections.Generic;
-using Avalonia.Gtk3;
-using Avalonia.Input;
-
-namespace Avalonia.Gtk.Common
-{
-    static class KeyTransform
-    {
-        private static readonly Dictionary<GdkKey, Key> KeyDic = new Dictionary<GdkKey, Key>
-        {
-            { GdkKey.Cancel, Key.Cancel },
-            { GdkKey.BackSpace, Key.Back },
-            { GdkKey.Tab, Key.Tab },
-            { GdkKey.Linefeed, Key.LineFeed },
-            { GdkKey.Clear, Key.Clear },
-            { GdkKey.Return, Key.Return },
-            { GdkKey.KP_Enter, Key.Return },
-            { GdkKey.Pause, Key.Pause },
-            { GdkKey.Caps_Lock, Key.CapsLock },
-            //{ GdkKey.?, Key.HangulMode }
-            //{ GdkKey.?, Key.JunjaMode }
-            //{ GdkKey.?, Key.FinalMode }
-            //{ GdkKey.?, Key.KanjiMode }
-            { GdkKey.Escape, Key.Escape },
-            //{ GdkKey.?, Key.ImeConvert }
-            //{ GdkKey.?, Key.ImeNonConvert }
-            //{ GdkKey.?, Key.ImeAccept }
-            //{ GdkKey.?, Key.ImeModeChange }
-            { GdkKey.space, Key.Space },
-            { GdkKey.Prior, Key.Prior },
-            { GdkKey.KP_Prior, Key.Prior },
-            { GdkKey.Page_Down, Key.PageDown },
-            { GdkKey.KP_Page_Down, Key.PageDown },
-            { GdkKey.End, Key.End },
-            { GdkKey.KP_End, Key.End },
-            { GdkKey.Home, Key.Home },
-            { GdkKey.KP_Home, Key.Home },
-            { GdkKey.Left, Key.Left },
-            { GdkKey.KP_Left, Key.Left },
-            { GdkKey.Up, Key.Up },
-            { GdkKey.KP_Up, Key.Up },
-            { GdkKey.Right, Key.Right },
-            { GdkKey.KP_Right, Key.Right },
-            { GdkKey.Down, Key.Down },
-            { GdkKey.KP_Down, Key.Down },
-            { GdkKey.Select, Key.Select },
-            { GdkKey.Print, Key.Print },
-            { GdkKey.Execute, Key.Execute },
-            //{ GdkKey.?, Key.Snapshot }
-            { GdkKey.Insert, Key.Insert },
-            { GdkKey.KP_Insert, Key.Insert },
-            { GdkKey.Delete, Key.Delete },
-            { GdkKey.KP_Delete, Key.Delete },
-            { GdkKey.Help, Key.Help },
-            { GdkKey.Key_0, Key.D0 },
-            { GdkKey.Key_1, Key.D1 },
-            { GdkKey.Key_2, Key.D2 },
-            { GdkKey.Key_3, Key.D3 },
-            { GdkKey.Key_4, Key.D4 },
-            { GdkKey.Key_5, Key.D5 },
-            { GdkKey.Key_6, Key.D6 },
-            { GdkKey.Key_7, Key.D7 },
-            { GdkKey.Key_8, Key.D8 },
-            { GdkKey.Key_9, Key.D9 },
-            { GdkKey.A, Key.A },
-            { GdkKey.B, Key.B },
-            { GdkKey.C, Key.C },
-            { GdkKey.D, Key.D },
-            { GdkKey.E, Key.E },
-            { GdkKey.F, Key.F },
-            { GdkKey.G, Key.G },
-            { GdkKey.H, Key.H },
-            { GdkKey.I, Key.I },
-            { GdkKey.J, Key.J },
-            { GdkKey.K, Key.K },
-            { GdkKey.L, Key.L },
-            { GdkKey.M, Key.M },
-            { GdkKey.N, Key.N },
-            { GdkKey.O, Key.O },
-            { GdkKey.P, Key.P },
-            { GdkKey.Q, Key.Q },
-            { GdkKey.R, Key.R },
-            { GdkKey.S, Key.S },
-            { GdkKey.T, Key.T },
-            { GdkKey.U, Key.U },
-            { GdkKey.V, Key.V },
-            { GdkKey.W, Key.W },
-            { GdkKey.X, Key.X },
-            { GdkKey.Y, Key.Y },
-            { GdkKey.Z, Key.Z },
-            { GdkKey.a, Key.A },
-            { GdkKey.b, Key.B },
-            { GdkKey.c, Key.C },
-            { GdkKey.d, Key.D },
-            { GdkKey.e, Key.E },
-            { GdkKey.f, Key.F },
-            { GdkKey.g, Key.G },
-            { GdkKey.h, Key.H },
-            { GdkKey.i, Key.I },
-            { GdkKey.j, Key.J },
-            { GdkKey.k, Key.K },
-            { GdkKey.l, Key.L },
-            { GdkKey.m, Key.M },
-            { GdkKey.n, Key.N },
-            { GdkKey.o, Key.O },
-            { GdkKey.p, Key.P },
-            { GdkKey.q, Key.Q },
-            { GdkKey.r, Key.R },
-            { GdkKey.s, Key.S },
-            { GdkKey.t, Key.T },
-            { GdkKey.u, Key.U },
-            { GdkKey.v, Key.V },
-            { GdkKey.w, Key.W },
-            { GdkKey.x, Key.X },
-            { GdkKey.y, Key.Y },
-            { GdkKey.z, Key.Z },
-            //{ GdkKey.?, Key.LWin }
-            //{ GdkKey.?, Key.RWin }
-            { GdkKey.Menu, Key.Apps },
-            //{ GdkKey.?, Key.Sleep }
-            { GdkKey.KP_0, Key.NumPad0 },
-            { GdkKey.KP_1, Key.NumPad1 },
-            { GdkKey.KP_2, Key.NumPad2 },
-            { GdkKey.KP_3, Key.NumPad3 },
-            { GdkKey.KP_4, Key.NumPad4 },
-            { GdkKey.KP_5, Key.NumPad5 },
-            { GdkKey.KP_6, Key.NumPad6 },
-            { GdkKey.KP_7, Key.NumPad7 },
-            { GdkKey.KP_8, Key.NumPad8 },
-            { GdkKey.KP_9, Key.NumPad9 },
-            { GdkKey.multiply, Key.Multiply },
-            { GdkKey.KP_Multiply, Key.Multiply },
-            { GdkKey.KP_Add, Key.Add },
-            //{ GdkKey.?, Key.Separator }
-            { GdkKey.KP_Subtract, Key.Subtract },
-            { GdkKey.KP_Decimal, Key.Decimal },
-            { GdkKey.KP_Divide, Key.Divide },
-            { GdkKey.F1, Key.F1 },
-            { GdkKey.F2, Key.F2 },
-            { GdkKey.F3, Key.F3 },
-            { GdkKey.F4, Key.F4 },
-            { GdkKey.F5, Key.F5 },
-            { GdkKey.F6, Key.F6 },
-            { GdkKey.F7, Key.F7 },
-            { GdkKey.F8, Key.F8 },
-            { GdkKey.F9, Key.F9 },
-            { GdkKey.F10, Key.F10 },
-            { GdkKey.F11, Key.F11 },
-            { GdkKey.F12, Key.F12 },
-            { GdkKey.L3, Key.F13 },
-            { GdkKey.F14, Key.F14 },
-            { GdkKey.L5, Key.F15 },
-            { GdkKey.F16, Key.F16 },
-            { GdkKey.F17, Key.F17 },
-            { GdkKey.L8, Key.F18 },
-            { GdkKey.L9, Key.F19 },
-            { GdkKey.L10, Key.F20 },
-            { GdkKey.R1, Key.F21 },
-            { GdkKey.R2, Key.F22 },
-            { GdkKey.F23, Key.F23 },
-            { GdkKey.R4, Key.F24 },
-            { GdkKey.Num_Lock, Key.NumLock },
-            { GdkKey.Scroll_Lock, Key.Scroll },
-            { GdkKey.Shift_L, Key.LeftShift },
-            { GdkKey.Shift_R, Key.RightShift },
-            { GdkKey.Control_L, Key.LeftCtrl },
-            { GdkKey.Control_R, Key.RightCtrl },
-            { GdkKey.Alt_L, Key.LeftAlt },
-            { GdkKey.Alt_R, Key.RightAlt },
-            //{ GdkKey.?, Key.BrowserBack }
-            //{ GdkKey.?, Key.BrowserForward }
-            //{ GdkKey.?, Key.BrowserRefresh }
-            //{ GdkKey.?, Key.BrowserStop }
-            //{ GdkKey.?, Key.BrowserSearch }
-            //{ GdkKey.?, Key.BrowserFavorites }
-            //{ GdkKey.?, Key.BrowserHome }
-            //{ GdkKey.?, Key.VolumeMute }
-            //{ GdkKey.?, Key.VolumeDown }
-            //{ GdkKey.?, Key.VolumeUp }
-            //{ GdkKey.?, Key.MediaNextTrack }
-            //{ GdkKey.?, Key.MediaPreviousTrack }
-            //{ GdkKey.?, Key.MediaStop }
-            //{ GdkKey.?, Key.MediaPlayPause }
-            //{ GdkKey.?, Key.LaunchMail }
-            //{ GdkKey.?, Key.SelectMedia }
-            //{ GdkKey.?, Key.LaunchApplication1 }
-            //{ GdkKey.?, Key.LaunchApplication2 }
-            { GdkKey.semicolon, Key.OemSemicolon },
-            { GdkKey.plus, Key.OemPlus },
-            { GdkKey.equal, Key.OemPlus },
-            { GdkKey.comma, Key.OemComma },
-            { GdkKey.minus, Key.OemMinus },
-            { GdkKey.period, Key.OemPeriod },
-            { GdkKey.slash, Key.Oem2 },
-            { GdkKey.grave, Key.OemTilde },
-            //{ GdkKey.?, Key.AbntC1 }
-            //{ GdkKey.?, Key.AbntC2 }
-            { GdkKey.bracketleft, Key.OemOpenBrackets },
-            { GdkKey.backslash, Key.OemPipe },
-            { GdkKey.bracketright, Key.OemCloseBrackets },
-            { GdkKey.apostrophe, Key.OemQuotes },
-            //{ GdkKey.?, Key.Oem8 }
-            //{ GdkKey.?, Key.Oem102 }
-            //{ GdkKey.?, Key.ImeProcessed }
-            //{ GdkKey.?, Key.System }
-            //{ GdkKey.?, Key.OemAttn }
-            //{ GdkKey.?, Key.OemFinish }
-            //{ GdkKey.?, Key.DbeHiragana }
-            //{ GdkKey.?, Key.OemAuto }
-            //{ GdkKey.?, Key.DbeDbcsChar }
-            //{ GdkKey.?, Key.OemBackTab }
-            //{ GdkKey.?, Key.Attn }
-            //{ GdkKey.?, Key.DbeEnterWordRegisterMode }
-            //{ GdkKey.?, Key.DbeEnterImeConfigureMode }
-            //{ GdkKey.?, Key.EraseEof }
-            //{ GdkKey.?, Key.Play }
-            //{ GdkKey.?, Key.Zoom }
-            //{ GdkKey.?, Key.NoName }
-            //{ GdkKey.?, Key.DbeEnterDialogConversionMode }
-            //{ GdkKey.?, Key.OemClear }
-            //{ GdkKey.?, Key.DeadCharProcessed }
-        };
-
-        public static Key ConvertKey(GdkKey key)
-        {
-            Key result;
-            return KeyDic.TryGetValue(key, out result) ? result : Key.None;
-        }
-    }
-}

+ 0 - 20
src/Gtk/Avalonia.Gtk3/PlatformIconLoader.cs

@@ -1,20 +0,0 @@
-using System.IO;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Platform;
-
-namespace Avalonia.Gtk3
-{
-    class PlatformIconLoader : IPlatformIconLoader
-    {
-        public IWindowIconImpl LoadIcon(string fileName) => Pixbuf.NewFromFile(fileName);
-
-        public IWindowIconImpl LoadIcon(Stream stream) => Pixbuf.NewFromStream(stream);
-
-        public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
-        {
-            var ms = new MemoryStream();
-            bitmap.Save(ms);
-            return Pixbuf.NewFromBytes(ms.ToArray());
-        }
-    }
-}

+ 0 - 19
src/Gtk/Avalonia.Gtk3/PopupImpl.cs

@@ -1,19 +0,0 @@
-using Avalonia.Gtk3.Interop;
-using Avalonia.Platform;
-
-namespace Avalonia.Gtk3
-{
-    class PopupImpl : WindowBaseImpl, IPopupImpl
-    {
-        static GtkWindow CreateWindow()
-        {
-            var window = Native.GtkWindowNew(GtkWindowType.Popup);
-            return window;
-        }
-
-        public PopupImpl() : base(CreateWindow())
-        {
-            OverrideRedirect = true;
-        }
-    }
-}

+ 0 - 10
src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs

@@ -1,10 +0,0 @@
-using System.Reflection;
-using Avalonia.Gtk3;
-using Avalonia.Platform;
-
-// 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: ExportWindowingSubsystem(OperatingSystemType.WinNT, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]
-[assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 1, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]
-[assembly: ExportWindowingSubsystem(OperatingSystemType.OSX, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]

+ 0 - 8
src/Gtk/Avalonia.Gtk3/README.md

@@ -1,8 +0,0 @@
-P/Invoke based GTK3 backend
-===========================
-
-Code is EXPERIMENTAL at this point. It also needs Direct2D/Skia for rendering.
-
-Windows GTK3 binaries aren't included in the repo, you need to download them from https://sourceforge.net/projects/gtk3win/
-
-On Linux it should work out of the box with system-provided GTK3. On OSX you should be able to wire GTK3 using DYLD_LIBRARY_PATH environment variable.

+ 0 - 56
src/Gtk/Avalonia.Gtk3/ScreenImpl.cs

@@ -1,56 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Platform;
-
-namespace Avalonia.Gtk3
-{
-    internal class ScreenImpl : IScreenImpl
-    {
-        public int ScreenCount
-        {
-            get => _allScreens.Length;
-        }
-        
-        private Screen[] _allScreens;
-        public IReadOnlyList<Screen> AllScreens
-        {
-            get
-            {
-                if (_allScreens == null)
-                {
-                    IntPtr display = Native.GdkGetDefaultDisplay();
-                    GdkScreen screen = Native.GdkDisplayGetDefaultScreen(display);
-                    short primary = Native.GdkScreenGetPrimaryMonitor(screen);
-                    Screen[] screens = new Screen[Native.GdkScreenGetNMonitors(screen)];
-                    for (short i = 0; i < screens.Length; i++)
-                    {
-                        GdkRectangle workArea = new GdkRectangle(), geometry = new GdkRectangle();
-                        Native.GdkScreenGetMonitorGeometry(screen, i, ref geometry);
-                        Native.GdkScreenGetMonitorWorkarea(screen, i, ref workArea);
-                        PixelRect workAreaRect = new PixelRect(workArea.X, workArea.Y, workArea.Width, workArea.Height);
-                        PixelRect geometryRect = new PixelRect(geometry.X, geometry.Y, geometry.Width, geometry.Height);
-                        GtkScreen s = new GtkScreen(geometryRect, workAreaRect, i == primary, i);
-                        screens[i] = s;
-                    }
-
-                    _allScreens = screens;
-                }
-
-                return _allScreens;
-            }
-        }
-
-        public ScreenImpl()
-        {
-            IntPtr display = Native.GdkGetDefaultDisplay();
-            GdkScreen screen = Native.GdkDisplayGetDefaultScreen(display);
-            Signal.Connect<Native.D.monitors_changed>(screen, "monitors-changed", MonitorsChanged);
-        }
-
-        private unsafe void MonitorsChanged(IntPtr screen, IntPtr userData)
-        {
-            _allScreens = null;
-        }
-    }
-}

+ 0 - 110
src/Gtk/Avalonia.Gtk3/SystemDialogs.cs

@@ -1,110 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Avalonia.Controls;
-using Avalonia.Controls.Platform;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Platform;
-using Avalonia.Platform.Interop;
-
-namespace Avalonia.Gtk3
-{
-    class SystemDialogBase
-    {
-
-        public unsafe static Task<string[]> ShowDialog(string title, GtkWindow parent, GtkFileChooserAction action,
-            bool multiselect, string initialFileName, Action<GtkFileChooser> modify)
-        {
-            GtkFileChooser dlg;
-            parent = parent ?? GtkWindow.Null;
-            using (var name = new Utf8Buffer(title))
-                dlg = Native.GtkFileChooserDialogNew(name, parent, action, IntPtr.Zero);
-            modify?.Invoke(dlg);
-            if (multiselect)
-                Native.GtkFileChooserSetSelectMultiple(dlg, true);
-
-            Native.GtkWindowSetModal(dlg, true);
-            var tcs = new TaskCompletionSource<string[]>();
-            List<IDisposable> disposables = null;
-            Action dispose = () =>
-            {
-                // ReSharper disable once PossibleNullReferenceException
-                foreach (var d in disposables)
-                    d.Dispose();
-                disposables.Clear();
-            };
-            disposables = new List<IDisposable>
-            {
-                Signal.Connect<Native.D.signal_generic>(dlg, "close", delegate
-                {
-                    tcs.TrySetResult(null);
-                    dispose();
-                    return false;
-                }),
-                Signal.Connect<Native.D.signal_dialog_response>(dlg, "response", (_, resp, __) =>
-                {
-                    string[] result = null;
-                    if (resp == GtkResponseType.Accept)
-                    {
-                        var rlst = new List<string>();
-                        var gs = Native.GtkFileChooserGetFilenames(dlg);
-                        var cgs = gs;
-                        while (cgs != null)
-                        {
-                            if (cgs->Data != IntPtr.Zero)
-                                rlst.Add(Utf8Buffer.StringFromPtr(cgs->Data));
-                            cgs = cgs->Next;
-                        }
-
-                        Native.GSlistFree(gs);
-                        result = rlst.ToArray();
-                    }
-
-                    Native.GtkWidgetHide(dlg);
-                    dispose();
-                    tcs.TrySetResult(result);
-                    return false;
-                }),
-                dlg
-            };
-            using (var open = new Utf8Buffer("Open"))
-                Native.GtkDialogAddButton(dlg, open, GtkResponseType.Accept);
-            using (var open = new Utf8Buffer("Cancel"))
-                Native.GtkDialogAddButton(dlg, open, GtkResponseType.Cancel);
-            if (initialFileName != null)
-                using (var fn = new Utf8Buffer(initialFileName))
-                    Native.GtkFileChooserSetFilename(dlg, fn);
-            Native.GtkWindowPresent(dlg);
-            return tcs.Task;
-        }
-
-        public Task<string[]> ShowFileDialogAsync(FileDialog dialog, GtkWindow parent,
-            Action<GtkFileChooser> modify = null)
-        {
-            return ShowDialog(dialog.Title, parent,
-                dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save,
-                (dialog as OpenFileDialog)?.AllowMultiple ?? false,
-                Path.Combine(string.IsNullOrEmpty(dialog.InitialDirectory) ? "" : dialog.InitialDirectory,
-                    string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName), modify);
-        }
-
-        public async Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, GtkWindow parent,
-            Action<GtkFileChooser> modify = null)
-        {
-            var res = await ShowDialog(dialog.Title, parent,
-                GtkFileChooserAction.SelectFolder, false, dialog.InitialDirectory, modify);
-            return res?.FirstOrDefault();
-        }
-    }
-
-    class SystemDialog : SystemDialogBase, ISystemDialogImpl
-    {
-        public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
-            => ShowFolderDialogAsync(dialog, ((WindowBaseImpl)parent)?.GtkWidget);
-
-        public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
-            => ShowFileDialogAsync(dialog, ((WindowBaseImpl)parent)?.GtkWidget);
-    }
-}

+ 0 - 527
src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs

@@ -1,527 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Threading;
-using Avalonia.Controls;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Input;
-using Avalonia.Input.Raw;
-using Avalonia.OpenGL;
-using Avalonia.Platform;
-using Avalonia.Platform.Interop;
-using Avalonia.Rendering;
-using Avalonia.Threading;
-
-namespace Avalonia.Gtk3
-{
-    abstract class WindowBaseImpl : IWindowBaseImpl, IPlatformHandle, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
-    {
-        public readonly GtkWindow GtkWidget;
-        private IInputRoot _inputRoot;
-        private readonly GtkImContext _imContext;
-        private readonly FramebufferManager _framebuffer;
-        private readonly EglGlPlatformSurface _egl;
-        protected readonly List<IDisposable> Disposables = new List<IDisposable>();
-        private Size _lastSize;
-        private PixelPoint _lastPosition;
-        private double _lastScaling;
-        private uint _lastKbdEvent;
-        private uint _lastSmoothScrollEvent;
-        private GCHandle _gcHandle;
-        private object _lock = new object();
-        private IDeferredRenderOperation _nextRenderOperation;
-        private readonly AutoResetEvent _canSetNextOperation = new AutoResetEvent(true);
-        internal IntPtr? GdkWindowHandle;
-        private bool _overrideRedirect;
-        private uint? _tickCallback;
-        public WindowBaseImpl(GtkWindow gtkWidget)
-        {
-            
-            GtkWidget = gtkWidget;
-            
-            var glf = AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>() as EglGlPlatformFeature;
-            if (glf != null)
-                _egl = new EglGlPlatformSurface((EglDisplay)glf.Display, glf.DeferredContext, this);
-            else
-                _framebuffer = new FramebufferManager(this);
-            
-            _imContext = Native.GtkImMulticontextNew();
-            Disposables.Add(_imContext);
-            Native.GtkWidgetSetEvents(gtkWidget, 0xFFFFFE);
-            Disposables.Add(Signal.Connect<Native.D.signal_commit>(_imContext, "commit", OnCommit));
-            Connect<Native.D.signal_widget_draw>("draw", OnDraw);
-            Connect<Native.D.signal_generic>("realize", OnRealized);
-            ConnectEvent("configure-event", OnConfigured);
-            ConnectEvent("button-press-event", OnButton);
-            ConnectEvent("button-release-event", OnButton);
-            ConnectEvent("motion-notify-event", OnMotion);
-            ConnectEvent("scroll-event", OnScroll);
-            ConnectEvent("window-state-event", OnStateChanged);
-            ConnectEvent("key-press-event", OnKeyEvent);
-            ConnectEvent("key-release-event", OnKeyEvent);
-            ConnectEvent("leave-notify-event", OnLeaveNotifyEvent);
-            ConnectEvent("delete-event", OnClosingEvent);
-            Connect<Native.D.signal_generic>("destroy", OnDestroy);
-            Native.GtkWidgetRealize(gtkWidget);
-            GdkWindowHandle = this.Handle.Handle;
-            _lastSize = ClientSize;
-
-            if (_egl != null)
-                Native.GtkWidgetSetDoubleBuffered(gtkWidget, false);
-            else if (Gtk3Platform.UseDeferredRendering)
-            {
-                Native.GtkWidgetSetDoubleBuffered(gtkWidget, false);
-                _gcHandle = GCHandle.Alloc(this);
-                _tickCallback = Native.GtkWidgetAddTickCallback(GtkWidget, PinnedStaticCallback,
-                    GCHandle.ToIntPtr(_gcHandle), IntPtr.Zero);
-            }
-        }
-
-        private bool OnConfigured(IntPtr gtkwidget, IntPtr ev, IntPtr userdata)
-        {
-            int w, h;
-            if (!OverrideRedirect)
-            {
-                Native.GtkWindowGetSize(GtkWidget, out w, out h);
-                var size = ClientSize = new Size(w, h);
-                if (_lastSize != size)
-                {
-                    Resized?.Invoke(size);
-                    _lastSize = size;
-                }
-            }
-            var pos = Position;
-            if (_lastPosition != pos)
-            {
-                PositionChanged?.Invoke(pos);
-                _lastPosition = pos;
-            }
-            var scaling = Scaling;
-            if (_lastScaling != scaling)
-            {
-                ScalingChanged?.Invoke(scaling);
-                _lastScaling = scaling;
-            }
-            return false;
-        }
-
-        private bool OnRealized(IntPtr gtkwidget, IntPtr userdata)
-        {
-            Native.GtkImContextSetClientWindow(_imContext, Native.GtkWidgetGetWindow(GtkWidget));
-            return false;
-        }
-
-        private bool OnDestroy(IntPtr gtkwidget, IntPtr userdata)
-        {
-            DoDispose(true);
-            return false;
-        }
-
-        private static InputModifiers GetModifierKeys(GdkModifierType state)
-        {
-            var rv = InputModifiers.None;
-            if (state.HasFlag(GdkModifierType.ControlMask))
-                rv |= InputModifiers.Control;
-            if (state.HasFlag(GdkModifierType.ShiftMask))
-                rv |= InputModifiers.Shift;
-            if (state.HasFlag(GdkModifierType.Mod1Mask))
-                rv |= InputModifiers.Alt;
-            if (state.HasFlag(GdkModifierType.Button1Mask))
-                rv |= InputModifiers.LeftMouseButton;
-            if (state.HasFlag(GdkModifierType.Button2Mask))
-                rv |= InputModifiers.RightMouseButton;
-            if (state.HasFlag(GdkModifierType.Button3Mask))
-                rv |= InputModifiers.MiddleMouseButton;
-            return rv;
-        }
-
-        private unsafe bool OnClosingEvent(IntPtr w, IntPtr ev, IntPtr userdata)
-        {
-            bool? preventClosing = Closing?.Invoke();
-            return preventClosing ?? false;
-        }
-
-        private unsafe bool OnButton(IntPtr w, IntPtr ev, IntPtr userdata)
-        {
-            var evnt = (GdkEventButton*)ev;
-            var e = new RawPointerEventArgs(
-                Gtk3Platform.Mouse,
-                evnt->time,
-                _inputRoot,
-                evnt->type == GdkEventType.ButtonRelease
-                    ? evnt->button == 1
-                        ? RawPointerEventType.LeftButtonUp
-                        : evnt->button == 3 ? RawPointerEventType.RightButtonUp : RawPointerEventType.MiddleButtonUp
-                    : evnt->button == 1
-                        ? RawPointerEventType.LeftButtonDown
-                        : evnt->button == 3 ? RawPointerEventType.RightButtonDown : RawPointerEventType.MiddleButtonDown,
-                new Point(evnt->x, evnt->y), GetModifierKeys(evnt->state));
-            OnInput(e);
-            return true;
-        }
-
-        protected virtual unsafe bool OnStateChanged(IntPtr w, IntPtr pev, IntPtr userData)
-        {
-            var ev = (GdkEventWindowState*) pev;
-            if (ev->changed_mask.HasFlag(GdkWindowState.Focused))
-            {
-                if(ev->new_window_state.HasFlag(GdkWindowState.Focused))
-                    Activated?.Invoke();
-                else
-                    Deactivated?.Invoke();
-            }
-            return true;
-        }
-
-        private unsafe bool OnMotion(IntPtr w, IntPtr ev, IntPtr userdata)
-        {
-            var evnt = (GdkEventMotion*)ev;
-            var position = new Point(evnt->x, evnt->y);
-            Native.GdkEventRequestMotions(ev);
-            var e = new RawPointerEventArgs(
-                Gtk3Platform.Mouse,
-                evnt->time,
-                _inputRoot,
-                RawPointerEventType.Move,
-                position, GetModifierKeys(evnt->state));
-            OnInput(e);
-            
-            return true;
-        }
-        private unsafe bool OnScroll(IntPtr w, IntPtr ev, IntPtr userdata)
-        {
-            var evnt = (GdkEventScroll*)ev;
-
-            //Ignore duplicates
-            if (evnt->time - _lastSmoothScrollEvent < 10 && evnt->direction != GdkScrollDirection.Smooth)
-                return true;
-
-            var delta = new Vector();
-            const double step = (double) 1;
-            if (evnt->direction == GdkScrollDirection.Down)
-                delta = new Vector(0, -step);
-            else if (evnt->direction == GdkScrollDirection.Up)
-                delta = new Vector(0, step);
-            else if (evnt->direction == GdkScrollDirection.Right)
-                delta = new Vector(-step, 0);
-            else if (evnt->direction == GdkScrollDirection.Left)
-                delta = new Vector(step, 0);
-            else if (evnt->direction == GdkScrollDirection.Smooth)
-            {
-                delta = new Vector(-evnt->delta_x, -evnt->delta_y);
-                _lastSmoothScrollEvent = evnt->time;
-            }
-            var e = new RawMouseWheelEventArgs(Gtk3Platform.Mouse, evnt->time, _inputRoot,
-                new Point(evnt->x, evnt->y), delta, GetModifierKeys(evnt->state));
-            OnInput(e);
-            return true;
-        }
-
-        private unsafe bool OnKeyEvent(IntPtr w, IntPtr pev, IntPtr userData)
-        {
-            var evnt = (GdkEventKey*) pev;
-            _lastKbdEvent = evnt->time;
-            var e = new RawKeyEventArgs(
-                Gtk3Platform.Keyboard,
-                evnt->time,
-                evnt->type == GdkEventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
-                Avalonia.Gtk.Common.KeyTransform.ConvertKey((GdkKey)evnt->keyval), GetModifierKeys((GdkModifierType)evnt->state));
-            OnInput(e);
-            if (Native.GtkImContextFilterKeypress(_imContext, pev))
-                return true;
-            return true;
-        }
-
-        private unsafe bool OnLeaveNotifyEvent(IntPtr w, IntPtr pev, IntPtr userData)
-        {
-            var evnt = (GdkEventCrossing*) pev;
-            var position = new Point(evnt->x, evnt->y);
-            OnInput(new RawPointerEventArgs(Gtk3Platform.Mouse,
-                evnt->time,
-                _inputRoot,
-                RawPointerEventType.Move,
-                position, GetModifierKeys(evnt->state)));
-            return true;
-        }
-
-        private unsafe bool OnCommit(IntPtr gtkwidget, IntPtr utf8string, IntPtr userdata)
-        {
-            OnInput(new RawTextInputEventArgs(Gtk3Platform.Keyboard, _lastKbdEvent, Utf8Buffer.StringFromPtr(utf8string)));
-            return true;
-        }
-
-        protected void ConnectEvent(string name, Native.D.signal_onevent handler) 
-            => Disposables.Add(Signal.Connect<Native.D.signal_onevent>(GtkWidget, name, handler));
-        void Connect<T>(string name, T handler) => Disposables.Add(Signal.Connect(GtkWidget, name, handler));
-
-        internal IntPtr CurrentCairoContext { get; private set; }
-
-        private bool OnDraw(IntPtr gtkwidget, IntPtr cairocontext, IntPtr userdata)
-        {
-            if (!Gtk3Platform.UseDeferredRendering)
-            {
-                CurrentCairoContext = cairocontext;
-                Paint?.Invoke(new Rect(ClientSize));
-                CurrentCairoContext = IntPtr.Zero;
-            }
-            else
-                Paint?.Invoke(new Rect(ClientSize));
-            return true;
-        }
-
-        private static Native.D.TickCallback PinnedStaticCallback = StaticTickCallback;
-
-        static bool StaticTickCallback(IntPtr widget, IntPtr clock, IntPtr userData)
-        {
-            var impl = (WindowBaseImpl) GCHandle.FromIntPtr(userData).Target;
-            impl.OnRenderTick();
-            return true;
-        }
-
-        public void SetNextRenderOperation(IDeferredRenderOperation op)
-        {
-            while (true)
-            {
-                lock (_lock)
-                {
-                    if (_nextRenderOperation == null)
-                    {
-                        _nextRenderOperation = op;
-                        return;
-                    }
-                }
-                _canSetNextOperation.WaitOne();
-            }
-            
-        }
-
-        private void OnRenderTick()
-        {
-            IDeferredRenderOperation op = null;
-            lock (_lock)
-            {
-                if (_nextRenderOperation != null)
-                {
-                    op = _nextRenderOperation;
-                    _nextRenderOperation = null;
-                }
-                _canSetNextOperation.Set();
-            }
-            if (op != null)
-            {
-                op?.RenderNow(null);
-                op?.Dispose();
-            }
-        }
-
-
-        public void Dispose() => DoDispose(false);
-        
-        void DoDispose(bool fromDestroy)
-        {
-            if (_tickCallback.HasValue)
-            {
-                if (!GtkWidget.IsClosed)
-                    Native.GtkWidgetRemoveTickCallback(GtkWidget, _tickCallback.Value);
-                _tickCallback = null;
-            }
-            
-            //We are calling it here, since signal handler will be detached
-            if (!GtkWidget.IsClosed)
-                Closed?.Invoke();
-            foreach(var d in Disposables.AsEnumerable().Reverse())
-                d.Dispose();
-            Disposables.Clear();
-            
-            if (!fromDestroy && !GtkWidget.IsClosed)
-                Native.GtkWindowClose(GtkWidget);
-            GtkWidget.Dispose();
-            
-            if (_gcHandle.IsAllocated)
-            {
-                _gcHandle.Free();
-            }
-        }
-
-        public Size MaxClientSize
-        {
-            get
-            {
-                var s = Native.GtkWidgetGetScreen(GtkWidget);
-                return new Size(Native.GdkScreenGetWidth(s), Native.GdkScreenGetHeight(s));
-            }
-        }
-
-        public void SetMinMaxSize(Size minSize, Size maxSize)
-        {
-            if (GtkWidget.IsClosed)
-                return;
-
-            GdkGeometry geometry = new GdkGeometry();
-            geometry.min_width = minSize.Width > 0 ? (int)minSize.Width : -1;
-            geometry.min_height = minSize.Height > 0 ? (int)minSize.Height : -1;
-            geometry.max_width = !Double.IsInfinity(maxSize.Width) && maxSize.Width > 0 ? (int)maxSize.Width : 999999;
-            geometry.max_height = !Double.IsInfinity(maxSize.Height) && maxSize.Height > 0 ? (int)maxSize.Height : 999999;
-
-            Native.GtkWindowSetGeometryHints(GtkWidget, IntPtr.Zero, ref geometry, GdkWindowHints.GDK_HINT_MIN_SIZE | GdkWindowHints.GDK_HINT_MAX_SIZE);
-        } 
-
-        public IMouseDevice MouseDevice => Gtk3Platform.Mouse;
-
-        public double Scaling => LastKnownScaleFactor = (int) (Native.GtkWidgetGetScaleFactor?.Invoke(GtkWidget) ?? 1);
-
-        public IPlatformHandle Handle => this;
-
-        string IPlatformHandle.HandleDescriptor => "HWND";
-
-        public Action Activated { get; set; }
-        public Func<bool> Closing { get; set; }
-        public Action Closed { get; set; }
-        public Action Deactivated { get; set; }
-        public Action<RawInputEventArgs> Input { get; set; }
-        public Action<Rect> Paint { get; set; }
-        public Action<Size> Resized { get; set; }
-        public Action<double> ScalingChanged { get; set; } //TODO
-        public Action<PixelPoint> PositionChanged { get; set; }
-
-        public void Activate() => Native.GtkWidgetActivate(GtkWidget);
-
-        public void Invalidate(Rect rect)
-        {
-            if(GtkWidget.IsClosed)
-                return;
-            var s = ClientSize;
-            Native.GtkWidgetQueueDrawArea(GtkWidget, 0, 0, (int) s.Width, (int) s.Height);
-        }
-
-        public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
-
-        void OnInput(RawInputEventArgs args)
-        {
-            Dispatcher.UIThread.Post(() => Input?.Invoke(args), DispatcherPriority.Input);
-        }
-
-        public Point PointToClient(PixelPoint point)
-        {
-            int x, y;
-            Native.GdkWindowGetOrigin(Native.GtkWidgetGetWindow(GtkWidget), out x, out y);
-
-            return new Point(point.X - x, point.Y - y);
-        }
-
-        public PixelPoint PointToScreen(Point point)
-        {
-            int x, y;
-            Native.GdkWindowGetOrigin(Native.GtkWidgetGetWindow(GtkWidget), out x, out y);
-            return new PixelPoint((int)(point.X + x), (int)(point.Y + y));
-        }
-
-        public void SetCursor(IPlatformHandle cursor)
-        {
-            if (GtkWidget.IsClosed)
-                return;
-            Native.GdkWindowSetCursor(Native.GtkWidgetGetWindow(GtkWidget), cursor?.Handle ??  IntPtr.Zero);
-        }
-
-        public virtual void Show() => Native.GtkWindowPresent(GtkWidget);
-
-        public void Hide() => Native.GtkWidgetHide(GtkWidget);
-
-        public void SetTopmost(bool value) => Native.GtkWindowSetKeepAbove(GtkWidget, value);
-
-        void GetGlobalPointer(out int x, out int y)
-        {
-            int mask;
-            Native.GdkWindowGetPointer(Native.GdkScreenGetRootWindow(Native.GtkWidgetGetScreen(GtkWidget)),
-                out x, out y, out mask);
-        }
-
-        public void BeginMoveDrag()
-        {
-            int x, y;
-            GetGlobalPointer(out x, out y);
-            Native.GdkWindowBeginMoveDrag(Native.GtkWidgetGetWindow(GtkWidget), 1, x, y, 0);
-        }
-
-        public void BeginResizeDrag(WindowEdge edge)
-        {
-            int x, y;
-            GetGlobalPointer(out x, out y);
-            Native.GdkWindowBeginResizeDrag(Native.GtkWidgetGetWindow(GtkWidget), edge, 1, x, y, 0);
-        }
-
-
-        public Size ClientSize { get; private set; }
-        public int LastKnownScaleFactor { get; private set; }
-
-        public void Resize(Size value)
-        {
-            if (GtkWidget.IsClosed)
-                return;
-         
-            Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height);
-            if (OverrideRedirect)
-            {
-                var size = ClientSize = value;
-                if (_lastSize != size)
-                {
-                    Resized?.Invoke(size);
-                    _lastSize = size;
-                }
-            }
-        }
-
-        public bool OverrideRedirect
-        {
-            get => _overrideRedirect;
-            set
-            {
-                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
-                {
-                    Native.GdkWindowSetOverrideRedirect(Native.GtkWidgetGetWindow(GtkWidget), value);
-                    _overrideRedirect = value;
-                }
-            }
-        }
-        
-        public IScreenImpl Screen
-        {
-            get;
-        } = new ScreenImpl();
-
-        public PixelPoint Position
-        {
-            get
-            {
-                int x, y;
-                Native.GtkWindowGetPosition(GtkWidget, out x, out y);
-                return new PixelPoint(x, y);
-            }
-            set { Native.GtkWindowMove(GtkWidget, (int)value.X, (int)value.Y); }
-        }
-
-        IntPtr IPlatformHandle.Handle => Native.GetNativeGdkWindowHandle(Native.GtkWidgetGetWindow(GtkWidget));
-        public IEnumerable<object> Surfaces => new object[] {Handle, _egl, _framebuffer};
-
-        public IRenderer CreateRenderer(IRenderRoot root)
-        {
-            var loop = AvaloniaLocator.Current.GetService<IRenderLoop>();
-            return Gtk3Platform.UseDeferredRendering
-                ? (IRenderer) new DeferredRenderer(root, loop)
-                : new ImmediateRenderer(root);
-        }
-
-        PixelSize EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Size
-        {
-            get
-            {
-                var cs = ClientSize;
-                return new PixelSize((int)Math.Max(1, LastKnownScaleFactor * cs.Width),
-                    (int)Math.Max(1, LastKnownScaleFactor * ClientSize.Height));
-            }
-        }
-        double EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Scaling => LastKnownScaleFactor;
-        IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle;
-    }
-}

+ 0 - 102
src/Gtk/Avalonia.Gtk3/WindowImpl.cs

@@ -1,102 +0,0 @@
-using System;
-using Avalonia.Controls;
-using Avalonia.Gtk3.Interop;
-using Avalonia.Platform;
-using Avalonia.Platform.Interop;
-
-namespace Avalonia.Gtk3
-{
-    class WindowImpl : WindowBaseImpl, IWindowImpl
-    {
-        private WindowState _lastWindowState;
-
-        public WindowImpl() : base(Native.GtkWindowNew(GtkWindowType.TopLevel))
-        {
-        }
-
-        protected unsafe override bool OnStateChanged(IntPtr w, IntPtr pev, IntPtr userData)
-        {
-            var windowStateEvent = (GdkEventWindowState*)pev;
-            var newWindowState = windowStateEvent->new_window_state;
-            var windowState = newWindowState.HasFlag(GdkWindowState.Iconified) ? WindowState.Minimized
-                : (newWindowState.HasFlag(GdkWindowState.Maximized) ? WindowState.Maximized : WindowState.Normal);
-
-            if (windowState != _lastWindowState)
-            {
-                _lastWindowState = windowState;
-                WindowStateChanged?.Invoke(windowState);
-            }
-
-            return base.OnStateChanged(w, pev, userData);
-        }
-
-        public void SetTitle(string title)
-        {
-            using (var t = new Utf8Buffer(title))
-                Native.GtkWindowSetTitle(GtkWidget, t);
-        }
-
-        public WindowState WindowState
-        {
-            get
-            {
-                var state = Native.GdkWindowGetState(Native.GtkWidgetGetWindow(GtkWidget));
-                if (state.HasFlag(GdkWindowState.Iconified))
-                    return WindowState.Minimized;
-                if (state.HasFlag(GdkWindowState.Maximized))
-                    return WindowState.Maximized;
-                return WindowState.Normal;
-            }
-            set
-            {
-                if (value == WindowState.Minimized)
-                    Native.GtkWindowIconify(GtkWidget);
-                else if (value == WindowState.Maximized)
-                    Native.GtkWindowMaximize(GtkWidget);
-                else
-                {
-                    Native.GtkWindowUnmaximize(GtkWidget);
-                    Native.GtkWindowDeiconify(GtkWidget);
-                }
-            }
-        }
-
-        public Action<WindowState> WindowStateChanged { get; set; }
-
-        public void ShowDialog(IWindowImpl parent)
-        {
-            Native.GtkWindowSetModal(GtkWidget, true);
-            Native.GtkWindowSetTransientFor(GtkWidget, ((WindowImpl)parent).GtkWidget.DangerousGetHandle());
-            Native.GtkWindowPresent(GtkWidget);
-        }
-
-        public override void Show()
-        {
-            Native.GtkWindowSetModal(GtkWidget, false);
-            Native.GtkWindowSetTransientFor(GtkWidget, IntPtr.Zero);
-            Native.GtkWindowPresent(GtkWidget);
-        }
-
-        public void SetSystemDecorations(bool enabled) => Native.GtkWindowSetDecorated(GtkWidget, enabled);
-
-        public void SetIcon(IWindowIconImpl icon) => Native.GtkWindowSetIcon(GtkWidget, (Pixbuf) icon);
-
-        public void SetCoverTaskbarWhenMaximized(bool enable)
-        {
-            //Why do we even have that?
-        }
-
-        public void ShowTaskbarIcon(bool value) => Native.GtkWindowSetSkipTaskbarHint(GtkWidget, !value);
-
-        public void CanResize(bool value) => Native.GtkWindowSetResizable(GtkWidget, value);
-
-
-        class EmptyDisposable : IDisposable
-        {
-            public void Dispose()
-            {
-
-            }
-        }
-    }
-}

+ 0 - 78
src/Gtk/Avalonia.Gtk3/X11.cs

@@ -1,78 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Avalonia.Gtk3
-{
-    class X11
-    {
-        [DllImport("libX11.so.6")]
-        public static extern IntPtr XInitThreads();
-        
-        [DllImport("libX11.so.6")]
-        public static extern IntPtr XOpenDisplay(IntPtr name);
-        
-        [DllImport("libX11.so.6")]
-        public static extern IntPtr XLockDisplay(IntPtr display);
-        
-        [DllImport("libX11.so.6")]
-        public static extern IntPtr XUnlockDisplay(IntPtr display);
-        
-        [DllImport("libX11.so.6")]
-        public static extern IntPtr XFreeGC(IntPtr display, IntPtr gc);
-        
-        [DllImport("libX11.so.6")]
-        public static extern IntPtr XCreateGC(IntPtr display, IntPtr drawable, ulong valuemask, IntPtr values);
-        
-        [DllImport("libX11.so.6")]
-        public static extern int XInitImage(ref XImage image);
-        
-        [DllImport("libX11.so.6")]
-        public static extern int XDestroyImage(ref XImage image);
-        
-        [DllImport("libX11.so.6")]
-        public static extern IntPtr XSetErrorHandler(XErrorHandler handler);
-
-        [DllImport("libX11.so.6")]
-        public static extern int XSync(IntPtr display, bool discard);
-
-        public delegate int XErrorHandler(IntPtr display, ref XErrorEvent error);
-
-        [DllImport("libX11.so.6")]
-        public static extern int XPutImage(IntPtr display, IntPtr drawable, IntPtr gc, ref XImage image,
-            int srcx, int srcy, int destx, int desty, uint width, uint height);
-
-        [StructLayout(LayoutKind.Sequential)]
-        public unsafe struct XErrorEvent
-        {
-            public int type;
-            public IntPtr* display; /* Display the event was read from */
-            public ulong serial; /* serial number of failed request */
-            public byte error_code; /* error code of failed request */
-            public byte request_code; /* Major op-code of failed request */
-            public byte minor_code; /* Minor op-code of failed request */
-            public IntPtr resourceid; /* resource id */
-        }
-
-        [StructLayout(LayoutKind.Sequential)]
-        public unsafe struct XImage
-        {
-            public int width, height; /* size of image */
-            public int xoffset; /* number of pixels offset in X direction */
-            public int format; /* XYBitmap, XYPixmap, ZPixmap */
-            public IntPtr data; /* pointer to image data */
-            public int byte_order; /* data byte order, LSBFirst, MSBFirst */
-            public int bitmap_unit; /* quant. of scanline 8, 16, 32 */
-            public int bitmap_bit_order; /* LSBFirst, MSBFirst */
-            public int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */
-            public int depth; /* depth of image */
-            public int bytes_per_line; /* accelerator to next scanline */
-            public int bits_per_pixel; /* bits per pixel (ZPixmap) */
-            public ulong red_mask; /* bits in z arrangement */
-            public ulong green_mask;
-            public ulong blue_mask;
-            private fixed byte funcs[128];
-        }
-        
-        
-    }
-}

+ 0 - 55
src/Gtk/Avalonia.Gtk3/X11Framebuffer.cs

@@ -1,55 +0,0 @@
-using System;
-using Avalonia.Platform;
-
-namespace Avalonia.Gtk3
-{
-    class X11Framebuffer : ILockedFramebuffer
-    {
-        private readonly IntPtr _display;
-        private readonly IntPtr _xid;
-        private IUnmanagedBlob _blob;
-
-        public X11Framebuffer(IntPtr display, IntPtr xid, int width, int height, int factor)
-        {
-            _display = display;
-            _xid = xid;
-            Size = new PixelSize(width * factor, height * factor);
-            RowBytes = Size.Width * 4;
-            Dpi = new Vector(96, 96) * factor;
-            Format = PixelFormat.Bgra8888;
-            _blob = AvaloniaLocator.Current.GetService<IRuntimePlatform>().AllocBlob(RowBytes * Size.Height);
-            Address = _blob.Address;
-        }
-        
-        public void Dispose()
-        {
-            var image = new X11.XImage();
-            int bitsPerPixel = 32;
-            image.width = Size.Width;
-            image.height = Size.Height;
-            image.format = 2; //ZPixmap;
-            image.data = Address;
-            image.byte_order = 0;// LSBFirst;
-            image.bitmap_unit = bitsPerPixel;
-            image.bitmap_bit_order = 0;// LSBFirst;
-            image.bitmap_pad = bitsPerPixel;
-            image.depth = 24;
-            image.bytes_per_line = RowBytes - Size.Width * 4;
-            image.bits_per_pixel = bitsPerPixel;
-            X11.XLockDisplay(_display);
-            X11.XInitImage(ref image);
-            var gc = X11.XCreateGC(_display, _xid, 0, IntPtr.Zero);
-            X11.XPutImage(_display, _xid, gc, ref image, 0, 0, 0, 0, (uint)Size.Width, (uint)Size.Height);
-            X11.XFreeGC(_display, gc);
-            X11.XSync(_display, true);
-            X11.XUnlockDisplay(_display);
-            _blob.Dispose();
-        }
-
-        public IntPtr Address { get; }
-        public PixelSize Size { get; }
-        public int RowBytes { get; }
-        public Vector Dpi { get; }
-        public PixelFormat Format { get; }
-    }
-}

+ 1 - 1
src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs

@@ -18,7 +18,7 @@ namespace Avalonia.LinuxFramebuffer
         {
             _fb = fb;
             Invalidate(default(Rect));
-            var mice = new Mice(ClientSize.Width, ClientSize.Height);
+            var mice = new Mice(this, ClientSize.Width, ClientSize.Height);
             mice.Start();
             mice.Event += e => Input?.Invoke(e);
         }

+ 1 - 3
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebuffer.cs

@@ -43,12 +43,10 @@ namespace Avalonia.LinuxFramebuffer
 
                 SetBpp();
 
-                _varInfo.yoffset = 100;
                 if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOPUT_VSCREENINFO, pnfo))
                     _varInfo.transp = new fb_bitfield();
 
-                if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOPUT_VSCREENINFO, pnfo))
-                    throw new Exception("FBIOPUT_VSCREENINFO error: " + Marshal.GetLastWin32Error());
+                NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOPUT_VSCREENINFO, pnfo);
 
                 if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_VSCREENINFO, pnfo))
                     throw new Exception("FBIOGET_VSCREENINFO error: " + Marshal.GetLastWin32Error());

+ 55 - 19
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@@ -2,6 +2,7 @@
 using System.Diagnostics;
 using System.Threading;
 using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Controls.Embedding;
 using Avalonia.Controls.Platform;
 using Avalonia.Input;
@@ -21,7 +22,6 @@ namespace Avalonia.LinuxFramebuffer
         private static readonly Stopwatch St = Stopwatch.StartNew();
         internal static uint Timestamp => (uint)St.ElapsedTicks;
         public static InternalPlatformThreadingInterface Threading;
-        public static FramebufferToplevelImpl TopLevel;
         LinuxFramebufferPlatform(string fbdev = null)
         {
             _fb = new LinuxFramebuffer(fbdev);
@@ -41,37 +41,73 @@ namespace Avalonia.LinuxFramebuffer
                 .Bind<IRenderTimer>().ToConstant(Threading);
         }
 
-        internal static TopLevel Initialize<T>(T builder, string fbdev = null) where T : AppBuilderBase<T>, new()
+        internal static LinuxFramebufferLifetime Initialize<T>(T builder, string fbdev = null) where T : AppBuilderBase<T>, new()
         {
             var platform = new LinuxFramebufferPlatform(fbdev);
-            builder.UseSkia().UseWindowingSubsystem(platform.Initialize, "fbdev")
-                .SetupWithoutStarting();
-            var tl = new EmbeddableControlRoot(TopLevel = new FramebufferToplevelImpl(platform._fb));
-            tl.Prepare();
-            return tl;
+            builder.UseSkia().UseWindowingSubsystem(platform.Initialize, "fbdev");
+            return new LinuxFramebufferLifetime(platform._fb);
         }
     }
-}
 
-public static class LinuxFramebufferPlatformExtensions
-{
-    class TokenClosable : ICloseable
+    class LinuxFramebufferLifetime : IControlledApplicationLifetime, ISingleViewApplicationLifetime
     {
-        public event EventHandler Closed;
+        private readonly LinuxFramebuffer _fb;
+        private TopLevel _topLevel;
+        private readonly CancellationTokenSource _cts = new CancellationTokenSource();
+        public CancellationToken Token => _cts.Token;
 
-        public TokenClosable(CancellationToken token)
+        public LinuxFramebufferLifetime(LinuxFramebuffer fb)
+        {
+            _fb = fb;
+        }
+        
+        public Control MainView
         {
-            token.Register(() => Dispatcher.UIThread.Post(() => Closed?.Invoke(this, new EventArgs())));
+            get => (Control)_topLevel?.Content;
+            set
+            {
+                if (_topLevel == null)
+                {
+
+                    var tl = new EmbeddableControlRoot(new FramebufferToplevelImpl(_fb));
+                    tl.Prepare();
+                    _topLevel = tl;
+                }
+                _topLevel.Content = value;
+            }
+        }
+
+        public int ExitCode { get; private set; }
+        public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
+        public event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit;
+
+        public void Start(string[] args)
+        {
+            Startup?.Invoke(this, new ControlledApplicationLifetimeStartupEventArgs(args));
+        }
+        
+        public void Shutdown(int exitCode)
+        {
+            ExitCode = exitCode;
+            var e = new ControlledApplicationLifetimeExitEventArgs(exitCode);
+            Exit?.Invoke(this, e);
+            ExitCode = e.ApplicationExitCode;
+            _cts.Cancel();
         }
     }
+}
 
-    public static void InitializeWithLinuxFramebuffer<T>(this T builder, Action<TopLevel> setup,
-        CancellationToken stop = default(CancellationToken), string fbdev = null)
+public static class LinuxFramebufferPlatformExtensions
+{
+    public static int StartLinuxFramebuffer<T>(this T builder, string[] args, string fbdev = null)
         where T : AppBuilderBase<T>, new()
     {
-        setup(LinuxFramebufferPlatform.Initialize(builder, fbdev));
-        builder.BeforeStartCallback(builder);
-        builder.Instance.Run(new TokenClosable(stop));
+        var lifetime = LinuxFramebufferPlatform.Initialize(builder, fbdev);
+        builder.Instance.ApplicationLifetime = lifetime;
+        builder.SetupWithoutStarting();
+        lifetime.Start(args);
+        builder.Instance.Run(lifetime.Token);
+        return lifetime.ExitCode;
     }
 }
 

+ 7 - 5
src/Linux/Avalonia.LinuxFramebuffer/Mice.cs

@@ -7,8 +7,9 @@ using Avalonia.Platform;
 
 namespace Avalonia.LinuxFramebuffer
 {
-    public unsafe class Mice
+    unsafe class Mice
     {
+        private readonly FramebufferToplevelImpl _topLevel;
         private readonly double _width;
         private readonly double _height;
         private double _x;
@@ -16,8 +17,9 @@ namespace Avalonia.LinuxFramebuffer
 
         public event Action<RawInputEventArgs> Event;
 
-        public Mice(double width, double height)
+        public Mice(FramebufferToplevelImpl topLevel, double width, double height)
         {
+            _topLevel = topLevel;
             _width = width;
             _height = height;
         }
@@ -78,7 +80,7 @@ namespace Avalonia.LinuxFramebuffer
                     return;
                 Event?.Invoke(new RawPointerEventArgs(LinuxFramebufferPlatform.MouseDevice,
                     LinuxFramebufferPlatform.Timestamp,
-                    LinuxFramebufferPlatform.TopLevel.InputRoot, RawPointerEventType.Move, new Point(_x, _y),
+                    _topLevel.InputRoot, RawPointerEventType.Move, new Point(_x, _y),
                     InputModifiers.None));
             }
             if (ev.type ==(int) EvType.EV_ABS)
@@ -91,7 +93,7 @@ namespace Avalonia.LinuxFramebuffer
                     return;
                 Event?.Invoke(new RawPointerEventArgs(LinuxFramebufferPlatform.MouseDevice,
                     LinuxFramebufferPlatform.Timestamp,
-                    LinuxFramebufferPlatform.TopLevel.InputRoot, RawPointerEventType.Move, new Point(_x, _y),
+                    _topLevel.InputRoot, RawPointerEventType.Move, new Point(_x, _y),
                     InputModifiers.None));
             }
             if (ev.type == (short) EvType.EV_KEY)
@@ -108,7 +110,7 @@ namespace Avalonia.LinuxFramebuffer
 
                 Event?.Invoke(new RawPointerEventArgs(LinuxFramebufferPlatform.MouseDevice,
                     LinuxFramebufferPlatform.Timestamp,
-                    LinuxFramebufferPlatform.TopLevel.InputRoot, type.Value, new Point(_x, _y), default(InputModifiers)));
+                    _topLevel.InputRoot, type.Value, new Point(_x, _y), default(InputModifiers)));
             }
         }
     }

+ 0 - 8
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs

@@ -2,18 +2,10 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
-using System.Collections.Generic;
-using System.ComponentModel;
 using System.IO;
-using System.Linq;
 using System.Reflection;
-using System.Runtime.Serialization;
 using System.Text;
-using System.Xml.Linq;
 using Avalonia.Markup.Xaml.XamlIl;
-using Avalonia.Controls;
-using Avalonia.Markup.Data;
-using Avalonia.Markup.Xaml.PortableXaml;
 using Avalonia.Platform;
 
 namespace Avalonia.Markup.Xaml

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@@ -1 +1 @@
-Subproject commit 610cda30c69e32e83c8235060606480904c937bc
+Subproject commit 894b2c02827fd5eb16a338de5d5b6c9fbc60fef5

+ 12 - 16
src/Markup/Avalonia.Markup/Data/MultiBinding.cs

@@ -64,14 +64,19 @@ namespace Avalonia.Data
             object anchor = null,
             bool enableDataValidation = false)
         {
-            if (Converter == null)
+            var targetType = targetProperty?.PropertyType ?? typeof(object);
+            var converter = Converter;
+            // We only respect `StringFormat` if the type of the property we're assigning to will
+            // accept a string. Note that this is slightly different to WPF in that WPF only applies
+            // `StringFormat` for target type `string` (not `object`).
+            if (!string.IsNullOrWhiteSpace(StringFormat) && 
+                (targetType == typeof(string) || targetType == typeof(object)))
             {
-                throw new NotSupportedException("MultiBinding without Converter not currently supported.");
+                converter = new StringFormatMultiValueConverter(StringFormat, converter);
             }
-
-            var targetType = targetProperty?.PropertyType ?? typeof(object);
+            
             var children = Bindings.Select(x => x.Initiate(target, null));
-            var input = children.Select(x => x.Observable).CombineLatest().Select(x => ConvertValue(x, targetType));
+            var input = children.Select(x => x.Observable).CombineLatest().Select(x => ConvertValue(x, targetType, converter));
             var mode = Mode == BindingMode.Default ?
                 targetProperty?.GetMetadata(target.GetType()).DefaultBindingMode : Mode;
 
@@ -87,10 +92,10 @@ namespace Avalonia.Data
             }
         }
 
-        private object ConvertValue(IList<object> values, Type targetType)
+        private object ConvertValue(IList<object> values, Type targetType, IMultiValueConverter converter)
         {
             var culture = CultureInfo.CurrentCulture;
-            var converted = Converter.Convert(values, targetType, ConverterParameter, culture);
+            var converted = converter.Convert(values, targetType, ConverterParameter, culture);
 
             if (converted == BindingOperations.DoNothing)
             {
@@ -102,15 +107,6 @@ namespace Avalonia.Data
                 converted = FallbackValue;
             }
 
-            // We only respect `StringFormat` if the type of the property we're assigning to will
-            // accept a string. Note that this is slightly different to WPF in that WPF only applies
-            // `StringFormat` for target type `string` (not `object`).
-            if (!string.IsNullOrWhiteSpace(StringFormat) && 
-                (targetType == typeof(string) || targetType == typeof(object)))
-            {
-                converted = string.Format(culture, StringFormat, converted);
-            }
-
             return converted;
         }
     }

+ 0 - 120
tests/Avalonia.Controls.UnitTests/ApplicationTests.cs

@@ -11,113 +11,6 @@ namespace Avalonia.Controls.UnitTests
 {
     public class ApplicationTests
     {
-        [Fact]
-        public void Should_Exit_After_MainWindow_Closed()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
-
-                var hasExit = false;
-
-                Application.Current.Exit += (s, e) => hasExit = true;
-
-                var mainWindow = new Window();
-
-                mainWindow.Show();
-
-                Application.Current.MainWindow = mainWindow;
-
-                var window = new Window();
-
-                window.Show();
-
-                mainWindow.Close();
-
-                Assert.True(hasExit);
-            }
-        }
-
-        [Fact]
-        public void Should_Exit_After_Last_Window_Closed()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                Application.Current.ShutdownMode = ShutdownMode.OnLastWindowClose;
-
-                var hasExit = false;
-
-                Application.Current.Exit += (s, e) => hasExit = true;
-
-                var windowA = new Window();
-
-                windowA.Show();
-
-                var windowB = new Window();
-
-                windowB.Show();
-
-                windowA.Close();
-
-                Assert.False(hasExit);
-
-                windowB.Close();
-
-                Assert.True(hasExit);
-            }
-        }
-
-        [Fact]
-        public void Should_Only_Exit_On_Explicit_Exit()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
-
-                var hasExit = false;
-
-                Application.Current.Exit += (s, e) => hasExit = true;
-
-                var windowA = new Window();
-
-                windowA.Show();
-
-                var windowB = new Window();
-
-                windowB.Show();
-
-                windowA.Close();
-
-                Assert.False(hasExit);
-
-                windowB.Close();
-
-                Assert.False(hasExit);
-
-                Application.Current.Shutdown();
-
-                Assert.True(hasExit);
-            }
-        }
-
-        [Fact]
-        public void Should_Close_All_Remaining_Open_Windows_After_Explicit_Exit_Call()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                var windows = new List<Window> { new Window(), new Window(), new Window(), new Window() };
-
-                foreach (var window in windows)
-                {
-                    window.Show();
-                }
-
-                Application.Current.Shutdown();
-
-                Assert.Empty(Application.Current.Windows);
-            }
-        }
-
         [Fact]
         public void Throws_ArgumentNullException_On_Run_If_MainWindow_Is_Null()
         {
@@ -142,18 +35,5 @@ namespace Avalonia.Controls.UnitTests
                 Assert.True(raised);
             }
         }
-
-        [Fact]
-        public void Should_Set_ExitCode_After_Shutdown()
-        {
-            using (UnitTestApplication.Start(TestServices.MockThreadingInterface))
-            {
-                Application.Current.Shutdown(1337);
-
-                var exitCode = Application.Current.Run();
-
-                Assert.Equal(1337, exitCode);
-            }
-        }
     }
 }

+ 1 - 3
tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs

@@ -59,9 +59,7 @@ namespace Avalonia.Controls.UnitTests
                 };
 
                 var window = new Window { Content = target };
-
-                Avalonia.Application.Current.MainWindow = window;
-
+                
                 _mouse.Click(target, MouseButton.Right);
 
                 Assert.True(sut.IsOpen);

+ 213 - 0
tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs

@@ -0,0 +1,213 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Platform;
+using Avalonia.Threading;
+using Avalonia.UnitTests;
+using Moq;
+using Xunit;
+
+namespace Avalonia.Controls.UnitTests
+{
+    
+    public class DesktopStyleApplicationLifetimeTests
+    {
+        [Fact]
+        public void Should_Set_ExitCode_After_Shutdown()
+        {
+            using (UnitTestApplication.Start(TestServices.MockThreadingInterface))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))    
+            {
+                lifetime.Shutdown(1337);
+
+                var exitCode = lifetime.Start(Array.Empty<string>());
+
+                Assert.Equal(1337, exitCode);
+            }
+        }
+        
+        
+        [Fact]
+        public void Should_Close_All_Remaining_Open_Windows_After_Explicit_Exit_Call()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))
+            {
+                var windows = new List<Window> { new Window(), new Window(), new Window(), new Window() };
+
+                foreach (var window in windows)
+                {
+                    window.Show();
+                }
+                Assert.Equal(4, lifetime.Windows.Count);
+                lifetime.Shutdown();
+
+                Assert.Empty(lifetime.Windows);
+            }
+        }
+        
+        [Fact]
+        public void Should_Only_Exit_On_Explicit_Exit()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))
+            {
+                lifetime.ShutdownMode = ShutdownMode.OnExplicitShutdown;
+
+                var hasExit = false;
+
+                lifetime.Exit += (s, e) => hasExit = true;
+
+                var windowA = new Window();
+
+                windowA.Show();
+
+                var windowB = new Window();
+
+                windowB.Show();
+
+                windowA.Close();
+
+                Assert.False(hasExit);
+
+                windowB.Close();
+
+                Assert.False(hasExit);
+
+                lifetime.Shutdown();
+
+                Assert.True(hasExit);
+            }
+        }
+        
+        [Fact]
+        public void Should_Exit_After_MainWindow_Closed()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))
+            {
+                lifetime.ShutdownMode = ShutdownMode.OnMainWindowClose;
+
+                var hasExit = false;
+
+                lifetime.Exit += (s, e) => hasExit = true;
+
+                var mainWindow = new Window();
+
+                mainWindow.Show();
+
+                lifetime.MainWindow = mainWindow;
+
+                var window = new Window();
+
+                window.Show();
+
+                mainWindow.Close();
+
+                Assert.True(hasExit);
+            }
+        }
+
+        [Fact]
+        public void Should_Exit_After_Last_Window_Closed()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))
+            {
+                lifetime.ShutdownMode = ShutdownMode.OnLastWindowClose;
+
+                var hasExit = false;
+
+                lifetime.Exit += (s, e) => hasExit = true;
+
+                var windowA = new Window();
+
+                windowA.Show();
+
+                var windowB = new Window();
+
+                windowB.Show();
+
+                windowA.Close();
+
+                Assert.False(hasExit);
+
+                windowB.Close();
+
+                Assert.True(hasExit);
+            }
+        }
+        
+        [Fact]
+        public void Show_Should_Add_Window_To_OpenWindows()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))
+            {
+                var window = new Window();
+
+                window.Show();
+
+                Assert.Equal(new[] { window }, lifetime.Windows);
+            }
+        }
+
+        [Fact]
+        public void Window_Should_Be_Added_To_OpenWindows_Only_Once()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))
+            {
+                var window = new Window();
+
+                window.Show();
+                window.Show();
+                window.IsVisible = true;
+
+                Assert.Equal(new[] { window }, lifetime.Windows);
+
+                window.Close();
+            }
+        }
+
+        [Fact]
+        public void Close_Should_Remove_Window_From_OpenWindows()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))
+            {
+                var window = new Window();
+
+                window.Show();
+                Assert.Equal(1, lifetime.Windows.Count);
+                window.Close();
+
+                Assert.Empty(lifetime.Windows);
+            }
+        }
+        
+        [Fact]
+        public void Impl_Closing_Should_Remove_Window_From_OpenWindows()
+        {
+            var windowImpl = new Mock<IWindowImpl>();
+            windowImpl.SetupProperty(x => x.Closed);
+            windowImpl.Setup(x => x.Scaling).Returns(1);
+
+            var services = TestServices.StyledWindow.With(
+                windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object));
+
+            using (UnitTestApplication.Start(services))
+            using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current))
+            {
+                var window = new Window();
+
+                window.Show();
+                Assert.Equal(1, lifetime.Windows.Count);
+                windowImpl.Object.Closed();
+
+                Assert.Empty(lifetime.Windows);
+            }
+        }
+    }
+    
+}

+ 38 - 1
tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs

@@ -8,6 +8,7 @@ using Avalonia.Controls.Templates;
 using Avalonia.Data;
 using Avalonia.Markup.Data;
 using Avalonia.Styling;
+using Avalonia.UnitTests;
 using Xunit;
 
 namespace Avalonia.Controls.UnitTests.Primitives
@@ -22,6 +23,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Minimum = 100,
                 Maximum = 50,
             };
+            var root = new TestRoot(target);
 
             Assert.Equal(100, target.Minimum);
             Assert.Equal(100, target.Maximum);
@@ -36,6 +38,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Maximum = 50,
                 Value = 100,
             };
+            var root = new TestRoot(target);
 
             Assert.Equal(0, target.Minimum);
             Assert.Equal(50, target.Maximum);
@@ -51,6 +54,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Maximum = 100,
                 Value = 50,
             };
+            var root = new TestRoot(target);
 
             target.Minimum = 200;
 
@@ -68,6 +72,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Maximum = 100,
                 Value = 100,
             };
+            var root = new TestRoot(target);
 
             target.Maximum = 50;
 
@@ -160,6 +165,38 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.Equal(expected, track.Value);
         }
 
+        [Fact]
+        public void Coercion_Should_Not_Be_Done_During_Initialization()
+        {
+            var target = new TestRange();
+
+            target.BeginInit();
+
+            var root = new TestRoot(target);
+            target.Minimum = 1;
+            Assert.Equal(0, target.Value);
+
+            target.Value = 50;
+            target.EndInit();
+
+            Assert.Equal(50, target.Value);
+        }
+
+        [Fact]
+        public void Coercion_Should_Be_Done_After_Initialization()
+        {
+            var target = new TestRange();
+
+            target.BeginInit();
+
+            var root = new TestRoot(target);
+            target.Minimum = 1;
+
+            target.EndInit();
+
+            Assert.Equal(1, target.Value);
+        }
+
         private class TestRange : RangeBase
         {
         }
@@ -199,4 +236,4 @@ namespace Avalonia.Controls.UnitTests.Primitives
             }
         }
     }
-}
+}

+ 113 - 2
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@@ -536,6 +536,9 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 SelectedIndex = 1,
             };
 
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
             var called = false;
 
             target.SelectionChanged += (s, e) =>
@@ -545,8 +548,6 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 called = true;
             };
 
-            target.ApplyTemplate();
-            target.Presenter.ApplyTemplate();
             target.SelectedIndex = -1;
 
             Assert.True(called);
@@ -783,6 +784,116 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.Equal(2, vm.Child.SelectedIndex);
         }
 
+        [Fact]
+        public void Should_Select_Correct_Item_When_Duplicate_Items_Are_Present()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz"},
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
+
+            Assert.Equal(3, target.SelectedIndex);
+        }
+
+        [Fact]
+        public void Should_Apply_Selected_Pseudoclass_To_Correct_Item_When_Duplicate_Items_Are_Present()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
+
+            Assert.Equal(new[] { ":selected" }, target.Presenter.Panel.Children[3].Classes);
+        }
+
+        [Fact]
+        public void Adding_Item_Before_SelectedItem_Should_Update_SelectedIndex()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "Baz"
+            };
+
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = items,
+                SelectedIndex = 1,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            items.Insert(0, "Qux");
+
+            Assert.Equal(2, target.SelectedIndex);
+            Assert.Equal("Bar", target.SelectedItem);
+        }
+
+        [Fact]
+        public void Removing_Item_Before_SelectedItem_Should_Update_SelectedIndex()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "Baz"
+            };
+
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = items,
+                SelectedIndex = 1,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            items.RemoveAt(0);
+
+            Assert.Equal(0, target.SelectedIndex);
+            Assert.Equal("Bar", target.SelectedItem);
+        }
+
+        [Fact]
+        public void Replacing_Selected_Item_Should_Update_SelectedItem()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "Baz"
+            };
+
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = items,
+                SelectedIndex = 1,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            items[1] = "Qux";
+
+            Assert.Equal(1, target.SelectedIndex);
+            Assert.Equal("Qux", target.SelectedItem);
+        }
+
         private FuncControlTemplate Template()
         {
             return new FuncControlTemplate<SelectingItemsControl>(control =>

+ 493 - 30
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs

@@ -4,12 +4,15 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.Linq;
 using Avalonia.Collections;
 using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.Data;
+using Avalonia.Input;
+using Avalonia.Interactivity;
 using Avalonia.Markup.Data;
 using Xunit;
 
@@ -17,6 +20,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
 {
     public class SelectingItemsControlTests_Multiple
     {
+        private MouseTestHelper _helper = new MouseTestHelper();
+
         [Fact]
         public void Setting_SelectedIndex_Should_Add_To_SelectedItems()
         {
@@ -258,31 +263,25 @@ namespace Avalonia.Controls.UnitTests.Primitives
         }
 
         [Fact]
-        public void Replacing_First_SelectedItem_Should_Update_SelectedItem_SelectedIndex()
+        public void Setting_SelectedIndex_Should_Unmark_Previously_Selected_Containers()
         {
-            var items = new[]
-            {
-                new ListBoxItem(),
-                new ListBoxItem(),
-                new ListBoxItem(),
-            };
-
             var target = new TestSelector
             {
-                Items = items,
+                Items = new[] { "foo", "bar", "baz" },
                 Template = Template(),
             };
 
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
-            target.SelectedIndex = 1;
-            target.SelectedItems[0] = items[2];
 
-            Assert.Equal(2, target.SelectedIndex);
-            Assert.Equal(items[2], target.SelectedItem);
-            Assert.False(items[0].IsSelected);
-            Assert.False(items[1].IsSelected);
-            Assert.True(items[2].IsSelected);
+            target.SelectedItems.Add("foo");
+            target.SelectedItems.Add("bar");
+
+            Assert.Equal(new[] { 0, 1 }, SelectedContainers(target));
+
+            target.SelectedIndex = 2;
+
+            Assert.Equal(new[] { 2 }, SelectedContainers(target));
         }
 
         [Fact]
@@ -361,6 +360,52 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.Equal(new[] { "baz", "qux", "qiz" }, target.SelectedItems.Cast<object>().ToList());
         }
 
+        [Fact]
+        public void Setting_SelectedIndex_After_Range_Should_Unmark_Previously_Selected_Containers()
+        {
+            var target = new TestSelector
+            {
+                Items = new[] { "foo", "bar", "baz", "qux" },
+                Template = Template(),
+                SelectedIndex = 0,
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            target.SelectRange(2);
+
+            Assert.Equal(new[] { 0, 1, 2 }, SelectedContainers(target));
+
+            target.SelectedIndex = 3;
+
+            Assert.Equal(new[] { 3 }, SelectedContainers(target));
+        }
+
+        [Fact]
+        public void Toggling_Selection_After_Range_Should_Work()
+        {
+            var target = new TestSelector
+            {
+                Items = new[] { "foo", "bar", "baz", "foo", "bar", "baz" },
+                Template = Template(),
+                SelectedIndex = 0,
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            target.SelectRange(3);
+
+            Assert.Equal(new[] { 0, 1, 2, 3 }, SelectedContainers(target));
+
+            target.Toggle(4);
+
+            Assert.Equal(new[] { 0, 1, 2, 3, 4 }, SelectedContainers(target));
+        }
+
         [Fact]
         public void Suprious_SelectedIndex_Changes_Should_Not_Be_Triggered()
         {
@@ -382,6 +427,40 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.Equal(new[] { -1, 1, 0 }, selectedIndexes);
         }
 
+        [Fact]
+        public void Can_Set_SelectedIndex_To_Another_Selected_Item()
+        {
+            var target = new TestSelector
+            {
+                Items = new[] { "foo", "bar", "baz" },
+                Template = Template(),
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            target.SelectedItems.Add("foo");
+            target.SelectedItems.Add("bar");
+
+            Assert.Equal(0, target.SelectedIndex);
+            Assert.Equal(new[] { "foo", "bar" }, target.SelectedItems);
+            Assert.Equal(new[] { 0, 1 }, SelectedContainers(target));
+
+            var raised = false;
+            target.SelectionChanged += (s, e) =>
+            {
+                raised = true;
+                Assert.Empty(e.AddedItems);
+                Assert.Equal(new[] { "foo" }, e.RemovedItems);
+            };
+
+            target.SelectedIndex = 1;
+
+            Assert.True(raised);
+            Assert.Equal(1, target.SelectedIndex);
+            Assert.Equal(new[] { "bar" }, target.SelectedItems);
+            Assert.Equal(new[] { 1 }, SelectedContainers(target));
+        }
+
         /// <summary>
         /// Tests a problem discovered with ListBox with selection.
         /// </summary>
@@ -471,6 +550,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
             {
                 DataContext = items,
                 Template = Template(),
+                Items = items,
             };
 
             var called = false;
@@ -540,35 +620,418 @@ namespace Avalonia.Controls.UnitTests.Primitives
 
             Assert.True(called);
         }
+        
+        [Fact]
+        public void Shift_Selecting_From_No_Selection_Selects_From_Start()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: InputModifiers.Shift);
+
+            var panel = target.Presenter.Panel;
+
+            Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems);
+            Assert.Equal(new[] { 0, 1, 2 }, SelectedContainers(target));
+        }
 
         [Fact]
-        public void Replacing_SelectedItems_Should_Raise_SelectionChanged_With_CorrectItems()
+        public void Ctrl_Selecting_SelectedItem_With_Multiple_Selection_Active_Sets_SelectedItem_To_Next_Selection()
         {
-            var items = new[] { "foo", "bar", "baz" };
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz", "Qux" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Click((Interactive)target.Presenter.Panel.Children[1]);
+            _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: InputModifiers.Control);
+            _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: InputModifiers.Control);
+
+            Assert.Equal(1, target.SelectedIndex);
+            Assert.Equal("Bar", target.SelectedItem);
+            Assert.Equal(new[] { "Bar", "Baz", "Qux" }, target.SelectedItems);
+
+            _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: InputModifiers.Control);
+
+            Assert.Equal(2, target.SelectedIndex);
+            Assert.Equal("Baz", target.SelectedItem);
+            Assert.Equal(new[] { "Baz", "Qux" }, target.SelectedItems);
+        }
+
+        [Fact]
+        public void Ctrl_Selecting_Non_SelectedItem_With_Multiple_Selection_Active_Leaves_SelectedItem_The_Same()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Click((Interactive)target.Presenter.Panel.Children[1]);
+            _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: InputModifiers.Control);
+
+            Assert.Equal(1, target.SelectedIndex);
+            Assert.Equal("Bar", target.SelectedItem);
+
+            _helper.Click((Interactive)target.Presenter.Panel.Children[2], modifiers: InputModifiers.Control);
+
+            Assert.Equal(1, target.SelectedIndex);
+            Assert.Equal("Bar", target.SelectedItem);
+        }
+
+        [Fact]
+        public void Should_Ctrl_Select_Correct_Item_When_Duplicate_Items_Are_Present()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Click((Interactive)target.Presenter.Panel.Children[3]);
+            _helper.Click((Interactive)target.Presenter.Panel.Children[4], modifiers: InputModifiers.Control);
+
+            var panel = target.Presenter.Panel;
+
+            Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems);
+            Assert.Equal(new[] { 3, 4 }, SelectedContainers(target));
+        }
+
+        [Fact]
+        public void Should_Shift_Select_Correct_Item_When_Duplicates_Are_Present()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Click((Interactive)target.Presenter.Panel.Children[3]);
+            _helper.Click((Interactive)target.Presenter.Panel.Children[5], modifiers: InputModifiers.Shift);
+
+            var panel = target.Presenter.Panel;
 
+            Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems);
+            Assert.Equal(new[] { 3, 4, 5 }, SelectedContainers(target));
+        }
+
+        [Fact]
+        public void Can_Shift_Select_All_Items_When_Duplicates_Are_Present()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Click((Interactive)target.Presenter.Panel.Children[0]);
+            _helper.Click((Interactive)target.Presenter.Panel.Children[5], modifiers: InputModifiers.Shift);
+
+            var panel = target.Presenter.Panel;
+
+            Assert.Equal(new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, target.SelectedItems);
+            Assert.Equal(new[] { 0, 1, 2, 3, 4, 5 }, SelectedContainers(target));
+        }
+
+        [Fact]
+        public void Duplicate_Items_Are_Added_To_SelectedItems_In_Order()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Click((Interactive)target.Presenter.Panel.Children[0]);
+
+            Assert.Equal(new[] { "Foo" }, target.SelectedItems);
+
+            _helper.Click((Interactive)target.Presenter.Panel.Children[4], modifiers: InputModifiers.Control);
+
+            Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems);
+
+            _helper.Click((Interactive)target.Presenter.Panel.Children[3], modifiers: InputModifiers.Control);
+
+            Assert.Equal(new[] { "Foo", "Bar", "Foo" }, target.SelectedItems);
+
+            _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: InputModifiers.Control);
+
+            Assert.Equal(new[] { "Foo", "Bar", "Foo", "Bar" }, target.SelectedItems);
+        }
+
+        [Fact]
+        public void SelectAll_Sets_SelectedIndex_And_SelectedItem()
+        {
+            var target = new TestSelector
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            target.SelectAll();
+
+            Assert.Equal(0, target.SelectedIndex);
+            Assert.Equal("Foo", target.SelectedItem);
+        }
+
+        [Fact]
+        public void UnselectAll_Clears_SelectedIndex_And_SelectedItem()
+        {
+            var target = new TestSelector
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+                SelectedIndex = 0,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            target.UnselectAll();
+
+            Assert.Equal(-1, target.SelectedIndex);
+            Assert.Equal(null, target.SelectedItem);
+        }
+
+        [Fact]
+        public void SelectAll_Handles_Duplicate_Items()
+        {
             var target = new TestSelector
             {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            target.SelectAll();
+
+            Assert.Equal(new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, target.SelectedItems);
+        }
+
+        [Fact]
+        public void Adding_Item_Before_SelectedItems_Should_Update_Selection()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "Baz"
+            };
+
+            var target = new ListBox
+            {
+                Template = Template(),
                 Items = items,
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            target.SelectAll();
+            items.Insert(0, "Qux");
+
+            Assert.Equal(1, target.SelectedIndex);
+            Assert.Equal("Foo", target.SelectedItem);
+            Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems);
+            Assert.Equal(new[] { 1, 2, 3 }, SelectedContainers(target));
+        }
+
+        [Fact]
+        public void Removing_Item_Before_SelectedItem_Should_Update_Selection()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "Baz"
+            };
+
+            var target = new TestSelector
+            {
                 Template = Template(),
-                SelectedItem = "bar",
+                Items = items,
+                SelectionMode = SelectionMode.Multiple,
             };
 
-            var called = false;
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
 
-            target.SelectionChanged += (s, e) =>
+            target.SelectedIndex = 1;
+            target.SelectRange(2);
+
+            Assert.Equal(new[] { "Bar", "Baz" }, target.SelectedItems);
+
+            items.RemoveAt(0);
+
+            Assert.Equal(0, target.SelectedIndex);
+            Assert.Equal("Bar", target.SelectedItem);
+            Assert.Equal(new[] { "Bar", "Baz" }, target.SelectedItems);
+            Assert.Equal(new[] { 0, 1 }, SelectedContainers(target));
+        }
+
+        [Fact]
+        public void Removing_SelectedItem_With_Multiple_Selection_Active_Should_Update_Selection()
+        {
+            var items = new ObservableCollection<string>
             {
-                Assert.Equal(new[] { "foo",}, e.AddedItems.Cast<object>());
-                Assert.Equal(new[] { "bar" }, e.RemovedItems.Cast<object>());
-                called = true;
+               "Foo",
+               "Bar",
+               "Baz"
+            };
+
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = items,
+                SelectionMode = SelectionMode.Multiple,
             };
 
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
-            target.SelectedItems[0] = "foo";
 
-            Assert.True(called);
+            target.SelectAll();
+            items.RemoveAt(0);
+
+            Assert.Equal(0, target.SelectedIndex);
+            Assert.Equal("Bar", target.SelectedItem);
+            Assert.Equal(new[] { "Bar", "Baz" }, target.SelectedItems);
+            Assert.Equal(new[] { 0, 1 }, SelectedContainers(target));
         }
 
+        [Fact]
+        public void Replacing_Selected_Item_Should_Update_SelectedItems()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "Baz"
+            };
+
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = items,
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            target.SelectAll();
+            items[1] = "Qux";
+
+            Assert.Equal(new[] { "Foo", "Qux", "Baz" }, target.SelectedItems);
+        }
+
+        [Fact]
+        public void Left_Click_On_SelectedItem_Should_Clear_Existing_Selection()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz" },
+                ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Width = 20, Height = 10 }),
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            target.SelectAll();
+
+            Assert.Equal(3, target.SelectedItems.Count);
+
+            _helper.Click((Interactive)target.Presenter.Panel.Children[0]);
+
+            Assert.Equal(1, target.SelectedItems.Count);
+            Assert.Equal(new[] { "Foo", }, target.SelectedItems);
+            Assert.Equal(new[] { 0 }, SelectedContainers(target));
+        }
+
+        [Fact]
+        public void Right_Click_On_SelectedItem_Should_Not_Clear_Existing_Selection()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz" },
+                ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Width = 20, Height = 10 }),
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            target.SelectAll();
+
+            Assert.Equal(3, target.SelectedItems.Count);
+
+            _helper.Click((Interactive)target.Presenter.Panel.Children[0], MouseButton.Right);
+
+            Assert.Equal(3, target.SelectedItems.Count);
+        }
+
+        [Fact]
+        public void Right_Click_On_UnselectedItem_Should_Clear_Existing_Selection()
+        {
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = new[] { "Foo", "Bar", "Baz" },
+                ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Width = 20, Height = 10 }),
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            _helper.Click((Interactive)target.Presenter.Panel.Children[0]);
+            _helper.Click((Interactive)target.Presenter.Panel.Children[1], modifiers: InputModifiers.Shift);
+
+            Assert.Equal(2, target.SelectedItems.Count);
+
+            _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right);
+
+            Assert.Equal(1, target.SelectedItems.Count);
+        }
+
+        private IEnumerable<int> SelectedContainers(SelectingItemsControl target)
+        {
+            return target.Presenter.Panel.Children
+                .Select((x, i) => x.Classes.Contains(":selected") ? i : -1)
+                .Where(x => x != -1);
+        }
 
         private FuncControlTemplate Template()
         {
@@ -598,10 +1061,10 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 set { base.SelectionMode = value; }
             }
 
-            public void SelectRange(int index)
-            {
-                UpdateSelection(index, true, true);
-            }
+            public new void SelectAll() => base.SelectAll();
+            public new void UnselectAll() => base.UnselectAll();
+            public void SelectRange(int index) => UpdateSelection(index, true, true);
+            public void Toggle(int index) => UpdateSelection(index, true, false, true);
         }
 
         private class OldDataContextViewModel

+ 0 - 19
tests/Avalonia.Controls.UnitTests/TopLevelTests.cs

@@ -207,19 +207,6 @@ namespace Avalonia.Controls.UnitTests
             }
         }
 
-        [Fact]
-        public void Exiting_Application_Notifies_Top_Level()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                var impl = new Mock<ITopLevelImpl>();
-                impl.SetupAllProperties();
-                var target = new TestTopLevel(impl.Object);
-                UnitTestApplication.Current.Shutdown();
-                Assert.True(target.IsClosed);
-            }
-        }
-
         [Fact]
         public void Adding_Resource_To_Application_Should_Raise_ResourcesChanged()
         {
@@ -259,12 +246,6 @@ namespace Avalonia.Controls.UnitTests
             }
 
             protected override ILayoutManager CreateLayoutManager() => _layoutManager;
-
-            protected override void HandleApplicationExiting()
-            {
-                base.HandleApplicationExiting();
-                IsClosed = true;
-            }
         }
     }
 }

+ 0 - 6
tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs

@@ -276,12 +276,6 @@ namespace Avalonia.Controls.UnitTests
                 : base(impl)
             {
             }
-
-            protected override void HandleApplicationExiting()
-            {
-                base.HandleApplicationExiting();
-                IsClosed = true;
-            }
         }
     }
 }

+ 0 - 76
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@@ -121,75 +121,6 @@ namespace Avalonia.Controls.UnitTests
             }
         }
 
-        [Fact]
-        public void Show_Should_Add_Window_To_OpenWindows()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                ClearOpenWindows();
-                var window = new Window();
-
-                window.Show();
-
-                Assert.Equal(new[] { window }, Application.Current.Windows);
-            }
-        }
-
-        [Fact]
-        public void Window_Should_Be_Added_To_OpenWindows_Only_Once()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                ClearOpenWindows();
-                var window = new Window();
-
-                window.Show();
-                window.Show();
-                window.IsVisible = true;
-
-                Assert.Equal(new[] { window }, Application.Current.Windows);
-
-                window.Close();
-            }
-        }
-
-        [Fact]
-        public void Close_Should_Remove_Window_From_OpenWindows()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                ClearOpenWindows();
-                var window = new Window();
-
-                window.Show();
-                window.Close();
-
-                Assert.Empty(Application.Current.Windows);
-            }
-        }
-
-        [Fact]
-        public void Impl_Closing_Should_Remove_Window_From_OpenWindows()
-        {
-            var windowImpl = new Mock<IWindowImpl>();
-            windowImpl.SetupProperty(x => x.Closed);
-            windowImpl.Setup(x => x.Scaling).Returns(1);
-
-            var services = TestServices.StyledWindow.With(
-                windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object));
-
-            using (UnitTestApplication.Start(services))
-            {
-                ClearOpenWindows();
-                var window = new Window();
-
-                window.Show();
-                windowImpl.Object.Closed();
-
-                Assert.Empty(Application.Current.Windows);
-            }
-        }
-
         [Fact]
         public void Closing_Should_Only_Be_Invoked_Once()
         {
@@ -420,12 +351,5 @@ namespace Avalonia.Controls.UnitTests
                 x.Scaling == 1 &&
                 x.CreateRenderer(It.IsAny<IRenderRoot>()) == renderer.Object);
         }
-
-        private void ClearOpenWindows()
-        {
-            // HACK: We really need a decent way to have "statics" that can be scoped to
-            // AvaloniaLocator scopes.
-            Application.Current.Windows.Clear();
-        }
     }
 }

+ 31 - 9
tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs

@@ -5,11 +5,10 @@ using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
-using System.Text;
 using Avalonia.Controls;
 using Avalonia.Data;
 using Avalonia.Data.Converters;
-using Avalonia.Data.Core;
+using Avalonia.Layout;
 using Xunit;
 
 namespace Avalonia.Markup.UnitTests.Data
@@ -21,7 +20,30 @@ namespace Avalonia.Markup.UnitTests.Data
         {
             var textBlock = new TextBlock
             {
-                DataContext = new MultiBindingTests_Converters.Class1(),
+                DataContext = new Class1(),
+            };
+
+            var target = new MultiBinding
+            {
+                StringFormat = "{0:0.0} + {1:00}",
+                Bindings =
+                {
+                    new Binding(nameof(Class1.Foo)),
+                    new Binding(nameof(Class1.Bar)),
+                }
+            };
+
+            textBlock.Bind(TextBlock.TextProperty, target);
+
+            Assert.Equal("1.0 + 02", textBlock.Text);
+        }
+
+        [Fact]
+        public void StringFormat_Should_Be_Applied_After_Converter()
+        {
+            var textBlock = new TextBlock
+            {
+                DataContext = new Class1(),
             };
 
             var target = new MultiBinding
@@ -30,8 +52,8 @@ namespace Avalonia.Markup.UnitTests.Data
                 Converter = new SumOfDoublesConverter(),
                 Bindings =
                 {
-                    new Binding(nameof(MultiBindingTests_Converters.Class1.Foo)),
-                    new Binding(nameof(MultiBindingTests_Converters.Class1.Bar)),
+                    new Binding(nameof(Class1.Foo)),
+                    new Binding(nameof(Class1.Bar)),
                 }
             };
 
@@ -45,7 +67,7 @@ namespace Avalonia.Markup.UnitTests.Data
         {
             var textBlock = new TextBlock
             {
-                DataContext = new MultiBindingTests_Converters.Class1(),
+                DataContext = new Class1(),
             };
             
             var target = new MultiBinding
@@ -54,12 +76,12 @@ namespace Avalonia.Markup.UnitTests.Data
                 Converter = new SumOfDoublesConverter(),
                 Bindings =
                 {
-                    new Binding(nameof(MultiBindingTests_Converters.Class1.Foo)),
-                    new Binding(nameof(MultiBindingTests_Converters.Class1.Bar)),
+                    new Binding(nameof(Class1.Foo)),
+                    new Binding(nameof(Class1.Bar)),
                 }
             };
 
-            textBlock.Bind(TextBlock.WidthProperty, target);
+            textBlock.Bind(Layoutable.WidthProperty, target);
             
             Assert.Equal(3.0, textBlock.Width);
         }

+ 19 - 0
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@@ -907,6 +907,25 @@ do we need it?")]
             }
         }
 
+        [Fact]
+        public void Slider_Properties_Can_Be_Set_In_Any_Order()
+        {
+            using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
+            {
+                var xaml = @"
+<Window xmlns='https://github.com/avaloniaui'>
+    <Slider Width='400' Value='500' Minimum='0' Maximum='1000'/>
+</Window>";
+
+                var window = AvaloniaXamlLoader.Parse<Window>(xaml);
+                var slider = (Slider)window.Content;
+
+                Assert.Equal(0, slider.Minimum);
+                Assert.Equal(1000, slider.Maximum);
+                Assert.Equal(500, slider.Value);
+            }
+        }
+
         private class SelectedItemsViewModel : INotifyPropertyChanged
         {
             public string[] Items { get; set; }

+ 31 - 0
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs

@@ -331,6 +331,35 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
             }
         }
 
+        [Fact(Skip="Issue #2592")]
+        public void MultiBinding_To_TextBlock_Text_With_StringConverter_Works()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var xaml = @"
+<Window xmlns='https://github.com/avaloniaui'
+        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+        xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
+    <TextBlock Name='textBlock'>
+        <TextBlock.Text>
+            <MultiBinding StringFormat='\{0\} \{1\}!'>
+                <Binding Path='Greeting1'/>
+                <Binding Path='Greeting2'/>
+            </MultiBinding>
+        </TextBlock.Text>
+    </TextBlock> 
+</Window>";
+                var loader = new AvaloniaXamlLoader();
+                var window = (Window)loader.Load(xaml);
+                var textBlock = window.FindControl<TextBlock>("textBlock");
+
+                textBlock.DataContext = new WindowViewModel();
+                window.ApplyTemplate();
+
+                Assert.Equal("Hello World!", textBlock.Text);
+            }
+        }
+
         [Fact]
         public void Binding_OneWayToSource_Works()
         {
@@ -356,6 +385,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
         private class WindowViewModel
         {
             public bool ShowInTaskbar { get; set; }
+            public string Greeting1 { get; set; } = "Hello";
+            public string Greeting2 { get; set; } = "World";
         }
     }
 }

+ 1 - 2
tests/Avalonia.UnitTests/UnitTestApplication.cs

@@ -66,8 +66,7 @@ namespace Avalonia.UnitTests
                 .Bind<IStandardCursorFactory>().ToConstant(Services.StandardCursorFactory)
                 .Bind<IStyler>().ToConstant(Services.Styler)
                 .Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform)
-                .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
-                .Bind<IApplicationLifecycle>().ToConstant(this);
+                .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
             var styles = Services.Theme?.Invoke();
 
             if (styles != null)