Browse Source

Merge branch 'master' into scenegraph

Conflicts:
	src/Gtk/Avalonia.Gtk/WindowImplBase.cs
	src/Skia/Avalonia.Skia.Android/RenderTarget.cs
	src/Skia/Avalonia.Skia.Android/SkiaRenderView.cs
	tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs
	tests/Avalonia.LeakTests/ControlTests.cs
scenegraph-after-breakage
Steven Kirk 9 years ago
parent
commit
ff9654a7b0
  1. 2
      .gitignore
  2. 216
      Avalonia.sln
  3. 696
      build.cake
  4. 469
      packages.cake
  5. 143
      parameters.cake
  6. 5
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  7. 24
      samples/ControlCatalog.Android/MainActivity.cs
  8. 7
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  9. 27
      samples/ControlCatalog/Pages/TreeViewPage.xaml.cs
  10. 25
      src/Android/Avalonia.Android/AndroidPlatform.cs
  11. 12
      src/Android/Avalonia.Android/AndroidThreadingInterface.cs
  12. 9
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  13. 50
      src/Android/Avalonia.Android/AvaloniaActivity.cs
  14. 59
      src/Android/Avalonia.Android/AvaloniaView.cs
  15. 101
      src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
  16. 8
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  17. 44
      src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs
  18. 38
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  19. 60
      src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs
  20. 2
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  21. 2
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
  22. 12
      src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs
  23. 17
      src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
  24. 32
      src/Android/Avalonia.AndroidTestApplication/MainActivity.cs
  25. 3
      src/Android/Avalonia.AndroidTestApplication/packages.config
  26. 4
      src/Avalonia.Animation/Avalonia.Animation.csproj
  27. 4
      src/Avalonia.Base/Avalonia.Base.csproj
  28. 7
      src/Avalonia.Controls/Avalonia.Controls.csproj
  29. 3
      src/Avalonia.Controls/Expander.cs
  30. 13
      src/Avalonia.Controls/Platform/ITopLevelImpl.cs
  31. 5
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  32. 19
      src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs
  33. 37
      src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs
  34. 15
      src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs
  35. 6
      src/Avalonia.Controls/TopLevel.cs
  36. 20
      src/Avalonia.Controls/Window.cs
  37. 4
      src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
  38. 4
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  39. 53
      src/Avalonia.DotNetCoreRuntime/AppBuilder.cs
  40. 89
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  41. 5
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.v3.ncrunchproject
  42. 47
      src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs
  43. 41
      src/Avalonia.DotNetCoreRuntime/RuntimeInfo.cs
  44. 11
      src/Avalonia.DotNetCoreRuntime/project.json
  45. 4
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  46. 6
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject
  47. 4
      src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
  48. 4
      src/Avalonia.Input/Avalonia.Input.csproj
  49. 4
      src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
  50. 4
      src/Avalonia.Layout/Avalonia.Layout.csproj
  51. 4
      src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj
  52. 4
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  53. 4
      src/Avalonia.Styling/Avalonia.Styling.csproj
  54. 4
      src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
  55. 4
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  56. 7
      src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
  57. 22
      src/Gtk/Avalonia.Cairo/CairoPlatform.cs
  58. 19
      src/Gtk/Avalonia.Cairo/RenderTarget.cs
  59. 5
      src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj
  60. 39
      src/Gtk/Avalonia.Gtk/FramebufferManager.cs
  61. 209
      src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs
  62. 224
      src/Gtk/Avalonia.Gtk/KeyTransform.cs
  63. 55
      src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs
  64. 4
      src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs
  65. 2
      src/Gtk/Avalonia.Gtk/WindowImpl.cs
  66. 35
      src/Gtk/Avalonia.Gtk/WindowImplBase.cs
  67. 1
      src/Gtk/Avalonia.Gtk3/.gitignore
  68. 103
      src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj
  69. 5
      src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.v3.ncrunchproject
  70. 53
      src/Gtk/Avalonia.Gtk3/ClipboardImpl.cs
  71. 79
      src/Gtk/Avalonia.Gtk3/CursorFactory.cs
  72. 32
      src/Gtk/Avalonia.Gtk3/FramebufferManager.cs
  73. 91
      src/Gtk/Avalonia.Gtk3/GdkCursor.cs
  74. 1347
      src/Gtk/Avalonia.Gtk3/GdkKey.cs
  75. 116
      src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs
  76. 54
      src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs
  77. 20
      src/Gtk/Avalonia.Gtk3/Interop/CairoSurface.cs
  78. 129
      src/Gtk/Avalonia.Gtk3/Interop/DynLoader.cs
  79. 33
      src/Gtk/Avalonia.Gtk3/Interop/GException.cs
  80. 62
      src/Gtk/Avalonia.Gtk3/Interop/GObject.cs
  81. 64
      src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs
  82. 17
      src/Gtk/Avalonia.Gtk3/Interop/ICustomGtk3NativeLibraryResolver.cs
  83. 571
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  84. 24
      src/Gtk/Avalonia.Gtk3/Interop/NativeException.cs
  85. 68
      src/Gtk/Avalonia.Gtk3/Interop/Pixbuf.cs
  86. 155
      src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs
  87. 50
      src/Gtk/Avalonia.Gtk3/Interop/Signal.cs
  88. 45
      src/Gtk/Avalonia.Gtk3/Interop/Utf8Buffer.cs
  89. 20
      src/Gtk/Avalonia.Gtk3/PlatformIconLoader.cs
  90. 24
      src/Gtk/Avalonia.Gtk3/PopupImpl.cs
  91. 10
      src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs
  92. 8
      src/Gtk/Avalonia.Gtk3/README.md
  93. 92
      src/Gtk/Avalonia.Gtk3/SystemDialogs.cs
  94. 336
      src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs
  95. 45
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs
  96. 10
      src/Gtk/Avalonia.Gtk3/project.json
  97. 5
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  98. 6
      src/Markup/Avalonia.Markup.Xaml/packages.config
  99. 6
      src/Shared/PlatformSupport/AssetLoader.cs
  100. 9
      src/Shared/PlatformSupport/StandardRuntimePlatform.cs

2
.gitignore

@ -161,3 +161,5 @@ tools/
.nuget
artifacts/
nuget
Avalonia.XBuild.sln
project.lock.json

216
Avalonia.sln

@ -99,8 +99,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Desktop", "sr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Android", "src\Skia\Avalonia.Skia.Android\Avalonia.Skia.Android.csproj", "{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Android.TestApp", "src\Skia\Avalonia.Skia.Android.TestApp\Avalonia.Skia.Android.TestApp.csproj", "{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.iOS.TestApp", "src\Skia\Avalonia.Skia.iOS.TestApp\Avalonia.Skia.iOS.TestApp.csproj", "{DA49C5F3-BE95-461C-B999-072128CCF59E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.iOS", "src\Skia\Avalonia.Skia.iOS\Avalonia.Skia.iOS.csproj", "{47BE08A7-5985-410B-9FFC-2264B8EA595F}"
@ -130,6 +128,9 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{D0A739B9-3C68-4BA6-A328-41606954B6BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Desktop", "samples\ControlCatalog.Desktop\ControlCatalog.Desktop.csproj", "{2B888490-D14A-4BCA-AB4B-48676FA93C9B}"
ProjectSection(ProjectDependencies) = postProject
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658} = {BB1F7BB5-6AD4-4776-94D9-C09D0A972658}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}"
EndProject
@ -155,19 +156,35 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderTest", "samples\Rende
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Android", "samples\ControlCatalog.Android\ControlCatalog.Android.csproj", "{29132311-1848-4FD6-AE0C-4FF841151BD3}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Avalonia.Win32.Shared", "src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.shproj", "{9DEFC6B7-845B-4D8F-AFC0-D32BF0032B8C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.NetStandard", "src\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj", "{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DotNetCoreRuntime", "src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj", "{7863EA94-F0FB-4386-BF8C-E5BFA761560A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Desktop.NetStandard", "src\Skia\Avalonia.Skia.Desktop.NetStandard\Avalonia.Skia.Desktop.NetStandard.csproj", "{7D2D3083-71DD-4CC9-8907-39A0D86FB322}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Gtk3", "src\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj", "{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4
src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{40759a76-d0f2-464e-8000-6ff0f5c4bd7c}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4
src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4
tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{48840edd-24bf-495d-911e-2eb12ae75d3b}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{7863ea94-f0fb-4386-bf8c-e5bfa761560a}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4
src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4
src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{9defc6b7-845b-4d8f-afc0-d32bf0032b8c}*SharedItemsImports = 13
src\Shared\RenderHelpers\RenderHelpers.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{d35a9f3d-8bb0-496e-bf72-444038a7debb}*SharedItemsImports = 4
@ -1469,38 +1486,6 @@ Global
{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|Mono.ActiveCfg = Release|Any CPU
{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.ActiveCfg = Release|Any CPU
{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.Build.0 = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.Deploy.0 = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|Mono.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.Build.0 = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.Deploy.0 = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Mono.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.ActiveCfg = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.Build.0 = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.Deploy.0 = Debug|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.Build.0 = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.Deploy.0 = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|iPhone.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Mono.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.ActiveCfg = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.Build.0 = Release|Any CPU
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.Deploy.0 = Release|Any CPU
{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
@ -2329,6 +2314,164 @@ Global
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.ActiveCfg = Release|Any CPU
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.Build.0 = Release|Any CPU
{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.Deploy.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|Any CPU.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|iPhone.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|Mono.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|Mono.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|x86.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.AppStore|x86.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|iPhone.Build.0 = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|Mono.ActiveCfg = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|x86.ActiveCfg = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Debug|x86.Build.0 = Debug|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|Any CPU.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|iPhone.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|iPhone.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|Mono.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|x86.ActiveCfg = Release|Any CPU
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C}.Release|x86.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|Any CPU.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|iPhone.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|Mono.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|Mono.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|x86.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.AppStore|x86.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|iPhone.Build.0 = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|Mono.ActiveCfg = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|Mono.Build.0 = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|x86.ActiveCfg = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Debug|x86.Build.0 = Debug|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|Any CPU.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|iPhone.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|iPhone.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|Mono.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|Mono.Build.0 = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|x86.ActiveCfg = Release|Any CPU
{7863EA94-F0FB-4386-BF8C-E5BFA761560A}.Release|x86.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|Any CPU.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|iPhone.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|Mono.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|Mono.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|x86.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|x86.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|iPhone.Build.0 = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Mono.ActiveCfg = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Mono.Build.0 = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|x86.ActiveCfg = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|x86.Build.0 = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|iPhone.ActiveCfg = Release|Any CPU
{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
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Mono.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Mono.Build.0 = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|x86.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|x86.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}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Ad-Hoc|x86.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}.AppStore|Mono.ActiveCfg = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|Mono.Build.0 = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|x86.ActiveCfg = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.AppStore|x86.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}.Debug|Mono.ActiveCfg = Debug|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|Mono.Build.0 = Debug|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|x86.ActiveCfg = Debug|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Debug|x86.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
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|Mono.ActiveCfg = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|Mono.Build.0 = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|x86.ActiveCfg = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2359,7 +2502,6 @@ Global
{2F59F3D0-748D-4652-B01E-E0D954756308} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{925DD807-B651-475F-9F7C-CBEB974CE43D} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{F92E55A5-ED73-4CCB-AB4B-0541B6757F31} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{DA49C5F3-BE95-461C-B999-072128CCF59E} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{47BE08A7-5985-410B-9FFC-2264B8EA595F} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
@ -2382,5 +2524,9 @@ Global
{BD7F352C-6DC1-4740-BAF2-2D34A038728C} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{F1FDC5B0-4654-416F-AE69-E3E9BBD87801} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{9DEFC6B7-845B-4D8F-AFC0-D32BF0032B8C} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658} = {B9894058-278A-46B5-B6ED-AD613FCC03B3}
EndGlobalSection
EndGlobal

696
build.cake

@ -24,574 +24,118 @@ using Polly;
using NuGet;
///////////////////////////////////////////////////////////////////////////////
// ARGUMENTS
// SCRIPTS
///////////////////////////////////////////////////////////////////////////////
var target = Argument("target", "Default");
var platform = Argument("platform", "Any CPU");
var configuration = Argument("configuration", "Release");
var skipTests = HasArgument("skip-tests");
#load "./parameters.cake"
#load "./packages.cake"
///////////////////////////////////////////////////////////////////////////////
// CONFIGURATION
///////////////////////////////////////////////////////////////////////////////
var MainRepo = "AvaloniaUI/Avalonia";
var MasterBranch = "master";
var AssemblyInfoPath = File("./src/Shared/SharedAssemblyInfo.cs");
var ReleasePlatform = "Any CPU";
var ReleaseConfiguration = "Release";
var MSBuildSolution = "./Avalonia.sln";
var XBuildSolution = "./Avalonia.sln";
///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// PARAMETERS
///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
var isPlatformAnyCPU = StringComparer.OrdinalIgnoreCase.Equals(platform, "Any CPU");
var isPlatformX86 = StringComparer.OrdinalIgnoreCase.Equals(platform, "x86");
var isPlatformX64 = StringComparer.OrdinalIgnoreCase.Equals(platform, "x64");
var isLocalBuild = BuildSystem.IsLocalBuild;
var isRunningOnUnix = IsRunningOnUnix();
var isRunningOnWindows = IsRunningOnWindows();
var isRunningOnAppVeyor = BuildSystem.AppVeyor.IsRunningOnAppVeyor;
var isPullRequest = BuildSystem.AppVeyor.Environment.PullRequest.IsPullRequest;
var isMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, BuildSystem.AppVeyor.Environment.Repository.Name);
var isMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch, BuildSystem.AppVeyor.Environment.Repository.Branch);
var isTagged = BuildSystem.AppVeyor.Environment.Repository.Tag.IsTag
&& !string.IsNullOrWhiteSpace(BuildSystem.AppVeyor.Environment.Repository.Tag.Name);
var isReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleasePlatform, platform)
&& StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, configuration);
var isMyGetRelease = !isTagged && isReleasable;
var isNuGetRelease = isTagged && isReleasable;
Parameters parameters = new Parameters(Context);
Packages packages = new Packages(Context, parameters);
///////////////////////////////////////////////////////////////////////////////
// VERSION
// SETUP
///////////////////////////////////////////////////////////////////////////////
var version = ParseAssemblyInfo(AssemblyInfoPath).AssemblyVersion;
if (isRunningOnAppVeyor)
Setup(context =>
{
if (isTagged)
{
// Use Tag Name as version
version = BuildSystem.AppVeyor.Environment.Repository.Tag.Name;
}
else
Information("Building version {0} of Avalonia ({1}, {2}, {3}) using version {4} of Cake.",
parameters.Version,
parameters.Platform,
parameters.Configuration,
parameters.Target,
typeof(ICakeContext).Assembly.GetName().Version.ToString());
if (parameters.IsRunningOnAppVeyor)
{
// Use AssemblyVersion with Build as version
version += "-build" + EnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-alpha";
Information("Repository Name: " + BuildSystem.AppVeyor.Environment.Repository.Name);
Information("Repository Branch: " + BuildSystem.AppVeyor.Environment.Repository.Branch);
}
}
///////////////////////////////////////////////////////////////////////////////
// DIRECTORIES
///////////////////////////////////////////////////////////////////////////////
var artifactsDir = (DirectoryPath)Directory("./artifacts");
var nugetRoot = artifactsDir.Combine("nuget");
var zipRoot = artifactsDir.Combine("zip");
var binRoot = artifactsDir.Combine("bin");
var testsRoot = artifactsDir.Combine("tests");
var dirSuffix = configuration;
var dirSuffixSkia = (isPlatformAnyCPU ? "x86" : platform) + "/" + configuration;
var dirSuffixIOS = "iPhone" + "/" + configuration;
var buildDirs =
GetDirectories("./src/**/bin/" + dirSuffix) +
GetDirectories("./src/**/obj/" + dirSuffix) +
GetDirectories("./src/Markup/**/bin/" + dirSuffix) +
GetDirectories("./src/Markup/**/obj/" + dirSuffix) +
GetDirectories("./src/Android/**/bin/" + dirSuffix) +
GetDirectories("./src/Android/**/obj/" + dirSuffix) +
GetDirectories("./src/Gtk/**/bin/" + dirSuffix) +
GetDirectories("./src/Gtk/**/obj/" + dirSuffix) +
GetDirectories("./src/iOS/**/bin/" + dirSuffixIOS) +
GetDirectories("./src/iOS/**/obj/" + dirSuffixIOS) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Android/bin/" + dirSuffix) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Android/obj/" + dirSuffix) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Android.TestApp/bin/" + dirSuffix) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Android.TestApp/obj/" + dirSuffix) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Desktop/bin/" + dirSuffixSkia) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Desktop/obj/" + dirSuffixSkia) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.iOS/bin/" + dirSuffixIOS) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.iOS/obj/" + dirSuffixIOS) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.iOS.TestApp/bin/" + dirSuffixIOS) +
(DirectoryPath)Directory("./src/Skia/Avalonia.Skia.iOS.TestApp/obj/" + dirSuffixIOS) +
GetDirectories("./src/Windows/**/bin/" + dirSuffix) +
GetDirectories("./src/Windows/**/obj/" + dirSuffix) +
GetDirectories("./tests/**/bin/" + dirSuffix) +
GetDirectories("./tests/**/obj/" + dirSuffix) +
GetDirectories("./Samples/**/bin/" + dirSuffix) +
GetDirectories("./Samples/**/obj/" + dirSuffix);
var fileZipSuffix = version + ".zip";
var zipCoreArtifacts = zipRoot.CombineWithFilePath("Avalonia-" + fileZipSuffix);
var zipSourceControlCatalogDesktopDirs = (DirectoryPath)Directory("./samples/ControlCatalog.Desktop/bin/" + dirSuffix);
var zipTargetControlCatalogDesktopDirs = zipRoot.CombineWithFilePath("ControlCatalog.Desktop-" + fileZipSuffix);
Information("Target: " + parameters.Target);
Information("Platform: " + parameters.Platform);
Information("Configuration: " + parameters.Configuration);
Information("IsLocalBuild: " + parameters.IsLocalBuild);
Information("IsRunningOnUnix: " + parameters.IsRunningOnUnix);
Information("IsRunningOnWindows: " + parameters.IsRunningOnWindows);
Information("IsRunningOnAppVeyor: " + parameters.IsRunningOnAppVeyor);
Information("IsPullRequest: " + parameters.IsPullRequest);
Information("IsMainRepo: " + parameters.IsMainRepo);
Information("IsMasterBranch: " + parameters.IsMasterBranch);
Information("IsTagged: " + parameters.IsTagged);
Information("IsReleasable: " + parameters.IsReleasable);
Information("IsMyGetRelease: " + parameters.IsMyGetRelease);
Information("IsNuGetRelease: " + parameters.IsNuGetRelease);
});
///////////////////////////////////////////////////////////////////////////////
// NUGET NUSPECS
// TEARDOWN
///////////////////////////////////////////////////////////////////////////////
Information("Getting git modules:");
var ignoredSubModulesPaths = System.IO.File.ReadAllLines(".git/config").Where(m=>m.StartsWith("[submodule ")).Select(m =>
Teardown(context =>
{
var path = m.Split(' ')[1].Trim("\"[] \t".ToArray());
Information(path);
return ((DirectoryPath)Directory(path)).FullPath;
}).ToList();
var normalizePath = new Func<string, string>(
path => path.Replace(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar).ToUpperInvariant());
// Key: Package Id
// Value is Tuple where Item1: Package Version, Item2: The packages.config file path.
var packageVersions = new Dictionary<string, IList<Tuple<string,string>>>();
System.IO.Directory.EnumerateFiles(((DirectoryPath)Directory("./src")).FullPath, "packages.config", SearchOption.AllDirectories).ToList().ForEach(fileName =>
{
if (!ignoredSubModulesPaths.Any(i => normalizePath(fileName).Contains(normalizePath(i))))
{
var file = new PackageReferenceFile(fileName);
foreach (PackageReference packageReference in file.GetPackageReferences())
{
IList<Tuple<string, string>> versions;
packageVersions.TryGetValue(packageReference.Id, out versions);
if (versions == null)
{
versions = new List<Tuple<string, string>>();
packageVersions[packageReference.Id] = versions;
}
versions.Add(Tuple.Create(packageReference.Version.ToString(), fileName));
}
}
Information("Finished running tasks.");
});
Information("Checking installed NuGet package dependencies versions:");
///////////////////////////////////////////////////////////////////////////////
// TASKS
///////////////////////////////////////////////////////////////////////////////
packageVersions.ToList().ForEach(package =>
Task("Clean")
.Does(() =>
{
var packageVersion = package.Value.First().Item1;
bool isValidVersion = package.Value.All(x => x.Item1 == packageVersion);
if (!isValidVersion)
{
Information("Error: package {0} has multiple versions installed:", package.Key);
foreach (var v in package.Value)
{
Information("{0}, file: {1}", v.Item1, v.Item2);
}
throw new Exception("Detected multiple NuGet package version installed for different projects.");
}
});
Information("Setting NuGet package dependencies versions:");
var SerilogVersion = packageVersions["Serilog"].FirstOrDefault().Item1;
var SplatVersion = packageVersions["Splat"].FirstOrDefault().Item1;
var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1;
var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1;
var SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
var SharpDXVersion = packageVersions["SharpDX"].FirstOrDefault().Item1;
var SharpDXDirect2D1Version = packageVersions["SharpDX.Direct2D1"].FirstOrDefault().Item1;
var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1;
Information("Package: Serilog, version: {0}", SerilogVersion);
Information("Package: Splat, version: {0}", SplatVersion);
Information("Package: Sprache, version: {0}", SpracheVersion);
Information("Package: System.Reactive, version: {0}", SystemReactiveVersion);
Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion);
Information("Package: SharpDX, version: {0}", SharpDXVersion);
Information("Package: SharpDX.Direct2D1, version: {0}", SharpDXDirect2D1Version);
Information("Package: SharpDX.DXGI, version: {0}", SharpDXDXGIVersion);
var SetNuGetNuspecCommonProperties = new Action<NuGetPackSettings> ((nuspec) => {
nuspec.Version = version;
nuspec.Authors = new [] { "Avalonia Team" };
nuspec.Owners = new [] { "stevenk" };
nuspec.LicenseUrl = new Uri("http://opensource.org/licenses/MIT");
nuspec.ProjectUrl = new Uri("https://github.com/AvaloniaUI/Avalonia/");
nuspec.RequireLicenseAcceptance = false;
nuspec.Symbols = false;
nuspec.NoPackageAnalysis = true;
nuspec.Description = "The Avalonia UI framework";
nuspec.Copyright = "Copyright 2015";
nuspec.Tags = new [] { "Avalonia" };
CleanDirectories(parameters.BuildDirs);
CleanDirectory(parameters.ArtifactsDir);
CleanDirectory(parameters.NugetRoot);
CleanDirectory(parameters.ZipRoot);
CleanDirectory(parameters.BinRoot);
CleanDirectory(parameters.TestsRoot);
});
var coreLibraries = new string[][]
Task("Prepare-XBuild-Solution")
.Does(() =>
{
new [] { "./src/", "Avalonia.Animation", ".dll" },
new [] { "./src/", "Avalonia.Animation", ".xml" },
new [] { "./src/", "Avalonia.Base", ".dll" },
new [] { "./src/", "Avalonia.Base", ".xml" },
new [] { "./src/", "Avalonia.Controls", ".dll" },
new [] { "./src/", "Avalonia.Controls", ".xml" },
new [] { "./src/", "Avalonia.DesignerSupport", ".dll" },
new [] { "./src/", "Avalonia.DesignerSupport", ".xml" },
new [] { "./src/", "Avalonia.Diagnostics", ".dll" },
new [] { "./src/", "Avalonia.Diagnostics", ".xml" },
new [] { "./src/", "Avalonia.Input", ".dll" },
new [] { "./src/", "Avalonia.Input", ".xml" },
new [] { "./src/", "Avalonia.Interactivity", ".dll" },
new [] { "./src/", "Avalonia.Interactivity", ".xml" },
new [] { "./src/", "Avalonia.Layout", ".dll" },
new [] { "./src/", "Avalonia.Layout", ".xml" },
new [] { "./src/", "Avalonia.Logging.Serilog", ".dll" },
new [] { "./src/", "Avalonia.Logging.Serilog", ".xml" },
new [] { "./src/", "Avalonia.Visuals", ".dll" },
new [] { "./src/", "Avalonia.Visuals", ".xml" },
new [] { "./src/", "Avalonia.Styling", ".dll" },
new [] { "./src/", "Avalonia.Styling", ".xml" },
new [] { "./src/", "Avalonia.ReactiveUI", ".dll" },
new [] { "./src/", "Avalonia.Themes.Default", ".dll" },
new [] { "./src/", "Avalonia.Themes.Default", ".xml" },
new [] { "./src/Markup/", "Avalonia.Markup", ".dll" },
new [] { "./src/Markup/", "Avalonia.Markup", ".xml" },
new [] { "./src/Markup/", "Avalonia.Markup.Xaml", ".dll" },
new [] { "./src/Markup/", "Avalonia.Markup.Xaml", ".xml" }
};
var coreLibrariesFiles = coreLibraries.Select((lib) => {
return (FilePath)File(lib[0] + lib[1] + "/bin/" + dirSuffix + "/" + lib[1] + lib[2]);
}).ToList();
var coreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
return new NuSpecContent {
Source = file.FullPath, Target = "lib/portable-windows8+net45"
};
});
var win32CoreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
return new NuSpecContent {
Source = file.FullPath, Target = "lib/net45"
};
});
var net45RuntimePlatformExtensions = new [] {".xml", ".dll"};
var net45RuntimePlatform = net45RuntimePlatformExtensions.Select(libSuffix => {
return new NuSpecContent {
Source = ((FilePath)File("./src/Avalonia.DotNetFrameworkRuntime/bin/" + dirSuffix + "/Avalonia.DotNetFrameworkRuntime" + libSuffix)).FullPath,
Target = "lib/net45"
var blacklistedProjects = new[]
{
"Avalonia.Win32.NetStandard",
"Avalonia.DotNetCoreRuntime",
"Avalonia.Skia.Desktop.NetStandard",
"Avalonia.Gtk3"
};
});
var blacklistedGuids = System.IO.File.ReadAllLines(parameters.MSBuildSolution)
.Where(l=>l.StartsWith("Project") && blacklistedProjects.Any(p=>l.Contains(p)))
.Select(l => l.Split(',').Select(part => part.Trim()).FirstOrDefault(part => part.StartsWith("\"{")))
.Where(g=>g!=null)
.Select(l=>l.Trim(new[]{'"', '}', '{'}).ToLower()).ToArray();
var nuspecNuGetSettingsCore = new []
{
///////////////////////////////////////////////////////////////////////////////
// Avalonia
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia",
Dependencies = new []
{
new NuSpecDependency() { Id = "Serilog", Version = SerilogVersion },
new NuSpecDependency() { Id = "Splat", Version = SplatVersion },
new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion },
new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion }
},
Files = coreLibrariesNuSpecContent.Concat(win32CoreLibrariesNuSpecContent).Concat(net45RuntimePlatform).ToList(),
BasePath = Directory("./"),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.HtmlRenderer
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.HtmlRenderer",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.HtmlRenderer.dll", Target = "lib/portable-windows8+net45" }
},
BasePath = Directory("./src/Avalonia.HtmlRenderer/bin/" + dirSuffix),
OutputDirectory = nugetRoot
}
};
Console.WriteLine("Blacklisted guids are: " + string.Join(",", blacklistedGuids));
var removeUntilEndProject = false;
var nuspecNuGetSettingsMobile = new []
{
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Android
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Android",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version },
new NuSpecDependency() { Id = "Avalonia.Skia.Android", Version = version }
},
Files = new []
System.IO.File.WriteAllLines(parameters.XBuildSolution, System.IO.File.ReadAllLines(parameters.MSBuildSolution)
.Where(l =>
{
new NuSpecContent { Source = "Avalonia.Android.dll", Target = "lib/MonoAndroid10" }
},
BasePath = Directory("./src/Android/Avalonia.Android/bin/" + dirSuffix),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Skia.Android
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Skia.Android",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Skia.Android.dll", Target = "lib/MonoAndroid10" }
},
BasePath = Directory("./src/Skia/Avalonia.Skia.Android/bin/" + dirSuffix),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.iOS
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.iOS",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version },
new NuSpecDependency() { Id = "Avalonia.Skia.iOS", Version = version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.iOS.dll", Target = "lib/Xamarin.iOS10" }
},
BasePath = Directory("./src/iOS/Avalonia.iOS/bin/" + dirSuffixIOS),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Skia.iOS
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Skia.iOS",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Skia.iOS.dll", Target = "lib/Xamarin.iOS10" }
},
BasePath = Directory("./src/Skia/Avalonia.Skia.iOS/bin/" + dirSuffixIOS),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Mobile
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Mobile",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia.Android", Version = version },
new NuSpecDependency() { Id = "Avalonia.iOS", Version = version }
},
Files = new NuSpecContent[]
{
new NuSpecContent { Source = "licence.md", Target = "" }
},
BasePath = Directory("./"),
OutputDirectory = nugetRoot
}
};
var nuspecNuGetSettingsDesktop = new []
{
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Win32
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Win32",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Win32.dll", Target = "lib/net45" }
},
BasePath = Directory("./src/Windows/Avalonia.Win32/bin/" + dirSuffix),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Direct2D1
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Direct2D1",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version },
new NuSpecDependency() { Id = "SharpDX", Version = SharpDXVersion },
new NuSpecDependency() { Id = "SharpDX.Direct2D1", Version = SharpDXDirect2D1Version },
new NuSpecDependency() { Id = "SharpDX.DXGI", Version = SharpDXDXGIVersion }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Direct2D1.dll", Target = "lib/net45" }
},
BasePath = Directory("./src/Windows/Avalonia.Direct2D1/bin/" + dirSuffix),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Gtk
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Gtk",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Gtk.dll", Target = "lib/net45" }
},
BasePath = Directory("./src/Gtk/Avalonia.Gtk/bin/" + dirSuffix),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Cairo
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Cairo",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Cairo.dll", Target = "lib/net45" }
},
BasePath = Directory("./src/Gtk/Avalonia.Cairo/bin/" + dirSuffix),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Skia.Desktop
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Skia.Desktop",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = version },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Skia.Desktop.dll", Target = "lib/net45" }
},
BasePath = Directory("./src/Skia/Avalonia.Skia.Desktop/bin/" + dirSuffixSkia),
OutputDirectory = nugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Desktop
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Desktop",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia.Win32", Version = version },
new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = version },
new NuSpecDependency() { Id = "Avalonia.Gtk", Version = version },
new NuSpecDependency() { Id = "Avalonia.Cairo", Version = version },
new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", Version = version }
},
Files = new NuSpecContent[]
{
new NuSpecContent { Source = "licence.md", Target = "" }
},
BasePath = Directory("./"),
OutputDirectory = nugetRoot
}
};
var nuspecNuGetSettings = new List<NuGetPackSettings>();
nuspecNuGetSettings.AddRange(nuspecNuGetSettingsCore);
nuspecNuGetSettings.AddRange(nuspecNuGetSettingsDesktop);
nuspecNuGetSettings.AddRange(nuspecNuGetSettingsMobile);
nuspecNuGetSettings.ForEach((nuspec) => SetNuGetNuspecCommonProperties(nuspec));
var nugetPackages = nuspecNuGetSettings.Select(nuspec => {
return nuspec.OutputDirectory.CombineWithFilePath(string.Concat(nuspec.Id, ".", nuspec.Version, ".nupkg"));
}).ToArray();
var binFiles = nuspecNuGetSettings.SelectMany(nuspec => {
return nuspec.Files.Select(file => {
return ((DirectoryPath)nuspec.BasePath).CombineWithFilePath(file.Source);
});
}).GroupBy(f => f.FullPath).Select(g => g.First());
///////////////////////////////////////////////////////////////////////////////
// INFORMATION
///////////////////////////////////////////////////////////////////////////////
Information("Building version {0} of Avalonia ({1}, {2}, {3}) using version {4} of Cake.",
version,
platform,
configuration,
target,
typeof(ICakeContext).Assembly.GetName().Version.ToString());
if (isRunningOnAppVeyor)
{
Information("Repository Name: " + BuildSystem.AppVeyor.Environment.Repository.Name);
Information("Repository Branch: " + BuildSystem.AppVeyor.Environment.Repository.Branch);
}
Information("Target: " + target);
Information("Platform: " + platform);
Information("Configuration: " + configuration);
Information("IsLocalBuild: " + isLocalBuild);
Information("IsRunningOnUnix: " + isRunningOnUnix);
Information("IsRunningOnWindows: " + isRunningOnWindows);
Information("IsRunningOnAppVeyor: " + isRunningOnAppVeyor);
Information("IsPullRequest: " + isPullRequest);
Information("IsMainRepo: " + isMainRepo);
Information("IsMasterBranch: " + isMasterBranch);
Information("IsTagged: " + isTagged);
Information("IsReleasable: " + isReleasable);
Information("IsMyGetRelease: " + isMyGetRelease);
Information("IsNuGetRelease: " + isNuGetRelease);
///////////////////////////////////////////////////////////////////////////////
// TASKS
///////////////////////////////////////////////////////////////////////////////
Task("Clean")
.Does(() =>
{
CleanDirectories(buildDirs);
CleanDirectory(artifactsDir);
CleanDirectory(nugetRoot);
CleanDirectory(zipRoot);
CleanDirectory(binRoot);
CleanDirectory(testsRoot);
if(removeUntilEndProject)
{
if(l.StartsWith("EndProject"))
removeUntilEndProject = false;
return false;
}
var blacklist = blacklistedGuids.Any(g => l.ToLower().Contains(g));
if(blacklist && l.StartsWith("Project"))
removeUntilEndProject = true;
return !blacklist;
}));
});
Task("Restore-NuGet-Packages")
.IsDependentOn("Clean")
.IsDependentOn("Prepare-XBuild-Solution")
.Does(() =>
{
var maxRetryCount = 5;
@ -609,15 +153,15 @@ Task("Restore-NuGet-Packages")
toolTimeout+=0.5;
}})
.Execute(()=> {
if(isRunningOnWindows)
if(parameters.IsRunningOnWindows)
{
NuGetRestore(MSBuildSolution, new NuGetRestoreSettings {
NuGetRestore(parameters.MSBuildSolution, new NuGetRestoreSettings {
ToolTimeout = TimeSpan.FromMinutes(toolTimeout)
});
}
else
{
NuGetRestore(XBuildSolution, new NuGetRestoreSettings {
NuGetRestore(parameters.XBuildSolution, new NuGetRestoreSettings {
ToolTimeout = TimeSpan.FromMinutes(toolTimeout)
});
}
@ -628,11 +172,11 @@ Task("Build")
.IsDependentOn("Restore-NuGet-Packages")
.Does(() =>
{
if(isRunningOnWindows)
if(parameters.IsRunningOnWindows)
{
MSBuild(MSBuildSolution, settings => {
settings.SetConfiguration(configuration);
settings.WithProperty("Platform", "\"" + platform + "\"");
MSBuild(parameters.MSBuildSolution, settings => {
settings.SetConfiguration(parameters.Configuration);
settings.WithProperty("Platform", "\"" + parameters.Platform + "\"");
settings.SetVerbosity(Verbosity.Minimal);
settings.WithProperty("Windows", "True");
settings.UseToolVersion(MSBuildToolVersion.VS2015);
@ -641,9 +185,9 @@ Task("Build")
}
else
{
XBuild(XBuildSolution, settings => {
settings.SetConfiguration(configuration);
settings.WithProperty("Platform", "\"" + platform + "\"");
XBuild(parameters.XBuildSolution, settings => {
settings.SetConfiguration(parameters.Configuration);
settings.WithProperty("Platform", "\"" + parameters.Platform + "\"");
settings.SetVerbosity(Verbosity.Minimal);
});
}
@ -651,23 +195,23 @@ Task("Build")
Task("Run-Unit-Tests")
.IsDependentOn("Build")
.WithCriteria(() => !skipTests)
.WithCriteria(() => !parameters.SkipTests)
.Does(() =>
{
var unitTests = GetDirectories("./tests/Avalonia.*.UnitTests")
.Select(dir => System.IO.Path.GetFileName(dir.FullPath))
.Where(name => isRunningOnWindows ? true : !(name.IndexOf("Direct2D", StringComparison.OrdinalIgnoreCase) >= 0))
.Select(name => MakeAbsolute(File("./tests/" + name + "/bin/" + dirSuffix + "/" + name + ".dll")))
.Where(name => parameters.IsRunningOnWindows ? true : !(name.IndexOf("Direct2D", StringComparison.OrdinalIgnoreCase) >= 0))
.Select(name => MakeAbsolute(File("./tests/" + name + "/bin/" + parameters.DirSuffix + "/" + name + ".dll")))
.ToList();
if (isRunningOnWindows)
if (parameters.IsRunningOnWindows)
{
var leakTests = GetFiles("./tests/Avalonia.LeakTests/bin/" + dirSuffix + "/*.LeakTests.dll");
var leakTests = GetFiles("./tests/Avalonia.LeakTests/bin/" + parameters.DirSuffix + "/*.LeakTests.dll");
unitTests.AddRange(leakTests);
}
var toolPath = (isPlatformAnyCPU || isPlatformX86) ?
var toolPath = (parameters.IsPlatformAnyCPU || parameters.IsPlatformX86) ?
"./tools/xunit.runner.console/tools/xunit.console.x86.exe" :
"./tools/xunit.runner.console/tools/xunit.console.exe";
@ -678,9 +222,9 @@ Task("Run-Unit-Tests")
ShadowCopy = false
};
xUnitSettings.NoAppDomain = !isRunningOnWindows;
xUnitSettings.NoAppDomain = !parameters.IsRunningOnWindows;
var openCoverOutput = artifactsDir.GetFilePath(new FilePath("./coverage.xml"));
var openCoverOutput = parameters.ArtifactsDir.GetFilePath(new FilePath("./coverage.xml"));
var openCoverSettings = new OpenCoverSettings()
.WithFilter("+[Avalonia.*]* -[*Test*]* -[ControlCatalog*]*")
.WithFilter("-[Avalonia.*]OmniXaml.* -[Avalonia.*]Glass.*")
@ -690,11 +234,11 @@ Task("Run-Unit-Tests")
foreach(var test in unitTests.Where(testFile => FileExists(testFile)))
{
CopyDirectory(test.GetDirectory(), testsRoot);
CopyDirectory(test.GetDirectory(), parameters.TestsRoot);
}
var testsInDirectoryToRun = new List<FilePath>();
if(isRunningOnWindows)
if(parameters.IsRunningOnWindows)
{
testsInDirectoryToRun.AddRange(GetFiles("./artifacts/tests/*Tests.dll"));
}
@ -703,7 +247,7 @@ Task("Run-Unit-Tests")
testsInDirectoryToRun.AddRange(GetFiles("./artifacts/tests/*.UnitTests.dll"));
}
if(isRunningOnWindows)
if(parameters.IsRunningOnWindows)
{
OpenCover(context => {
context.XUnit2(testsInDirectoryToRun, xUnitSettings);
@ -719,26 +263,26 @@ Task("Copy-Files")
.IsDependentOn("Run-Unit-Tests")
.Does(() =>
{
CopyFiles(binFiles, binRoot);
CopyFiles(packages.BinFiles, parameters.BinRoot);
});
Task("Zip-Files")
.IsDependentOn("Copy-Files")
.Does(() =>
{
Zip(binRoot, zipCoreArtifacts);
Zip(parameters.BinRoot, parameters.ZipCoreArtifacts);
Zip(zipSourceControlCatalogDesktopDirs,
zipTargetControlCatalogDesktopDirs,
GetFiles(zipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") +
GetFiles(zipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
Zip(parameters.ZipSourceControlCatalogDesktopDirs,
parameters.ZipTargetControlCatalogDesktopDirs,
GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") +
GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
});
Task("Create-NuGet-Packages")
.IsDependentOn("Run-Unit-Tests")
.Does(() =>
{
foreach(var nuspec in nuspecNuGetSettings)
foreach(var nuspec in packages.NuspecNuGetSettings)
{
NuGetPack(nuspec);
}
@ -746,11 +290,11 @@ Task("Create-NuGet-Packages")
Task("Publish-MyGet")
.IsDependentOn("Create-NuGet-Packages")
.WithCriteria(() => !isLocalBuild)
.WithCriteria(() => !isPullRequest)
.WithCriteria(() => isMainRepo)
.WithCriteria(() => isMasterBranch)
.WithCriteria(() => isMyGetRelease)
.WithCriteria(() => !parameters.IsLocalBuild)
.WithCriteria(() => !parameters.IsPullRequest)
.WithCriteria(() => parameters.IsMainRepo)
.WithCriteria(() => parameters.IsMasterBranch)
.WithCriteria(() => parameters.IsMyGetRelease)
.Does(() =>
{
var apiKey = EnvironmentVariable("MYGET_API_KEY");
@ -765,7 +309,7 @@ Task("Publish-MyGet")
throw new InvalidOperationException("Could not resolve MyGet API url.");
}
foreach(var nupkg in nugetPackages)
foreach(var nupkg in packages.NugetPackages)
{
NuGetPush(nupkg, new NuGetPushSettings {
Source = apiUrl,
@ -780,11 +324,11 @@ Task("Publish-MyGet")
Task("Publish-NuGet")
.IsDependentOn("Create-NuGet-Packages")
.WithCriteria(() => !isLocalBuild)
.WithCriteria(() => !isPullRequest)
.WithCriteria(() => isMainRepo)
.WithCriteria(() => isMasterBranch)
.WithCriteria(() => isNuGetRelease)
.WithCriteria(() => !parameters.IsLocalBuild)
.WithCriteria(() => !parameters.IsPullRequest)
.WithCriteria(() => parameters.IsMainRepo)
.WithCriteria(() => parameters.IsMasterBranch)
.WithCriteria(() => parameters.IsNuGetRelease)
.Does(() =>
{
var apiKey = EnvironmentVariable("NUGET_API_KEY");
@ -799,7 +343,7 @@ Task("Publish-NuGet")
throw new InvalidOperationException("Could not resolve NuGet API url.");
}
foreach(var nupkg in nugetPackages)
foreach(var nupkg in packages.NugetPackages)
{
NuGetPush(nupkg, new NuGetPushSettings {
ApiKey = apiKey,
@ -834,4 +378,4 @@ Task("Travis")
// EXECUTE
///////////////////////////////////////////////////////////////////////////////
RunTarget(target);
RunTarget(parameters.Target);

469
packages.cake

@ -0,0 +1,469 @@
public class Packages
{
public List<NuGetPackSettings> NuspecNuGetSettings { get; private set; }
public FilePath[] NugetPackages { get; private set; }
public FilePath[] BinFiles { get; private set; }
public Packages(ICakeContext context, Parameters parameters)
{
// NUGET NUSPECS
context.Information("Getting git modules:");
var ignoredSubModulesPaths = System.IO.File.ReadAllLines(".git/config").Where(m=>m.StartsWith("[submodule ")).Select(m =>
{
var path = m.Split(' ')[1].Trim("\"[] \t".ToArray());
context.Information(path);
return ((DirectoryPath)context.Directory(path)).FullPath;
}).ToList();
var normalizePath = new Func<string, string>(
path => path.Replace(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar).ToUpperInvariant());
// Key: Package Id
// Value is Tuple where Item1: Package Version, Item2: The packages.config file path.
var packageVersions = new Dictionary<string, IList<Tuple<string,string>>>();
System.IO.Directory.EnumerateFiles(((DirectoryPath)context.Directory("./src")).FullPath, "packages.config", SearchOption.AllDirectories).ToList().ForEach(fileName =>
{
if (!ignoredSubModulesPaths.Any(i => normalizePath(fileName).Contains(normalizePath(i))))
{
var file = new PackageReferenceFile(fileName);
foreach (PackageReference packageReference in file.GetPackageReferences())
{
IList<Tuple<string, string>> versions;
packageVersions.TryGetValue(packageReference.Id, out versions);
if (versions == null)
{
versions = new List<Tuple<string, string>>();
packageVersions[packageReference.Id] = versions;
}
versions.Add(Tuple.Create(packageReference.Version.ToString(), fileName));
}
}
});
context.Information("Checking installed NuGet package dependencies versions:");
packageVersions.ToList().ForEach(package =>
{
var packageVersion = package.Value.First().Item1;
bool isValidVersion = package.Value.All(x => x.Item1 == packageVersion);
if (!isValidVersion)
{
context.Information("Error: package {0} has multiple versions installed:", package.Key);
foreach (var v in package.Value)
{
context.Information("{0}, file: {1}", v.Item1, v.Item2);
}
throw new Exception("Detected multiple NuGet package version installed for different projects.");
}
});
context.Information("Setting NuGet package dependencies versions:");
var SerilogVersion = packageVersions["Serilog"].FirstOrDefault().Item1;
var SplatVersion = packageVersions["Splat"].FirstOrDefault().Item1;
var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1;
var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1;
var SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
var SharpDXVersion = packageVersions["SharpDX"].FirstOrDefault().Item1;
var SharpDXDirect2D1Version = packageVersions["SharpDX.Direct2D1"].FirstOrDefault().Item1;
var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1;
var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1;
context.Information("Package: Serilog, version: {0}", SerilogVersion);
context.Information("Package: Splat, version: {0}", SplatVersion);
context.Information("Package: Sprache, version: {0}", SpracheVersion);
context.Information("Package: System.Reactive, version: {0}", SystemReactiveVersion);
context.Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion);
context.Information("Package: SharpDX, version: {0}", SharpDXVersion);
context.Information("Package: SharpDX.Direct2D1, version: {0}", SharpDXDirect2D1Version);
context.Information("Package: SharpDX.Direct3D11, version: {0}", SharpDXDirect3D11Version);
context.Information("Package: SharpDX.DXGI, version: {0}", SharpDXDXGIVersion);
var SetNuGetNuspecCommonProperties = new Action<NuGetPackSettings> ((nuspec) => {
nuspec.Version = parameters.Version;
nuspec.Authors = new [] { "Avalonia Team" };
nuspec.Owners = new [] { "stevenk" };
nuspec.LicenseUrl = new Uri("http://opensource.org/licenses/MIT");
nuspec.ProjectUrl = new Uri("https://github.com/AvaloniaUI/Avalonia/");
nuspec.RequireLicenseAcceptance = false;
nuspec.Symbols = false;
nuspec.NoPackageAnalysis = true;
nuspec.Description = "The Avalonia UI framework";
nuspec.Copyright = "Copyright 2015";
nuspec.Tags = new [] { "Avalonia" };
});
var coreLibraries = new string[][]
{
new [] { "./src/", "Avalonia.Animation", ".dll" },
new [] { "./src/", "Avalonia.Animation", ".xml" },
new [] { "./src/", "Avalonia.Base", ".dll" },
new [] { "./src/", "Avalonia.Base", ".xml" },
new [] { "./src/", "Avalonia.Controls", ".dll" },
new [] { "./src/", "Avalonia.Controls", ".xml" },
new [] { "./src/", "Avalonia.DesignerSupport", ".dll" },
new [] { "./src/", "Avalonia.DesignerSupport", ".xml" },
new [] { "./src/", "Avalonia.Diagnostics", ".dll" },
new [] { "./src/", "Avalonia.Diagnostics", ".xml" },
new [] { "./src/", "Avalonia.Input", ".dll" },
new [] { "./src/", "Avalonia.Input", ".xml" },
new [] { "./src/", "Avalonia.Interactivity", ".dll" },
new [] { "./src/", "Avalonia.Interactivity", ".xml" },
new [] { "./src/", "Avalonia.Layout", ".dll" },
new [] { "./src/", "Avalonia.Layout", ".xml" },
new [] { "./src/", "Avalonia.Logging.Serilog", ".dll" },
new [] { "./src/", "Avalonia.Logging.Serilog", ".xml" },
new [] { "./src/", "Avalonia.Visuals", ".dll" },
new [] { "./src/", "Avalonia.Visuals", ".xml" },
new [] { "./src/", "Avalonia.Styling", ".dll" },
new [] { "./src/", "Avalonia.Styling", ".xml" },
new [] { "./src/", "Avalonia.ReactiveUI", ".dll" },
new [] { "./src/", "Avalonia.Themes.Default", ".dll" },
new [] { "./src/", "Avalonia.Themes.Default", ".xml" },
new [] { "./src/Markup/", "Avalonia.Markup", ".dll" },
new [] { "./src/Markup/", "Avalonia.Markup", ".xml" },
new [] { "./src/Markup/", "Avalonia.Markup.Xaml", ".dll" },
new [] { "./src/Markup/", "Avalonia.Markup.Xaml", ".xml" }
};
var coreLibrariesFiles = coreLibraries.Select((lib) => {
return (FilePath)context.File(lib[0] + lib[1] + "/bin/" + parameters.DirSuffix + "/" + lib[1] + lib[2]);
}).ToList();
var coreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
return new NuSpecContent {
Source = file.FullPath, Target = "lib/portable-windows8+net45"
};
});
var win32CoreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
return new NuSpecContent {
Source = file.FullPath, Target = "lib/net45"
};
});
var netcoreappCoreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
return new NuSpecContent {
Source = file.FullPath, Target = "lib/netcoreapp1.0"
};
});
var net45RuntimePlatformExtensions = new [] {".xml", ".dll"};
var net45RuntimePlatform = net45RuntimePlatformExtensions.Select(libSuffix => {
return new NuSpecContent {
Source = ((FilePath)context.File("./src/Avalonia.DotNetFrameworkRuntime/bin/" + parameters.DirSuffix + "/Avalonia.DotNetFrameworkRuntime" + libSuffix)).FullPath,
Target = "lib/net45"
};
});
var netCoreRuntimePlatformExtensions = new [] {".xml", ".dll"};
var netCoreRuntimePlatform = netCoreRuntimePlatformExtensions.Select(libSuffix => {
return new NuSpecContent {
Source = ((FilePath)context.File("./src/Avalonia.DotNetCoreRuntime/bin/" + parameters.DirSuffix + "/Avalonia.DotNetCoreRuntime" + libSuffix)).FullPath,
Target = "lib/netcoreapp1.0"
};
});
var nuspecNuGetSettingsCore = new []
{
///////////////////////////////////////////////////////////////////////////////
// Avalonia
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia",
Dependencies = new []
{
new NuSpecDependency() { Id = "Serilog", Version = SerilogVersion },
new NuSpecDependency() { Id = "Splat", Version = SplatVersion },
new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion },
new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion },
new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp1.0", Version = "4.3.0" },
//.NET Core
new NuSpecDependency() { Id = "NETStandard.Library", TargetFramework = "netcoreapp1.0", Version = "1.6.0" },
new NuSpecDependency() { Id = "Microsoft.NETCore.Portable.Compatibility", TargetFramework = "netcoreapp1.0", Version = "1.0.1" },
new NuSpecDependency() { Id = "Splat", TargetFramework = "netcoreapp1.0", Version = "2.0.0" },
new NuSpecDependency() { Id = "Serilog", TargetFramework = "netcoreapp1.0", Version = "2.3.0" },
new NuSpecDependency() { Id = "Sprache", TargetFramework = "netcoreapp1.0", Version = SpracheVersion },
new NuSpecDependency() { Id = "System.Reactive", TargetFramework = "netcoreapp1.0", Version = SystemReactiveVersion }
},
Files = coreLibrariesNuSpecContent
.Concat(win32CoreLibrariesNuSpecContent).Concat(net45RuntimePlatform)
.Concat(netcoreappCoreLibrariesNuSpecContent).Concat(netCoreRuntimePlatform)
.ToList(),
BasePath = context.Directory("./"),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.HtmlRenderer
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.HtmlRenderer",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.HtmlRenderer.dll", Target = "lib/portable-windows8+net45" }
},
BasePath = context.Directory("./src/Avalonia.HtmlRenderer/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot
}
};
var nuspecNuGetSettingsMobile = new []
{
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Android
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Android",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Skia.Android", Version = parameters.Version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Android.dll", Target = "lib/MonoAndroid10" }
},
BasePath = context.Directory("./src/Android/Avalonia.Android/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Skia.Android
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Skia.Android",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Skia.Android.dll", Target = "lib/MonoAndroid10" }
},
BasePath = context.Directory("./src/Skia/Avalonia.Skia.Android/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.iOS
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.iOS",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Skia.iOS", Version = parameters.Version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.iOS.dll", Target = "lib/Xamarin.iOS10" }
},
BasePath = context.Directory("./src/iOS/Avalonia.iOS/bin/" + parameters.DirSuffixIOS),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Skia.iOS
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Skia.iOS",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Skia.iOS.dll", Target = "lib/Xamarin.iOS10" }
},
BasePath = context.Directory("./src/Skia/Avalonia.Skia.iOS/bin/" + parameters.DirSuffixIOS),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Mobile
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Mobile",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia.Android", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.iOS", Version = parameters.Version }
},
Files = new NuSpecContent[]
{
new NuSpecContent { Source = "licence.md", Target = "" }
},
BasePath = context.Directory("./"),
OutputDirectory = parameters.NugetRoot
}
};
var nuspecNuGetSettingsDesktop = new []
{
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Win32
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Win32",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Win32/bin/" + parameters.DirSuffix + "/Avalonia.Win32.dll", Target = "lib/net45" },
new NuSpecContent { Source = "Avalonia.Win32.NetStandard/bin/" + parameters.DirSuffix + "/Avalonia.Win32.dll", Target = "lib/netstandard1.1" }
},
BasePath = context.Directory("./src/Windows"),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Direct2D1
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Direct2D1",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
new NuSpecDependency() { Id = "SharpDX", Version = SharpDXVersion },
new NuSpecDependency() { Id = "SharpDX.Direct2D1", Version = SharpDXDirect2D1Version },
new NuSpecDependency() { Id = "SharpDX.Direct3D11", Version = SharpDXDirect3D11Version },
new NuSpecDependency() { Id = "SharpDX.DXGI", Version = SharpDXDXGIVersion }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Direct2D1.dll", Target = "lib/net45" }
},
BasePath = context.Directory("./src/Windows/Avalonia.Direct2D1/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Gtk
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Gtk",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Gtk.dll", Target = "lib/net45" }
},
BasePath = context.Directory("./src/Gtk/Avalonia.Gtk/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Gtk3
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Gtk3",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Gtk3.dll", Target = "lib/netstandard1.1" }
},
BasePath = context.Directory("./src/Gtk/Avalonia.Gtk3/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Cairo
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Cairo",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Cairo.dll", Target = "lib/net45" }
},
BasePath = context.Directory("./src/Gtk/Avalonia.Cairo/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Skia.Desktop
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Skia.Desktop",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion },
//.NET Core
new NuSpecDependency() { Id = "Avalonia", TargetFramework = "netcoreapp1.0", Version = parameters.Version },
new NuSpecDependency() { Id = "SkiaSharp", TargetFramework = "netcoreapp1.0", Version = SkiaSharpVersion },
new NuSpecDependency() { Id = "NETStandard.Library", TargetFramework = "netcoreapp1.0", Version = "1.6.0" },
new NuSpecDependency() { Id = "Microsoft.NETCore.Portable.Compatibility", TargetFramework = "netcoreapp1.0", Version = "1.0.1" }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Skia.Desktop/bin/" + parameters.DirSuffixSkia + "/Avalonia.Skia.Desktop.dll", Target = "lib/net45" },
new NuSpecContent { Source = "Avalonia.Skia.Desktop.NetStandard/bin/" + parameters.DirSuffix + "/Avalonia.Skia.Desktop.dll", Target = "lib/netcoreapp1.0" }
},
BasePath = context.Directory("./src/Skia/"),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Desktop
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Desktop",
Dependencies = new []
{
new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Gtk", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Cairo", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", Version = parameters.Version }
},
Files = new NuSpecContent[]
{
new NuSpecContent { Source = "licence.md", Target = "" }
},
BasePath = context.Directory("./"),
OutputDirectory = parameters.NugetRoot
}
};
NuspecNuGetSettings = new List<NuGetPackSettings>();
NuspecNuGetSettings.AddRange(nuspecNuGetSettingsCore);
NuspecNuGetSettings.AddRange(nuspecNuGetSettingsDesktop);
NuspecNuGetSettings.AddRange(nuspecNuGetSettingsMobile);
NuspecNuGetSettings.ForEach((nuspec) => SetNuGetNuspecCommonProperties(nuspec));
NugetPackages = NuspecNuGetSettings.Select(nuspec => {
return nuspec.OutputDirectory.CombineWithFilePath(string.Concat(nuspec.Id, ".", nuspec.Version, ".nupkg"));
}).ToArray();
BinFiles = NuspecNuGetSettings.SelectMany(nuspec => {
return nuspec.Files.Select(file => {
return ((DirectoryPath)nuspec.BasePath).CombineWithFilePath(file.Source);
});
}).GroupBy(f => f.FullPath).Select(g => g.First()).ToArray();
}
}

143
parameters.cake

@ -0,0 +1,143 @@
public class Parameters
{
public string Target { get; private set; }
public string Platform { get; private set; }
public string Configuration { get; private set; }
public bool SkipTests { get; private set; }
public string MainRepo { get; private set; }
public string MasterBranch { get; private set; }
public string AssemblyInfoPath { get; private set; }
public string ReleasePlatform { get; private set; }
public string ReleaseConfiguration { get; private set; }
public string MSBuildSolution { get; private set; }
public string XBuildSolution { get; private set; }
public bool IsPlatformAnyCPU { get; private set; }
public bool IsPlatformX86 { get; private set; }
public bool IsPlatformX64 { get; private set; }
public bool IsLocalBuild { get; private set; }
public bool IsRunningOnUnix { get; private set; }
public bool IsRunningOnWindows { get; private set; }
public bool IsRunningOnAppVeyor { get; private set; }
public bool IsPullRequest { get; private set; }
public bool IsMainRepo { get; private set; }
public bool IsMasterBranch { get; private set; }
public bool IsTagged { get; private set; }
public bool IsReleasable { get; private set; }
public bool IsMyGetRelease { get; private set; }
public bool IsNuGetRelease { get; private set; }
public string Version { get; private set; }
public DirectoryPath ArtifactsDir { get; private set; }
public DirectoryPath NugetRoot { get; private set; }
public DirectoryPath ZipRoot { get; private set; }
public DirectoryPath BinRoot { get; private set; }
public DirectoryPath TestsRoot { get; private set; }
public string DirSuffix { get; private set; }
public string DirSuffixSkia { get; private set; }
public string DirSuffixIOS { get; private set; }
public DirectoryPathCollection BuildDirs { get; private set; }
public string FileZipSuffix { get; private set; }
public FilePath ZipCoreArtifacts { get; private set; }
public DirectoryPath ZipSourceControlCatalogDesktopDirs { get; private set; }
public FilePath ZipTargetControlCatalogDesktopDirs { get; private set; }
public Parameters(ICakeContext context)
{
var buildSystem = context.BuildSystem();
// ARGUMENTS
Target = context.Argument("target", "Default");
Platform = context.Argument("platform", "Any CPU");
Configuration = context.Argument("configuration", "Release");
SkipTests = context.HasArgument("skip-tests");
// CONFIGURATION
MainRepo = "AvaloniaUI/Avalonia";
MasterBranch = "master";
AssemblyInfoPath = context.File("./src/Shared/SharedAssemblyInfo.cs");
ReleasePlatform = "Any CPU";
ReleaseConfiguration = "Release";
MSBuildSolution = "./Avalonia.sln";
XBuildSolution = "./Avalonia.XBuild.sln";
// PARAMETERS
IsPlatformAnyCPU = StringComparer.OrdinalIgnoreCase.Equals(Platform, "Any CPU");
IsPlatformX86 = StringComparer.OrdinalIgnoreCase.Equals(Platform, "x86");
IsPlatformX64 = StringComparer.OrdinalIgnoreCase.Equals(Platform, "x64");
IsLocalBuild = buildSystem.IsLocalBuild;
IsRunningOnUnix = context.IsRunningOnUnix();
IsRunningOnWindows = context.IsRunningOnWindows();
IsRunningOnAppVeyor = buildSystem.AppVeyor.IsRunningOnAppVeyor;
IsPullRequest = buildSystem.AppVeyor.Environment.PullRequest.IsPullRequest;
IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, buildSystem.AppVeyor.Environment.Repository.Name);
IsMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch, buildSystem.AppVeyor.Environment.Repository.Branch);
IsTagged = buildSystem.AppVeyor.Environment.Repository.Tag.IsTag
&& !string.IsNullOrWhiteSpace(buildSystem.AppVeyor.Environment.Repository.Tag.Name);
IsReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleasePlatform, Platform)
&& StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, Configuration);
IsMyGetRelease = !IsTagged && IsReleasable;
IsNuGetRelease = IsTagged && IsReleasable;
// VERSION
Version = context.Argument("force-nuget-version", context.ParseAssemblyInfo(AssemblyInfoPath).AssemblyVersion);
if (IsRunningOnAppVeyor)
{
if (IsTagged)
{
// Use Tag Name as version
Version = buildSystem.AppVeyor.Environment.Repository.Tag.Name;
}
else
{
// Use AssemblyVersion with Build as version
Version += "-build" + context.EnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-alpha";
}
}
// DIRECTORIES
ArtifactsDir = (DirectoryPath)context.Directory("./artifacts");
NugetRoot = ArtifactsDir.Combine("nuget");
ZipRoot = ArtifactsDir.Combine("zip");
BinRoot = ArtifactsDir.Combine("bin");
TestsRoot = ArtifactsDir.Combine("tests");
DirSuffix = Configuration;
DirSuffixSkia = (IsPlatformAnyCPU ? "x86" : Platform) + "/" + Configuration;
DirSuffixIOS = "iPhone" + "/" + Configuration;
BuildDirs =
context.GetDirectories("./src/**/bin/" + DirSuffix) +
context.GetDirectories("./src/**/obj/" + DirSuffix) +
context.GetDirectories("./src/Markup/**/bin/" + DirSuffix) +
context.GetDirectories("./src/Markup/**/obj/" + DirSuffix) +
context.GetDirectories("./src/Android/**/bin/" + DirSuffix) +
context.GetDirectories("./src/Android/**/obj/" + DirSuffix) +
context.GetDirectories("./src/Gtk/**/bin/" + DirSuffix) +
context.GetDirectories("./src/Gtk/**/obj/" + DirSuffix) +
context.GetDirectories("./src/iOS/**/bin/" + DirSuffixIOS) +
context.GetDirectories("./src/iOS/**/obj/" + DirSuffixIOS) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.Android/bin/" + DirSuffix) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.Android/obj/" + DirSuffix) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.Android.TestApp/bin/" + DirSuffix) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.Android.TestApp/obj/" + DirSuffix) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.Desktop/bin/" + DirSuffixSkia) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.Desktop/obj/" + DirSuffixSkia) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.Desktop.NetStandard/bin/" + DirSuffix) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.Desktop.NetStandard/obj/" + DirSuffix) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.iOS/bin/" + DirSuffixIOS) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.iOS/obj/" + DirSuffixIOS) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.iOS.TestApp/bin/" + DirSuffixIOS) +
(DirectoryPath)context.Directory("./src/Skia/Avalonia.Skia.iOS.TestApp/obj/" + DirSuffixIOS) +
context.GetDirectories("./src/Windows/**/bin/" + DirSuffix) +
context.GetDirectories("./src/Windows/**/obj/" + DirSuffix) +
context.GetDirectories("./tests/**/bin/" + DirSuffix) +
context.GetDirectories("./tests/**/obj/" + DirSuffix) +
context.GetDirectories("./Samples/**/bin/" + DirSuffix) +
context.GetDirectories("./Samples/**/obj/" + DirSuffix);
FileZipSuffix = Version + ".zip";
ZipCoreArtifacts = ZipRoot.CombineWithFilePath("Avalonia-" + FileZipSuffix);
ZipSourceControlCatalogDesktopDirs = (DirectoryPath)context.Directory("./samples/ControlCatalog.Desktop/bin/" + DirSuffix);
ZipTargetControlCatalogDesktopDirs = ZipRoot.CombineWithFilePath("ControlCatalog.Desktop-" + FileZipSuffix);
}
}

5
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@ -32,9 +32,12 @@
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidSupportedAbis>armeabi;armeabi-v7a;x86</AndroidSupportedAbis>
<Debugger>Xamarin</Debugger>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<EnableProguard>False</EnableProguard>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>

24
samples/ControlCatalog.Android/MainActivity.cs

@ -1,9 +1,8 @@
using System;
using Android.App;
using Android.OS;
using Android.Content.PM;
using Avalonia.Android.Platform.Specific;
using Avalonia.Android;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Markup.Xaml;
@ -17,29 +16,16 @@ namespace ControlCatalog.Android
[Activity(Label = "ControlCatalog.Android", MainLauncher = true, Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance)]
public class MainActivity : AvaloniaActivity
{
public MainActivity() : base(typeof (App))
{
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
App app;
if (Avalonia.Application.Current != null)
app = (App)Avalonia.Application.Current;
else
if (Avalonia.Application.Current == null)
{
app = new App();
AppBuilder.Configure(app)
AppBuilder.Configure(new App())
.UseAndroid()
.UseSkia()
.SetupWithoutStarting();
Content = new MainView();
}
var mainWindow = new MainWindow();
app.Run(mainWindow);
base.OnCreate(savedInstanceState);
}
}
}

7
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@ -33,6 +33,9 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\packages\Serilog.1.5.14\lib\net45\Serilog.dll</HintPath>
@ -72,6 +75,10 @@
<Project>{FB05AC90-89BA-4F2F-A924-F37875FB547C}</Project>
<Name>Avalonia.Cairo</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj">
<Project>{bb1f7bb5-6ad4-4776-94d9-c09d0a972658}</Project>
<Name>Avalonia.Gtk3</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj">
<Project>{54F237D5-A70A-4752-9656-0C70B1A7B047}</Project>
<Name>Avalonia.Gtk</Name>

27
samples/ControlCatalog/Pages/TreeViewPage.xaml.cs

@ -11,7 +11,7 @@ namespace ControlCatalog.Pages
public TreeViewPage()
{
this.InitializeComponent();
DataContext = CreateNodes(0);
DataContext = new Node().Children;
}
private void InitializeComponent()
@ -19,19 +19,22 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this);
}
private IList<Node> CreateNodes(int level)
public class Node
{
return Enumerable.Range(0, 10).Select(x => new Node
private IList<Node> _children;
public string Header { get; private set; }
public IList<Node> Children
{
Header = $"Item {x}",
Children = level < 5 ? CreateNodes(level + 1) : null,
}).ToList();
}
private class Node
{
public string Header { get; set; }
public IList<Node> Children { get; set; }
get
{
if (_children == null)
{
_children = Enumerable.Range(1, 10).Select(i => new Node() {Header = $"Item {i}"})
.ToArray();
}
return _children;
}
}
}
}
}

25
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -1,5 +1,8 @@
using System;
using System.IO;
using System.Linq;
using Android.Content;
using Android.Views;
using Avalonia.Android.Platform;
using Avalonia.Android.Platform.Input;
using Avalonia.Android.Platform.SkiaPlatform;
@ -8,6 +11,7 @@ using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Shared.PlatformSupport;
using Avalonia.Skia;
@ -17,7 +21,8 @@ namespace Avalonia
{
public static T UseAndroid<T>(this T builder) where T : AppBuilderBase<T>, new()
{
builder.UseWindowingSubsystem(Android.AndroidPlatform.Initialize, "Android");
builder.UseWindowingSubsystem(() => Android.AndroidPlatform.Initialize(builder.Instance), "Android");
builder.UseSkia();
return builder;
}
}
@ -25,7 +30,7 @@ namespace Avalonia
namespace Avalonia.Android
{
public class AndroidPlatform : IPlatformSettings, IWindowingPlatform
class AndroidPlatform : IPlatformSettings, IWindowingPlatform
{
public static readonly AndroidPlatform Instance = new AndroidPlatform();
public Size DoubleClickSize => new Size(4, 4);
@ -40,7 +45,7 @@ namespace Avalonia.Android
_scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity;
}
public static void Initialize()
public static void Initialize(Avalonia.Application app)
{
AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToTransient<ClipboardImpl>()
@ -51,24 +56,22 @@ namespace Avalonia.Android
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(Instance)
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>();
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
.Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
SkiaPlatform.Initialize();
}
.Bind<IAssetLoader>().ToConstant(new AssetLoader(app.GetType().Assembly));
public void Init(Type applicationType)
{
StandardRuntimePlatformServices.Register(applicationType.Assembly);
SkiaPlatform.Initialize();
}
public IWindowImpl CreateWindow()
{
return new WindowImpl();
throw new NotSupportedException();
}
public IEmbeddableWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public IPopupImpl CreatePopup()

12
src/Android/Avalonia.Android/AndroidThreadingInterface.cs

@ -51,10 +51,16 @@ namespace Avalonia.Android
scheduled = true;
EnsureInvokeOnMainThread(() =>
{
tick();
lock (l)
try
{
scheduled = false;
tick();
}
finally
{
lock (l)
{
scheduled = false;
}
}
});
}

9
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -63,16 +63,17 @@
<ItemGroup>
<Compile Include="AndroidPlatform.cs" />
<Compile Include="AndroidThreadingInterface.cs" />
<Compile Include="AvaloniaActivity.cs" />
<Compile Include="AvaloniaView.cs" />
<Compile Include="PlatformIconLoader.cs" />
<Compile Include="Platform\ClipboardImpl.cs" />
<Compile Include="CursorFactory.cs" />
<Compile Include="Platform\Input\AndroidKeyboardDevice.cs" />
<Compile Include="Platform\Input\AndroidMouseDevice.cs" />
<Compile Include="Platform\SkiaPlatform\MainWindowImpl.cs" />
<Compile Include="Platform\SkiaPlatform\WindowImpl.cs" />
<Compile Include="Platform\SkiaPlatform\AndroidFramebuffer.cs" />
<Compile Include="Platform\SkiaPlatform\InvalidationAwareSurfaceView.cs" />
<Compile Include="Platform\SkiaPlatform\TopLevelImpl.cs" />
<Compile Include="Platform\Specific\IAndroidView.cs" />
<Compile Include="Platform\Specific\IAndroidActivity.cs" />
<Compile Include="Platform\Specific\AvaloniaActivity.cs" />
<Compile Include="Platform\Specific\Helpers\AndroidTouchEventsHelper.cs" />
<Compile Include="Platform\Specific\Helpers\AndroidKeyboardEventsHelper.cs" />
<Compile Include="Resources\Resource.Designer.cs" />

50
src/Android/Avalonia.Android/AvaloniaActivity.cs

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace Avalonia.Android
{
public abstract class AvaloniaActivity : Activity
{
AvaloniaView _view;
object _content;
protected override void OnCreate(Bundle savedInstanceState)
{
RequestWindowFeature(WindowFeatures.NoTitle);
_view = new AvaloniaView(this);
if(_content != null)
_view.Content = _content;
SetContentView(_view);
TakeKeyEvents(true);
base.OnCreate(savedInstanceState);
}
public object Content
{
get
{
return _content;
}
set
{
_content = value;
if (_view != null)
_view.Content = value;
}
}
public override bool DispatchKeyEvent(KeyEvent e)
{
return _view.DispatchKeyEvent(e);
}
}
}

59
src/Android/Avalonia.Android/AvaloniaView.cs

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Controls.Embedding;
using Avalonia.Platform;
namespace Avalonia.Android
{
public class AvaloniaView : FrameLayout
{
private readonly EmbeddableControlRoot _root;
private readonly ViewImpl _view;
public AvaloniaView(Context context) : base(context)
{
_view = new ViewImpl(context);
AddView(_view);
_root = new EmbeddableControlRoot(_view);
_root.Prepare();
}
public object Content
{
get { return _root.Content; }
set { _root.Content = value; }
}
public override bool DispatchKeyEvent(KeyEvent e)
{
return _view.DispatchKeyEvent(e);
}
class ViewImpl : TopLevelImpl, IEmbeddableWindowImpl
{
public event Action LostFocus;
public ViewImpl(Context context) : base(context)
{
Focusable = true;
FocusChange += ViewImpl_FocusChange;
}
private void ViewImpl_FocusChange(object sender, FocusChangeEventArgs e)
{
if(!e.HasFocus)
LostFocus?.Invoke();
}
}
}
}

101
src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs

@ -0,0 +1,101 @@
using System;
using System.Runtime.InteropServices;
using Android.Runtime;
using Android.Views;
using Avalonia.Controls.Platform.Surfaces;
namespace Avalonia.Android.Platform.SkiaPlatform
{
class AndroidFramebuffer : ILockedFramebuffer
{
private IntPtr _window;
public AndroidFramebuffer(Surface surface)
{
_window = ANativeWindow_fromSurface(JNIEnv.Handle, surface.Handle);
ANativeWindow_Buffer buffer;
var rc = new ARect()
{
right = Width = ANativeWindow_getWidth(_window),
bottom = Height = ANativeWindow_getHeight(_window)
};
ANativeWindow_lock(_window, out buffer, ref rc);
Format = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565
? PixelFormat.Rgb565 : PixelFormat.Rgba8888;
RowBytes = buffer.stride * (Format == PixelFormat.Rgb565 ? 2 : 4);
Address = buffer.bits;
}
public void Dispose()
{
ANativeWindow_unlockAndPost(_window);
ANativeWindow_release(_window);
_window = IntPtr.Zero;
Address = IntPtr.Zero;
}
public IntPtr Address { get; set; }
public int Width { get; }
public int Height { get; }
public int RowBytes { get; }
public Size Dpi { get; } = new Size(96, 96);
public PixelFormat Format { get; }
[DllImport("android")]
internal static extern IntPtr ANativeWindow_fromSurface(IntPtr jniEnv, IntPtr handle);
[DllImport("android")]
internal static extern int ANativeWindow_getWidth(IntPtr window);
[DllImport("android")]
internal static extern int ANativeWindow_getHeight(IntPtr window);
[DllImport("android")]
internal static extern void ANativeWindow_release(IntPtr window);
[DllImport("android")]
internal static extern void ANativeWindow_unlockAndPost(IntPtr window);
[DllImport("android")]
internal static extern int ANativeWindow_lock(IntPtr window, out ANativeWindow_Buffer outBuffer, ref ARect inOutDirtyBounds);
public enum AndroidPixelFormat
{
WINDOW_FORMAT_RGBA_8888 = 1,
WINDOW_FORMAT_RGBX_8888 = 2,
WINDOW_FORMAT_RGB_565 = 4,
}
internal struct ARect
{
public int left;
public int top;
public int right;
public int bottom;
}
internal struct ANativeWindow_Buffer
{
// The number of pixels that are show horizontally.
public int width;
// The number of pixels that are shown vertically.
public int height;
// The number of *pixels* that a line in the buffer takes in
// memory. This may be >= width.
public int stride;
// The format of the buffer. One of WINDOW_FORMAT_*
public AndroidPixelFormat format;
// The actual bits.
public IntPtr bits;
// Do not touch.
uint reserved1;
uint reserved2;
uint reserved3;
uint reserved4;
uint reserved5;
uint reserved6;
}
}
}

8
src/Skia/Avalonia.Skia.Android/SkiaView.cs → src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@ -14,16 +14,16 @@ using Android.Widget;
using Avalonia.Media;
using Avalonia.Platform;
namespace Avalonia.Skia.Android
namespace Avalonia.Android
{
public abstract class SkiaView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle
public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle
{
private readonly Activity _context;
private readonly Context _context;
bool _invalidateQueued;
readonly object _lock = new object();
private readonly Handler _handler;
public SkiaView(Activity context) : base(context)
public InvalidationAwareSurfaceView(Context context) : base(context)
{
_context = context;
Holder.AddCallback(this);

44
src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs

@ -1,44 +0,0 @@
using Android.Views;
using Avalonia.Android.Platform.Specific;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Platform;
namespace Avalonia.Android.Platform.SkiaPlatform
{
public class MainWindowImpl :
WindowImpl
, IWindowImpl
{
public MainWindowImpl()
{
}
public new WindowState WindowState
{
get { return WindowState.Normal; }
set { }
}
protected override void Init()
{
base.Init();
HandleEvents = true;
_keyboardHelper.ActivateAutoShowKeybord();
}
void ITopLevelImpl.Show()
{
(Parent as ViewGroup)?.RemoveAllViews();
AvaloniaLocator.Current.GetService<IAndroidActivity>().ContentView = this;
//this.Visibility = ViewStates.Visible;
}
void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot)
{
base.SetInputRoot(inputRoot);
_keyboardHelper.UpdateKeyboardState(inputRoot);
}
}
}

38
src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs → src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -7,31 +7,30 @@ using Avalonia.Android.Platform.Specific.Helpers;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Skia.Android;
using System;
using System.Collections.Generic;
using Avalonia.Controls;
using Avalonia.Controls.Platform.Surfaces;
namespace Avalonia.Android.Platform.SkiaPlatform
{
public class WindowImpl : SkiaView, IAndroidView, IWindowImpl, ISurfaceHolderCallback
class TopLevelImpl : InvalidationAwareSurfaceView, IAndroidView, ITopLevelImpl,
ISurfaceHolderCallback, IFramebufferPlatformSurface
{
protected AndroidKeyboardEventsHelper<WindowImpl> _keyboardHelper;
protected AndroidKeyboardEventsHelper<TopLevelImpl> _keyboardHelper;
private AndroidTouchEventsHelper<WindowImpl> _touchHelper;
private AndroidTouchEventsHelper<TopLevelImpl> _touchHelper;
public WindowImpl(Context context) : base((Activity)context)
public TopLevelImpl(Context context) : base(context)
{
_keyboardHelper = new AndroidKeyboardEventsHelper<WindowImpl>(this);
_touchHelper = new AndroidTouchEventsHelper<WindowImpl>(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p));
_keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this);
_touchHelper = new AndroidTouchEventsHelper<TopLevelImpl>(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p));
MaxClientSize = new Size(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels);
ClientSize = MaxClientSize;
Init();
}
public WindowImpl() : this(AvaloniaLocator.Current.GetService<IAndroidActivity>().Activity)
{
}
void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{
@ -45,11 +44,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
base.SurfaceChanged(holder, format, width, height);
}
protected virtual void Init()
{
}
private bool _handleEvents;
public bool HandleEvents
@ -95,6 +90,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
IPlatformHandle ITopLevelImpl.Handle => this;
public IEnumerable<object> Surfaces => new object[] { this };
public void Activate()
{
}
@ -108,11 +105,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
}
public void SetCoverTaskbarWhenMaximized(bool enable)
{
//Not supported
}
public void Invalidate(Rect rect)
{
if (Holder?.Surface?.IsValid == true) base.Invalidate();
@ -193,5 +185,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
// No window icons for mobile platforms
}
ILockedFramebuffer IFramebufferPlatformSurface.Lock()=>new AndroidFramebuffer(Holder.Surface);
}
}

60
src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs

@ -1,60 +0,0 @@
using System;
using Android.App;
using Android.OS;
using Android.Views;
using Android.Widget;
namespace Avalonia.Android.Platform.Specific
{
public class AvaloniaActivity : Activity, IAndroidActivity
{
private IAndroidView _contentView;
public AvaloniaActivity(Type applicationType)
{
AndroidPlatform.Instance.Init(applicationType);
}
public Activity Activity => this;
public IAndroidView ContentView
{
get
{
return this._contentView;
}
set
{
this._contentView = value;
var fl = new FrameLayout(this);
fl.AddView(this._contentView.View);
//this.SetContentView(value.View);
this.SetContentView(fl);
}
}
protected override void OnCreate(Bundle savedInstanceState)
{
AvaloniaLocator.CurrentMutable.Bind<IAndroidActivity>().ToConstant(this);
RequestWindowFeature(WindowFeatures.NoTitle);
base.OnCreate(savedInstanceState);
}
public override void SetContentView(View view)
{
base.SetContentView(view);
TakeKeyEvents(true);
}
public override bool DispatchKeyEvent(KeyEvent e)
{
if (_contentView != null)
{
_contentView.View.DispatchKeyEvent(e);
}
return base.DispatchKeyEvent(e);
}
}
}

2
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs

@ -12,7 +12,7 @@ using System.ComponentModel;
namespace Avalonia.Android.Platform.Specific.Helpers
{
public class AndroidKeyboardEventsHelper<TView> : IDisposable where TView : View, IWindowImpl, IAndroidView
public class AndroidKeyboardEventsHelper<TView> : IDisposable where TView : View, ITopLevelImpl, IAndroidView
{
private TView _view;
private IInputElement _lastFocusedElement;

2
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs

@ -8,7 +8,7 @@ using System;
namespace Avalonia.Android.Platform.Specific.Helpers
{
public class AndroidTouchEventsHelper<TView> : IDisposable where TView : View, IWindowImpl, IAndroidView
public class AndroidTouchEventsHelper<TView> : IDisposable where TView : View, ITopLevelImpl, IAndroidView
{
private TView _view;
public bool HandleEvents { get; set; }

12
src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs

@ -1,12 +0,0 @@
using Android.App;
using Android.Views;
namespace Avalonia.Android.Platform.Specific
{
public interface IAndroidActivity
{
Activity Activity { get; }
IAndroidView ContentView { get; set; }
}
}

17
src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj

@ -20,7 +20,7 @@
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
@ -29,16 +29,16 @@
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
<AndroidLinkSkip />
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidStoreUncompressedFileExtensions />
<MandroidI18n />
<AndroidSupportedAbis>armeabi;armeabi-v7a;x86</AndroidSupportedAbis>
<Debugger>Xamarin</Debugger>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<DevInstrumentationEnabled>True</DevInstrumentationEnabled>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<EnableProguard>False</EnableProguard>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -72,9 +72,8 @@
<HintPath>..\..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Sprache, Version=2.0.0.51, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Sprache.2.0.0.51\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid+Xamarin.iOS10+MonoTouch\Sprache.dll</HintPath>
<Private>True</Private>
<Reference Include="Sprache, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Sprache.2.1.0\lib\netstandard1.0\Sprache.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

32
src/Android/Avalonia.AndroidTestApplication/MainActivity.cs

@ -2,7 +2,7 @@ using System;
using Android.App;
using Android.Content.PM;
using Android.OS;
using Avalonia.Android.Platform.Specific;
using Avalonia.Android;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Markup.Xaml;
@ -17,36 +17,24 @@ namespace Avalonia.AndroidTestApplication
Icon = "@drawable/icon",
LaunchMode = LaunchMode.SingleInstance/*,
ScreenOrientation = ScreenOrientation.Landscape*/)]
public class MainBaseActivity : AvaloniaActivity
public class MainBaseActivity : Activity
{
public MainBaseActivity() : base(typeof (App))
{
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
App app;
if (Avalonia.Application.Current != null)
app = (App)Avalonia.Application.Current;
else
if (Avalonia.Application.Current == null)
{
app = new App();
AppBuilder.Configure(app)
AppBuilder.Configure<App>()
.UseAndroid()
.UseSkia()
.SetupWithoutStarting();
}
app.Run();
SetContentView(new AvaloniaView(this) { Content = App.CreateSimpleWindow() });
}
}
public class App : Application
{
public void Run()
public override void Initialize()
{
Styles.Add(new DefaultTheme());
@ -55,18 +43,14 @@ namespace Avalonia.AndroidTestApplication
new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"));
Styles.Add(baseLight);
var wnd = App.CreateSimpleWindow();
wnd.AttachDevTools();
Run(wnd);
}
// This provides a simple UI tree for testing input handling, drawing, etc
public static Window CreateSimpleWindow()
public static ContentControl CreateSimpleWindow()
{
Window window = new Window
ContentControl window = new ContentControl()
{
Title = "Avalonia Test Application",
Background = Brushes.Red,
Content = new StackPanel
{

3
src/Android/Avalonia.AndroidTestApplication/packages.config

@ -2,7 +2,7 @@
<packages>
<package id="Serilog" version="1.5.14" targetFramework="monoandroid44" />
<package id="Splat" version="1.6.2" targetFramework="monoandroid51" />
<package id="Sprache" version="2.0.0.51" targetFramework="monoandroid44" />
<package id="Sprache" version="2.1.0" targetFramework="monoandroid44" />
<package id="System.Collections" version="4.0.11" targetFramework="monoandroid44" />
<package id="System.Collections.Concurrent" version="4.0.12" targetFramework="monoandroid44" />
<package id="System.ComponentModel" version="4.0.1" targetFramework="monoandroid44" />
@ -19,6 +19,7 @@
<package id="System.Resources.ResourceManager" version="4.0.1" targetFramework="monoandroid44" />
<package id="System.Runtime" version="4.1.0" targetFramework="monoandroid44" />
<package id="System.Runtime.Extensions" version="4.1.0" targetFramework="monoandroid44" />
<package id="System.Text.RegularExpressions" version="4.1.0" targetFramework="monoandroid44" />
<package id="System.Threading" version="4.0.11" targetFramework="monoandroid44" />
<package id="System.Threading.Tasks" version="4.0.11" targetFramework="monoandroid44" />
</packages>

4
src/Avalonia.Animation/Avalonia.Animation.csproj

@ -16,7 +16,7 @@
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -27,7 +27,7 @@
<DocumentationFile>bin\Debug\Avalonia.Animation.XML</DocumentationFile>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Base/Avalonia.Base.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.Base.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

7
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.Controls.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
@ -57,6 +57,9 @@
<Compile Include="HotkeyManager.cs" />
<Compile Include="IApplicationLifecycle.cs" />
<Compile Include="IScrollable.cs" />
<Compile Include="Platform\Surfaces\IFramebufferPlatformSurface.cs" />
<Compile Include="Platform\Surfaces\ILockedFramebuffer.cs" />
<Compile Include="Platform\Surfaces\PixelFormat.cs" />
<Compile Include="PointEventArgs.cs" />
<Compile Include="Embedding\EmbeddableControlRoot.cs" />
<Compile Include="Platform\IEmbeddableWindowImpl.cs" />

3
src/Avalonia.Controls/Expander.cs

@ -31,7 +31,8 @@ namespace Avalonia.Controls
AvaloniaProperty.RegisterDirect<Expander, bool>(
nameof(IsExpanded),
o => o.IsExpanded,
(o, v) => o.IsExpanded = v);
(o, v) => o.IsExpanded = v,
defaultBindingMode: Data.BindingMode.TwoWay);
static Expander()
{

13
src/Avalonia.Controls/Platform/ITopLevelImpl.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Raw;
@ -37,6 +38,18 @@ namespace Avalonia.Platform
/// </summary>
IPlatformHandle Handle { get; }
/// <summary>
/// The list of native platform's surfaces that can be consumed by rendering subsystems.
/// </summary>
/// <remarks>
/// Rendering platform will check that list and see if it can utilize one of them to output.
/// It should be enough to expose a native window handle via IPlatformHandle
/// and add support for framebuffer (even if it's emulated one) via IFramebufferPlatformSurface.
/// If you have some rendering platform that's tied to your particular windowing platform,
/// just expose some toolkit-specific object (e. g. Func&lt;Gdk.Drawable&gt; in case of GTK#+Cairo)
/// </remarks>
IEnumerable<object> Surfaces { get; }
/// <summary>
/// Gets or sets a method called when the window is activated (receives focus).
/// </summary>

5
src/Avalonia.Controls/Platform/IWindowImpl.cs

@ -35,11 +35,6 @@ namespace Avalonia.Platform
/// </summary>
void SetSystemDecorations(bool enabled);
/// <summary>
/// When system decorations are disabled sets if the maximized state covers the entire screen or just the working area.
/// </summary>
void SetCoverTaskbarWhenMaximized(bool enable);
/// <summary>
/// Sets the icon of this window.
/// </summary>

19
src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Controls.Platform.Surfaces
{
public interface IFramebufferPlatformSurface
{
/// <summary>
/// Provides a framebuffer descriptor for drawing.
/// </summary>
/// <remarks>
/// Contents should be drawn on actual window after disposing
/// </remarks>
ILockedFramebuffer Lock();
}
}

37
src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs

@ -0,0 +1,37 @@
using System;
namespace Avalonia.Controls.Platform.Surfaces
{
public interface ILockedFramebuffer : IDisposable
{
/// <summary>
/// Address of the first pixel
/// </summary>
IntPtr Address { get; }
/// <summary>
/// Framebuffer width
/// </summary>
int Width { get; }
/// <summary>
/// Framebuffer height
/// </summary>
int Height { get; }
/// <summary>
/// Number of bytes per row
/// </summary>
int RowBytes { get; }
/// <summary>
/// DPI of underling screen
/// </summary>
Size Dpi { get; }
/// <summary>
/// Pixel format
/// </summary>
PixelFormat Format { get; }
}
}

15
src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Controls.Platform.Surfaces
{
public enum PixelFormat
{
Rgb565,
Rgba8888,
Bgra8888
}
}

6
src/Avalonia.Controls/TopLevel.cs

@ -185,7 +185,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets the renderer for the window.
/// </summary>
public IRenderer Renderer { get; }
public IRenderer Renderer { get; private set; }
/// <summary>
/// Gets the access key handler for the window.
@ -241,7 +241,7 @@ namespace Avalonia.Controls
/// <inheritdoc/>
IRenderTarget IRenderRoot.CreateRenderTarget(IVisualBrushRenderer visualBrushRenderer)
{
return _renderInterface.CreateRenderTarget(PlatformImpl.Handle);
return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces);
}
/// <inheritdoc/>
@ -386,6 +386,8 @@ namespace Avalonia.Controls
{
IsVisible = false;
Closed?.Invoke(this, EventArgs.Empty);
Renderer?.Dispose();
Renderer = null;
_applicationLifecycle.OnExit -= OnApplicationExiting;
}

20
src/Avalonia.Controls/Window.cs

@ -64,13 +64,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
/// <summary>
/// Sets if the window should cover the taskbar when maximized. Only applies to Windows
/// with HasSystemDecorations = false.
/// </summary>
public static readonly StyledProperty<bool> CoverTaskbarOnMaximizeProperty =
AvaloniaProperty.Register<Window, bool>(nameof(CoverTaskbarOnMaximize), true);
/// <summary>
/// Defines the <see cref="Title"/> property.
/// </summary>
@ -97,9 +90,6 @@ namespace Avalonia.Controls
HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
(s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue));
CoverTaskbarOnMaximizeProperty.Changed.AddClassHandler<Window>(
(s, e) => s.PlatformImpl.SetCoverTaskbarWhenMaximized((bool)e.NewValue));
IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
}
@ -168,16 +158,6 @@ namespace Avalonia.Controls
set { SetValue(HasSystemDecorationsProperty, value); }
}
/// <summary>
/// Sets if the window should cover the taskbar when maximized. Only applies to Windows
/// with HasSystemDecorations = false.
/// </summary>
public bool CoverTaskbarOnMaximize
{
get { return GetValue(CoverTaskbarOnMaximizeProperty); }
set { SetValue(CoverTaskbarOnMaximizeProperty, value); }
}
/// <summary>
/// Gets or sets the minimized/maximized state of the window.
/// </summary>

4
src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.DesignerSupport.xml</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.Diagnostics.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

53
src/Avalonia.DotNetCoreRuntime/AppBuilder.cs

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
namespace Avalonia
{
public sealed class AppBuilder : AppBuilderBase<AppBuilder>
{
/// <summary>
/// Initializes a new instance of the <see cref="AppBuilder"/> class.
/// </summary>
public AppBuilder()
: base(new StandardRuntimePlatform(), () => StandardRuntimePlatformServices.Register())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AppBuilder"/> class.
/// </summary>
/// <param name="app">The <see cref="Application"/> instance.</param>
public AppBuilder(Application app) : this()
{
Instance = app;
}
/// <summary>
/// Instructs the <see cref="AppBuilder"/> to use the best settings for the platform.
/// </summary>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UsePlatformDetect()
{
//We don't have the ability to load every assembly right now, so we are
//stuck with manual configuration here
//Helpers are extracted to separate methods to take the advantage of the fact
//that CLR doesn't try to load dependencies before referencing method is jitted
if (RuntimePlatform.GetRuntimeInfo().OperatingSystem == OperatingSystemType.WinNT)
LoadWin32();
else
LoadGtk3();
this.UseSkia();
return this;
}
void LoadWin32() => this.UseWin32();
void LoadGtk3() => this.UseGtk3();
}
}

89
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{7863EA94-F0FB-4386-BF8C-E5BFA761560A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Avalonia.DotNetCoreRuntime</RootNamespace>
<AssemblyName>Avalonia.DotNetCoreRuntime</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;NETSTANDARD</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Avalonia.DotNetCoreRuntime.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NETSTANDARD</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\Avalonia.DotNetCoreRuntime.XML</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AppBuilder.cs" />
<Compile Include="NetCoreRuntimePlatform.cs" />
<Compile Include="RuntimeInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name>
</ProjectReference>
<ProjectReference Include="..\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj">
<Project>{bb1f7bb5-6ad4-4776-94d9-c09d0a972658}</Project>
<Name>Avalonia.Gtk3</Name>
</ProjectReference>
<ProjectReference Include="..\Skia\Avalonia.Skia.Desktop.NetStandard\Avalonia.Skia.Desktop.NetStandard.csproj">
<Project>{7d2d3083-71dd-4cc9-8907-39a0d86fb322}</Project>
<Name>Avalonia.Skia.Desktop.NetStandard</Name>
</ProjectReference>
<ProjectReference Include="..\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj">
<Project>{40759a76-d0f2-464e-8000-6ff0f5c4bd7c}</Project>
<Name>Avalonia.Win32.NetStandard</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

5
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.v3.ncrunchproject

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

47
src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Shared.PlatformSupport
{
internal partial class StandardRuntimePlatform
{
private static readonly Lazy<Assembly[]> Assemblies = new Lazy<Assembly[]>(LoadAssemblies);
public Assembly[] GetLoadedAssemblies() => Assemblies.Value;
static Assembly[] LoadAssemblies()
{
var rv = new List<Assembly>();
var entry = Assembly.GetEntryAssembly();
rv.Add(entry);
var queue = new Queue<AssemblyName>(entry.GetReferencedAssemblies());
var aset = new HashSet<string>(queue.Select(r => r.ToString()));
while (queue.Count > 0)
{
Assembly asm;
try
{
asm = Assembly.Load(queue.Dequeue());
}
catch (Exception e)
{
Debug.Write(e.ToString());
continue;
}
rv.Add(asm);
foreach (var r in asm.GetReferencedAssemblies())
{
if (aset.Add(r.ToString()))
queue.Enqueue(r);
}
}
return rv.Distinct().ToArray();
}
}
}

41
src/Avalonia.DotNetCoreRuntime/RuntimeInfo.cs

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Platform;
namespace Avalonia.Shared.PlatformSupport
{
internal partial class StandardRuntimePlatform
{
private static readonly Lazy<RuntimePlatformInfo> Info = new Lazy<RuntimePlatformInfo>(() =>
{
OperatingSystemType os;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
os = OperatingSystemType.OSX;
else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
os = OperatingSystemType.Linux;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
os = OperatingSystemType.WinNT;
else
throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription);
return new RuntimePlatformInfo
{
IsCoreClr = true,
IsDesktop = true,
IsDotNetFramework = false,
IsMono = false,
IsMobile = false,
IsUnix = os != OperatingSystemType.WinNT,
OperatingSystem = os,
};
});
public RuntimePlatformInfo GetRuntimeInfo() => Info.Value;
}
}

11
src/Avalonia.DotNetCoreRuntime/project.json

@ -0,0 +1,11 @@
{
"supports": {},
"dependencies": {
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
"NETStandard.Library": "1.6.0",
"System.Threading.ThreadPool": "4.3.0"
},
"frameworks": {
"netstandard1.5": {}
}
}

4
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@ -13,7 +13,7 @@
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -23,7 +23,7 @@
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Avalonia.DotNetFrameworkRuntime.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

6
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject

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

4
src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -27,7 +27,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Input/Avalonia.Input.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.Input.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Interactivity/Avalonia.Interactivity.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.Interactivity.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Layout/Avalonia.Layout.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.Layout.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj

@ -16,7 +16,7 @@
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -26,7 +26,7 @@
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Avalonia.Logging.Serilog.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -16,7 +16,7 @@
<TargetFrameworkProfile>Profile259</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -25,7 +25,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Styling/Avalonia.Styling.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.Styling.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -28,7 +28,7 @@
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Avalonia.Themes.Default.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

4
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@ -18,7 +18,7 @@
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -29,7 +29,7 @@
<DocumentationFile>bin\Debug\Avalonia.Visuals.xml</DocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>

7
src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs

@ -1,6 +1,7 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Generic;
using System.IO;
using Avalonia.Media;
@ -42,9 +43,11 @@ namespace Avalonia.Platform
/// <summary>
/// Creates a renderer.
/// </summary>
/// <param name="handle">The platform handle for the renderer.</param>
/// <param name="surfaces">
/// The list of native platform surfaces that can be used for output.
/// </param>
/// <returns>An <see cref="IRenderTarget"/>.</returns>
IRenderTarget CreateRenderTarget(IPlatformHandle handle);
IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces);
/// <summary>
/// Creates a render target bitmap implementation.

22
src/Gtk/Avalonia.Cairo/CairoPlatform.cs

@ -2,6 +2,8 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Cairo.Media;
using Avalonia.Cairo.Media.Imaging;
using Avalonia.Media;
@ -51,24 +53,14 @@ namespace Avalonia.Cairo
return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight, constraint);
}
public IRenderTarget CreateRenderTarget(IPlatformHandle handle)
public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{
var window = handle as Gtk.Window;
if (window != null)
{
window.DoubleBuffered = true;
return new RenderTarget(window);
}
var area = handle as Gtk.DrawingArea;
if (area != null)
{
area.DoubleBuffered = true;
return new RenderTarget(area);
}
var accessor = surfaces?.OfType<Func<Gdk.Drawable>>().FirstOrDefault();
if(accessor!=null)
return new RenderTarget(accessor);
throw new NotSupportedException(string.Format(
"Don't know how to create a Cairo renderer from a '{0}' handle which isn't Gtk.Window or Gtk.DrawingArea",
handle.HandleDescriptor));
"Don't know how to create a Cairo renderer from any of the provided surfaces."));
}
public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height, double dpiX, double dpiY)

19
src/Gtk/Avalonia.Cairo/RenderTarget.cs

@ -20,8 +20,8 @@ namespace Avalonia.Cairo
public class RenderTarget : IRenderTarget
{
private readonly Surface _surface;
private readonly Gtk.Window _window;
private readonly Gtk.DrawingArea _area;
private readonly Func<Gdk.Drawable> _drawableAccessor;
/// <summary>
/// Initializes a new instance of the <see cref="RenderTarget"/> class.
@ -29,9 +29,9 @@ namespace Avalonia.Cairo
/// <param name="window">The window.</param>
/// <param name="width">The width of the window.</param>
/// <param name="height">The height of the window.</param>
public RenderTarget(Gtk.Window window)
public RenderTarget(Func<Gdk.Drawable> drawable)
{
_window = window;
_drawableAccessor = drawable;
}
public RenderTarget(ImageSurface surface)
@ -39,11 +39,6 @@ namespace Avalonia.Cairo
_surface = surface;
}
public RenderTarget(DrawingArea area)
{
_area = area;
}
/// <summary>
/// Creates a cairo surface that targets a platform-specific resource.
/// </summary>
@ -51,12 +46,10 @@ namespace Avalonia.Cairo
/// <returns>A surface wrapped in an <see cref="Avalonia.Media.DrawingContext"/>.</returns>
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
{
if (_window != null)
return new Media.DrawingContext(_window.GdkWindow);
if (_drawableAccessor != null)
return new Media.DrawingContext(_drawableAccessor());
if (_surface != null)
return new Media.DrawingContext(_surface);
if (_area != null)
return new Media.DrawingContext(_area.GdkWindow);
throw new InvalidOperationException("Unspecified render target");
}

5
src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj

@ -30,6 +30,8 @@
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Cairo, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
</Reference>
<Reference Include="System" />
<Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
<Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
@ -48,7 +50,10 @@
<Compile Include="ClipboardImpl.cs" />
<Compile Include="EmbeddableImpl.cs" />
<Compile Include="Embedding\GtkAvaloniaControlHost.cs" />
<Compile Include="FramebufferManager.cs" />
<Compile Include="IconImpl.cs" />
<Compile Include="KeyTransform.cs" />
<Compile Include="SurfaceFramebuffer.cs" />
<Compile Include="SystemDialogImpl.cs" />
<Compile Include="CursorFactory.cs" />
<Compile Include="GtkExtensions.cs" />

39
src/Gtk/Avalonia.Gtk/FramebufferManager.cs

@ -0,0 +1,39 @@
using System;
using Avalonia.Controls.Platform.Surfaces;
namespace Avalonia.Gtk
{
class FramebufferManager : IFramebufferPlatformSurface, IDisposable
{
private readonly WindowImplBase _window;
private SurfaceFramebuffer _fb;
public FramebufferManager(WindowImplBase window)
{
_window = window;
}
public void Dispose()
{
_fb?.Deallocate();
}
public ILockedFramebuffer Lock()
{
if(_window.CurrentDrawable == null)
throw new InvalidOperationException("Window is not in drawing state");
var drawable = _window.CurrentDrawable;
var width = (int) _window.ClientSize.Width;
var height = (int) _window.ClientSize.Height;
if (_fb == null || _fb.Width != width ||
_fb.Height != height)
{
_fb?.Deallocate();
_fb = new SurfaceFramebuffer(width, height);
}
_fb.SetDrawable(drawable);
return _fb;
}
}
}

209
src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs

@ -8,218 +8,11 @@ using System.Reflection;
using System.Text;
using Avalonia.Input;
namespace Avalonia.Gtk
{
public class GtkKeyboardDevice : KeyboardDevice
{
private static readonly Dictionary<Gdk.Key, Key> KeyDic = new Dictionary<Gdk.Key, Key>
{
{ Gdk.Key.Cancel, Key.Cancel },
{ Gdk.Key.BackSpace, Key.Back },
{ Gdk.Key.Tab, Key.Tab },
{ Gdk.Key.Linefeed, Key.LineFeed },
{ Gdk.Key.Clear, Key.Clear },
{ Gdk.Key.Return, Key.Return },
{ Gdk.Key.Pause, Key.Pause },
//{ Gdk.Key.?, Key.CapsLock }
//{ Gdk.Key.?, Key.HangulMode }
//{ Gdk.Key.?, Key.JunjaMode }
//{ Gdk.Key.?, Key.FinalMode }
//{ Gdk.Key.?, Key.KanjiMode }
{ Gdk.Key.Escape, Key.Escape },
//{ Gdk.Key.?, Key.ImeConvert }
//{ Gdk.Key.?, Key.ImeNonConvert }
//{ Gdk.Key.?, Key.ImeAccept }
//{ Gdk.Key.?, Key.ImeModeChange }
{ Gdk.Key.space, Key.Space },
{ Gdk.Key.Prior, Key.Prior },
//{ Gdk.Key.?, Key.PageDown }
{ Gdk.Key.End, Key.End },
{ Gdk.Key.Home, Key.Home },
{ Gdk.Key.Left, Key.Left },
{ Gdk.Key.Up, Key.Up },
{ Gdk.Key.Right, Key.Right },
{ Gdk.Key.Down, Key.Down },
{ Gdk.Key.Select, Key.Select },
{ Gdk.Key.Print, Key.Print },
{ Gdk.Key.Execute, Key.Execute },
//{ Gdk.Key.?, Key.Snapshot }
{ Gdk.Key.Insert, Key.Insert },
{ Gdk.Key.Delete, Key.Delete },
{ Gdk.Key.Help, Key.Help },
//{ Gdk.Key.?, Key.D0 }
//{ Gdk.Key.?, Key.D1 }
//{ Gdk.Key.?, Key.D2 }
//{ Gdk.Key.?, Key.D3 }
//{ Gdk.Key.?, Key.D4 }
//{ Gdk.Key.?, Key.D5 }
//{ Gdk.Key.?, Key.D6 }
//{ Gdk.Key.?, Key.D7 }
//{ Gdk.Key.?, Key.D8 }
//{ Gdk.Key.?, Key.D9 }
{ Gdk.Key.A, Key.A },
{ Gdk.Key.B, Key.B },
{ Gdk.Key.C, Key.C },
{ Gdk.Key.D, Key.D },
{ Gdk.Key.E, Key.E },
{ Gdk.Key.F, Key.F },
{ Gdk.Key.G, Key.G },
{ Gdk.Key.H, Key.H },
{ Gdk.Key.I, Key.I },
{ Gdk.Key.J, Key.J },
{ Gdk.Key.K, Key.K },
{ Gdk.Key.L, Key.L },
{ Gdk.Key.M, Key.M },
{ Gdk.Key.N, Key.N },
{ Gdk.Key.O, Key.O },
{ Gdk.Key.P, Key.P },
{ Gdk.Key.Q, Key.Q },
{ Gdk.Key.R, Key.R },
{ Gdk.Key.S, Key.S },
{ Gdk.Key.T, Key.T },
{ Gdk.Key.U, Key.U },
{ Gdk.Key.V, Key.V },
{ Gdk.Key.W, Key.W },
{ Gdk.Key.X, Key.X },
{ Gdk.Key.Y, Key.Y },
{ Gdk.Key.Z, Key.Z },
{ Gdk.Key.a, Key.A },
{ Gdk.Key.b, Key.B },
{ Gdk.Key.c, Key.C },
{ Gdk.Key.d, Key.D },
{ Gdk.Key.e, Key.E },
{ Gdk.Key.f, Key.F },
{ Gdk.Key.g, Key.G },
{ Gdk.Key.h, Key.H },
{ Gdk.Key.i, Key.I },
{ Gdk.Key.j, Key.J },
{ Gdk.Key.k, Key.K },
{ Gdk.Key.l, Key.L },
{ Gdk.Key.m, Key.M },
{ Gdk.Key.n, Key.N },
{ Gdk.Key.o, Key.O },
{ Gdk.Key.p, Key.P },
{ Gdk.Key.q, Key.Q },
{ Gdk.Key.r, Key.R },
{ Gdk.Key.s, Key.S },
{ Gdk.Key.t, Key.T },
{ Gdk.Key.u, Key.U },
{ Gdk.Key.v, Key.V },
{ Gdk.Key.w, Key.W },
{ Gdk.Key.x, Key.X },
{ Gdk.Key.y, Key.Y },
{ Gdk.Key.z, Key.Z },
//{ Gdk.Key.?, Key.LWin }
//{ Gdk.Key.?, Key.RWin }
//{ Gdk.Key.?, Key.Apps }
//{ Gdk.Key.?, Key.Sleep }
//{ Gdk.Key.?, Key.NumPad0 }
//{ Gdk.Key.?, Key.NumPad1 }
//{ Gdk.Key.?, Key.NumPad2 }
//{ Gdk.Key.?, Key.NumPad3 }
//{ Gdk.Key.?, Key.NumPad4 }
//{ Gdk.Key.?, Key.NumPad5 }
//{ Gdk.Key.?, Key.NumPad6 }
//{ Gdk.Key.?, Key.NumPad7 }
//{ Gdk.Key.?, Key.NumPad8 }
//{ Gdk.Key.?, Key.NumPad9 }
{ Gdk.Key.multiply, Key.Multiply },
//{ Gdk.Key.?, Key.Add }
//{ Gdk.Key.?, Key.Separator }
//{ Gdk.Key.?, Key.Subtract }
//{ Gdk.Key.?, Key.Decimal }
//{ Gdk.Key.?, Key.Divide }
{ Gdk.Key.F1, Key.F1 },
{ Gdk.Key.F2, Key.F2 },
{ Gdk.Key.F3, Key.F3 },
{ Gdk.Key.F4, Key.F4 },
{ Gdk.Key.F5, Key.F5 },
{ Gdk.Key.F6, Key.F6 },
{ Gdk.Key.F7, Key.F7 },
{ Gdk.Key.F8, Key.F8 },
{ Gdk.Key.F9, Key.F9 },
{ Gdk.Key.F10, Key.F10 },
{ Gdk.Key.F11, Key.F11 },
{ Gdk.Key.F12, Key.F12 },
{ Gdk.Key.L3, Key.F13 },
{ Gdk.Key.F14, Key.F14 },
{ Gdk.Key.L5, Key.F15 },
{ Gdk.Key.F16, Key.F16 },
{ Gdk.Key.F17, Key.F17 },
{ Gdk.Key.L8, Key.F18 },
{ Gdk.Key.L9, Key.F19 },
{ Gdk.Key.L10, Key.F20 },
{ Gdk.Key.R1, Key.F21 },
{ Gdk.Key.R2, Key.F22 },
{ Gdk.Key.F23, Key.F23 },
{ Gdk.Key.R4, Key.F24 },
//{ Gdk.Key.?, Key.NumLock }
//{ Gdk.Key.?, Key.Scroll }
//{ Gdk.Key.?, Key.LeftShift }
//{ Gdk.Key.?, Key.RightShift }
//{ Gdk.Key.?, Key.LeftCtrl }
//{ Gdk.Key.?, Key.RightCtrl }
//{ Gdk.Key.?, Key.LeftAlt }
//{ Gdk.Key.?, Key.RightAlt }
//{ Gdk.Key.?, Key.BrowserBack }
//{ Gdk.Key.?, Key.BrowserForward }
//{ Gdk.Key.?, Key.BrowserRefresh }
//{ Gdk.Key.?, Key.BrowserStop }
//{ Gdk.Key.?, Key.BrowserSearch }
//{ Gdk.Key.?, Key.BrowserFavorites }
//{ Gdk.Key.?, Key.BrowserHome }
//{ Gdk.Key.?, Key.VolumeMute }
//{ Gdk.Key.?, Key.VolumeDown }
//{ Gdk.Key.?, Key.VolumeUp }
//{ Gdk.Key.?, Key.MediaNextTrack }
//{ Gdk.Key.?, Key.MediaPreviousTrack }
//{ Gdk.Key.?, Key.MediaStop }
//{ Gdk.Key.?, Key.MediaPlayPause }
//{ Gdk.Key.?, Key.LaunchMail }
//{ Gdk.Key.?, Key.SelectMedia }
//{ Gdk.Key.?, Key.LaunchApplication1 }
//{ Gdk.Key.?, Key.LaunchApplication2 }
//{ Gdk.Key.?, Key.OemSemicolon }
//{ Gdk.Key.?, Key.OemPlus }
//{ Gdk.Key.?, Key.OemComma }
//{ Gdk.Key.?, Key.OemMinus }
//{ Gdk.Key.?, Key.OemPeriod }
//{ Gdk.Key.?, Key.Oem2 }
//{ Gdk.Key.?, Key.OemTilde }
//{ Gdk.Key.?, Key.AbntC1 }
//{ Gdk.Key.?, Key.AbntC2 }
//{ Gdk.Key.?, Key.Oem4 }
//{ Gdk.Key.?, Key.OemPipe }
//{ Gdk.Key.?, Key.OemCloseBrackets }
//{ Gdk.Key.?, Key.Oem7 }
//{ Gdk.Key.?, Key.Oem8 }
//{ Gdk.Key.?, Key.Oem102 }
//{ Gdk.Key.?, Key.ImeProcessed }
//{ Gdk.Key.?, Key.System }
//{ Gdk.Key.?, Key.OemAttn }
//{ Gdk.Key.?, Key.OemFinish }
//{ Gdk.Key.?, Key.DbeHiragana }
//{ Gdk.Key.?, Key.OemAuto }
//{ Gdk.Key.?, Key.DbeDbcsChar }
//{ Gdk.Key.?, Key.OemBackTab }
//{ Gdk.Key.?, Key.Attn }
//{ Gdk.Key.?, Key.DbeEnterWordRegisterMode }
//{ Gdk.Key.?, Key.DbeEnterImeConfigureMode }
//{ Gdk.Key.?, Key.EraseEof }
//{ Gdk.Key.?, Key.Play }
//{ Gdk.Key.?, Key.Zoom }
//{ Gdk.Key.?, Key.NoName }
//{ Gdk.Key.?, Key.DbeEnterDialogConversionMode }
//{ Gdk.Key.?, Key.OemClear }
//{ Gdk.Key.?, Key.DeadCharProcessed }
};
public new static GtkKeyboardDevice Instance { get; } = new GtkKeyboardDevice();
public static Key ConvertKey(Gdk.Key key)
{
Key result;
return KeyDic.TryGetValue(key, out result) ? result : Key.None;
}
}
}

224
src/Gtk/Avalonia.Gtk/KeyTransform.cs

@ -0,0 +1,224 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Input;
#if GTK3_PINVOKE
using Avalonia.Gtk3;
#else
using GdkKey = Gdk.Key;
#endif
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.Pause, Key.Pause },
//{ GdkKey.?, 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.?, Key.PageDown }
{ GdkKey.End, Key.End },
{ GdkKey.Home, Key.Home },
{ GdkKey.Left, Key.Left },
{ GdkKey.Up, Key.Up },
{ GdkKey.Right, Key.Right },
{ GdkKey.Down, Key.Down },
{ GdkKey.Select, Key.Select },
{ GdkKey.Print, Key.Print },
{ GdkKey.Execute, Key.Execute },
//{ GdkKey.?, Key.Snapshot }
{ GdkKey.Insert, Key.Insert },
{ GdkKey.Delete, Key.Delete },
{ GdkKey.Help, Key.Help },
//{ GdkKey.?, Key.D0 }
//{ GdkKey.?, Key.D1 }
//{ GdkKey.?, Key.D2 }
//{ GdkKey.?, Key.D3 }
//{ GdkKey.?, Key.D4 }
//{ GdkKey.?, Key.D5 }
//{ GdkKey.?, Key.D6 }
//{ GdkKey.?, Key.D7 }
//{ GdkKey.?, Key.D8 }
//{ GdkKey.?, 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.?, Key.Apps }
//{ GdkKey.?, Key.Sleep }
//{ GdkKey.?, Key.NumPad0 }
//{ GdkKey.?, Key.NumPad1 }
//{ GdkKey.?, Key.NumPad2 }
//{ GdkKey.?, Key.NumPad3 }
//{ GdkKey.?, Key.NumPad4 }
//{ GdkKey.?, Key.NumPad5 }
//{ GdkKey.?, Key.NumPad6 }
//{ GdkKey.?, Key.NumPad7 }
//{ GdkKey.?, Key.NumPad8 }
//{ GdkKey.?, Key.NumPad9 }
{ GdkKey.multiply, Key.Multiply },
//{ GdkKey.?, Key.Add }
//{ GdkKey.?, Key.Separator }
//{ GdkKey.?, Key.Subtract }
//{ GdkKey.?, Key.Decimal }
//{ GdkKey.?, 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.?, Key.NumLock }
//{ GdkKey.?, Key.Scroll }
//{ GdkKey.?, Key.LeftShift }
//{ GdkKey.?, Key.RightShift }
//{ GdkKey.?, Key.LeftCtrl }
//{ GdkKey.?, Key.RightCtrl }
//{ GdkKey.?, Key.LeftAlt }
//{ GdkKey.?, 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.?, Key.OemSemicolon }
//{ GdkKey.?, Key.OemPlus }
//{ GdkKey.?, Key.OemComma }
//{ GdkKey.?, Key.OemMinus }
//{ GdkKey.?, Key.OemPeriod }
//{ GdkKey.?, Key.Oem2 }
//{ GdkKey.?, Key.OemTilde }
//{ GdkKey.?, Key.AbntC1 }
//{ GdkKey.?, Key.AbntC2 }
//{ GdkKey.?, Key.Oem4 }
//{ GdkKey.?, Key.OemPipe }
//{ GdkKey.?, Key.OemCloseBrackets }
//{ GdkKey.?, Key.Oem7 }
//{ 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;
}
}
}

55
src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
using Cairo;
using Gdk;
namespace Avalonia.Gtk
{
class SurfaceFramebuffer : ILockedFramebuffer
{
private Drawable _drawable;
private ImageSurface _surface;
public SurfaceFramebuffer(int width, int height)
{
_surface = new ImageSurface(Cairo.Format.RGB24, width, height);
}
public void SetDrawable(Drawable drawable)
{
_drawable = drawable;
_surface.Flush();
}
public void Deallocate()
{
_surface.Dispose();
_surface = null;
}
public void Dispose()
{
using (var ctx = CairoHelper.Create(_drawable))
{
_surface.MarkDirty();
ctx.SetSourceSurface(_surface, 0, 0);
ctx.Paint();
}
_drawable = null;
}
public IntPtr Address => _surface.DataPtr;
public int Width => _surface.Width;
public int Height => _surface.Height;
public int RowBytes => _surface.Stride;
//TODO: Proper DPI detect
public Size Dpi => new Size(96, 96);
public PixelFormat Format => PixelFormat.Bgra8888;
}
}

4
src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs

@ -15,7 +15,7 @@ namespace Avalonia.Gtk
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
{
var tcs = new TaskCompletionSource<string[]>();
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImplBase)parent).Widget.Toplevel as Window,
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImplBase)parent)?.Widget.Toplevel as Window,
dialog is OpenFileDialog
? FileChooserAction.Open
: FileChooserAction.Save,
@ -57,7 +57,7 @@ namespace Avalonia.Gtk
public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
{
var tcs = new TaskCompletionSource<string>();
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImplBase)parent).Widget.Toplevel as Window,
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImplBase)parent)?.Widget.Toplevel as Window,
FileChooserAction.SelectFolder,
"Cancel", ResponseType.Cancel,
"Select Folder", ResponseType.Accept)

2
src/Gtk/Avalonia.Gtk/WindowImpl.cs

@ -10,7 +10,7 @@ namespace Avalonia.Gtk
{
private Gtk.Window _window;
private Gtk.Window Window => _window ?? (_window = (Gtk.Window) Widget);
public WindowImpl(Gtk.WindowType type) : base(new PlatformHandleAwareWindow(type))
{
Init();

35
src/Gtk/Avalonia.Gtk/WindowImplBase.cs

@ -2,16 +2,14 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using Gdk;
using Avalonia.Controls;
using System.Collections.Generic;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Input;
using Avalonia.Threading;
using Gdk;
using Action = System.Action;
using WindowEdge = Avalonia.Controls.WindowEdge;
using GLib;
namespace Avalonia.Gtk
{
@ -21,8 +19,7 @@ namespace Avalonia.Gtk
{
private IInputRoot _inputRoot;
protected Gtk.Widget _window;
public Gtk.Widget Widget => _window;
private FramebufferManager _framebuffer;
private Gtk.IMContext _imContext;
@ -33,6 +30,7 @@ namespace Avalonia.Gtk
protected WindowImplBase(Gtk.Widget window)
{
_window = window;
_framebuffer = new FramebufferManager(this);
Init();
}
@ -54,10 +52,13 @@ namespace Avalonia.Gtk
_window.KeyReleaseEvent += OnKeyReleaseEvent;
_window.ExposeEvent += OnExposeEvent;
_window.MotionNotifyEvent += OnMotionNotifyEvent;
}
public IPlatformHandle Handle { get; private set; }
public Gtk.Widget Widget => _window;
public Gdk.Drawable CurrentDrawable { get; private set; }
void OnRealized (object sender, EventArgs eventArgs)
{
@ -128,6 +129,13 @@ namespace Avalonia.Gtk
public Action<double> ScalingChanged { get; set; }
public IEnumerable<object> Surfaces => new object[]
{
Handle,
new Func<Gdk.Drawable>(() => CurrentDrawable),
_framebuffer
};
public IPopupImpl CreatePopup()
{
return new PopupImpl();
@ -261,10 +269,11 @@ namespace Avalonia.Gtk
GtkKeyboardDevice.Instance,
evnt.Time,
evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State));
Common.KeyTransform.ConvertKey(evnt.Key), GetModifierKeys(evnt.State));
Input(e);
}
[ConnectBefore]
void OnKeyPressEvent(object o, Gtk.KeyPressEventArgs args)
{
args.RetVal = true;
@ -284,7 +293,9 @@ namespace Avalonia.Gtk
void OnExposeEvent(object o, Gtk.ExposeEventArgs args)
{
CurrentDrawable = args.Event.Window;
Paint(args.Event.Area.ToAvalonia());
CurrentDrawable = null;
args.RetVal = true;
}
@ -305,13 +316,9 @@ namespace Avalonia.Gtk
args.RetVal = true;
}
public void SetCoverTaskbarWhenMaximized(bool enable)
{
// No action neccesary on Gtk.
}
public void Dispose()
{
_framebuffer.Dispose();
_window.Hide();
_window.Dispose();
_window = null;

1
src/Gtk/Avalonia.Gtk3/.gitignore

@ -0,0 +1 @@
project.lock.json

103
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Avalonia.Gtk3</RootNamespace>
<AssemblyName>Avalonia.Gtk3</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;GTK3_PINVOKE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;GTK3_PINVOKE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Gtk\KeyTransform.cs">
<Link>KeyTransform.cs</Link>
</Compile>
<Compile Include="Interop\CairoSurface.cs" />
<Compile Include="ClipboardImpl.cs" />
<Compile Include="CursorFactory.cs" />
<Compile Include="FramebufferManager.cs" />
<Compile Include="GdkCursor.cs" />
<Compile Include="GdkKey.cs" />
<Compile Include="Gtk3Platform.cs" />
<Compile Include="Interop\GException.cs" />
<Compile Include="Interop\GObject.cs" />
<Compile Include="Interop\ICustomGtk3NativeLibraryResolver.cs" />
<Compile Include="Interop\DynLoader.cs" />
<Compile Include="Interop\GlibTimeout.cs" />
<Compile Include="Interop\Native.cs" />
<Compile Include="Interop\NativeException.cs" />
<Compile Include="Interop\Pixbuf.cs" />
<Compile Include="Interop\Resolver.cs" />
<Compile Include="Interop\Signal.cs" />
<Compile Include="ImageSurfaceFramebuffer.cs" />
<Compile Include="PlatformIconLoader.cs" />
<Compile Include="PopupImpl.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SystemDialogs.cs" />
<Compile Include="TopLevelImpl.cs" />
<Compile Include="Interop\Utf8Buffer.cs" />
<Compile Include="WindowImpl.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj">
<Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj">
<Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project>
<Name>Avalonia.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Avalonia.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{EB582467-6ABB-43A1-B052-E981BA910E3A}</Project>
<Name>Avalonia.SceneGraph</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

5
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.v3.ncrunchproject

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

53
src/Gtk/Avalonia.Gtk3/ClipboardImpl.cs

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Gtk3.Interop;
using Avalonia.Input.Platform;
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);
}
}
}

79
src/Gtk/Avalonia.Gtk3/CursorFactory.cs

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using Avalonia.Gtk3.Interop;
using Avalonia.Input;
using Avalonia.Platform;
using CursorType = Avalonia.Gtk3.GdkCursorType;
namespace Avalonia.Gtk3
{
class CursorFactory : IStandardCursorFactory
{
private static readonly Dictionary<StandardCursorType, object> CursorTypeMapping = new Dictionary
<StandardCursorType, object>
{
{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}
};
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;
}
}
}

32
src/Gtk/Avalonia.Gtk3/FramebufferManager.cs

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Platform.Surfaces;
namespace Avalonia.Gtk3
{
class FramebufferManager : IFramebufferPlatformSurface, IDisposable
{
private readonly TopLevelImpl _window;
public FramebufferManager(TopLevelImpl window)
{
_window = window;
}
public void Dispose()
{
//
}
public ILockedFramebuffer Lock()
{
if(_window.CurrentCairoContext == IntPtr.Zero)
throw new InvalidOperationException("Window is not in drawing state");
var width = (int) _window.ClientSize.Width;
var height = (int) _window.ClientSize.Height;
return new ImageSurfaceFramebuffer(_window.CurrentCairoContext, width, height);
}
}
}

91
src/Gtk/Avalonia.Gtk3/GdkCursor.cs

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Gtk3
{
enum GdkCursorType
{
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,
}
}

1347
src/Gtk/Avalonia.Gtk3/GdkKey.cs

File diff suppressed because it is too large

116
src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Gtk3.Interop;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Gtk3;
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; }
public static void Initialize()
{
Resolver.Resolve();
Native.GtkInit(0, IntPtr.Zero);
using (var utf = new Utf8Buffer("avalonia.app." + Guid.NewGuid()))
App = Native.GtkApplicationNew(utf, 0);
//Mark current thread as UI thread
s_tlsMarker = true;
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatform>().ToConstant(Instance)
.Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToConstant(new CursorFactory())
.Bind<IKeyboardDevice>().ToConstant(Keyboard)
.Bind<IMouseDevice>().ToConstant(Mouse)
.Bind<IPlatformSettings>().ToConstant(Instance)
.Bind<IPlatformThreadingInterface>().ToConstant(Instance)
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialog>()
.Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
.Bind<IPlatformIconLoader>().ToConstant(new PlatformIconLoader());
}
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(TimeSpan interval, Action tick)
{
return GlibTimeout.StarTimer((uint) interval.TotalMilliseconds, tick);
}
private bool _signaled = false;
object _lock = new object();
public void Signal()
{
lock(_lock)
if (!_signaled)
{
_signaled = true;
GlibTimeout.Add(0, () =>
{
lock (_lock)
{
_signaled = false;
}
Signaled?.Invoke();
return false;
});
}
}
public event Action Signaled;
[ThreadStatic]
private static bool s_tlsMarker;
public bool CurrentThreadIsLoopThread => s_tlsMarker;
}
}
namespace Avalonia
{
public static class Gtk3AppBuilderExtensions
{
public static T UseGtk3<T>(this AppBuilderBase<T> builder, ICustomGtk3NativeLibraryResolver resolver = null)
where T : AppBuilderBase<T>, new()
{
Resolver.Custom = resolver;
return builder.UseWindowingSubsystem(Gtk3Platform.Initialize, "GTK3");
}
}
}

54
src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Gtk3.Interop;
using Avalonia.Platform;
namespace Avalonia.Gtk3
{
class ImageSurfaceFramebuffer : ILockedFramebuffer
{
private IntPtr _context;
private CairoSurface _surface;
public ImageSurfaceFramebuffer(IntPtr context, int width, int height)
{
_context = context;
_surface = Native.CairoImageSurfaceCreate(1, width, height);
Width = width;
Height = height;
Address = Native.CairoImageSurfaceGetData(_surface);
RowBytes = Native.CairoImageSurfaceGetStride(_surface);
Native.CairoSurfaceFlush(_surface);
}
public void Dispose()
{
if(_context == IntPtr.Zero || _surface == null)
return;
Native.CairoSurfaceMarkDirty(_surface);
Native.CairoSetSourceSurface(_context, _surface, 0, 0);
Native.CairoPaint(_context);
_context = IntPtr.Zero;
_surface.Dispose();
_surface = null;
}
public IntPtr Address { get; }
public int Width { get; }
public int Height { get; }
public int RowBytes { get; }
//TODO: Proper DPI detect
public Size Dpi => new Size(96, 96);
public PixelFormat Format => PixelFormat.Bgra8888;
}
}

20
src/Gtk/Avalonia.Gtk3/Interop/CairoSurface.cs

@ -0,0 +1,20 @@
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;
}
}

129
src/Gtk/Avalonia.Gtk3/Interop/DynLoader.cs

@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
/*
* Source code imported from https://github.com/kekekeks/evhttp-sharp
* Source is provided under MIT license for Avalonia project and derived works
*/
namespace Avalonia.Gtk3.Interop
{
internal interface IDynLoader
{
IntPtr LoadLibrary(string dll);
IntPtr GetProcAddress(IntPtr dll, string proc);
}
class UnixLoader : IDynLoader
{
// ReSharper disable InconsistentNaming
static class LinuxImports
{
[DllImport("libdl.so.2")]
private static extern IntPtr dlopen(string path, int flags);
[DllImport("libdl.so.2")]
private static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libdl.so.2")]
private static extern IntPtr dlerror();
public static void Init()
{
DlOpen = dlopen;
DlSym = dlsym;
DlError = dlerror;
}
}
static class OsXImports
{
[DllImport("/usr/lib/libSystem.dylib")]
private static extern IntPtr dlopen(string path, int flags);
[DllImport("/usr/lib/libSystem.dylib")]
private static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("/usr/lib/libSystem.dylib")]
private static extern IntPtr dlerror();
public static void Init()
{
DlOpen = dlopen;
DlSym = dlsym;
DlError = dlerror;
}
}
[DllImport("libc")]
static extern int uname(IntPtr buf);
static UnixLoader()
{
var buffer = Marshal.AllocHGlobal(0x1000);
uname(buffer);
var unixName = Marshal.PtrToStringAnsi(buffer);
Marshal.FreeHGlobal(buffer);
if(unixName == "Darwin")
OsXImports.Init();
else
LinuxImports.Init();
}
private static Func<string, int, IntPtr> DlOpen;
private static Func<IntPtr, string, IntPtr> DlSym;
private static Func<IntPtr> DlError;
// ReSharper restore InconsistentNaming
static string DlErrorString() => Marshal.PtrToStringAnsi(DlError());
public IntPtr LoadLibrary(string dll)
{
var handle = DlOpen(dll, 1);
if (handle == IntPtr.Zero)
throw new NativeException(DlErrorString());
return handle;
}
public IntPtr GetProcAddress(IntPtr dll, string proc)
{
var ptr = DlSym(dll, proc);
if (ptr == IntPtr.Zero)
throw new NativeException(DlErrorString());
return ptr;
}
}
internal class Win32Loader : IDynLoader
{
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32", EntryPoint = "LoadLibraryW", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string lpszLib);
IntPtr IDynLoader.LoadLibrary(string dll)
{
var handle = LoadLibrary(dll);
if (handle != IntPtr.Zero)
return handle;
var err = Marshal.GetLastWin32Error();
throw new NativeException("Error loading " + dll + " error " + err);
}
IntPtr IDynLoader.GetProcAddress(IntPtr dll, string proc)
{
var ptr = GetProcAddress(dll, proc);
if (ptr == IntPtr.Zero)
throw new NativeException("Error " + Marshal.GetLastWin32Error());
return ptr;
}
}
}

33
src/Gtk/Avalonia.Gtk3/Interop/GException.cs

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
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))
{
}
}
}

62
src/Gtk/Avalonia.Gtk3/Interop/GObject.cs

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
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)
Native.GObjectUnref(handle);
handle = IntPtr.Zero;
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero;
}
class GInputStream : GObject
{
}
class GtkWidget : GObject
{
}
class GtkWindow : GtkWidget
{
}
class GtkImContext : GObject
{
}
class GtkDialog : GtkWindow
{
}
class GtkFileChooser : GtkDialog
{
}
}

64
src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
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 GCHandle PinnedHandle;
private static readonly Native.D.timeout_callback PinnedHandler;
static GlibTimeout()
{
PinnedHandler = Handler;
}
public static void Add(uint interval, Func<bool> callback)
{
var handle = GCHandle.Alloc(callback);
Native.GTimeoutAdd(interval, PinnedHandler, GCHandle.ToIntPtr(handle));
}
class Timer : IDisposable
{
public bool Stopped;
public void Dispose()
{
Stopped = true;
}
}
public static IDisposable StarTimer(uint interval, Action tick)
{
var timer = new Timer ();
GlibTimeout.Add(interval,
() =>
{
if (timer.Stopped)
return false;
tick();
return !timer.Stopped;
});
return timer;
}
}
}

17
src/Gtk/Avalonia.Gtk3/Interop/ICustomGtk3NativeLibraryResolver.cs

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Gtk3.Interop;
namespace Avalonia.Gtk3
{
public interface ICustomGtk3NativeLibraryResolver
{
string GetName(GtkDll dll);
string BasePath { get; }
bool TrySystemFirst { get; }
string Lookup(GtkDll dll);
}
}

571
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@ -0,0 +1,571 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using gint8 = System.Byte;
using gint16 = System.Int16;
using gint32 = System.Int32;
using gint = System.Int32;
using guint16 = System.UInt16;
using guint32 = System.UInt32;
using guint = System.UInt32;
using gdouble = System.Double;
namespace Avalonia.Gtk3.Interop
{
static class Native
{
public static class D
{
[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 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_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)] //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)]
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.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_decorated(GtkWindow gtkWindow, bool decorated);
[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 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_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_paint(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 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 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_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.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 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_free(IntPtr data);
[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 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);
}
public static D.gtk_window_set_decorated GtkWindowSetDecorated;
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_init GtkInit;
public static D.gtk_window_present GtkWindowPresent;
public static D.gtk_widget_hide GtkWidgetHide;
public static D.gdk_get_native_handle GetNativeGdkWindowHandle;
public static D.gtk_widget_get_window GtkWidgetGetWindow;
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.gtk_widget_set_size_request GtkWindowSetSizeRequest;
public static D.gtk_window_set_default_size GtkWindowSetDefaultSize;
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_signal_connect_object GSignalConnectObject;
public static D.g_signal_handler_disconnect GSignalHandlerDisconnect;
public static D.g_timeout_add GTimeoutAdd;
public static D.g_free GFree;
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_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_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_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.cairo_image_surface_create CairoImageSurfaceCreate;
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_flush CairoSurfaceFlush;
public static D.cairo_surface_destroy CairoSurfaceDestroy;
public static D.cairo_set_source_surface CairoSetSourceSurface;
public static D.cairo_paint CairoPaint;
}
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 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)]
struct GdkGeometry
{
gint min_width;
gint min_height;
gint max_width;
gint max_height;
gint base_width;
gint base_height;
gint width_inc;
gint height_inc;
gdouble min_aspect;
gdouble max_aspect;
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
}
}

24
src/Gtk/Avalonia.Gtk3/Interop/NativeException.cs

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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)
{
}
}
}

68
src/Gtk/Avalonia.Gtk3/Interop/Pixbuf.cs

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Platform;
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);
}
}
}

155
src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Platform;
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(IDynLoader 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);
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 = Platform.Value == OperatingSystemType.WinNT ? (IDynLoader)new Win32Loader() : new UnixLoader();
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);
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)
{
try
{
Native.GetNativeGdkWindowHandle = (Native.D.gdk_get_native_handle)Marshal
.GetDelegateForFunctionPointer(loader.GetProcAddress(dlls[GtkDll.Gdk], name), typeof(Native.D.gdk_get_native_handle));
break;
}
catch { }
}
if (Native.GetNativeGdkWindowHandle == null)
throw new Exception($"Unable to locate any of [{string.Join(", ", nativeHandleNames)}] in libgdk");
}
}
}

50
src/Gtk/Avalonia.Gtk3/Interop/Signal.cs

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
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);
}
}
}
}

45
src/Gtk/Avalonia.Gtk3/Interop/Utf8Buffer.cs

@ -0,0 +1,45 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Avalonia.Gtk3.Interop
{
class Utf8Buffer : SafeHandle
{
private GCHandle _gchandle;
private byte[] _data;
public Utf8Buffer(string s) : base(IntPtr.Zero, true)
{
_data = Encoding.UTF8.GetBytes(s);
_gchandle = GCHandle.Alloc(_data, GCHandleType.Pinned);
handle = _gchandle.AddrOfPinnedObject();
}
public int ByteLen => _data.Length;
protected override bool ReleaseHandle()
{
if (handle != IntPtr.Zero)
{
handle = IntPtr.Zero;
_data = null;
_gchandle.Free();
}
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero;
public static unsafe string StringFromPtr(IntPtr s)
{
var pstr = (byte*)s;
int len;
for (len = 0; pstr[len] != 0; len++) ;
var bytes = new byte[len];
Marshal.Copy(s, bytes, 0, len);
return Encoding.UTF8.GetString(bytes, 0, len);
}
}
}

20
src/Gtk/Avalonia.Gtk3/PlatformIconLoader.cs

@ -0,0 +1,20 @@
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());
}
}
}

24
src/Gtk/Avalonia.Gtk3/PopupImpl.cs

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Gtk3.Interop;
using Avalonia.Platform;
namespace Avalonia.Gtk3
{
class PopupImpl : TopLevelImpl, IPopupImpl
{
static GtkWindow CreateWindow()
{
var window = Native.GtkWindowNew(GtkWindowType.Popup);
return window;
}
public PopupImpl() : base(CreateWindow())
{
}
}
}

10
src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs → src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs

@ -1,20 +1,20 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Avalonia.Skia.Android.TestApp")]
[assembly: AssemblyTitle("Avalonia.Gtk3")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Avalonia.Skia.Android.TestApp")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyProduct("Avalonia.Gtk3")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//

8
src/Gtk/Avalonia.Gtk3/README.md

@ -0,0 +1,8 @@
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.

92
src/Gtk/Avalonia.Gtk3/SystemDialogs.cs

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Gtk3.Interop;
using Avalonia.Input.Platform;
using Avalonia.Platform;
namespace Avalonia.Gtk3
{
class SystemDialog : ISystemDialogImpl
{
unsafe static Task<string[]> ShowDialog(string title, GtkWindow parent, GtkFileChooserAction action,
bool multiselect, string initialFileName)
{
GtkFileChooser dlg;
using (var name = title != null ? new Utf8Buffer(title) : null)
dlg = Native.GtkFileChooserDialogNew(name, parent, action, IntPtr.Zero);
if (multiselect)
Native.GtkFileChooserSetSelectMultiple(dlg, true);
Native.GtkWindowSetModal(dlg, true);
var tcs = new TaskCompletionSource<string[]>();
List<IDisposable> disposables = null;
Action dispose = () =>
{
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, IWindowImpl parent)
{
return ShowDialog(dialog.Title, ((TopLevelImpl) parent)?.GtkWidget,
dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save,
(dialog as OpenFileDialog)?.AllowMultiple ?? false, dialog.InitialFileName);
}
public async Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
{
var res = await ShowDialog(dialog.Title, ((TopLevelImpl) parent)?.GtkWidget,
GtkFileChooserAction.SelectFolder, false, dialog.InitialDirectory);
return res?.FirstOrDefault();
}
}
}

336
src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs

@ -0,0 +1,336 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Avalonia.Controls;
using Avalonia.Gtk3.Interop;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Platform;
namespace Avalonia.Gtk3
{
abstract class TopLevelImpl : ITopLevelImpl, IPlatformHandle
{
public readonly GtkWindow GtkWidget;
private IInputRoot _inputRoot;
private readonly GtkImContext _imContext;
private readonly FramebufferManager _framebuffer;
protected readonly List<IDisposable> Disposables = new List<IDisposable>();
private Size _lastSize;
private Point _lastPosition;
private uint _lastKbdEvent;
private uint _lastSmoothScrollEvent;
public TopLevelImpl(GtkWindow gtkWidget)
{
GtkWidget = gtkWidget;
Disposables.Add(gtkWidget);
_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);
Connect<Native.D.signal_generic>("destroy", OnDestroy);
Native.GtkWidgetRealize(gtkWidget);
_lastSize = ClientSize;
}
private bool OnConfigured(IntPtr gtkwidget, IntPtr ev, IntPtr userdata)
{
var size = ClientSize;
if (_lastSize != size)
{
Resized?.Invoke(size);
_lastSize = size;
}
var pos = Position;
if (_lastPosition != pos)
{
PositionChanged?.Invoke(pos);
_lastPosition = pos;
}
return false;
}
private bool OnRealized(IntPtr gtkwidget, IntPtr userdata)
{
Native.GtkImContextSetClientWindow(_imContext, Native.GtkWidgetGetWindow(GtkWidget));
return false;
}
private bool OnDestroy(IntPtr gtkwidget, IntPtr userdata)
{
Dispose();
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.Control;
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 OnButton(IntPtr w, IntPtr ev, IntPtr userdata)
{
var evnt = (GdkEventButton*)ev;
var e = new RawMouseEventArgs(
Gtk3Platform.Mouse,
evnt->time,
_inputRoot,
evnt->type == GdkEventType.ButtonRelease
? evnt->button == 1
? RawMouseEventType.LeftButtonUp
: evnt->button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp
: evnt->button == 1
? RawMouseEventType.LeftButtonDown
: evnt->button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown,
new Point(evnt->x, evnt->y), GetModifierKeys(evnt->state));
Input?.Invoke(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 RawMouseEventArgs(
Gtk3Platform.Mouse,
evnt->time,
_inputRoot,
RawMouseEventType.Move,
position, GetModifierKeys(evnt->state));
Input(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));
Input(e);
return true;
}
private unsafe bool OnKeyEvent(IntPtr w, IntPtr pev, IntPtr userData)
{
var evnt = (GdkEventKey*) pev;
_lastKbdEvent = evnt->time;
if (Native.GtkImContextFilterKeypress(_imContext, pev))
return true;
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));
Input(e);
return true;
}
private unsafe bool OnCommit(IntPtr gtkwidget, IntPtr utf8string, IntPtr userdata)
{
Input(new RawTextInputEventArgs(Gtk3Platform.Keyboard, _lastKbdEvent, Utf8Buffer.StringFromPtr(utf8string)));
return true;
}
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)
{
CurrentCairoContext = cairocontext;
Paint?.Invoke(new Rect(ClientSize));
CurrentCairoContext = IntPtr.Zero;
return true;
}
public void Dispose()
{
//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();
}
public Size MaxClientSize
{
get
{
var s = Native.GtkWidgetGetScreen(GtkWidget);
return new Size(Native.GdkScreenGetWidth(s), Native.GdkScreenGetHeight(s));
}
}
public double Scaling => 1; //TODO: Implement scaling
public IPlatformHandle Handle => this;
string IPlatformHandle.HandleDescriptor => "HWND";
public Action Activated { 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<Point> PositionChanged { get; set; }
public void Activate() => Native.GtkWidgetActivate(GtkWidget);
public void Invalidate(Rect rect)
{
if(GtkWidget.IsClosed)
return;
Native.GtkWidgetQueueDrawArea(GtkWidget, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
}
public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
public Point PointToClient(Point point)
{
int x, y;
Native.GdkWindowGetOrigin(Native.GtkWidgetGetWindow(GtkWidget), out x, out y);
return new Point(point.X - x, point.Y - y);
}
public Point PointToScreen(Point point)
{
int x, y;
Native.GdkWindowGetOrigin(Native.GtkWidgetGetWindow(GtkWidget), out x, out y);
return new Point(point.X + x, point.Y + y);
}
public void SetCursor(IPlatformHandle cursor)
{
if (GtkWidget.IsClosed)
return;
Native.GdkWindowSetCursor(Native.GtkWidgetGetWindow(GtkWidget), cursor?.Handle ?? IntPtr.Zero);
}
public void Show() => Native.GtkWindowPresent(GtkWidget);
public void Hide() => Native.GtkWidgetHide(GtkWidget);
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
{
if (GtkWidget.IsClosed)
return new Size();
int w, h;
Native.GtkWindowGetSize(GtkWidget, out w, out h);
return new Size(w, h);
}
set
{
if (GtkWidget.IsClosed)
return;
Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height);
}
}
public Point Position
{
get
{
int x, y;
Native.GtkWindowGetPosition(GtkWidget, out x, out y);
return new Point(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, _framebuffer};
}
}

45
src/Gtk/Avalonia.Gtk3/WindowImpl.cs

@ -0,0 +1,45 @@
using System;
using Avalonia.Controls;
using Avalonia.Gtk3.Interop;
using Avalonia.Platform;
namespace Avalonia.Gtk3
{
class WindowImpl : TopLevelImpl, IWindowImpl
{
public WindowState WindowState { get; set; } //STUB
public void SetTitle(string title)
{
using (var t = new Utf8Buffer(title))
Native.GtkWindowSetTitle(GtkWidget, t);
}
class EmptyDisposable : IDisposable
{
public void Dispose()
{
}
}
public IDisposable ShowDialog()
{
Native.GtkWindowSetModal(GtkWidget, true);
Show();
return new EmptyDisposable();
}
public void SetSystemDecorations(bool enabled) => Native.GtkWindowSetDecorated(GtkWidget, enabled);
public void SetIcon(IWindowIconImpl icon) => Native.GtkWindowSetIcon(GtkWidget, (Pixbuf) icon);
public WindowImpl() : base(Native.GtkWindowNew(GtkWindowType.TopLevel))
{
}
public void SetCoverTaskbarWhenMaximized(bool enable)
{
//Why do we even have that?
}
}
}

10
src/Gtk/Avalonia.Gtk3/project.json

@ -0,0 +1,10 @@
{
"supports": {},
"dependencies": {
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
"NETStandard.Library": "1.6.0"
},
"frameworks": {
"netstandard1.1": {}
}
}

5
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -322,9 +322,8 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="Sprache, Version=2.0.0.51, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Sprache.2.0.0.51\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid+Xamarin.iOS10+MonoTouch\Sprache.dll</HintPath>
<Private>True</Private>
<Reference Include="Sprache, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Sprache.2.1.0\lib\netstandard1.0\Sprache.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Core, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll</HintPath>

6
src/Markup/Avalonia.Markup.Xaml/packages.config

@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Sprache" version="2.0.0.51" targetFramework="portable45-net45+win8" />
<package id="Sprache" version="2.1.0" targetFramework="portable45-net45+win8" />
<package id="System.Globalization" version="4.0.11" targetFramework="portable45-net45+win8" />
<package id="System.Linq" version="4.1.0" targetFramework="portable45-net45+win8" />
<package id="System.Reactive" version="3.0.0" targetFramework="portable45-net45+win8" />
<package id="System.Reactive.Core" version="3.0.0" targetFramework="portable45-net45+win8" />
<package id="System.Reactive.Interfaces" version="3.0.0" targetFramework="portable45-net45+win8" />
<package id="System.Reactive.Linq" version="3.0.0" targetFramework="portable45-net45+win8" />
<package id="System.Reactive.PlatformServices" version="3.0.0" targetFramework="portable45-net45+win8" />
<package id="System.Runtime" version="4.1.0" targetFramework="portable45-net45+win8" />
<package id="System.Text.RegularExpressions" version="4.1.0" targetFramework="portable45-net45+win8" />
</packages>

6
src/Shared/PlatformSupport/AssetLoader.cs

@ -138,7 +138,7 @@ namespace Avalonia.Shared.PlatformSupport
AssemblyDescriptor rv;
if (!AssemblyNameCache.TryGetValue(name, out rv))
{
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var loadedAssemblies = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetLoadedAssemblies();
var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name);
if (match != null)
{
@ -148,7 +148,9 @@ namespace Avalonia.Shared.PlatformSupport
{
// iOS does not support loading assemblies dynamically!
//
#if !__IOS__
#if NETSTANDARD
AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(new AssemblyName(name)));
#elif !__IOS__
AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name));
#endif
}

9
src/Shared/PlatformSupport/StandardRuntimePlatform.cs

@ -2,7 +2,6 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Disposables;
using System.Reflection;
using System.Resources;
using System.Threading;
@ -12,12 +11,16 @@ namespace Avalonia.Shared.PlatformSupport
{
internal partial class StandardRuntimePlatform : IRuntimePlatform
{
#if NETSTANDARD
public void PostThreadPoolItem(Action cb) => ThreadPool.QueueUserWorkItem(_ => cb(), null);
#else
public Assembly[] GetLoadedAssemblies() => AppDomain.CurrentDomain.GetAssemblies();
public void PostThreadPoolItem(Action cb) => ThreadPool.UnsafeQueueUserWorkItem(_ => cb(), null);
#endif
public IDisposable StartSystemTimer(TimeSpan interval, Action tick)
{
var timer = new Timer(_ => tick(), null, interval, interval);
return Disposable.Create(() => timer.Dispose());
return new Timer(_ => tick(), null, interval, interval);
}

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

Loading…
Cancel
Save