diff --git a/.gitignore b/.gitignore index d16287cfb4..d965a09574 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,5 @@ tools/ .nuget artifacts/ nuget +Avalonia.XBuild.sln +project.lock.json diff --git a/Avalonia.sln b/Avalonia.sln index a6fdcbd421..4e897b86c7 100644 --- a/Avalonia.sln +++ b/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 diff --git a/build.cake b/build.cake index e902c5d24e..ee68c74bb3 100644 --- a/build.cake +++ b/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( - 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>>(); - -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> versions; - packageVersions.TryGetValue(packageReference.Id, out versions); - if (versions == null) - { - versions = new List>(); - 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 ((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(); - -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(); - 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); diff --git a/packages.cake b/packages.cake new file mode 100644 index 0000000000..67483c4579 --- /dev/null +++ b/packages.cake @@ -0,0 +1,469 @@ +public class Packages +{ + public List 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( + 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>>(); + + 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> versions; + packageVersions.TryGetValue(packageReference.Id, out versions); + if (versions == null) + { + versions = new List>(); + 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 ((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(); + + 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(); + } +} diff --git a/parameters.cake b/parameters.cake new file mode 100644 index 0000000000..4a7270011c --- /dev/null +++ b/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); + } +} diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 5b39aa3dfb..fa29610b18 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -32,9 +32,12 @@ False False False - armeabi,armeabi-v7a,x86 + armeabi;armeabi-v7a;x86 Xamarin False + False + False + False pdbonly diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs index 3f357b0e70..157609088f 100644 --- a/samples/ControlCatalog.Android/MainActivity.cs +++ b/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); } } } diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj index 53cb277233..ca5743dd5c 100644 --- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj +++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj @@ -33,6 +33,9 @@ prompt 4 + + + ..\..\packages\Serilog.1.5.14\lib\net45\Serilog.dll @@ -72,6 +75,10 @@ {FB05AC90-89BA-4F2F-A924-F37875FB547C} Avalonia.Cairo + + {bb1f7bb5-6ad4-4776-94d9-c09d0a972658} + Avalonia.Gtk3 + {54F237D5-A70A-4752-9656-0C70B1A7B047} Avalonia.Gtk diff --git a/samples/ControlCatalog/Pages/TreeViewPage.xaml.cs b/samples/ControlCatalog/Pages/TreeViewPage.xaml.cs index a630b90dbd..a83f9cf43f 100644 --- a/samples/ControlCatalog/Pages/TreeViewPage.xaml.cs +++ b/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 CreateNodes(int level) + public class Node { - return Enumerable.Range(0, 10).Select(x => new Node + private IList _children; + public string Header { get; private set; } + public IList Children { - Header = $"Item {x}", - Children = level < 5 ? CreateNodes(level + 1) : null, - }).ToList(); - } - - private class Node - { - public string Header { get; set; } - public IList Children { get; set; } + get + { + if (_children == null) + { + _children = Enumerable.Range(1, 10).Select(i => new Node() {Header = $"Item {i}"}) + .ToArray(); + } + return _children; + } + } } } } diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs index afaa314e6c..5b3170a0c7 100644 --- a/src/Android/Avalonia.Android/AndroidPlatform.cs +++ b/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(this T builder) where T : AppBuilderBase, 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().ToTransient() @@ -51,24 +56,22 @@ namespace Avalonia.Android .Bind().ToConstant(new AndroidThreadingInterface()) .Bind().ToTransient() .Bind().ToConstant(Instance) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToConstant(new DefaultRenderLoop(60)) - SkiaPlatform.Initialize(); - } + .Bind().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() diff --git a/src/Android/Avalonia.Android/AndroidThreadingInterface.cs b/src/Android/Avalonia.Android/AndroidThreadingInterface.cs index b4059e3114..6327be12a5 100644 --- a/src/Android/Avalonia.Android/AndroidThreadingInterface.cs +++ b/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; + } } }); } diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 654cb13678..0dfab3f518 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -63,16 +63,17 @@ + + - - + + + - - diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs new file mode 100644 index 0000000000..a9b04c882b --- /dev/null +++ b/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); + } + } +} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs new file mode 100644 index 0000000000..71eea14a1d --- /dev/null +++ b/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(); + } + } + } +} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs new file mode 100644 index 0000000000..982c79560b --- /dev/null +++ b/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; + } + } +} \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android/SkiaView.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs similarity index 88% rename from src/Skia/Avalonia.Skia.Android/SkiaView.cs rename to src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs index a45a80cf18..2213ebddcc 100644 --- a/src/Skia/Avalonia.Skia.Android/SkiaView.cs +++ b/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); diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs deleted file mode 100644 index 690c509b53..0000000000 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs +++ /dev/null @@ -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().ContentView = this; - //this.Visibility = ViewStates.Visible; - } - - void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) - { - base.SetInputRoot(inputRoot); - _keyboardHelper.UpdateKeyboardState(inputRoot); - } - } -} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs similarity index 83% rename from src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs rename to src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 0e1540b5fd..26d2b0aad9 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/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 _keyboardHelper; + protected AndroidKeyboardEventsHelper _keyboardHelper; - private AndroidTouchEventsHelper _touchHelper; + private AndroidTouchEventsHelper _touchHelper; - public WindowImpl(Context context) : base((Activity)context) + public TopLevelImpl(Context context) : base(context) { - _keyboardHelper = new AndroidKeyboardEventsHelper(this); - _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p)); + _keyboardHelper = new AndroidKeyboardEventsHelper(this); + _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p)); MaxClientSize = new Size(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels); ClientSize = MaxClientSize; - Init(); - } - - public WindowImpl() : this(AvaloniaLocator.Current.GetService().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 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); } } \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs b/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs deleted file mode 100644 index 4ccff10455..0000000000 --- a/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs +++ /dev/null @@ -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().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); - } - } -} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs index 17e1f62e8c..7bac0ff814 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs +++ b/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 : IDisposable where TView : View, IWindowImpl, IAndroidView + public class AndroidKeyboardEventsHelper : IDisposable where TView : View, ITopLevelImpl, IAndroidView { private TView _view; private IInputElement _lastFocusedElement; diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs index c6d1833d2d..a448044ee6 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs @@ -8,7 +8,7 @@ using System; namespace Avalonia.Android.Platform.Specific.Helpers { - public class AndroidTouchEventsHelper : IDisposable where TView : View, IWindowImpl, IAndroidView + public class AndroidTouchEventsHelper : IDisposable where TView : View, ITopLevelImpl, IAndroidView { private TView _view; public bool HandleEvents { get; set; } diff --git a/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs b/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs deleted file mode 100644 index b2a999d4be..0000000000 --- a/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs +++ /dev/null @@ -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; } - } -} \ No newline at end of file diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj index e004121323..0e94cecc2d 100644 --- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj +++ b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj @@ -20,7 +20,7 @@ Properties\AndroidManifest.xml - true + True full false bin\Debug\ @@ -29,16 +29,16 @@ 4 True None - - False + True False False - armeabi,armeabi-v7a,x86 - - + armeabi;armeabi-v7a;x86 Xamarin False True + False + False + False pdbonly @@ -72,9 +72,8 @@ ..\..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll True - - ..\..\..\packages\Sprache.2.0.0.51\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid+Xamarin.iOS10+MonoTouch\Sprache.dll - True + + ..\..\..\packages\Sprache.2.1.0\lib\netstandard1.0\Sprache.dll diff --git a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs b/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs index ff27e12f6e..7973ad72e5 100644 --- a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs +++ b/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() .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 { diff --git a/src/Android/Avalonia.AndroidTestApplication/packages.config b/src/Android/Avalonia.AndroidTestApplication/packages.config index 470074798d..d353146747 100644 --- a/src/Android/Avalonia.AndroidTestApplication/packages.config +++ b/src/Android/Avalonia.AndroidTestApplication/packages.config @@ -2,7 +2,7 @@ - + @@ -19,6 +19,7 @@ + \ No newline at end of file diff --git a/src/Avalonia.Animation/Avalonia.Animation.csproj b/src/Avalonia.Animation/Avalonia.Animation.csproj index d74f4d9c69..46aac81b5a 100644 --- a/src/Avalonia.Animation/Avalonia.Animation.csproj +++ b/src/Avalonia.Animation/Avalonia.Animation.csproj @@ -16,7 +16,7 @@ Profile7 v4.5 - + true full false @@ -27,7 +27,7 @@ bin\Debug\Avalonia.Animation.XML false - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 5d944c6ff0..1ba96a96d6 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.Base.XML CS1591 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index 10fbe746e3..c05e44b357 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.Controls.XML CS1591 - + pdbonly true bin\Release\ @@ -57,6 +57,9 @@ + + + diff --git a/src/Avalonia.Controls/Expander.cs b/src/Avalonia.Controls/Expander.cs index 87eb427f3c..e7f75336f5 100644 --- a/src/Avalonia.Controls/Expander.cs +++ b/src/Avalonia.Controls/Expander.cs @@ -31,7 +31,8 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect( nameof(IsExpanded), o => o.IsExpanded, - (o, v) => o.IsExpanded = v); + (o, v) => o.IsExpanded = v, + defaultBindingMode: Data.BindingMode.TwoWay); static Expander() { diff --git a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs index 087a333e8a..77884acf73 100644 --- a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs +++ b/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 /// IPlatformHandle Handle { get; } + /// + /// The list of native platform's surfaces that can be consumed by rendering subsystems. + /// + /// + /// 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<Gdk.Drawable> in case of GTK#+Cairo) + /// + IEnumerable Surfaces { get; } + /// /// Gets or sets a method called when the window is activated (receives focus). /// diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index fd2feb539f..609e9834cb 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -35,11 +35,6 @@ namespace Avalonia.Platform /// void SetSystemDecorations(bool enabled); - /// - /// When system decorations are disabled sets if the maximized state covers the entire screen or just the working area. - /// - void SetCoverTaskbarWhenMaximized(bool enable); - /// /// Sets the icon of this window. /// diff --git a/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs b/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs new file mode 100644 index 0000000000..84988e912f --- /dev/null +++ b/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 + { + /// + /// Provides a framebuffer descriptor for drawing. + /// + /// + /// Contents should be drawn on actual window after disposing + /// + ILockedFramebuffer Lock(); + } +} diff --git a/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs b/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs new file mode 100644 index 0000000000..d6402d170d --- /dev/null +++ b/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs @@ -0,0 +1,37 @@ +using System; + +namespace Avalonia.Controls.Platform.Surfaces +{ + public interface ILockedFramebuffer : IDisposable + { + /// + /// Address of the first pixel + /// + IntPtr Address { get; } + + /// + /// Framebuffer width + /// + int Width { get; } + + /// + /// Framebuffer height + /// + int Height { get; } + + /// + /// Number of bytes per row + /// + int RowBytes { get; } + + /// + /// DPI of underling screen + /// + Size Dpi { get; } + + /// + /// Pixel format + /// + PixelFormat Format { get; } + } +} diff --git a/src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs b/src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs new file mode 100644 index 0000000000..c9f8eabe97 --- /dev/null +++ b/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 + } +} diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 96c09a8789..ba62d95c10 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -185,7 +185,7 @@ namespace Avalonia.Controls /// /// Gets the renderer for the window. /// - public IRenderer Renderer { get; } + public IRenderer Renderer { get; private set; } /// /// Gets the access key handler for the window. @@ -241,7 +241,7 @@ namespace Avalonia.Controls /// IRenderTarget IRenderRoot.CreateRenderTarget(IVisualBrushRenderer visualBrushRenderer) { - return _renderInterface.CreateRenderTarget(PlatformImpl.Handle); + return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces); } /// @@ -386,6 +386,8 @@ namespace Avalonia.Controls { IsVisible = false; Closed?.Invoke(this, EventArgs.Empty); + Renderer?.Dispose(); + Renderer = null; _applicationLifecycle.OnExit -= OnApplicationExiting; } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 52d6ffdf55..d14964d829 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -64,13 +64,6 @@ namespace Avalonia.Controls public static readonly StyledProperty HasSystemDecorationsProperty = AvaloniaProperty.Register(nameof(HasSystemDecorations), true); - /// - /// Sets if the window should cover the taskbar when maximized. Only applies to Windows - /// with HasSystemDecorations = false. - /// - public static readonly StyledProperty CoverTaskbarOnMaximizeProperty = - AvaloniaProperty.Register(nameof(CoverTaskbarOnMaximize), true); - /// /// Defines the property. /// @@ -97,9 +90,6 @@ namespace Avalonia.Controls HasSystemDecorationsProperty.Changed.AddClassHandler( (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue)); - CoverTaskbarOnMaximizeProperty.Changed.AddClassHandler( - (s, e) => s.PlatformImpl.SetCoverTaskbarWhenMaximized((bool)e.NewValue)); - IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); } @@ -168,16 +158,6 @@ namespace Avalonia.Controls set { SetValue(HasSystemDecorationsProperty, value); } } - /// - /// Sets if the window should cover the taskbar when maximized. Only applies to Windows - /// with HasSystemDecorations = false. - /// - public bool CoverTaskbarOnMaximize - { - get { return GetValue(CoverTaskbarOnMaximizeProperty); } - set { SetValue(CoverTaskbarOnMaximizeProperty, value); } - } - /// /// Gets or sets the minimized/maximized state of the window. /// diff --git a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj index 478d0eaa57..d9174d6f36 100644 --- a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj +++ b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.DesignerSupport.xml CS1591 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj index 5381f55288..a56575dab7 100644 --- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj +++ b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.Diagnostics.XML CS1591 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs b/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs new file mode 100644 index 0000000000..5a6b82573b --- /dev/null +++ b/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 + { + /// + /// Initializes a new instance of the class. + /// + public AppBuilder() + : base(new StandardRuntimePlatform(), () => StandardRuntimePlatformServices.Register()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The instance. + public AppBuilder(Application app) : this() + { + Instance = app; + } + + /// + /// Instructs the to use the best settings for the platform. + /// + /// An instance. + 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(); + } +} \ No newline at end of file diff --git a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj new file mode 100644 index 0000000000..8a60d5d9c7 --- /dev/null +++ b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj @@ -0,0 +1,89 @@ + + + + + 14.0 + Debug + AnyCPU + {7863EA94-F0FB-4386-BF8C-E5BFA761560A} + Library + Properties + Avalonia.DotNetCoreRuntime + Avalonia.DotNetCoreRuntime + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + v5.0 + + + true + full + false + bin\Debug\ + TRACE;DEBUG;NETSTANDARD + prompt + 4 + bin\Debug\Avalonia.DotNetCoreRuntime.XML + + + pdbonly + true + bin\Release\ + TRACE;NETSTANDARD + prompt + 4 + bin\Release\Avalonia.DotNetCoreRuntime.XML + + + + + + + + SharedAssemblyInfo.cs + + + + + + + + {b09b78d8-9b26-48b0-9149-d64a2f120f3f} + Avalonia.Base + + + {d2221c82-4a25-4583-9b43-d791e3f6820c} + Avalonia.Controls + + + {eb582467-6abb-43a1-b052-e981ba910e3a} + Avalonia.Visuals + + + {bb1f7bb5-6ad4-4776-94d9-c09d0a972658} + Avalonia.Gtk3 + + + {7d2d3083-71dd-4cc9-8907-39a0d86fb322} + Avalonia.Skia.Desktop.NetStandard + + + {40759a76-d0f2-464e-8000-6ff0f5c4bd7c} + Avalonia.Win32.NetStandard + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.v3.ncrunchproject b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs b/src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs new file mode 100644 index 0000000000..b131488109 --- /dev/null +++ b/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 Assemblies = new Lazy(LoadAssemblies); + public Assembly[] GetLoadedAssemblies() => Assemblies.Value; + + static Assembly[] LoadAssemblies() + { + + var rv = new List(); + var entry = Assembly.GetEntryAssembly(); + rv.Add(entry); + var queue = new Queue(entry.GetReferencedAssemblies()); + var aset = new HashSet(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(); + } + } +} diff --git a/src/Avalonia.DotNetCoreRuntime/RuntimeInfo.cs b/src/Avalonia.DotNetCoreRuntime/RuntimeInfo.cs new file mode 100644 index 0000000000..348c3f6e25 --- /dev/null +++ b/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 Info = new Lazy(() => + { + 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; + } +} diff --git a/src/Avalonia.DotNetCoreRuntime/project.json b/src/Avalonia.DotNetCoreRuntime/project.json new file mode 100644 index 0000000000..d6ae90b33b --- /dev/null +++ b/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": {} + } +} \ No newline at end of file diff --git a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj index f11b67dcc9..e87ec0b5a7 100644 --- a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj +++ b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj @@ -13,7 +13,7 @@ 512 - + true full false @@ -23,7 +23,7 @@ 4 bin\Debug\Avalonia.DotNetFrameworkRuntime.xml - + pdbonly true bin\Release\ diff --git a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject new file mode 100644 index 0000000000..3cd9a982c9 --- /dev/null +++ b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject @@ -0,0 +1,6 @@ + + + False + True + + \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj index dd0a6f2cef..8f16bad64a 100644 --- a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj +++ b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj @@ -18,7 +18,7 @@ - + true full false @@ -27,7 +27,7 @@ prompt 4 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Input/Avalonia.Input.csproj b/src/Avalonia.Input/Avalonia.Input.csproj index 5e0fb50b67..c1ed34c1c7 100644 --- a/src/Avalonia.Input/Avalonia.Input.csproj +++ b/src/Avalonia.Input/Avalonia.Input.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.Input.XML CS1591 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj index 499a55ef12..0d81690de0 100644 --- a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj +++ b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.Interactivity.XML CS1591 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Layout/Avalonia.Layout.csproj b/src/Avalonia.Layout/Avalonia.Layout.csproj index 4bc27fc96b..41b545b5cb 100644 --- a/src/Avalonia.Layout/Avalonia.Layout.csproj +++ b/src/Avalonia.Layout/Avalonia.Layout.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.Layout.XML CS1591 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj index e88dc86b00..0fb85db795 100644 --- a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj +++ b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj @@ -16,7 +16,7 @@ Profile7 v4.5 - + true full false @@ -26,7 +26,7 @@ 4 bin\Debug\Avalonia.Logging.Serilog.XML - + pdbonly true bin\Release\ diff --git a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj index 4ef0502fa0..98cf115eaf 100644 --- a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj +++ b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj @@ -16,7 +16,7 @@ Profile259 v4.5 - + true full false @@ -25,7 +25,7 @@ prompt 4 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Styling/Avalonia.Styling.csproj b/src/Avalonia.Styling/Avalonia.Styling.csproj index 3566ed7268..d38406caa7 100644 --- a/src/Avalonia.Styling/Avalonia.Styling.csproj +++ b/src/Avalonia.Styling/Avalonia.Styling.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.Styling.XML CS1591 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj index 578bb9cdff..26d168cb2a 100644 --- a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj +++ b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj @@ -18,7 +18,7 @@ - + true full false @@ -28,7 +28,7 @@ 4 bin\Debug\Avalonia.Themes.Default.XML - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj index 41e8857e6f..234a52b5cb 100644 --- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj +++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj @@ -18,7 +18,7 @@ - + true full false @@ -29,7 +29,7 @@ bin\Debug\Avalonia.Visuals.xml CS1591 - + pdbonly true bin\Release\ diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index 70f6ed6bd1..4ad2969de8 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/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 /// /// Creates a renderer. /// - /// The platform handle for the renderer. + /// + /// The list of native platform surfaces that can be used for output. + /// /// An . - IRenderTarget CreateRenderTarget(IPlatformHandle handle); + IRenderTarget CreateRenderTarget(IEnumerable surfaces); /// /// Creates a render target bitmap implementation. diff --git a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs index 9745f2bd8e..ef237cb35e 100644 --- a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs +++ b/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 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>().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) diff --git a/src/Gtk/Avalonia.Cairo/RenderTarget.cs b/src/Gtk/Avalonia.Cairo/RenderTarget.cs index 92ed71e0fd..dec8977d39 100644 --- a/src/Gtk/Avalonia.Cairo/RenderTarget.cs +++ b/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 _drawableAccessor; + /// /// Initializes a new instance of the class. @@ -29,9 +29,9 @@ namespace Avalonia.Cairo /// The window. /// The width of the window. /// The height of the window. - public RenderTarget(Gtk.Window window) + public RenderTarget(Func drawable) { - _window = window; + _drawableAccessor = drawable; } public RenderTarget(ImageSurface surface) @@ -39,11 +39,6 @@ namespace Avalonia.Cairo _surface = surface; } - public RenderTarget(DrawingArea area) - { - _area = area; - } - /// /// Creates a cairo surface that targets a platform-specific resource. /// @@ -51,12 +46,10 @@ namespace Avalonia.Cairo /// A surface wrapped in an . 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"); } diff --git a/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj b/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj index b001c7bc19..07a9ab56ed 100644 --- a/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj +++ b/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj @@ -30,6 +30,8 @@ false + + @@ -48,7 +50,10 @@ + + + diff --git a/src/Gtk/Avalonia.Gtk/FramebufferManager.cs b/src/Gtk/Avalonia.Gtk/FramebufferManager.cs new file mode 100644 index 0000000000..00a4727769 --- /dev/null +++ b/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; + } + } +} diff --git a/src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs b/src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs index 4e88dcda9a..a97a6190f1 100644 --- a/src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs +++ b/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 KeyDic = new Dictionary - { - { 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; - } } } \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk/KeyTransform.cs b/src/Gtk/Avalonia.Gtk/KeyTransform.cs new file mode 100644 index 0000000000..77de8d18a3 --- /dev/null +++ b/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 KeyDic = new Dictionary + { + { 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; + } + } +} diff --git a/src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs b/src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs new file mode 100644 index 0000000000..7e6da0e76a --- /dev/null +++ b/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; + } +} + diff --git a/src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs b/src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs index ed92a25873..962621856a 100644 --- a/src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs +++ b/src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs @@ -15,7 +15,7 @@ namespace Avalonia.Gtk public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) { var tcs = new TaskCompletionSource(); - 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 ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) { var tcs = new TaskCompletionSource(); - 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) diff --git a/src/Gtk/Avalonia.Gtk/WindowImpl.cs b/src/Gtk/Avalonia.Gtk/WindowImpl.cs index e075a31c4c..eca7c24136 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImpl.cs +++ b/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(); diff --git a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs index 3c883d75d6..a6120472ab 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs +++ b/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 ScalingChanged { get; set; } + public IEnumerable Surfaces => new object[] + { + Handle, + new Func(() => 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; diff --git a/src/Gtk/Avalonia.Gtk3/.gitignore b/src/Gtk/Avalonia.Gtk3/.gitignore new file mode 100644 index 0000000000..ddb0c6248b --- /dev/null +++ b/src/Gtk/Avalonia.Gtk3/.gitignore @@ -0,0 +1 @@ +project.lock.json \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj b/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj new file mode 100644 index 0000000000..785baeba8a --- /dev/null +++ b/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj @@ -0,0 +1,103 @@ + + + + + 14.0 + Debug + AnyCPU + {BB1F7BB5-6AD4-4776-94D9-C09D0A972658} + Library + Properties + Avalonia.Gtk3 + Avalonia.Gtk3 + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + v5.0 + + + true + full + false + bin\Debug\ + TRACE;DEBUG;GTK3_PINVOKE + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE;GTK3_PINVOKE + prompt + 4 + true + + + + + + + + KeyTransform.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {D2221C82-4A25-4583-9B43-D791E3F6820C} + Avalonia.Controls + + + {62024B2D-53EB-4638-B26B-85EEAA54866E} + Avalonia.Input + + + {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} + Avalonia.Interactivity + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + + + \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.v3.ncrunchproject b/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/ClipboardImpl.cs b/src/Gtk/Avalonia.Gtk3/ClipboardImpl.cs new file mode 100644 index 0000000000..333391a064 --- /dev/null +++ b/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) handle.Target) + .TrySetResult(Utf8Buffer.StringFromPtr(utf8string)); + handle.Free(); + } + + private static readonly Native.D.GtkClipboardTextReceivedFunc OnTextDelegate = OnText; + + static ClipboardImpl() + { + GCHandle.Alloc(OnTextDelegate); + } + + public Task GetTextAsync() + { + var tcs = new TaskCompletionSource(); + 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); + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/CursorFactory.cs b/src/Gtk/Avalonia.Gtk3/CursorFactory.cs new file mode 100644 index 0000000000..ac547b8bc2 --- /dev/null +++ b/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 CursorTypeMapping = new Dictionary + + { + {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 Cache = + new Dictionary(); + + 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; + } + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs b/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs new file mode 100644 index 0000000000..0a0a8fe0a6 --- /dev/null +++ b/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); + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/GdkCursor.cs b/src/Gtk/Avalonia.Gtk3/GdkCursor.cs new file mode 100644 index 0000000000..48815e1273 --- /dev/null +++ b/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, + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/GdkKey.cs b/src/Gtk/Avalonia.Gtk3/GdkKey.cs new file mode 100644 index 0000000000..b4a0f31b92 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk3/GdkKey.cs @@ -0,0 +1,1347 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Gtk3 +{ + enum GdkKey + { + space = 32, + exclam = 33, + quotedbl = 34, + numbersign = 35, + dollar = 36, + percent = 37, + ampersand = 38, + apostrophe = 39, + quoteright = 39, + parenleft = 40, + parenright = 41, + asterisk = 42, + plus = 43, + comma = 44, + minus = 45, + period = 46, + slash = 47, + Key_0 = 48, + Key_1 = 49, + Key_2 = 50, + Key_3 = 51, + Key_4 = 52, + Key_5 = 53, + Key_6 = 54, + Key_7 = 55, + Key_8 = 56, + Key_9 = 57, + colon = 58, + semicolon = 59, + less = 60, + equal = 61, + greater = 62, + question = 63, + at = 64, + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + bracketleft = 91, + backslash = 92, + bracketright = 93, + asciicircum = 94, + underscore = 95, + grave = 96, + quoteleft = 96, + a = 97, + b = 98, + c = 99, + d = 100, + e = 101, + f = 102, + g = 103, + h = 104, + i = 105, + j = 106, + k = 107, + l = 108, + m = 109, + n = 110, + o = 111, + p = 112, + q = 113, + r = 114, + s = 115, + t = 116, + u = 117, + v = 118, + w = 119, + x = 120, + y = 121, + z = 122, + braceleft = 123, + bar = 124, + braceright = 125, + asciitilde = 126, + nobreakspace = 160, + exclamdown = 161, + cent = 162, + sterling = 163, + currency = 164, + yen = 165, + brokenbar = 166, + section = 167, + diaeresis = 168, + copyright = 169, + ordfeminine = 170, + guillemotleft = 171, + notsign = 172, + hyphen = 173, + registered = 174, + macron = 175, + degree = 176, + plusminus = 177, + twosuperior = 178, + threesuperior = 179, + acute = 180, + mu = 181, + paragraph = 182, + periodcentered = 183, + cedilla = 184, + onesuperior = 185, + masculine = 186, + guillemotright = 187, + onequarter = 188, + onehalf = 189, + threequarters = 190, + questiondown = 191, + Agrave = 192, + Aacute = 193, + Acircumflex = 194, + Atilde = 195, + Adiaeresis = 196, + Aring = 197, + AE = 198, + Ccedilla = 199, + Egrave = 200, + Eacute = 201, + Ecircumflex = 202, + Ediaeresis = 203, + Igrave = 204, + Iacute = 205, + Icircumflex = 206, + Idiaeresis = 207, + ETH = 208, + Eth = 208, + Ntilde = 209, + Ograve = 210, + Oacute = 211, + Ocircumflex = 212, + Otilde = 213, + Odiaeresis = 214, + multiply = 215, + Ooblique = 216, + Ugrave = 217, + Uacute = 218, + Ucircumflex = 219, + Udiaeresis = 220, + Yacute = 221, + THORN = 222, + Thorn = 222, + ssharp = 223, + agrave = 224, + aacute = 225, + acircumflex = 226, + atilde = 227, + adiaeresis = 228, + aring = 229, + ae = 230, + ccedilla = 231, + egrave = 232, + eacute = 233, + ecircumflex = 234, + ediaeresis = 235, + igrave = 236, + iacute = 237, + icircumflex = 238, + idiaeresis = 239, + eth = 240, + ntilde = 241, + ograve = 242, + oacute = 243, + ocircumflex = 244, + otilde = 245, + odiaeresis = 246, + division = 247, + oslash = 248, + ugrave = 249, + uacute = 250, + ucircumflex = 251, + udiaeresis = 252, + yacute = 253, + thorn = 254, + ydiaeresis = 255, + Aogonek = 417, + breve = 418, + Lstroke = 419, + Lcaron = 421, + Sacute = 422, + Scaron = 425, + Scedilla = 426, + Tcaron = 427, + Zacute = 428, + Zcaron = 430, + Zabovedot = 431, + aogonek = 433, + ogonek = 434, + lstroke = 435, + lcaron = 437, + sacute = 438, + caron = 439, + scaron = 441, + scedilla = 442, + tcaron = 443, + zacute = 444, + doubleacute = 445, + zcaron = 446, + zabovedot = 447, + Racute = 448, + Abreve = 451, + Lacute = 453, + Cacute = 454, + Ccaron = 456, + Eogonek = 458, + Ecaron = 460, + Dcaron = 463, + Dstroke = 464, + Nacute = 465, + Ncaron = 466, + Odoubleacute = 469, + Rcaron = 472, + Uring = 473, + Udoubleacute = 475, + Tcedilla = 478, + racute = 480, + abreve = 483, + lacute = 485, + cacute = 486, + ccaron = 488, + eogonek = 490, + ecaron = 492, + dcaron = 495, + dstroke = 496, + nacute = 497, + ncaron = 498, + odoubleacute = 501, + rcaron = 504, + uring = 505, + udoubleacute = 507, + tcedilla = 510, + abovedot = 511, + Hstroke = 673, + Hcircumflex = 678, + Iabovedot = 681, + Gbreve = 683, + Jcircumflex = 684, + hstroke = 689, + hcircumflex = 694, + idotless = 697, + gbreve = 699, + jcircumflex = 700, + Cabovedot = 709, + Ccircumflex = 710, + Gabovedot = 725, + Gcircumflex = 728, + Ubreve = 733, + Scircumflex = 734, + cabovedot = 741, + ccircumflex = 742, + gabovedot = 757, + gcircumflex = 760, + ubreve = 765, + scircumflex = 766, + kappa = 930, + kra = 930, + Rcedilla = 931, + Itilde = 933, + Lcedilla = 934, + Emacron = 938, + Gcedilla = 939, + Tslash = 940, + rcedilla = 947, + itilde = 949, + lcedilla = 950, + emacron = 954, + gcedilla = 955, + tslash = 956, + ENG = 957, + eng = 959, + Amacron = 960, + Iogonek = 967, + Eabovedot = 972, + Imacron = 975, + Ncedilla = 977, + Omacron = 978, + Kcedilla = 979, + Uogonek = 985, + Utilde = 989, + Umacron = 990, + amacron = 992, + iogonek = 999, + eabovedot = 1004, + imacron = 1007, + ncedilla = 1009, + omacron = 1010, + kcedilla = 1011, + uogonek = 1017, + utilde = 1021, + umacron = 1022, + overline = 1150, + kana_fullstop = 1185, + kana_openingbracket = 1186, + kana_closingbracket = 1187, + kana_comma = 1188, + kana_conjunctive = 1189, + kana_middledot = 1189, + kana_WO = 1190, + kana_a = 1191, + kana_i = 1192, + kana_u = 1193, + kana_e = 1194, + kana_o = 1195, + kana_ya = 1196, + kana_yu = 1197, + kana_yo = 1198, + kana_tsu = 1199, + kana_tu = 1199, + prolongedsound = 1200, + kana_A = 1201, + kana_I = 1202, + kana_U = 1203, + kana_E = 1204, + kana_O = 1205, + kana_KA = 1206, + kana_KI = 1207, + kana_KU = 1208, + kana_KE = 1209, + kana_KO = 1210, + kana_SA = 1211, + kana_SHI = 1212, + kana_SU = 1213, + kana_SE = 1214, + kana_SO = 1215, + kana_TA = 1216, + kana_CHI = 1217, + kana_TI = 1217, + kana_TSU = 1218, + kana_TU = 1218, + kana_TE = 1219, + kana_TO = 1220, + kana_NA = 1221, + kana_NI = 1222, + kana_NU = 1223, + kana_NE = 1224, + kana_NO = 1225, + kana_HA = 1226, + kana_HI = 1227, + kana_FU = 1228, + kana_HU = 1228, + kana_HE = 1229, + kana_HO = 1230, + kana_MA = 1231, + kana_MI = 1232, + kana_MU = 1233, + kana_ME = 1234, + kana_MO = 1235, + kana_YA = 1236, + kana_YU = 1237, + kana_YO = 1238, + kana_RA = 1239, + kana_RI = 1240, + kana_RU = 1241, + kana_RE = 1242, + kana_RO = 1243, + kana_WA = 1244, + kana_N = 1245, + voicedsound = 1246, + semivoicedsound = 1247, + Arabic_comma = 1452, + Arabic_semicolon = 1467, + Arabic_question_mark = 1471, + Arabic_hamza = 1473, + Arabic_maddaonalef = 1474, + Arabic_hamzaonalef = 1475, + Arabic_hamzaonwaw = 1476, + Arabic_hamzaunderalef = 1477, + Arabic_hamzaonyeh = 1478, + Arabic_alef = 1479, + Arabic_beh = 1480, + Arabic_tehmarbuta = 1481, + Arabic_teh = 1482, + Arabic_theh = 1483, + Arabic_jeem = 1484, + Arabic_hah = 1485, + Arabic_khah = 1486, + Arabic_dal = 1487, + Arabic_thal = 1488, + Arabic_ra = 1489, + Arabic_zain = 1490, + Arabic_seen = 1491, + Arabic_sheen = 1492, + Arabic_sad = 1493, + Arabic_dad = 1494, + Arabic_tah = 1495, + Arabic_zah = 1496, + Arabic_ain = 1497, + Arabic_ghain = 1498, + Arabic_tatweel = 1504, + Arabic_feh = 1505, + Arabic_qaf = 1506, + Arabic_kaf = 1507, + Arabic_lam = 1508, + Arabic_meem = 1509, + Arabic_noon = 1510, + Arabic_ha = 1511, + Arabic_heh = 1511, + Arabic_waw = 1512, + Arabic_alefmaksura = 1513, + Arabic_yeh = 1514, + Arabic_fathatan = 1515, + Arabic_dammatan = 1516, + Arabic_kasratan = 1517, + Arabic_fatha = 1518, + Arabic_damma = 1519, + Arabic_kasra = 1520, + Arabic_shadda = 1521, + Arabic_sukun = 1522, + Serbian_dje = 1697, + Macedonia_gje = 1698, + Cyrillic_io = 1699, + Ukrainian_ie = 1700, + Ukranian_je = 1700, + Macedonia_dse = 1701, + Ukrainian_i = 1702, + Ukranian_i = 1702, + Ukrainian_yi = 1703, + Ukranian_yi = 1703, + Cyrillic_je = 1704, + Serbian_je = 1704, + Cyrillic_lje = 1705, + Serbian_lje = 1705, + Cyrillic_nje = 1706, + Serbian_nje = 1706, + Serbian_tshe = 1707, + Macedonia_kje = 1708, + Byelorussian_shortu = 1710, + Cyrillic_dzhe = 1711, + Serbian_dze = 1711, + numerosign = 1712, + Serbian_DJE = 1713, + Macedonia_GJE = 1714, + Cyrillic_IO = 1715, + Ukrainian_IE = 1716, + Ukranian_JE = 1716, + Macedonia_DSE = 1717, + Ukrainian_I = 1718, + Ukranian_I = 1718, + Ukrainian_YI = 1719, + Ukranian_YI = 1719, + Cyrillic_JE = 1720, + Serbian_JE = 1720, + Cyrillic_LJE = 1721, + Serbian_LJE = 1721, + Cyrillic_NJE = 1722, + Serbian_NJE = 1722, + Serbian_TSHE = 1723, + Macedonia_KJE = 1724, + Byelorussian_SHORTU = 1726, + Cyrillic_DZHE = 1727, + Serbian_DZE = 1727, + Cyrillic_yu = 1728, + Cyrillic_a = 1729, + Cyrillic_be = 1730, + Cyrillic_tse = 1731, + Cyrillic_de = 1732, + Cyrillic_ie = 1733, + Cyrillic_ef = 1734, + Cyrillic_ghe = 1735, + Cyrillic_ha = 1736, + Cyrillic_i = 1737, + Cyrillic_shorti = 1738, + Cyrillic_ka = 1739, + Cyrillic_el = 1740, + Cyrillic_em = 1741, + Cyrillic_en = 1742, + Cyrillic_o = 1743, + Cyrillic_pe = 1744, + Cyrillic_ya = 1745, + Cyrillic_er = 1746, + Cyrillic_es = 1747, + Cyrillic_te = 1748, + Cyrillic_u = 1749, + Cyrillic_zhe = 1750, + Cyrillic_ve = 1751, + Cyrillic_softsign = 1752, + Cyrillic_yeru = 1753, + Cyrillic_ze = 1754, + Cyrillic_sha = 1755, + Cyrillic_e = 1756, + Cyrillic_shcha = 1757, + Cyrillic_che = 1758, + Cyrillic_hardsign = 1759, + Cyrillic_YU = 1760, + Cyrillic_A = 1761, + Cyrillic_BE = 1762, + Cyrillic_TSE = 1763, + Cyrillic_DE = 1764, + Cyrillic_IE = 1765, + Cyrillic_EF = 1766, + Cyrillic_GHE = 1767, + Cyrillic_HA = 1768, + Cyrillic_I = 1769, + Cyrillic_SHORTI = 1770, + Cyrillic_KA = 1771, + Cyrillic_EL = 1772, + Cyrillic_EM = 1773, + Cyrillic_EN = 1774, + Cyrillic_O = 1775, + Cyrillic_PE = 1776, + Cyrillic_YA = 1777, + Cyrillic_ER = 1778, + Cyrillic_ES = 1779, + Cyrillic_TE = 1780, + Cyrillic_U = 1781, + Cyrillic_ZHE = 1782, + Cyrillic_VE = 1783, + Cyrillic_SOFTSIGN = 1784, + Cyrillic_YERU = 1785, + Cyrillic_ZE = 1786, + Cyrillic_SHA = 1787, + Cyrillic_E = 1788, + Cyrillic_SHCHA = 1789, + Cyrillic_CHE = 1790, + Cyrillic_HARDSIGN = 1791, + Greek_ALPHAaccent = 1953, + Greek_EPSILONaccent = 1954, + Greek_ETAaccent = 1955, + Greek_IOTAaccent = 1956, + Greek_IOTAdiaeresis = 1957, + Greek_OMICRONaccent = 1959, + Greek_UPSILONaccent = 1960, + Greek_UPSILONdieresis = 1961, + Greek_OMEGAaccent = 1963, + Greek_accentdieresis = 1966, + Greek_horizbar = 1967, + Greek_alphaaccent = 1969, + Greek_epsilonaccent = 1970, + Greek_etaaccent = 1971, + Greek_iotaaccent = 1972, + Greek_iotadieresis = 1973, + Greek_iotaaccentdieresis = 1974, + Greek_omicronaccent = 1975, + Greek_upsilonaccent = 1976, + Greek_upsilondieresis = 1977, + Greek_upsilonaccentdieresis = 1978, + Greek_omegaaccent = 1979, + Greek_ALPHA = 1985, + Greek_BETA = 1986, + Greek_GAMMA = 1987, + Greek_DELTA = 1988, + Greek_EPSILON = 1989, + Greek_ZETA = 1990, + Greek_ETA = 1991, + Greek_THETA = 1992, + Greek_IOTA = 1993, + Greek_KAPPA = 1994, + Greek_LAMBDA = 1995, + Greek_LAMDA = 1995, + Greek_MU = 1996, + Greek_NU = 1997, + Greek_XI = 1998, + Greek_OMICRON = 1999, + Greek_PI = 2000, + Greek_RHO = 2001, + Greek_SIGMA = 2002, + Greek_TAU = 2004, + Greek_UPSILON = 2005, + Greek_PHI = 2006, + Greek_CHI = 2007, + Greek_PSI = 2008, + Greek_OMEGA = 2009, + Greek_alpha = 2017, + Greek_beta = 2018, + Greek_gamma = 2019, + Greek_delta = 2020, + Greek_epsilon = 2021, + Greek_zeta = 2022, + Greek_eta = 2023, + Greek_theta = 2024, + Greek_iota = 2025, + Greek_kappa = 2026, + Greek_lambda = 2027, + Greek_lamda = 2027, + Greek_mu = 2028, + Greek_nu = 2029, + Greek_xi = 2030, + Greek_omicron = 2031, + Greek_pi = 2032, + Greek_rho = 2033, + Greek_sigma = 2034, + Greek_finalsmallsigma = 2035, + Greek_tau = 2036, + Greek_upsilon = 2037, + Greek_phi = 2038, + Greek_chi = 2039, + Greek_psi = 2040, + Greek_omega = 2041, + leftradical = 2209, + topleftradical = 2210, + horizconnector = 2211, + topintegral = 2212, + botintegral = 2213, + vertconnector = 2214, + topleftsqbracket = 2215, + botleftsqbracket = 2216, + toprightsqbracket = 2217, + botrightsqbracket = 2218, + topleftparens = 2219, + botleftparens = 2220, + toprightparens = 2221, + botrightparens = 2222, + leftmiddlecurlybrace = 2223, + rightmiddlecurlybrace = 2224, + topleftsummation = 2225, + botleftsummation = 2226, + topvertsummationconnector = 2227, + botvertsummationconnector = 2228, + toprightsummation = 2229, + botrightsummation = 2230, + rightmiddlesummation = 2231, + lessthanequal = 2236, + notequal = 2237, + greaterthanequal = 2238, + integral = 2239, + therefore = 2240, + variation = 2241, + infinity = 2242, + nabla = 2245, + approximate = 2248, + similarequal = 2249, + ifonlyif = 2253, + implies = 2254, + identical = 2255, + radical = 2262, + includedin = 2266, + includes = 2267, + intersection = 2268, + union = 2269, + logicaland = 2270, + logicalor = 2271, + partialderivative = 2287, + function = 2294, + leftarrow = 2299, + uparrow = 2300, + rightarrow = 2301, + downarrow = 2302, + blank = 2527, + soliddiamond = 2528, + checkerboard = 2529, + ht = 2530, + ff = 2531, + cr = 2532, + lf = 2533, + nl = 2536, + vt = 2537, + lowrightcorner = 2538, + uprightcorner = 2539, + upleftcorner = 2540, + lowleftcorner = 2541, + crossinglines = 2542, + horizlinescan1 = 2543, + horizlinescan3 = 2544, + horizlinescan5 = 2545, + horizlinescan7 = 2546, + horizlinescan9 = 2547, + leftt = 2548, + rightt = 2549, + bott = 2550, + topt = 2551, + vertbar = 2552, + emspace = 2721, + enspace = 2722, + em3space = 2723, + em4space = 2724, + digitspace = 2725, + punctspace = 2726, + thinspace = 2727, + hairspace = 2728, + emdash = 2729, + endash = 2730, + signifblank = 2732, + ellipsis = 2734, + doubbaselinedot = 2735, + onethird = 2736, + twothirds = 2737, + onefifth = 2738, + twofifths = 2739, + threefifths = 2740, + fourfifths = 2741, + onesixth = 2742, + fivesixths = 2743, + careof = 2744, + figdash = 2747, + leftanglebracket = 2748, + decimalpoint = 2749, + rightanglebracket = 2750, + marker = 2751, + oneeighth = 2755, + threeeighths = 2756, + fiveeighths = 2757, + seveneighths = 2758, + trademark = 2761, + signaturemark = 2762, + trademarkincircle = 2763, + leftopentriangle = 2764, + rightopentriangle = 2765, + emopencircle = 2766, + emopenrectangle = 2767, + leftsinglequotemark = 2768, + rightsinglequotemark = 2769, + leftdoublequotemark = 2770, + rightdoublequotemark = 2771, + prescription = 2772, + minutes = 2774, + seconds = 2775, + latincross = 2777, + hexagram = 2778, + filledrectbullet = 2779, + filledlefttribullet = 2780, + filledrighttribullet = 2781, + emfilledcircle = 2782, + emfilledrect = 2783, + enopencircbullet = 2784, + enopensquarebullet = 2785, + openrectbullet = 2786, + opentribulletup = 2787, + opentribulletdown = 2788, + openstar = 2789, + enfilledcircbullet = 2790, + enfilledsqbullet = 2791, + filledtribulletup = 2792, + filledtribulletdown = 2793, + leftpointer = 2794, + rightpointer = 2795, + club = 2796, + diamond = 2797, + heart = 2798, + maltesecross = 2800, + dagger = 2801, + doubledagger = 2802, + checkmark = 2803, + ballotcross = 2804, + musicalsharp = 2805, + musicalflat = 2806, + malesymbol = 2807, + femalesymbol = 2808, + telephone = 2809, + telephonerecorder = 2810, + phonographcopyright = 2811, + caret = 2812, + singlelowquotemark = 2813, + doublelowquotemark = 2814, + cursor = 2815, + leftcaret = 2979, + rightcaret = 2982, + downcaret = 2984, + upcaret = 2985, + overbar = 3008, + downtack = 3010, + upshoe = 3011, + downstile = 3012, + underbar = 3014, + jot = 3018, + quad = 3020, + uptack = 3022, + circle = 3023, + upstile = 3027, + downshoe = 3030, + rightshoe = 3032, + leftshoe = 3034, + lefttack = 3036, + righttack = 3068, + hebrew_doublelowline = 3295, + hebrew_aleph = 3296, + hebrew_bet = 3297, + hebrew_beth = 3297, + hebrew_gimel = 3298, + hebrew_gimmel = 3298, + hebrew_dalet = 3299, + hebrew_daleth = 3299, + hebrew_he = 3300, + hebrew_waw = 3301, + hebrew_zain = 3302, + hebrew_zayin = 3302, + hebrew_chet = 3303, + hebrew_het = 3303, + hebrew_tet = 3304, + hebrew_teth = 3304, + hebrew_yod = 3305, + hebrew_finalkaph = 3306, + hebrew_kaph = 3307, + hebrew_lamed = 3308, + hebrew_finalmem = 3309, + hebrew_mem = 3310, + hebrew_finalnun = 3311, + hebrew_nun = 3312, + hebrew_samech = 3313, + hebrew_samekh = 3313, + hebrew_ayin = 3314, + hebrew_finalpe = 3315, + hebrew_pe = 3316, + hebrew_finalzade = 3317, + hebrew_finalzadi = 3317, + hebrew_zade = 3318, + hebrew_zadi = 3318, + hebrew_kuf = 3319, + hebrew_qoph = 3319, + hebrew_resh = 3320, + hebrew_shin = 3321, + hebrew_taf = 3322, + hebrew_taw = 3322, + Thai_kokai = 3489, + Thai_khokhai = 3490, + Thai_khokhuat = 3491, + Thai_khokhwai = 3492, + Thai_khokhon = 3493, + Thai_khorakhang = 3494, + Thai_ngongu = 3495, + Thai_chochan = 3496, + Thai_choching = 3497, + Thai_chochang = 3498, + Thai_soso = 3499, + Thai_chochoe = 3500, + Thai_yoying = 3501, + Thai_dochada = 3502, + Thai_topatak = 3503, + Thai_thothan = 3504, + Thai_thonangmontho = 3505, + Thai_thophuthao = 3506, + Thai_nonen = 3507, + Thai_dodek = 3508, + Thai_totao = 3509, + Thai_thothung = 3510, + Thai_thothahan = 3511, + Thai_thothong = 3512, + Thai_nonu = 3513, + Thai_bobaimai = 3514, + Thai_popla = 3515, + Thai_phophung = 3516, + Thai_fofa = 3517, + Thai_phophan = 3518, + Thai_fofan = 3519, + Thai_phosamphao = 3520, + Thai_moma = 3521, + Thai_yoyak = 3522, + Thai_rorua = 3523, + Thai_ru = 3524, + Thai_loling = 3525, + Thai_lu = 3526, + Thai_wowaen = 3527, + Thai_sosala = 3528, + Thai_sorusi = 3529, + Thai_sosua = 3530, + Thai_hohip = 3531, + Thai_lochula = 3532, + Thai_oang = 3533, + Thai_honokhuk = 3534, + Thai_paiyannoi = 3535, + Thai_saraa = 3536, + Thai_maihanakat = 3537, + Thai_saraaa = 3538, + Thai_saraam = 3539, + Thai_sarai = 3540, + Thai_saraii = 3541, + Thai_saraue = 3542, + Thai_sarauee = 3543, + Thai_sarau = 3544, + Thai_sarauu = 3545, + Thai_phinthu = 3546, + Thai_maihanakat_maitho = 3550, + Thai_baht = 3551, + Thai_sarae = 3552, + Thai_saraae = 3553, + Thai_sarao = 3554, + Thai_saraaimaimuan = 3555, + Thai_saraaimaimalai = 3556, + Thai_lakkhangyao = 3557, + Thai_maiyamok = 3558, + Thai_maitaikhu = 3559, + Thai_maiek = 3560, + Thai_maitho = 3561, + Thai_maitri = 3562, + Thai_maichattawa = 3563, + Thai_thanthakhat = 3564, + Thai_nikhahit = 3565, + Thai_leksun = 3568, + Thai_leknung = 3569, + Thai_leksong = 3570, + Thai_leksam = 3571, + Thai_leksi = 3572, + Thai_lekha = 3573, + Thai_lekhok = 3574, + Thai_lekchet = 3575, + Thai_lekpaet = 3576, + Thai_lekkao = 3577, + Hangul_Kiyeog = 3745, + Hangul_SsangKiyeog = 3746, + Hangul_KiyeogSios = 3747, + Hangul_Nieun = 3748, + Hangul_NieunJieuj = 3749, + Hangul_NieunHieuh = 3750, + Hangul_Dikeud = 3751, + Hangul_SsangDikeud = 3752, + Hangul_Rieul = 3753, + Hangul_RieulKiyeog = 3754, + Hangul_RieulMieum = 3755, + Hangul_RieulPieub = 3756, + Hangul_RieulSios = 3757, + Hangul_RieulTieut = 3758, + Hangul_RieulPhieuf = 3759, + Hangul_RieulHieuh = 3760, + Hangul_Mieum = 3761, + Hangul_Pieub = 3762, + Hangul_SsangPieub = 3763, + Hangul_PieubSios = 3764, + Hangul_Sios = 3765, + Hangul_SsangSios = 3766, + Hangul_Ieung = 3767, + Hangul_Jieuj = 3768, + Hangul_SsangJieuj = 3769, + Hangul_Cieuc = 3770, + Hangul_Khieuq = 3771, + Hangul_Tieut = 3772, + Hangul_Phieuf = 3773, + Hangul_Hieuh = 3774, + Hangul_A = 3775, + Hangul_AE = 3776, + Hangul_YA = 3777, + Hangul_YAE = 3778, + Hangul_EO = 3779, + Hangul_E = 3780, + Hangul_YEO = 3781, + Hangul_YE = 3782, + Hangul_O = 3783, + Hangul_WA = 3784, + Hangul_WAE = 3785, + Hangul_OE = 3786, + Hangul_YO = 3787, + Hangul_U = 3788, + Hangul_WEO = 3789, + Hangul_WE = 3790, + Hangul_WI = 3791, + Hangul_YU = 3792, + Hangul_EU = 3793, + Hangul_YI = 3794, + Hangul_I = 3795, + Hangul_J_Kiyeog = 3796, + Hangul_J_SsangKiyeog = 3797, + Hangul_J_KiyeogSios = 3798, + Hangul_J_Nieun = 3799, + Hangul_J_NieunJieuj = 3800, + Hangul_J_NieunHieuh = 3801, + Hangul_J_Dikeud = 3802, + Hangul_J_Rieul = 3803, + Hangul_J_RieulKiyeog = 3804, + Hangul_J_RieulMieum = 3805, + Hangul_J_RieulPieub = 3806, + Hangul_J_RieulSios = 3807, + Hangul_J_RieulTieut = 3808, + Hangul_J_RieulPhieuf = 3809, + Hangul_J_RieulHieuh = 3810, + Hangul_J_Mieum = 3811, + Hangul_J_Pieub = 3812, + Hangul_J_PieubSios = 3813, + Hangul_J_Sios = 3814, + Hangul_J_SsangSios = 3815, + Hangul_J_Ieung = 3816, + Hangul_J_Jieuj = 3817, + Hangul_J_Cieuc = 3818, + Hangul_J_Khieuq = 3819, + Hangul_J_Tieut = 3820, + Hangul_J_Phieuf = 3821, + Hangul_J_Hieuh = 3822, + Hangul_RieulYeorinHieuh = 3823, + Hangul_SunkyeongeumMieum = 3824, + Hangul_SunkyeongeumPieub = 3825, + Hangul_PanSios = 3826, + Hangul_KkogjiDalrinIeung = 3827, + Hangul_SunkyeongeumPhieuf = 3828, + Hangul_YeorinHieuh = 3829, + Hangul_AraeA = 3830, + Hangul_AraeAE = 3831, + Hangul_J_PanSios = 3832, + Hangul_J_KkogjiDalrinIeung = 3833, + Hangul_J_YeorinHieuh = 3834, + Korean_Won = 3839, + OE = 5052, + oe = 5053, + Ydiaeresis = 5054, + EcuSign = 8352, + ColonSign = 8353, + CruzeiroSign = 8354, + FFrancSign = 8355, + LiraSign = 8356, + MillSign = 8357, + NairaSign = 8358, + PesetaSign = 8359, + RupeeSign = 8360, + WonSign = 8361, + NewSheqelSign = 8362, + DongSign = 8363, + EuroSign = 8364, + Key_3270_Duplicate = 64769, + Key_3270_FieldMark = 64770, + Key_3270_Right2 = 64771, + Key_3270_Left2 = 64772, + Key_3270_BackTab = 64773, + Key_3270_EraseEOF = 64774, + Key_3270_EraseInput = 64775, + Key_3270_Reset = 64776, + Key_3270_Quit = 64777, + Key_3270_PA1 = 64778, + Key_3270_PA2 = 64779, + Key_3270_PA3 = 64780, + Key_3270_Test = 64781, + Key_3270_Attn = 64782, + Key_3270_CursorBlink = 64783, + Key_3270_AltCursor = 64784, + Key_3270_KeyClick = 64785, + Key_3270_Jump = 64786, + Key_3270_Ident = 64787, + Key_3270_Rule = 64788, + Key_3270_Copy = 64789, + Key_3270_Play = 64790, + Key_3270_Setup = 64791, + Key_3270_Record = 64792, + Key_3270_ChangeScreen = 64793, + Key_3270_DeleteWord = 64794, + Key_3270_ExSelect = 64795, + Key_3270_CursorSelect = 64796, + Key_3270_PrintScreen = 64797, + Key_3270_Enter = 64798, + ISO_Lock = 65025, + ISO_Level2_Latch = 65026, + ISO_Level3_Shift = 65027, + ISO_Level3_Latch = 65028, + ISO_Level3_Lock = 65029, + ISO_Group_Latch = 65030, + ISO_Group_Lock = 65031, + ISO_Next_Group = 65032, + ISO_Next_Group_Lock = 65033, + ISO_Prev_Group = 65034, + ISO_Prev_Group_Lock = 65035, + ISO_First_Group = 65036, + ISO_First_Group_Lock = 65037, + ISO_Last_Group = 65038, + ISO_Last_Group_Lock = 65039, + ISO_Left_Tab = 65056, + ISO_Move_Line_Up = 65057, + ISO_Move_Line_Down = 65058, + ISO_Partial_Line_Up = 65059, + ISO_Partial_Line_Down = 65060, + ISO_Partial_Space_Left = 65061, + ISO_Partial_Space_Right = 65062, + ISO_Set_Margin_Left = 65063, + ISO_Set_Margin_Right = 65064, + ISO_Release_Margin_Left = 65065, + ISO_Release_Margin_Right = 65066, + ISO_Release_Both_Margins = 65067, + ISO_Fast_Cursor_Left = 65068, + ISO_Fast_Cursor_Right = 65069, + ISO_Fast_Cursor_Up = 65070, + ISO_Fast_Cursor_Down = 65071, + ISO_Continuous_Underline = 65072, + ISO_Discontinuous_Underline = 65073, + ISO_Emphasize = 65074, + ISO_Center_Object = 65075, + ISO_Enter = 65076, + dead_grave = 65104, + dead_acute = 65105, + dead_circumflex = 65106, + dead_tilde = 65107, + dead_macron = 65108, + dead_breve = 65109, + dead_abovedot = 65110, + dead_diaeresis = 65111, + dead_abovering = 65112, + dead_doubleacute = 65113, + dead_caron = 65114, + dead_cedilla = 65115, + dead_ogonek = 65116, + dead_iota = 65117, + dead_voiced_sound = 65118, + dead_semivoiced_sound = 65119, + dead_belowdot = 65120, + AccessX_Enable = 65136, + AccessX_Feedback_Enable = 65137, + RepeatKeys_Enable = 65138, + SlowKeys_Enable = 65139, + BounceKeys_Enable = 65140, + StickyKeys_Enable = 65141, + MouseKeys_Enable = 65142, + MouseKeys_Accel_Enable = 65143, + Overlay1_Enable = 65144, + Overlay2_Enable = 65145, + AudibleBell_Enable = 65146, + First_Virtual_Screen = 65232, + Prev_Virtual_Screen = 65233, + Next_Virtual_Screen = 65234, + Last_Virtual_Screen = 65236, + Terminate_Server = 65237, + Pointer_Left = 65248, + Pointer_Right = 65249, + Pointer_Up = 65250, + Pointer_Down = 65251, + Pointer_UpLeft = 65252, + Pointer_UpRight = 65253, + Pointer_DownLeft = 65254, + Pointer_DownRight = 65255, + Pointer_Button_Dflt = 65256, + Pointer_Button1 = 65257, + Pointer_Button2 = 65258, + Pointer_Button3 = 65259, + Pointer_Button4 = 65260, + Pointer_Button5 = 65261, + Pointer_DblClick_Dflt = 65262, + Pointer_DblClick1 = 65263, + Pointer_DblClick2 = 65264, + Pointer_DblClick3 = 65265, + Pointer_DblClick4 = 65266, + Pointer_DblClick5 = 65267, + Pointer_Drag_Dflt = 65268, + Pointer_Drag1 = 65269, + Pointer_Drag2 = 65270, + Pointer_Drag3 = 65271, + Pointer_Drag4 = 65272, + Pointer_EnableKeys = 65273, + Pointer_Accelerate = 65274, + Pointer_DfltBtnNext = 65275, + Pointer_DfltBtnPrev = 65276, + Pointer_Drag5 = 65277, + BackSpace = 65288, + Tab = 65289, + Linefeed = 65290, + Clear = 65291, + Return = 65293, + Pause = 65299, + Scroll_Lock = 65300, + Sys_Req = 65301, + Escape = 65307, + Multi_key = 65312, + Kanji = 65313, + Muhenkan = 65314, + Henkan = 65315, + Henkan_Mode = 65315, + Romaji = 65316, + Hiragana = 65317, + Katakana = 65318, + Hiragana_Katakana = 65319, + Zenkaku = 65320, + Hankaku = 65321, + Zenkaku_Hankaku = 65322, + Touroku = 65323, + Massyo = 65324, + Kana_Lock = 65325, + Kana_Shift = 65326, + Eisu_Shift = 65327, + Eisu_toggle = 65328, + Hangul = 65329, + Hangul_Start = 65330, + Hangul_End = 65331, + Hangul_Hanja = 65332, + Hangul_Jamo = 65333, + Hangul_Romaja = 65334, + Codeinput = 65335, + Hangul_Codeinput = 65335, + Kanji_Bangou = 65335, + Hangul_Jeonja = 65336, + Hangul_Banja = 65337, + Hangul_PreHanja = 65338, + Hangul_PostHanja = 65339, + Hangul_SingleCandidate = 65340, + SingleCandidate = 65340, + Hangul_MultipleCandidate = 65341, + MultipleCandidate = 65341, + Zen_Koho = 65341, + Hangul_PreviousCandidate = 65342, + Mae_Koho = 65342, + PreviousCandidate = 65342, + Hangul_Special = 65343, + Home = 65360, + Left = 65361, + Up = 65362, + Right = 65363, + Down = 65364, + Page_Up = 65365, + Prior = 65365, + Next = 65366, + Page_Down = 65366, + End = 65367, + Begin = 65368, + Select = 65376, + Print = 65377, + Execute = 65378, + Insert = 65379, + Undo = 65381, + Redo = 65382, + Menu = 65383, + Find = 65384, + Cancel = 65385, + Help = 65386, + Break = 65387, + Arabic_switch = 65406, + Greek_switch = 65406, + Hangul_switch = 65406, + Hebrew_switch = 65406, + ISO_Group_Shift = 65406, + Mode_switch = 65406, + kana_switch = 65406, + script_switch = 65406, + Num_Lock = 65407, + KP_Space = 65408, + KP_Tab = 65417, + KP_Enter = 65421, + KP_F1 = 65425, + KP_F2 = 65426, + KP_F3 = 65427, + KP_F4 = 65428, + KP_Home = 65429, + KP_Left = 65430, + KP_Up = 65431, + KP_Right = 65432, + KP_Down = 65433, + KP_Page_Up = 65434, + KP_Prior = 65434, + KP_Next = 65435, + KP_Page_Down = 65435, + KP_End = 65436, + KP_Begin = 65437, + KP_Insert = 65438, + KP_Delete = 65439, + KP_Multiply = 65450, + KP_Add = 65451, + KP_Separator = 65452, + KP_Subtract = 65453, + KP_Decimal = 65454, + KP_Divide = 65455, + KP_0 = 65456, + KP_1 = 65457, + KP_2 = 65458, + KP_3 = 65459, + KP_4 = 65460, + KP_5 = 65461, + KP_6 = 65462, + KP_7 = 65463, + KP_8 = 65464, + KP_9 = 65465, + KP_Equal = 65469, + F1 = 65470, + F2 = 65471, + F3 = 65472, + F4 = 65473, + F5 = 65474, + F6 = 65475, + F7 = 65476, + F8 = 65477, + F9 = 65478, + F10 = 65479, + F11 = 65480, + L1 = 65480, + F12 = 65481, + L2 = 65481, + F13 = 65482, + L3 = 65482, + F14 = 65483, + L4 = 65483, + F15 = 65484, + L5 = 65484, + F16 = 65485, + L6 = 65485, + F17 = 65486, + L7 = 65486, + F18 = 65487, + L8 = 65487, + F19 = 65488, + L9 = 65488, + F20 = 65489, + L10 = 65489, + F21 = 65490, + R1 = 65490, + F22 = 65491, + R2 = 65491, + F23 = 65492, + R3 = 65492, + F24 = 65493, + R4 = 65493, + F25 = 65494, + R5 = 65494, + F26 = 65495, + R6 = 65495, + F27 = 65496, + R7 = 65496, + F28 = 65497, + R8 = 65497, + F29 = 65498, + R9 = 65498, + F30 = 65499, + R10 = 65499, + F31 = 65500, + R11 = 65500, + F32 = 65501, + R12 = 65501, + F33 = 65502, + R13 = 65502, + F34 = 65503, + R14 = 65503, + F35 = 65504, + R15 = 65504, + Shift_L = 65505, + Shift_R = 65506, + Control_L = 65507, + Control_R = 65508, + Caps_Lock = 65509, + Shift_Lock = 65510, + Meta_L = 65511, + Meta_R = 65512, + Alt_L = 65513, + Alt_R = 65514, + Super_L = 65515, + Super_R = 65516, + Hyper_L = 65517, + Hyper_R = 65518, + Delete = 65535, + VoidSymbol = 16777215, + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs b/src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs new file mode 100644 index 0000000000..11209825dc --- /dev/null +++ b/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().ToConstant(Instance) + .Bind().ToSingleton() + .Bind().ToConstant(new CursorFactory()) + .Bind().ToConstant(Keyboard) + .Bind().ToConstant(Mouse) + .Bind().ToConstant(Instance) + .Bind().ToConstant(Instance) + .Bind().ToSingleton() + .Bind().ToConstant(new DefaultRenderLoop(60)) + .Bind().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(this AppBuilderBase builder, ICustomGtk3NativeLibraryResolver resolver = null) + where T : AppBuilderBase, new() + { + Resolver.Custom = resolver; + return builder.UseWindowingSubsystem(Gtk3Platform.Initialize, "GTK3"); + } + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs b/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs new file mode 100644 index 0000000000..d1964bf05d --- /dev/null +++ b/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; + } +} + + + diff --git a/src/Gtk/Avalonia.Gtk3/Interop/CairoSurface.cs b/src/Gtk/Avalonia.Gtk3/Interop/CairoSurface.cs new file mode 100644 index 0000000000..7838be9305 --- /dev/null +++ b/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; + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/DynLoader.cs b/src/Gtk/Avalonia.Gtk3/Interop/DynLoader.cs new file mode 100644 index 0000000000..afe526e2c3 --- /dev/null +++ b/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 DlOpen; + private static Func DlSym; + private static Func 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; + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/GException.cs b/src/Gtk/Avalonia.Gtk3/Interop/GException.cs new file mode 100644 index 0000000000..ab08df4ec3 --- /dev/null +++ b/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)) + { + + } + + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/GObject.cs b/src/Gtk/Avalonia.Gtk3/Interop/GObject.cs new file mode 100644 index 0000000000..9ead1d2cb3 --- /dev/null +++ b/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 + { + + } +} + diff --git a/src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs b/src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs new file mode 100644 index 0000000000..9971d8881d --- /dev/null +++ b/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) 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 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; + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/ICustomGtk3NativeLibraryResolver.cs b/src/Gtk/Avalonia.Gtk3/Interop/ICustomGtk3NativeLibraryResolver.cs new file mode 100644 index 0000000000..2f88b09896 --- /dev/null +++ b/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); + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs new file mode 100644 index 0000000000..cffdebeeab --- /dev/null +++ b/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 + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/NativeException.cs b/src/Gtk/Avalonia.Gtk3/Interop/NativeException.cs new file mode 100644 index 0000000000..43659f8f83 --- /dev/null +++ b/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) + { + } + + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Pixbuf.cs b/src/Gtk/Avalonia.Gtk3/Interop/Pixbuf.cs new file mode 100644 index 0000000000..1a0a772522 --- /dev/null +++ b/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); + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs b/src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs new file mode 100644 index 0000000000..c6b6326f80 --- /dev/null +++ b/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 Platform = + new Lazy( + () => AvaloniaLocator.Current.GetService().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(); + + 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().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().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"); + + } + + + } +} + diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Signal.cs b/src/Gtk/Avalonia.Gtk3/Interop/Signal.cs new file mode 100644 index 0000000000..5f173000a2 --- /dev/null +++ b/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(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); + } + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Utf8Buffer.cs b/src/Gtk/Avalonia.Gtk3/Interop/Utf8Buffer.cs new file mode 100644 index 0000000000..f108c291b8 --- /dev/null +++ b/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); + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/PlatformIconLoader.cs b/src/Gtk/Avalonia.Gtk3/PlatformIconLoader.cs new file mode 100644 index 0000000000..b4e293cdff --- /dev/null +++ b/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()); + } + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/PopupImpl.cs b/src/Gtk/Avalonia.Gtk3/PopupImpl.cs new file mode 100644 index 0000000000..5d23148b76 --- /dev/null +++ b/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()) + { + } + } +} diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs b/src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs similarity index 79% rename from src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs rename to src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs index 68efca2668..72e6388531 100644 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs +++ b/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: // diff --git a/src/Gtk/Avalonia.Gtk3/README.md b/src/Gtk/Avalonia.Gtk3/README.md new file mode 100644 index 0000000000..ea853bde75 --- /dev/null +++ b/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. \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs b/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs new file mode 100644 index 0000000000..04c224ff5b --- /dev/null +++ b/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 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(); + List disposables = null; + Action dispose = () => + { + foreach (var d in disposables) + d.Dispose(); + disposables.Clear(); + }; + disposables = new List + { + Signal.Connect(dlg, "close", delegate + { + tcs.TrySetResult(null); + dispose(); + return false; + }), + Signal.Connect(dlg, "response", (_, resp, __)=> + { + string[] result = null; + if (resp == GtkResponseType.Accept) + { + var rlst = new List(); + 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 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 ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) + { + var res = await ShowDialog(dialog.Title, ((TopLevelImpl) parent)?.GtkWidget, + GtkFileChooserAction.SelectFolder, false, dialog.InitialDirectory); + return res?.FirstOrDefault(); + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs b/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs new file mode 100644 index 0000000000..aadbe16d1d --- /dev/null +++ b/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 Disposables = new List(); + 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(_imContext, "commit", OnCommit)); + Connect("draw", OnDraw); + Connect("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("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(GtkWidget, name, handler)); + void Connect(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 Input { get; set; } + public Action Paint { get; set; } + public Action Resized { get; set; } + public Action ScalingChanged { get; set; } //TODO + public Action 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 Surfaces => new object[] {Handle, _framebuffer}; + } +} diff --git a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs new file mode 100644 index 0000000000..d1a689b75f --- /dev/null +++ b/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? + } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/project.json b/src/Gtk/Avalonia.Gtk3/project.json new file mode 100644 index 0000000000..7af946da1a --- /dev/null +++ b/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": {} + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 00edd205f3..4ed20629cf 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -322,9 +322,8 @@ - - ..\..\..\packages\Sprache.2.0.0.51\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid+Xamarin.iOS10+MonoTouch\Sprache.dll - True + + ..\..\..\packages\Sprache.2.1.0\lib\netstandard1.0\Sprache.dll ..\..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll diff --git a/src/Markup/Avalonia.Markup.Xaml/packages.config b/src/Markup/Avalonia.Markup.Xaml/packages.config index 762fe58c1f..7a9353bb05 100644 --- a/src/Markup/Avalonia.Markup.Xaml/packages.config +++ b/src/Markup/Avalonia.Markup.Xaml/packages.config @@ -1,9 +1,13 @@  - + + + + + \ No newline at end of file diff --git a/src/Shared/PlatformSupport/AssetLoader.cs b/src/Shared/PlatformSupport/AssetLoader.cs index 4edb2fdd3c..8da663f554 100644 --- a/src/Shared/PlatformSupport/AssetLoader.cs +++ b/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().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 } diff --git a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs b/src/Shared/PlatformSupport/StandardRuntimePlatform.cs index 5c02be7d5b..e2aafd562b 100644 --- a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs +++ b/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); } diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/App.cs b/src/Skia/Avalonia.Skia.Android.TestApp/App.cs deleted file mode 100644 index ca4d36b820..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/App.cs +++ /dev/null @@ -1,7 +0,0 @@ - -namespace Avalonia.Skia.Android.TestApp -{ - public class App : Application - { - } -} diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj b/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj deleted file mode 100644 index 041c8d9ecb..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Properties - Avalonia.Skia.Android.TestApp - Avalonia.Skia.Android.TestApp - 512 - true - Resources\Resource.Designer.cs - Off - False - v4.4 - Properties\AndroidManifest.xml - - - True - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - True - None - False - False - False - armeabi;armeabi-v7a;x86 - Xamarin - False - True - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - False - Full - True - False - False - Xamarin - False - False - False - False - False - armeabi;armeabi-v7a;x86 - - - - - - - - - - - - - - - - - - - - - - - - {7b92af71-6287-4693-9dcb-bd5b6e927e23} - Avalonia.Android - - - {d211e587-d8bc-45b9-95a4-f297c8fa5200} - Avalonia.Animation - - - {b09b78d8-9b26-48b0-9149-d64a2f120f3f} - Avalonia.Base - - - {d2221c82-4a25-4583-9b43-d791e3f6820c} - Avalonia.Controls - - - {4a1abb09-9047-4bd5-a4ad-a055e52c5ee0} - Avalonia.DotNetFrameworkRuntime - - - {62024b2d-53eb-4638-b26b-85eeaa54866e} - Avalonia.Input - - - {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} - Avalonia.Interactivity - - - {42472427-4774-4c81-8aff-9f27b8e31721} - Avalonia.Layout - - - {eb582467-6abb-43a1-b052-e981ba910e3a} - Avalonia.Visuals - - - {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} - Avalonia.Styling - - - {bd43f7c0-396b-4aa1-bad9-dfde54d51298} - Avalonia.Skia.Android - - - - - - - - - \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.v2.ncrunchproject b/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.v2.ncrunchproject deleted file mode 100644 index e1b4d7cf28..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.v2.ncrunchproject +++ /dev/null @@ -1,26 +0,0 @@ - - true - 1000 - false - false - false - true - false - false - true - false - false - false - true - false - true - true - true - 60000 - - - - AutoDetect - STA - x86 - \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs b/src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs deleted file mode 100644 index 9ac833a559..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Android.App; -using Android.OS; -using Android.Views; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Media; - -namespace Avalonia.Skia.Android.TestApp -{ - [Activity(Label = "Avalonia.Skia.Android.TestApp", MainLauncher = true, Icon = "@drawable/icon")] - public class MainActivity : Activity - { - - protected override void OnCreate(Bundle bundle) - { - base.OnCreate(bundle); - - App app; - if (Avalonia.Application.Current != null) - app = (App)Avalonia.Application.Current; - else - { - app = new App(); - AppBuilder.Configure(app) - .UseAndroid() - .UseSkia() - .SetupWithoutStarting(); - } - - SetContentView(new MainView(this)); - } - - class MainView : SkiaRenderView - { - float _radians = 0; - public MainView(Activity context) : base(context) - { - } - - protected override void OnRender(DrawingContext ctx) - { - ctx.FillRectangle(Brushes.Green, new Rect(0, 0, Width, Height)); - - var rc = new Rect(0, 0, Width/3, Height/3); - using (ctx.PushPostTransform( - Avalonia.Matrix.CreateTranslation(-Width/6, -Width/6)* - Avalonia.Matrix.CreateRotation(_radians)* - Avalonia.Matrix.CreateTranslation(Width/2, Height/2))) - { - ctx.FillRectangle(new LinearGradientBrush() - { - GradientStops = - { - new GradientStop() {Color = Colors.Blue}, - new GradientStop(Colors.Red, 1) - } - }, rc, 5); - } - - - } - - public override bool OnTouchEvent(MotionEvent e) - { - if (e.Action == MotionEventActions.Down) - return true; - if (e.Action == MotionEventActions.Move) - { - _radians = (e.RawY + e.RawY)/100; - Invalidate(); - return true; - } - return base.OnTouchEvent(e); - } - } - } -} - diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AndroidManifest.xml b/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AndroidManifest.xml deleted file mode 100644 index 5af8811830..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs b/src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs deleted file mode 100644 index 7d9036603f..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs +++ /dev/null @@ -1,114 +0,0 @@ -#pragma warning disable 1591 -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -[assembly: global::Android.Runtime.ResourceDesignerAttribute("Avalonia.Skia.Android.TestApp.Resource", IsApplication=true)] - -namespace Avalonia.Skia.Android.TestApp -{ - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] - public partial class Resource - { - - static Resource() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - public static void UpdateIdValues() - { - global::Avalonia.Android.Resource.String.ApplicationName = global::Avalonia.Skia.Android.TestApp.Resource.String.ApplicationName; - global::Avalonia.Android.Resource.String.Hello = global::Avalonia.Skia.Android.TestApp.Resource.String.Hello; - } - - public partial class Attribute - { - - static Attribute() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Attribute() - { - } - } - - public partial class Drawable - { - - // aapt resource value: 0x7f020000 - public const int Icon = 2130837504; - - static Drawable() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Drawable() - { - } - } - - public partial class Id - { - - // aapt resource value: 0x7f050000 - public const int MyButton = 2131034112; - - static Id() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Id() - { - } - } - - public partial class Layout - { - - // aapt resource value: 0x7f030000 - public const int Main = 2130903040; - - static Layout() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Layout() - { - } - } - - public partial class String - { - - // aapt resource value: 0x7f040001 - public const int ApplicationName = 2130968577; - - // aapt resource value: 0x7f040000 - public const int Hello = 2130968576; - - static String() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private String() - { - } - } - } -} -#pragma warning restore 1591 diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/drawable/Icon.png b/src/Skia/Avalonia.Skia.Android.TestApp/Resources/drawable/Icon.png deleted file mode 100644 index 8074c4c571..0000000000 Binary files a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/drawable/Icon.png and /dev/null differ diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/layout/Main.axml b/src/Skia/Avalonia.Skia.Android.TestApp/Resources/layout/Main.axml deleted file mode 100644 index 98be1643ef..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/layout/Main.axml +++ /dev/null @@ -1,13 +0,0 @@ - - -