Browse Source

Merge branch 'master' into issues/xamlilpathgeneration

pull/3151/head
danwalmsley 7 years ago
committed by GitHub
parent
commit
301a21933c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .ncrunch/BindingDemo.v3.ncrunchproject
  2. 5
      .ncrunch/RenderDemo.v3.ncrunchproject
  3. 5
      .ncrunch/VirtualizationDemo.v3.ncrunchproject
  4. 33
      Avalonia.sln
  5. 148
      CODE_OF_CONDUCT.md
  6. 69
      CONTRIBUTING.md
  7. 79
      Documentation/build.md
  8. 273
      NOTICE.md
  9. 16
      azure-pipelines.yml
  10. 1
      build/CoreLibraries.props
  11. 2
      build/Rx.props
  12. 2
      build/SharedVersion.props
  13. 4
      build/SkiaSharp.props
  14. 3
      global.json
  15. 5
      licence.md
  16. 3
      native/Avalonia.Native/inc/avalonia-native-guids.h
  17. 85
      native/Avalonia.Native/inc/avalonia-native.h
  18. 3
      native/Avalonia.Native/inc/com.h
  19. 13
      native/Avalonia.Native/inc/comimpl.h
  20. 3
      native/Avalonia.Native/inc/key.h
  21. 12
      native/Avalonia.Native/inc/rendertarget.h
  22. 20
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  23. 6
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
  24. 3
      native/Avalonia.Native/src/OSX/KeyTransform.h
  25. 3
      native/Avalonia.Native/src/OSX/KeyTransform.mm
  26. 3
      native/Avalonia.Native/src/OSX/Screens.mm
  27. 6
      native/Avalonia.Native/src/OSX/SystemDialogs.mm
  28. 7
      native/Avalonia.Native/src/OSX/app.mm
  29. 166
      native/Avalonia.Native/src/OSX/cgl.mm
  30. 3
      native/Avalonia.Native/src/OSX/clipboard.mm
  31. 20
      native/Avalonia.Native/src/OSX/common.h
  32. 3
      native/Avalonia.Native/src/OSX/cursor.h
  33. 3
      native/Avalonia.Native/src/OSX/cursor.mm
  34. 253
      native/Avalonia.Native/src/OSX/gl.mm
  35. 40
      native/Avalonia.Native/src/OSX/main.mm
  36. 36
      native/Avalonia.Native/src/OSX/menu.h
  37. 286
      native/Avalonia.Native/src/OSX/menu.mm
  38. 14
      native/Avalonia.Native/src/OSX/platformthreading.mm
  39. 284
      native/Avalonia.Native/src/OSX/rendertarget.mm
  40. 11
      native/Avalonia.Native/src/OSX/window.h
  41. 576
      native/Avalonia.Native/src/OSX/window.mm
  42. 165
      nukebuild/Build.cs
  43. 21
      nukebuild/BuildParameters.cs
  44. 8
      nukebuild/Shims.cs
  45. 8
      nukebuild/_build.csproj
  46. 52
      readme.md
  47. 3
      samples/BindingDemo/BindingDemo.csproj
  48. 5
      samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs
  49. 5
      samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
  50. 5
      samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs
  51. 2
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  52. 1
      samples/ControlCatalog/ControlCatalog.csproj
  53. 18
      samples/ControlCatalog/MainView.xaml
  54. 15
      samples/ControlCatalog/MainView.xaml.cs
  55. 26
      samples/ControlCatalog/MainWindow.xaml
  56. 15
      samples/ControlCatalog/MainWindow.xaml.cs
  57. 1
      samples/ControlCatalog/Pages/DialogsPage.xaml
  58. 43
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  59. 100
      samples/ControlCatalog/Pages/ImagePage.xaml
  60. 68
      samples/ControlCatalog/Pages/ImagePage.xaml.cs
  61. 4
      samples/ControlCatalog/Pages/MenuPage.xaml
  62. 8
      samples/ControlCatalog/Pages/ProgressBarPage.xaml
  63. 134
      samples/ControlCatalog/Pages/TextBlockPage.xaml
  64. 18
      samples/ControlCatalog/Pages/TextBlockPage.xaml.cs
  65. 15
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  66. 2
      samples/PlatformSanityChecks/PlatformSanityChecks.csproj
  67. 2
      samples/Previewer/Previewer.csproj
  68. 2
      samples/RemoteDemo/RemoteDemo.csproj
  69. 3
      samples/RenderDemo/App.xaml.cs
  70. 3
      samples/RenderDemo/MainWindow.xaml.cs
  71. 2
      samples/RenderDemo/Pages/RenderTargetBitmapPage.cs
  72. 3
      samples/RenderDemo/RenderDemo.csproj
  73. 3
      samples/VirtualizationDemo/App.xaml.cs
  74. 3
      samples/VirtualizationDemo/MainWindow.xaml.cs
  75. 5
      samples/VirtualizationDemo/Program.cs
  76. 5
      samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
  77. 5
      samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
  78. 3
      samples/VirtualizationDemo/VirtualizationDemo.csproj
  79. 5
      samples/interop/Direct3DInteropSample/MainWindow.cs
  80. 8
      scripts/ReplaceNugetCache.sh
  81. 64
      scripts/avalonia-rename.ps1
  82. 29
      src/Avalonia.Animation/Animatable.cs
  83. 7
      src/Avalonia.Animation/Animation.cs
  84. 9
      src/Avalonia.Animation/AnimatorKeyFrame.cs
  85. 8
      src/Avalonia.Animation/Animators/Animator`1.cs
  86. 5
      src/Avalonia.Animation/Animators/BoolAnimator.cs
  87. 5
      src/Avalonia.Animation/Animators/ByteAnimator.cs
  88. 5
      src/Avalonia.Animation/Animators/DecimalAnimator.cs
  89. 5
      src/Avalonia.Animation/Animators/DoubleAnimator.cs
  90. 5
      src/Avalonia.Animation/Animators/FloatAnimator.cs
  91. 5
      src/Avalonia.Animation/Animators/Int16Animator.cs
  92. 5
      src/Avalonia.Animation/Animators/Int32Animator.cs
  93. 5
      src/Avalonia.Animation/Animators/Int64Animator.cs
  94. 5
      src/Avalonia.Animation/Animators/UInt16Animator.cs
  95. 5
      src/Avalonia.Animation/Animators/UInt32Animator.cs
  96. 5
      src/Avalonia.Animation/Animators/UInt64Animator.cs
  97. 3
      src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
  98. 3
      src/Avalonia.Animation/Easing/BackEaseIn.cs
  99. 3
      src/Avalonia.Animation/Easing/BackEaseInOut.cs
  100. 3
      src/Avalonia.Animation/Easing/BackEaseOut.cs

5
.ncrunch/BindingDemo.v3.ncrunchproject

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

5
.ncrunch/RenderDemo.v3.ncrunchproject

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

5
.ncrunch/VirtualizationDemo.v3.ncrunchproject

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

33
Avalonia.sln

@ -204,14 +204,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Dialogs", "src\Ava
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.FreeDesktop", "src\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj", "{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.FreeDesktop", "src\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj", "{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.DataGrid.UnitTests", "tests\Avalonia.Controls.DataGrid.UnitTests\Avalonia.Controls.DataGrid.UnitTests.csproj", "{351337F5-D66F-461B-A957-4EF60BDB4BA6}"
EndProject
Global Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*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\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4 src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*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\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 5
tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{dabfd304-d6a4-4752-8123-c2ccf7ac7831}*SharedItemsImports = 4 src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13 src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
EndGlobalSection EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -1895,6 +1897,30 @@ Global
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhone.Build.0 = Release|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhone.Build.0 = Release|Any CPU
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|iPhone.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|iPhone.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|Any CPU.Build.0 = Release|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhone.ActiveCfg = Release|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhone.Build.0 = Release|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -1951,6 +1977,7 @@ Global
{41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} {41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

148
CODE_OF_CONDUCT.md

@ -1,76 +1,130 @@
# Contributor Covenant Code of Conduct # Contributor Covenant Code of Conduct
## Our Pledge ## Our Pledge
In the interest of fostering an open and welcoming environment, we as We as members, contributors, and leaders pledge to make participation in our
contributors and maintainers pledge to making participation in our project and community a harassment-free experience for everyone, regardless of age, body
our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender
size, disability, ethnicity, sex characteristics, gender identity and expression, identity and expression, level of experience, education, socio-economic status,
level of experience, education, socio-economic status, nationality, personal nationality, personal appearance, race, religion, or sexual identity
appearance, race, religion, or sexual identity and orientation. and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards ## Our Standards
Examples of behavior that contributes to creating a positive environment Examples of behavior that contributes to a positive environment for our
include: community include:
* Using welcoming and inclusive language * Demonstrating empathy and kindness toward other people
* Being respectful of differing viewpoints and experiences * Being respectful of differing opinions, viewpoints, and experiences
* Gracefully accepting constructive criticism * Giving and gracefully accepting constructive feedback
* Focusing on what is best for the community * Accepting responsibility and apologizing to those affected by our mistakes,
* Showing empathy towards other community members and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior by participants include: Examples of unacceptable behavior include:
* The use of sexualized language or imagery and unwelcome sexual attention or * The use of sexualized language or imagery, and sexual attention or
advances advances of any kind
* Trolling, insulting/derogatory comments, and personal or political attacks * Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment * Public or private harassment
* Publishing others' private information, such as a physical or electronic * Publishing others' private information, such as a physical or email
address, without explicit permission address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a * Other conduct which could reasonably be considered inappropriate in a
professional setting professional setting
## Our Responsibilities ## Enforcement Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable Community leaders are responsible for clarifying and enforcing our standards of
behavior and are expected to take appropriate and fair corrective action in acceptable behavior and will take appropriate and fair corrective action in
response to any instances of unacceptable behavior. response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Project maintainers have the right and responsibility to remove, edit, or Community leaders have the right and responsibility to remove, edit, or reject
reject comments, commits, code, wiki edits, issues, and other contributions comments, commits, code, wiki edits, issues, and other contributions that are
that are not aligned to this Code of Conduct, or to ban temporarily or not aligned to this Code of Conduct, and will communicate reasons for moderation
permanently any contributor for other behaviors that they deem inappropriate, decisions when appropriate.
threatening, offensive, or harmful.
## Scope ## Scope
This Code of Conduct applies both within project spaces and in public spaces This Code of Conduct applies within all community spaces, and also applies when
when an individual is representing the project or its community. Examples of an individual is officially representing the community in public spaces.
representing a project or community include using an official project e-mail Examples of representing our community include using an official e-mail address,
address, posting via an official social media account, or acting as an appointed posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be representative at an online or offline event.
further defined and clarified by project maintainers.
## Enforcement ## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at steven@avaloniaui.net. All reported to the community leaders responsible for enforcement at
complaints will be reviewed and investigated and will result in a response that steven@avaloniaui.net.
is deemed necessary and appropriate to the circumstances. The project team is All complaints will be reviewed and investigated promptly and fairly.
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately. All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
Project maintainers who do not follow or enforce the Code of Conduct in good **Community Impact**: A violation through a single incident or series
faith may face temporary or permanent repercussions as determined by other of actions.
members of the project's leadership.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution ## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, This Code of Conduct is adapted from the [Contributor Covenant][homepage],
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org [homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

69
CONTRIBUTING.md

@ -0,0 +1,69 @@
# Contributing to Avalonia
## Before You Start
Drop into our [gitter chat room](https://gitter.im/AvaloniaUI/Avalonia) and let us know what you're thinking of doing. We might be able to give you guidance or let you know if someone else is already working on the feature.
## Style
The codebase uses [.net core](https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md) coding style.
Try to keep lines of code around 100 characters in length or less, though this is not a hard limit.
If you're a few characters over then don't worry too much.
**DO NOT USE #REGIONS** full stop.
## Pull requests
A single pull request should be submitted for each change. If you're making more than one change,
please submit separate pull requests for each change for easy review. Rebase your changes to make
sense, so a history that looks like:
* Add class A
* Feature A didn't set Foo when Bar was set
* Fix spacing
* Add class B
* Sort using statements
Should be rebased to read:
* Add class A
* Add class B
Again, this makes review much easier.
Please try not to submit pull requests that don't add new features (e.g. moving stuff around)
unless you see something that is obviously wrong or that could be written in a more terse or
idiomatic style. It takes time to review each pull request - time that I'd prefer to spend writing
new features!
Prefer terseness to verbosity but don't try to be too clever.
## Tests
There are two types of tests currently in the codebase; unit tests and render tests.
Unit tests should be contained in a class name that mirrors the class being tested with the suffix
-Tests, e.g.
Avalonia.Controls.UnitTests.Presenters.TextPresenterTests
Where Avalonia.Controls.UnitTests is the name of the project.
Unit test methods should be named in a sentence style, separated by underscores, that describes in
English what the test is testing, e.g.
```csharp
void Calling_Foo_Should_Increment_Bar()
```
Render tests should describe what the produced image is:
```csharp
void Rectangle_2px_Stroke_Filled()
```
## Code of Conduct
This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
For more information see the [Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct)

79
Documentation/build.md

@ -0,0 +1,79 @@
# Windows
Avalonia requires at least Visual Studio 2019 and .NET Core SDK 3.1 to build on Windows.
### Clone the Avalonia repository
```
git clone https://github.com/AvaloniaUI/Avalonia.git
git submodule update --init
```
### Open in Visual Studio
Open the `Avalonia.sln` solution in Visual Studio 2019 or newer. The free Visual Studio Community
edition works fine. Run the `Samples\ControlCatalog.Desktop` project to see the sample application.
# Linux/macOS
It's *not* possible to build the *whole* project on Linux/macOS. You can only build the subset targeting .NET Standard and .NET Core (which is, however, sufficient to get UI working on Linux/macOS). If you want to something that involves changing platform-specific APIs you'll need a Windows machine.
MonoDevelop, Xamarin Studio and Visual Studio for Mac aren't capable of properly opening our solution. You can use Rider (at least 2017.2 EAP) or VSCode instead. They will fail to load most of platform specific projects, but you don't need them to run on .NET Core.
### Install the latest version of .NET Core
Go to https://www.microsoft.com/net/core and follow instructions for your OS. You need SDK (not just "runtime") package.
### Additional requirements for macOS
The build process needs [Xcode](https://developer.apple.com/xcode/) to build the native library. Following the install instructions at the [Xcode](https://developer.apple.com/xcode/) website to properly install.
Linux operating systems ship with their own respective package managers however we will use [Homebrew](https://brew.sh/) to manage packages on macOS. To install follow the instructions [here](https://docs.brew.sh/Installation).
### Install CastXML
Avalonia requires [CastXML](https://github.com/CastXML/CastXML) for XML processing during the build process. The easiest way to install this is via the operating system's package managers, such as below.
On macOS:
```
brew install castxml
```
On Debian based Linux (Debian, Ubuntu, Mint, etc):
```
sudo apt install castxml
```
On Red Hat based Linux (Fedora, CentOS, RHEL, etc) using `yum` (`dnf` takes same arguments though):
```
sudo yum install castxml
```
### Clone the Avalonia repository
```
git clone https://github.com/AvaloniaUI/Avalonia.git
cd Avalonia
git submodule update --init --recursive
```
### Build native libraries (macOS only)
On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). The steps to get this working correctly are:
- Navigate to the Avalonia/native/Avalonia.Native/src/OSX folder and open the `Avalonia.Native.OSX.xcodeproj` project
- Build the library via the Product->Build menu. This will generate binaries in your local path under ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-*guid* where "guid" is uniquely generated every time you build.
- Manually install the native library by copying it from the build artifacts folder into the shared dynamic library path:
```
cd ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-[guid]/Build/Products/Debug
cp libAvalonia.Native.OSX.dylib /usr/local/lib/libAvaloniaNative.dylib
```
### Build and Run Avalonia
```
cd samples/ControlCatalog.NetCore
dotnet restore
dotnet run
```

273
NOTICE.md

@ -0,0 +1,273 @@
# WPF
https://github.com/dotnet/wpf
The MIT License (MIT)
Copyright (c) .NET Foundation and Contributors
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# SharpDX
https://github.com/sharpdx/SharpDX
Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# Silverlight Toolkit
https://github.com/microsoftarchive/SilverlightToolkit
Microsoft Public License (MS-PL)
This license governs use of the accompanying software. If you use the software, you
accept this license. If you do not accept the license, do not use the software.
1. Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
same meaning here as under U.S. copyright law.
A "contribution" is the original software, or any additions or changes to the software.
A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
2. Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
3. Conditions and Limitations
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
# wayland-protocols
https://github.com/wayland-project/wayland-protocols
Copyright © 2008-2013 Kristian Høgsberg
Copyright © 2010-2013 Intel Corporation
Copyright © 2013 Rafael Antognolli
Copyright © 2013 Jasper St. Pierre
Copyright © 2014 Jonas Ådahl
Copyright © 2014 Jason Ekstrand
Copyright © 2014-2015 Collabora, Ltd.
Copyright © 2015 Red Hat Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
# Metsys.Bson
Copyright (c) 2010, Karl Seguin - http://www.openmymind.net/
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# RichTextKit
https://github.com/toptensoftware/RichTextKit
Copyright © 2019 Topten Software. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this product except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
# Mono
https://github.com/mono/mono
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Collections.Pooled
https://github.com/jtmueller/Collections.Pooled
The MIT License (MIT)
Copyright (c) Joel Mueller
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# EllipticalArc.java
http://www.spaceroots.org/documents/ellipse/EllipticalArc.java
http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
Copyright (c) 2003-2004, Luc Maisonobe
All rights reserved.
Redistribution and use in source and binary forms, with
or without modification, are permitted provided that
the following conditions are met:
Redistributions of source code must retain the
above copyright notice, this list of conditions and
the following disclaimer.
Redistributions in binary form must reproduce the
above copyright notice, this list of conditions and
the following disclaimer in the documentation
and/or other materials provided with the
distribution.
Neither the names of spaceroots.org, spaceroots.com
nor the names of their contributors may be used to
endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
# WinUI
https://github.com/microsoft/microsoft-ui-xaml
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

16
azure-pipelines.yml

@ -14,7 +14,7 @@ jobs:
displayName: 'Install Nuke' displayName: 'Install Nuke'
inputs: inputs:
script: | script: |
dotnet tool install --global Nuke.GlobalTool --version 0.12.3 dotnet tool install --global Nuke.GlobalTool --version 0.24.0
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Run Nuke' displayName: 'Run Nuke'
inputs: inputs:
@ -35,16 +35,16 @@ jobs:
vmImage: 'macOS-10.14' vmImage: 'macOS-10.14'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.0.x' displayName: 'Use .NET Core SDK 3.1.101'
inputs: inputs:
packageType: sdk packageType: sdk
version: 3.0.x version: 3.1.101
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core Runtime 2.1.x' displayName: 'Use .NET Core Runtime 3.1.1'
inputs: inputs:
packageType: runtime packageType: runtime
version: 2.1.x version: 3.1.1
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Mono 5.18' displayName: 'Install Mono 5.18'
@ -68,13 +68,13 @@ jobs:
inputs: inputs:
script: | script: |
brew update brew update
brew install castxml brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8a004a91a7fcd3f6620d5b01b6541ff0a640ffba/Formula/castxml.rb
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Nuke' displayName: 'Install Nuke'
inputs: inputs:
script: | script: |
dotnet tool install --global Nuke.GlobalTool --version 0.12.3 dotnet tool install --global Nuke.GlobalTool --version 0.24.0
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Run Nuke' displayName: 'Run Nuke'
@ -116,7 +116,7 @@ jobs:
displayName: 'Install Nuke' displayName: 'Install Nuke'
inputs: inputs:
script: | script: |
dotnet tool install --global Nuke.GlobalTool --version 0.12.3 dotnet tool install --global Nuke.GlobalTool --version 0.24.0
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Run Nuke' displayName: 'Run Nuke'

1
build/CoreLibraries.props

@ -4,7 +4,6 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Animation/Avalonia.Animation.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Animation/Avalonia.Animation.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Controls/Avalonia.Controls.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Controls/Avalonia.Controls.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Input/Avalonia.Input.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Input/Avalonia.Input.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Interactivity/Avalonia.Interactivity.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Interactivity/Avalonia.Interactivity.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Layout/Avalonia.Layout.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Layout/Avalonia.Layout.csproj" />

2
build/Rx.props

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

2
build/SharedVersion.props

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Product>Avalonia</Product> <Product>Avalonia</Product>
<Version>0.9.999</Version> <Version>0.9.999</Version>
<Copyright>Copyright 2019 &#169; The AvaloniaUI Project</Copyright> <Copyright>Copyright 2020 &#169; The AvaloniaUI Project</Copyright>
<PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl> <PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl> <RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>

4
build/SkiaSharp.props

@ -1,6 +1,6 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<PackageReference Include="SkiaSharp" Version="1.68.1" /> <PackageReference Include="SkiaSharp" Version="1.68.2" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="1.68.1" /> <PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="1.68.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

3
global.json

@ -1,4 +1,7 @@
{ {
"sdk": {
"version": "3.1.101"
},
"msbuild-sdks": { "msbuild-sdks": {
"Microsoft.Build.Traversal": "1.0.43", "Microsoft.Build.Traversal": "1.0.43",
"MSBuild.Sdk.Extras": "2.0.46", "MSBuild.Sdk.Extras": "2.0.46",

5
licence.md

@ -1,6 +1,7 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2014 Steven Kirk Copyright (c) .NET Foundation and Contributors
All Rights Reserved
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -18,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

3
native/Avalonia.Native/inc/avalonia-native-guids.h

@ -1,5 +1,2 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#define COM_GUIDS_MATERIALIZE #define COM_GUIDS_MATERIALIZE
#include "avalonia-native.h" #include "avalonia-native.h"

85
native/Avalonia.Native/inc/avalonia-native.h

@ -1,8 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#include "com.h" #include "com.h"
#include "key.h" #include "key.h"
#include "stddef.h"
#define AVNCOM(name, id) COMINTERFACE(name, 2e2cda0a, 9ae5, 4f1b, 8e, 20, 08, 1a, 04, 27, 9f, id) #define AVNCOM(name, id) COMINTERFACE(name, 2e2cda0a, 9ae5, 4f1b, 8e, 20, 08, 1a, 04, 27, 9f, id)
@ -22,8 +20,15 @@ struct IAvnGlContext;
struct IAvnGlDisplay; struct IAvnGlDisplay;
struct IAvnGlSurfaceRenderTarget; struct IAvnGlSurfaceRenderTarget;
struct IAvnGlSurfaceRenderingSession; struct IAvnGlSurfaceRenderingSession;
struct IAvnAppMenu; struct IAvnMenu;
struct IAvnAppMenuItem; struct IAvnMenuItem;
struct IAvnMenuEvents;
enum SystemDecorations {
SystemDecorationsNone = 0,
SystemDecorationsBorderOnly = 1,
SystemDecorationsFull = 2,
};
struct AvnSize struct AvnSize
{ {
@ -172,24 +177,30 @@ enum AvnWindowEdge
WindowEdgeSouthEast WindowEdgeSouthEast
}; };
enum AvnMenuItemToggleType
{
None,
CheckMark,
Radio
};
AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown
{ {
public: public:
virtual HRESULT Initialize() = 0; virtual HRESULT Initialize() = 0;
virtual IAvnMacOptions* GetMacOptions() = 0; virtual IAvnMacOptions* GetMacOptions() = 0;
virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv) = 0; virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnWindow** ppv) = 0;
virtual HRESULT CreatePopup (IAvnWindowEvents* cb, IAvnPopup** ppv) = 0; virtual HRESULT CreatePopup (IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnPopup** ppv) = 0;
virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) = 0; virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) = 0;
virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0; virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0;
virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0; virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0;
virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0; virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0;
virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0; virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0;
virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) = 0; virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) = 0;
virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) = 0; virtual HRESULT SetAppMenu(IAvnMenu* menu) = 0;
virtual HRESULT SetAppMenu(IAvnAppMenu* menu) = 0; virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) = 0;
virtual HRESULT CreateMenu (IAvnAppMenu** ppv) = 0; virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) = 0;
virtual HRESULT CreateMenuItem (IAvnAppMenuItem** ppv) = 0; virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) = 0;
virtual HRESULT CreateMenuItemSeperator (IAvnAppMenuItem** ppv) = 0;
}; };
AVNCOM(IAvnString, 17) : IUnknown AVNCOM(IAvnString, 17) : IUnknown
@ -219,15 +230,11 @@ AVNCOM(IAvnWindowBase, 02) : IUnknown
virtual HRESULT SetTopMost (bool value) = 0; virtual HRESULT SetTopMost (bool value) = 0;
virtual HRESULT SetCursor(IAvnCursor* cursor) = 0; virtual HRESULT SetCursor(IAvnCursor* cursor) = 0;
virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0; virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0;
virtual HRESULT GetSoftwareFramebuffer(AvnFramebuffer*ret) = 0; virtual HRESULT SetMainMenu(IAvnMenu* menu) = 0;
virtual HRESULT SetMainMenu(IAvnAppMenu* menu) = 0;
virtual HRESULT ObtainMainMenu(IAvnAppMenu** retOut) = 0;
virtual HRESULT ObtainNSWindowHandle(void** retOut) = 0; virtual HRESULT ObtainNSWindowHandle(void** retOut) = 0;
virtual HRESULT ObtainNSWindowHandleRetained(void** retOut) = 0; virtual HRESULT ObtainNSWindowHandleRetained(void** retOut) = 0;
virtual HRESULT ObtainNSViewHandle(void** retOut) = 0; virtual HRESULT ObtainNSViewHandle(void** retOut) = 0;
virtual HRESULT ObtainNSViewHandleRetained(void** retOut) = 0; virtual HRESULT ObtainNSViewHandleRetained(void** retOut) = 0;
virtual bool TryLock() = 0;
virtual void Unlock() = 0;
}; };
AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
@ -239,7 +246,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
{ {
virtual HRESULT ShowDialog (IAvnWindow* parent) = 0; virtual HRESULT ShowDialog (IAvnWindow* parent) = 0;
virtual HRESULT SetCanResize(bool value) = 0; virtual HRESULT SetCanResize(bool value) = 0;
virtual HRESULT SetHasDecorations(bool value) = 0; virtual HRESULT SetHasDecorations(SystemDecorations value) = 0;
virtual HRESULT SetTitle (void* utf8Title) = 0; virtual HRESULT SetTitle (void* utf8Title) = 0;
virtual HRESULT SetTitleBarColor (AvnColor color) = 0; virtual HRESULT SetTitleBarColor (AvnColor color) = 0;
virtual HRESULT SetWindowState(AvnWindowState state) = 0; virtual HRESULT SetWindowState(AvnWindowState state) = 0;
@ -360,24 +367,21 @@ AVNCOM(IAvnCursorFactory, 11) : IUnknown
virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut) = 0; virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut) = 0;
}; };
AVNCOM(IAvnGlFeature, 12) : IUnknown
{
virtual HRESULT ObtainDisplay(IAvnGlDisplay**retOut) = 0;
virtual HRESULT ObtainImmediateContext(IAvnGlContext**retOut) = 0;
};
AVNCOM(IAvnGlDisplay, 13) : IUnknown AVNCOM(IAvnGlDisplay, 13) : IUnknown
{ {
virtual HRESULT GetSampleCount(int* ret) = 0; virtual HRESULT CreateContext(IAvnGlContext* share, IAvnGlContext**ppv) = 0;
virtual HRESULT GetStencilSize(int* ret) = 0; virtual void LegacyClearCurrentContext() = 0;
virtual HRESULT ClearContext() = 0; virtual HRESULT WrapContext(void* native, IAvnGlContext**ppv) = 0;
virtual void* GetProcAddress(char* proc) = 0; virtual void* GetProcAddress(char* proc) = 0;
}; };
AVNCOM(IAvnGlContext, 14) : IUnknown AVNCOM(IAvnGlContext, 14) : IUnknown
{ {
virtual HRESULT MakeCurrent() = 0; virtual HRESULT MakeCurrent(IUnknown** ppv) = 0;
virtual HRESULT LegacyMakeCurrent() = 0;
virtual int GetSampleCount() = 0;
virtual int GetStencilSize() = 0;
virtual void* GetNativeHandle() = 0;
}; };
AVNCOM(IAvnGlSurfaceRenderTarget, 15) : IUnknown AVNCOM(IAvnGlSurfaceRenderTarget, 15) : IUnknown
@ -391,10 +395,10 @@ AVNCOM(IAvnGlSurfaceRenderingSession, 16) : IUnknown
virtual HRESULT GetScaling(double* ret) = 0; virtual HRESULT GetScaling(double* ret) = 0;
}; };
AVNCOM(IAvnAppMenu, 17) : IUnknown AVNCOM(IAvnMenu, 17) : IUnknown
{ {
virtual HRESULT AddItem (IAvnAppMenuItem* item) = 0; virtual HRESULT InsertItem (int index, IAvnMenuItem* item) = 0;
virtual HRESULT RemoveItem (IAvnAppMenuItem* item) = 0; virtual HRESULT RemoveItem (IAvnMenuItem* item) = 0;
virtual HRESULT SetTitle (void* utf8String) = 0; virtual HRESULT SetTitle (void* utf8String) = 0;
virtual HRESULT Clear () = 0; virtual HRESULT Clear () = 0;
}; };
@ -404,12 +408,23 @@ AVNCOM(IAvnPredicateCallback, 18) : IUnknown
virtual bool Evaluate() = 0; virtual bool Evaluate() = 0;
}; };
AVNCOM(IAvnAppMenuItem, 19) : IUnknown AVNCOM(IAvnMenuItem, 19) : IUnknown
{ {
virtual HRESULT SetSubMenu (IAvnAppMenu* menu) = 0; virtual HRESULT SetSubMenu (IAvnMenu* menu) = 0;
virtual HRESULT SetTitle (void* utf8String) = 0; virtual HRESULT SetTitle (void* utf8String) = 0;
virtual HRESULT SetGesture (void* utf8String, AvnInputModifiers modifiers) = 0; virtual HRESULT SetGesture (void* utf8String, AvnInputModifiers modifiers) = 0;
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) = 0; virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) = 0;
virtual HRESULT SetIsChecked (bool isChecked) = 0;
virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) = 0;
virtual HRESULT SetIcon (void* data, size_t length) = 0;
};
AVNCOM(IAvnMenuEvents, 1A) : IUnknown
{
/**
* NeedsUpdate
*/
virtual void NeedsUpdate () = 0;
}; };
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative(); extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();

3
native/Avalonia.Native/inc/com.h

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection" #pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
#ifndef COM_H_INCLUDED #ifndef COM_H_INCLUDED

13
native/Avalonia.Native/inc/comimpl.h

@ -162,6 +162,19 @@ public:
return _obj; return _obj;
} }
TInterface* getRetainedReference()
{
if(_obj == NULL)
return NULL;
_obj->AddRef();
return _obj;
}
TInterface** getPPV()
{
return &_obj;
}
operator TInterface*() const operator TInterface*() const
{ {
return _obj; return _obj;

3
native/Avalonia.Native/inc/key.h

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#ifndef _KEY_H_ #ifndef _KEY_H_
#define _KEY_H_ #define _KEY_H_

12
native/Avalonia.Native/inc/rendertarget.h

@ -0,0 +1,12 @@
@protocol IRenderTarget
-(void) setNewLayer: (CALayer*) layer;
-(HRESULT) setSwFrame: (AvnFramebuffer*) fb;
-(void) resize: (AvnPixelSize) size withScale: (float) scale;
-(AvnPixelSize) pixelSize;
-(IAvnGlSurfaceRenderTarget*) createSurfaceRenderTarget;
@end
@interface IOSurfaceRenderTarget : NSObject<IRenderTarget>
-(IOSurfaceRenderTarget*) initWithOpenGlContext: (IAvnGlContext*) context;
@end

20
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@ -8,6 +8,10 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1A002B9E232135EE00021753 /* app.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A002B9D232135EE00021753 /* app.mm */; }; 1A002B9E232135EE00021753 /* app.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A002B9D232135EE00021753 /* app.mm */; };
1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */; };
1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */; };
1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EAD23E9FB1300EDE661 /* cgl.mm */; };
1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */; };
37155CE4233C00EB0034DCE9 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 37155CE3233C00EB0034DCE9 /* menu.h */; }; 37155CE4233C00EB0034DCE9 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 37155CE3233C00EB0034DCE9 /* menu.h */; };
37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; }; 37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; };
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; }; 37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; };
@ -18,7 +22,6 @@
5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; }; 5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; }; AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; }; AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; };
AB573DC4217605E400D389A2 /* gl.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB573DC3217605E400D389A2 /* gl.mm */; };
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; }; AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
AB661C202148286E00291242 /* window.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB661C1F2148286E00291242 /* window.mm */; }; AB661C202148286E00291242 /* window.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB661C1F2148286E00291242 /* window.mm */; };
AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */; }; AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */; };
@ -26,6 +29,10 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1A002B9D232135EE00021753 /* app.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = app.mm; sourceTree = "<group>"; }; 1A002B9D232135EE00021753 /* app.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = app.mm; sourceTree = "<group>"; };
1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = rendertarget.mm; sourceTree = "<group>"; };
1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = System/Library/Frameworks/IOSurface.framework; sourceTree = SDKROOT; };
1A3E5EAD23E9FB1300EDE661 /* cgl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cgl.mm; sourceTree = "<group>"; };
1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
37155CE3233C00EB0034DCE9 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = "<group>"; }; 37155CE3233C00EB0034DCE9 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = "<group>"; };
379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = "<group>"; }; 379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = "<group>"; };
37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = "<group>"; }; 37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = "<group>"; };
@ -41,7 +48,6 @@
5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = "<group>"; }; 5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = "<group>"; };
AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; }; AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
AB573DC3217605E400D389A2 /* gl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = gl.mm; sourceTree = "<group>"; };
AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
AB661C1F2148286E00291242 /* window.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = window.mm; sourceTree = "<group>"; }; AB661C1F2148286E00291242 /* window.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = window.mm; sourceTree = "<group>"; };
AB661C212148288600291242 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; }; AB661C212148288600291242 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
@ -54,6 +60,8 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */,
1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */,
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */, AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */,
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */, AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */,
); );
@ -65,6 +73,8 @@
AB661C1C2148230E00291242 /* Frameworks */ = { AB661C1C2148230E00291242 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */,
1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */,
AB1E522B217613570091CD71 /* OpenGL.framework */, AB1E522B217613570091CD71 /* OpenGL.framework */,
AB661C1D2148230F00291242 /* AppKit.framework */, AB661C1D2148230F00291242 /* AppKit.framework */,
); );
@ -78,7 +88,7 @@
37DDA9B121933371002E132B /* AvnString.h */, 37DDA9B121933371002E132B /* AvnString.h */,
37DDA9AF219330F8002E132B /* AvnString.mm */, 37DDA9AF219330F8002E132B /* AvnString.mm */,
37A4E71A2178846A00EACBCD /* headers */, 37A4E71A2178846A00EACBCD /* headers */,
AB573DC3217605E400D389A2 /* gl.mm */, 1A3E5EAD23E9FB1300EDE661 /* cgl.mm */,
5BF943652167AD1D009CAE35 /* cursor.h */, 5BF943652167AD1D009CAE35 /* cursor.h */,
5B21A981216530F500CEE36E /* cursor.mm */, 5B21A981216530F500CEE36E /* cursor.mm */,
5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */, 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */,
@ -91,6 +101,7 @@
AB00E4F62147CA920032A60A /* main.mm */, AB00E4F62147CA920032A60A /* main.mm */,
37155CE3233C00EB0034DCE9 /* menu.h */, 37155CE3233C00EB0034DCE9 /* menu.h */,
520624B222973F4100C4DCEF /* menu.mm */, 520624B222973F4100C4DCEF /* menu.mm */,
1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */,
37A517B22159597E00FBA241 /* Screens.mm */, 37A517B22159597E00FBA241 /* Screens.mm */,
37C09D8721580FE4006A6758 /* SystemDialogs.mm */, 37C09D8721580FE4006A6758 /* SystemDialogs.mm */,
AB7A61F02147C815003C5833 /* Products */, AB7A61F02147C815003C5833 /* Products */,
@ -180,12 +191,13 @@
5B21A982216530F500CEE36E /* cursor.mm in Sources */, 5B21A982216530F500CEE36E /* cursor.mm in Sources */,
37DDA9B0219330F8002E132B /* AvnString.mm in Sources */, 37DDA9B0219330F8002E132B /* AvnString.mm in Sources */,
AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */, AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */,
1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */,
1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */,
37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */, 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */,
520624B322973F4100C4DCEF /* menu.mm in Sources */, 520624B322973F4100C4DCEF /* menu.mm in Sources */,
37A517B32159597E00FBA241 /* Screens.mm in Sources */, 37A517B32159597E00FBA241 /* Screens.mm in Sources */,
AB00E4F72147CA920032A60A /* main.mm in Sources */, AB00E4F72147CA920032A60A /* main.mm in Sources */,
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */, 37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */,
AB573DC4217605E400D389A2 /* gl.mm in Sources */,
AB661C202148286E00291242 /* window.mm in Sources */, AB661C202148286E00291242 /* window.mm in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;

6
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme

@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -58,12 +56,10 @@
</MacroExpansion> </MacroExpansion>
<CommandLineArguments> <CommandLineArguments>
<CommandLineArgument <CommandLineArgument
argument = "bin/Debug/netcoreapp2.0/ControlCatalog.NetCore.dll" argument = "bin/Debug/netcoreapp3.1/ControlCatalog.NetCore.dll"
isEnabled = "YES"> isEnabled = "YES">
</CommandLineArgument> </CommandLineArgument>
</CommandLineArguments> </CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

3
native/Avalonia.Native/src/OSX/KeyTransform.h

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#ifndef keytransform_h #ifndef keytransform_h
#define keytransform_h #define keytransform_h
#include "common.h" #include "common.h"

3
native/Avalonia.Native/src/OSX/KeyTransform.mm

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#include "KeyTransform.h" #include "KeyTransform.h"
const int kVK_ANSI_A = 0x00; const int kVK_ANSI_A = 0x00;

3
native/Avalonia.Native/src/OSX/Screens.mm

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#include "common.h" #include "common.h"
class Screens : public ComSingleObject<IAvnScreens, &IID_IAvnScreens> class Screens : public ComSingleObject<IAvnScreens, &IID_IAvnScreens>

6
native/Avalonia.Native/src/OSX/SystemDialogs.mm

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#include "common.h" #include "common.h"
#include "window.h" #include "window.h"
@ -23,6 +20,7 @@ public:
if(title != nullptr) if(title != nullptr)
{ {
panel.message = [NSString stringWithUTF8String:title];
panel.title = [NSString stringWithUTF8String:title]; panel.title = [NSString stringWithUTF8String:title];
} }
@ -97,6 +95,7 @@ public:
if(title != nullptr) if(title != nullptr)
{ {
panel.message = [NSString stringWithUTF8String:title];
panel.title = [NSString stringWithUTF8String:title]; panel.title = [NSString stringWithUTF8String:title];
} }
@ -185,6 +184,7 @@ public:
if(title != nullptr) if(title != nullptr)
{ {
panel.message = [NSString stringWithUTF8String:title];
panel.title = [NSString stringWithUTF8String:title]; panel.title = [NSString stringWithUTF8String:title];
} }

7
native/Avalonia.Native/src/OSX/app.mm

@ -2,7 +2,8 @@
@interface AvnAppDelegate : NSObject<NSApplicationDelegate> @interface AvnAppDelegate : NSObject<NSApplicationDelegate>
@end @end
extern NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular; NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular;
@implementation AvnAppDelegate @implementation AvnAppDelegate
- (void)applicationWillFinishLaunching:(NSNotification *)notification - (void)applicationWillFinishLaunching:(NSNotification *)notification
{ {
@ -14,6 +15,10 @@ extern NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationA
} }
[[NSApplication sharedApplication] setActivationPolicy: AvnDesiredActivationPolicy]; [[NSApplication sharedApplication] setActivationPolicy: AvnDesiredActivationPolicy];
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"];
[[NSApplication sharedApplication] setHelpMenu: [[NSMenu new] initWithTitle:@""]];
} }
} }

166
native/Avalonia.Native/src/OSX/cgl.mm

@ -0,0 +1,166 @@
#include "common.h"
#include <dlfcn.h>
static CGLContextObj CreateCglContext(CGLContextObj share)
{
int attributes[] = {
kCGLPFAAccelerated,
kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core,
kCGLPFADepthSize, 8,
kCGLPFAStencilSize, 8,
kCGLPFAColorSize, 32,
0
};
CGLPixelFormatObj pix;
CGLError errorCode;
GLint num; // stores the number of possible pixel formats
errorCode = CGLChoosePixelFormat( (CGLPixelFormatAttribute*)attributes, &pix, &num );
if(errorCode != 0)
return nil;
CGLContextObj ctx = nil;
errorCode = CGLCreateContext(pix, share, &ctx );
CGLDestroyPixelFormat( pix );
if(errorCode != 0)
return nil;
return ctx;
};
class AvnGlContext : public virtual ComSingleObject<IAvnGlContext, &IID_IAvnGlContext>
{
// Debug
int _usageCount = 0;
public:
CGLContextObj Context;
int SampleCount = 0, StencilBits = 0;
FORWARD_IUNKNOWN()
class SavedGlContext : public virtual ComUnknownObject
{
CGLContextObj _savedContext;
ComPtr<AvnGlContext> _parent;
public:
SavedGlContext(CGLContextObj saved, AvnGlContext* parent)
{
_savedContext = saved;
_parent = parent;
_parent->_usageCount++;
}
~SavedGlContext()
{
if(_parent->Context == CGLGetCurrentContext())
CGLSetCurrentContext(_savedContext);
_parent->_usageCount--;
CGLUnlockContext(_parent->Context);
}
};
AvnGlContext(CGLContextObj context)
{
Context = context;
CGLPixelFormatObj fmt = CGLGetPixelFormat(context);
CGLDescribePixelFormat(fmt, 0, kCGLPFASamples, &SampleCount);
CGLDescribePixelFormat(fmt, 0, kCGLPFAStencilSize, &StencilBits);
}
virtual HRESULT LegacyMakeCurrent() override
{
if(CGLSetCurrentContext(Context) != 0)
return E_FAIL;
return S_OK;
}
virtual HRESULT MakeCurrent(IUnknown** ppv) override
{
CGLContextObj saved = CGLGetCurrentContext();
CGLLockContext(Context);
if(CGLSetCurrentContext(Context) != 0)
{
CGLUnlockContext(Context);
return E_FAIL;
}
*ppv = new SavedGlContext(saved, this);
return S_OK;
}
virtual int GetSampleCount() override
{
return SampleCount;
}
virtual int GetStencilSize() override
{
return StencilBits;
}
virtual void* GetNativeHandle() override
{
return Context;
}
~AvnGlContext()
{
CGLReleaseContext(Context);
}
};
class AvnGlDisplay : public virtual ComSingleObject<IAvnGlDisplay, &IID_IAvnGlDisplay>
{
void* _libgl;
public:
FORWARD_IUNKNOWN()
AvnGlDisplay()
{
_libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", RTLD_LAZY);
}
virtual void* GetProcAddress(char* proc) override
{
return dlsym(_libgl, proc);
}
virtual HRESULT CreateContext(IAvnGlContext* share, IAvnGlContext**ppv) override
{
CGLContextObj shareContext = nil;
if(share != nil)
{
AvnGlContext* shareCtx = dynamic_cast<AvnGlContext*>(share);
if(shareCtx != nil)
shareContext = shareCtx->Context;
}
CGLContextObj ctx = ::CreateCglContext(shareContext);
if(ctx == nil)
return E_FAIL;
*ppv = new AvnGlContext(ctx);
return S_OK;
}
virtual HRESULT WrapContext(void* native, IAvnGlContext**ppv) override
{
if(native == nil)
return E_INVALIDARG;
*ppv = new AvnGlContext((CGLContextObj) native);
return S_OK;
}
virtual void LegacyClearCurrentContext() override
{
CGLSetCurrentContext(nil);
}
};
static IAvnGlDisplay* GlDisplay = new AvnGlDisplay();
extern IAvnGlDisplay* GetGlDisplay()
{
return GlDisplay;
};

3
native/Avalonia.Native/src/OSX/clipboard.mm

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#include "common.h" #include "common.h"
#include "AvnString.h" #include "AvnString.h"

20
native/Avalonia.Native/src/OSX/common.h

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#ifndef common_h #ifndef common_h
#define common_h #define common_h
#include "comimpl.h" #include "comimpl.h"
@ -11,19 +8,18 @@
#include <pthread.h> #include <pthread.h>
extern IAvnPlatformThreadingInterface* CreatePlatformThreading(); extern IAvnPlatformThreadingInterface* CreatePlatformThreading();
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events); extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl);
extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events); extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events, IAvnGlContext* gl);
extern IAvnSystemDialogs* CreateSystemDialogs(); extern IAvnSystemDialogs* CreateSystemDialogs();
extern IAvnScreens* CreateScreens(); extern IAvnScreens* CreateScreens();
extern IAvnClipboard* CreateClipboard(); extern IAvnClipboard* CreateClipboard();
extern IAvnCursorFactory* CreateCursorFactory(); extern IAvnCursorFactory* CreateCursorFactory();
extern IAvnGlFeature* GetGlFeature(); extern IAvnGlDisplay* GetGlDisplay();
extern IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(NSWindow* window, NSView* view); extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* events);
extern IAvnAppMenu* CreateAppMenu(); extern IAvnMenuItem* CreateAppMenuItem();
extern IAvnAppMenuItem* CreateAppMenuItem(); extern IAvnMenuItem* CreateAppMenuItemSeperator();
extern IAvnAppMenuItem* CreateAppMenuItemSeperator(); extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu);
extern void SetAppMenu (NSString* appName, IAvnAppMenu* appMenu); extern IAvnMenu* GetAppMenu ();
extern IAvnAppMenu* GetAppMenu ();
extern NSMenuItem* GetAppMenuItem (); extern NSMenuItem* GetAppMenuItem ();
extern void InitializeAvnApp(); extern void InitializeAvnApp();

3
native/Avalonia.Native/src/OSX/cursor.h

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#ifndef cursor_h #ifndef cursor_h
#define cursor_h #define cursor_h

3
native/Avalonia.Native/src/OSX/cursor.mm

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#include "common.h" #include "common.h"
#include "cursor.h" #include "cursor.h"
#include <map> #include <map>

253
native/Avalonia.Native/src/OSX/gl.mm

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

40
native/Avalonia.Native/src/OSX/main.mm

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
//This file will contain actual IID structures //This file will contain actual IID structures
#define COM_GUIDS_MATERIALIZE #define COM_GUIDS_MATERIALIZE
#include "common.h" #include "common.h"
@ -95,12 +92,11 @@ void SetProcessName(NSString* appTitle) {
PrivateLSASN asn = ls_get_current_application_asn_func(); PrivateLSASN asn = ls_get_current_application_asn_func();
// Constant used by WebKit; what exactly it means is unknown. // Constant used by WebKit; what exactly it means is unknown.
const int magic_session_constant = -2; const int magic_session_constant = -2;
OSErr err =
ls_set_application_information_item_func(magic_session_constant, asn, ls_set_application_information_item_func(magic_session_constant, asn,
ls_display_name_key, ls_display_name_key,
process_name, process_name,
NULL /* optional out param */); NULL /* optional out param */);
//LOG_IF(ERROR, err) << "Call to set process name failed, err " << err;
} }
class MacOptions : public ComSingleObject<IAvnMacOptions, &IID_IAvnMacOptions> class MacOptions : public ComSingleObject<IAvnMacOptions, &IID_IAvnMacOptions>
@ -174,20 +170,20 @@ public:
return (IAvnMacOptions*)new MacOptions(); return (IAvnMacOptions*)new MacOptions();
} }
virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv) override virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnWindow** ppv) override
{ {
if(cb == nullptr || ppv == nullptr) if(cb == nullptr || ppv == nullptr)
return E_POINTER; return E_POINTER;
*ppv = CreateAvnWindow(cb); *ppv = CreateAvnWindow(cb, gl);
return S_OK; return S_OK;
}; };
virtual HRESULT CreatePopup(IAvnWindowEvents* cb, IAvnPopup** ppv) override virtual HRESULT CreatePopup(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnPopup** ppv) override
{ {
if(cb == nullptr || ppv == nullptr) if(cb == nullptr || ppv == nullptr)
return E_POINTER; return E_POINTER;
*ppv = CreateAvnPopup(cb); *ppv = CreateAvnPopup(cb, gl);
return S_OK; return S_OK;
} }
@ -221,9 +217,9 @@ public:
return S_OK; return S_OK;
} }
virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) override virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) override
{ {
auto rv = ::GetGlFeature(); auto rv = ::GetGlDisplay();
if(rv == NULL) if(rv == NULL)
return E_FAIL; return E_FAIL;
rv->AddRef(); rv->AddRef();
@ -231,41 +227,29 @@ public:
return S_OK; return S_OK;
} }
virtual HRESULT CreateMenu (IAvnAppMenu** ppv) override virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) override
{ {
*ppv = ::CreateAppMenu(); *ppv = ::CreateAppMenu(cb);
return S_OK; return S_OK;
} }
virtual HRESULT CreateMenuItem (IAvnAppMenuItem** ppv) override virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) override
{ {
*ppv = ::CreateAppMenuItem(); *ppv = ::CreateAppMenuItem();
return S_OK; return S_OK;
} }
virtual HRESULT CreateMenuItemSeperator (IAvnAppMenuItem** ppv) override virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) override
{ {
*ppv = ::CreateAppMenuItemSeperator(); *ppv = ::CreateAppMenuItemSeperator();
return S_OK; return S_OK;
} }
virtual HRESULT SetAppMenu (IAvnAppMenu* appMenu) override virtual HRESULT SetAppMenu (IAvnMenu* appMenu) override
{ {
::SetAppMenu(s_appTitle, appMenu); ::SetAppMenu(s_appTitle, appMenu);
return S_OK; return S_OK;
} }
virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) override
{
if(retOut == nullptr)
{
return E_POINTER;
}
*retOut = ::GetAppMenu();
return S_OK;
}
}; };
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative() extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()

36
native/Avalonia.Native/src/OSX/menu.h

@ -14,8 +14,10 @@
class AvnAppMenuItem; class AvnAppMenuItem;
class AvnAppMenu; class AvnAppMenu;
@interface AvnMenu : NSMenu // for some reason it doesnt detect nsmenu here but compiler doesnt complain @interface AvnMenu : NSMenu
- (void)setMenu:(NSMenu*) menu; - (id) initWithDelegate: (NSObject<NSMenuDelegate>*) del;
- (void) setHasGlobalMenuItem: (bool) value;
- (bool) hasGlobalMenuItem;
@end @end
@interface AvnMenuItem : NSMenuItem @interface AvnMenuItem : NSMenuItem
@ -23,13 +25,14 @@ class AvnAppMenu;
- (void)didSelectItem:(id)sender; - (void)didSelectItem:(id)sender;
@end @end
class AvnAppMenuItem : public ComSingleObject<IAvnAppMenuItem, &IID_IAvnAppMenuItem> class AvnAppMenuItem : public ComSingleObject<IAvnMenuItem, &IID_IAvnMenuItem>
{ {
private: private:
NSMenuItem* _native; // here we hold a pointer to an AvnMenuItem NSMenuItem* _native; // here we hold a pointer to an AvnMenuItem
IAvnActionCallback* _callback; IAvnActionCallback* _callback;
IAvnPredicateCallback* _predicate; IAvnPredicateCallback* _predicate;
bool _isSeperator; bool _isSeperator;
bool _isCheckable;
public: public:
FORWARD_IUNKNOWN() FORWARD_IUNKNOWN()
@ -38,7 +41,7 @@ public:
NSMenuItem* GetNative(); NSMenuItem* GetNative();
virtual HRESULT SetSubMenu (IAvnAppMenu* menu) override; virtual HRESULT SetSubMenu (IAvnMenu* menu) override;
virtual HRESULT SetTitle (void* utf8String) override; virtual HRESULT SetTitle (void* utf8String) override;
@ -46,29 +49,36 @@ public:
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override; virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override;
virtual HRESULT SetIsChecked (bool isChecked) override;
virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) override;
virtual HRESULT SetIcon (void* data, size_t length) override;
bool EvaluateItemEnabled(); bool EvaluateItemEnabled();
void RaiseOnClicked(); void RaiseOnClicked();
}; };
class AvnAppMenu : public ComSingleObject<IAvnAppMenu, &IID_IAvnAppMenu> class AvnAppMenu : public ComSingleObject<IAvnMenu, &IID_IAvnMenu>
{ {
private: private:
AvnMenu* _native; AvnMenu* _native;
ComPtr<IAvnMenuEvents> _baseEvents;
public: public:
FORWARD_IUNKNOWN() FORWARD_IUNKNOWN()
AvnAppMenu(); AvnAppMenu(IAvnMenuEvents* events);
AvnAppMenu(AvnMenu* native);
AvnMenu* GetNative(); AvnMenu* GetNative();
virtual HRESULT AddItem (IAvnAppMenuItem* item) override; void RaiseNeedsUpdate ();
virtual HRESULT InsertItem (int index, IAvnMenuItem* item) override;
virtual HRESULT RemoveItem (IAvnAppMenuItem* item) override; virtual HRESULT RemoveItem (IAvnMenuItem* item) override;
virtual HRESULT SetTitle (void* utf8String) override; virtual HRESULT SetTitle (void* utf8String) override;
@ -76,5 +86,9 @@ public:
}; };
@interface AvnMenuDelegate : NSObject<NSMenuDelegate>
- (id) initWithParent: (AvnAppMenu*) parent;
@end
#endif #endif

286
native/Avalonia.Native/src/OSX/menu.mm

@ -4,6 +4,30 @@
#include "window.h" #include "window.h"
@implementation AvnMenu @implementation AvnMenu
{
bool _isReparented;
NSObject<NSMenuDelegate>* _wtf;
}
- (id) initWithDelegate: (NSObject<NSMenuDelegate>*)del
{
self = [super init];
self.delegate = del;
_wtf = del;
_isReparented = false;
return self;
}
- (bool)hasGlobalMenuItem
{
return _isReparented;
}
- (void)setHasGlobalMenuItem:(bool)value
{
_isReparented = value;
}
@end @end
@implementation AvnMenuItem @implementation AvnMenuItem
@ -46,6 +70,7 @@
AvnAppMenuItem::AvnAppMenuItem(bool isSeperator) AvnAppMenuItem::AvnAppMenuItem(bool isSeperator)
{ {
_isCheckable = false;
_isSeperator = isSeperator; _isSeperator = isSeperator;
if(isSeperator) if(isSeperator)
@ -65,49 +90,134 @@ NSMenuItem* AvnAppMenuItem::GetNative()
return _native; return _native;
} }
HRESULT AvnAppMenuItem::SetSubMenu (IAvnAppMenu* menu) HRESULT AvnAppMenuItem::SetSubMenu (IAvnMenu* menu)
{ {
auto nsMenu = dynamic_cast<AvnAppMenu*>(menu)->GetNative(); @autoreleasepool
{
[_native setSubmenu: nsMenu]; if(menu != nullptr)
{
return S_OK; auto nsMenu = dynamic_cast<AvnAppMenu*>(menu)->GetNative();
[_native setSubmenu: nsMenu];
}
else
{
[_native setSubmenu: nullptr];
}
return S_OK;
}
} }
HRESULT AvnAppMenuItem::SetTitle (void* utf8String) HRESULT AvnAppMenuItem::SetTitle (void* utf8String)
{ {
if (utf8String != nullptr) @autoreleasepool
{ {
[_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]]; if (utf8String != nullptr)
{
[_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
}
return S_OK;
} }
return S_OK;
} }
HRESULT AvnAppMenuItem::SetGesture (void* key, AvnInputModifiers modifiers) HRESULT AvnAppMenuItem::SetGesture (void* key, AvnInputModifiers modifiers)
{ {
NSEventModifierFlags flags = 0; @autoreleasepool
{
if (modifiers & Control) NSEventModifierFlags flags = 0;
flags |= NSEventModifierFlagControl;
if (modifiers & Shift) if (modifiers & Control)
flags |= NSEventModifierFlagShift; flags |= NSEventModifierFlagControl;
if (modifiers & Alt) if (modifiers & Shift)
flags |= NSEventModifierFlagOption; flags |= NSEventModifierFlagShift;
if (modifiers & Windows) if (modifiers & Alt)
flags |= NSEventModifierFlagCommand; flags |= NSEventModifierFlagOption;
if (modifiers & Windows)
[_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]]; flags |= NSEventModifierFlagCommand;
[_native setKeyEquivalentModifierMask:flags];
[_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]];
return S_OK; [_native setKeyEquivalentModifierMask:flags];
return S_OK;
}
} }
HRESULT AvnAppMenuItem::SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) HRESULT AvnAppMenuItem::SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback)
{ {
_predicate = predicate; @autoreleasepool
_callback = callback; {
return S_OK; _predicate = predicate;
_callback = callback;
return S_OK;
}
}
HRESULT AvnAppMenuItem::SetIsChecked (bool isChecked)
{
@autoreleasepool
{
[_native setState:(isChecked && _isCheckable ? NSOnState : NSOffState)];
return S_OK;
}
}
HRESULT AvnAppMenuItem::SetToggleType(AvnMenuItemToggleType toggleType)
{
@autoreleasepool
{
switch(toggleType)
{
case AvnMenuItemToggleType::None:
[_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]];
_isCheckable = false;
break;
case AvnMenuItemToggleType::CheckMark:
[_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]];
_isCheckable = true;
break;
case AvnMenuItemToggleType::Radio:
[_native setOnStateImage: [NSImage imageNamed:@"NSMenuItemBullet"]];
_isCheckable = true;
break;
}
return S_OK;
}
}
HRESULT AvnAppMenuItem::SetIcon(void *data, size_t length)
{
@autoreleasepool
{
if(data != nullptr)
{
NSData *imageData = [NSData dataWithBytes:data length:length];
NSImage *image = [[NSImage alloc] initWithData:imageData];
NSSize originalSize = [image size];
NSSize size;
size.height = [[NSFont menuFontOfSize:0] pointSize] * 1.333333;
auto scaleFactor = size.height / originalSize.height;
size.width = originalSize.width * scaleFactor;
[image setSize: size];
[_native setImage:image];
}
else
{
[_native setImage:nullptr];
}
return S_OK;
}
} }
bool AvnAppMenuItem::EvaluateItemEnabled() bool AvnAppMenuItem::EvaluateItemEnabled()
@ -130,71 +240,123 @@ void AvnAppMenuItem::RaiseOnClicked()
} }
} }
AvnAppMenu::AvnAppMenu() AvnAppMenu::AvnAppMenu(IAvnMenuEvents* events)
{ {
_native = [AvnMenu new]; _baseEvents = events;
id del = [[AvnMenuDelegate alloc] initWithParent: this];
_native = [[AvnMenu alloc] initWithDelegate: del];
} }
AvnAppMenu::AvnAppMenu(AvnMenu* native)
{
_native = native;
}
AvnMenu* AvnAppMenu::GetNative() AvnMenu* AvnAppMenu::GetNative()
{ {
return _native; return _native;
} }
HRESULT AvnAppMenu::AddItem (IAvnAppMenuItem* item) void AvnAppMenu::RaiseNeedsUpdate()
{ {
auto avnMenuItem = dynamic_cast<AvnAppMenuItem*>(item); if(_baseEvents != nullptr)
if(avnMenuItem != nullptr)
{ {
[_native addItem: avnMenuItem->GetNative()]; _baseEvents->NeedsUpdate();
} }
return S_OK;
} }
HRESULT AvnAppMenu::RemoveItem (IAvnAppMenuItem* item) HRESULT AvnAppMenu::InsertItem(int index, IAvnMenuItem *item)
{ {
auto avnMenuItem = dynamic_cast<AvnAppMenuItem*>(item); @autoreleasepool
if(avnMenuItem != nullptr)
{ {
[_native removeItem:avnMenuItem->GetNative()]; if([_native hasGlobalMenuItem])
{
index++;
}
auto avnMenuItem = dynamic_cast<AvnAppMenuItem*>(item);
if(avnMenuItem != nullptr)
{
[_native insertItem: avnMenuItem->GetNative() atIndex:index];
}
return S_OK;
}
}
HRESULT AvnAppMenu::RemoveItem (IAvnMenuItem* item)
{
@autoreleasepool
{
auto avnMenuItem = dynamic_cast<AvnAppMenuItem*>(item);
if(avnMenuItem != nullptr)
{
[_native removeItem:avnMenuItem->GetNative()];
}
return S_OK;
} }
return S_OK;
} }
HRESULT AvnAppMenu::SetTitle (void* utf8String) HRESULT AvnAppMenu::SetTitle (void* utf8String)
{ {
if (utf8String != nullptr) @autoreleasepool
{ {
[_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]]; if (utf8String != nullptr)
{
[_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
}
return S_OK;
} }
return S_OK;
} }
HRESULT AvnAppMenu::Clear() HRESULT AvnAppMenu::Clear()
{ {
[_native removeAllItems]; @autoreleasepool
return S_OK; {
[_native removeAllItems];
return S_OK;
}
}
@implementation AvnMenuDelegate
{
ComPtr<AvnAppMenu> _parent;
} }
- (id) initWithParent:(AvnAppMenu *)parent
{
self = [super init];
_parent = parent;
return self;
}
- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
{
if(shouldCancel)
return NO;
return YES;
}
- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
{
return [menu numberOfItems];
}
- (void)menuNeedsUpdate:(NSMenu *)menu
{
_parent->RaiseNeedsUpdate();
}
@end
extern IAvnAppMenu* CreateAppMenu() extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* cb)
{ {
@autoreleasepool @autoreleasepool
{ {
id menuBar = [NSMenu new]; return new AvnAppMenu(cb);
return new AvnAppMenu(menuBar);
} }
} }
extern IAvnAppMenuItem* CreateAppMenuItem() extern IAvnMenuItem* CreateAppMenuItem()
{ {
@autoreleasepool @autoreleasepool
{ {
@ -202,7 +364,7 @@ extern IAvnAppMenuItem* CreateAppMenuItem()
} }
} }
extern IAvnAppMenuItem* CreateAppMenuItemSeperator() extern IAvnMenuItem* CreateAppMenuItemSeperator()
{ {
@autoreleasepool @autoreleasepool
{ {
@ -210,10 +372,10 @@ extern IAvnAppMenuItem* CreateAppMenuItemSeperator()
} }
} }
static IAvnAppMenu* s_appMenu = nullptr; static IAvnMenu* s_appMenu = nullptr;
static NSMenuItem* s_appMenuItem = nullptr; static NSMenuItem* s_appMenuItem = nullptr;
extern void SetAppMenu (NSString* appName, IAvnAppMenu* menu) extern void SetAppMenu (NSString* appName, IAvnMenu* menu)
{ {
s_appMenu = menu; s_appMenu = menu;
@ -294,7 +456,7 @@ extern void SetAppMenu (NSString* appName, IAvnAppMenu* menu)
} }
} }
extern IAvnAppMenu* GetAppMenu () extern IAvnMenu* GetAppMenu ()
{ {
return s_appMenu; return s_appMenu;
} }

14
native/Avalonia.Native/src/OSX/platformthreading.mm

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#include "common.h" #include "common.h"
class PlatformThreadingInterface; class PlatformThreadingInterface;
@ -57,9 +54,11 @@ private:
{ {
public: public:
FORWARD_IUNKNOWN() FORWARD_IUNKNOWN()
bool Running = false; bool Running = false;
bool Cancelled = false; bool Cancelled = false;
virtual void Cancel()
virtual void Cancel() override
{ {
Cancelled = true; Cancelled = true;
if(Running) if(Running)
@ -157,11 +156,14 @@ NSArray<NSString*>* _modes;
-(void) perform -(void) perform
{ {
ComPtr<IAvnSignaledCallback> cb;
@synchronized (self) { @synchronized (self) {
_signaled = false; _signaled = false;
if(_parent != NULL && _parent->SignaledCallback != NULL) if(_parent != NULL)
_parent->SignaledCallback->Signaled(0, false); cb = _parent->SignaledCallback;
} }
if(cb != nullptr)
cb->Signaled(0, false);
} }
-(void) setParent:(PlatformThreadingInterface *)parent -(void) setParent:(PlatformThreadingInterface *)parent

284
native/Avalonia.Native/src/OSX/rendertarget.mm

@ -0,0 +1,284 @@
#include "common.h"
#include "rendertarget.h"
#import <IOSurface/IOSurface.h>
#import <IOSurface/IOSurfaceObjC.h>
#include <OpenGL/CGLIOSurface.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/glext.h>
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
@interface IOSurfaceHolder : NSObject
@end
@implementation IOSurfaceHolder
{
@public IOSurfaceRef surface;
@public AvnPixelSize size;
@public float scale;
ComPtr<IAvnGlContext> _context;
GLuint _framebuffer, _texture, _renderbuffer;
}
- (IOSurfaceHolder*) initWithSize: (AvnPixelSize) size
withScale: (float)scale
withOpenGlContext: (IAvnGlContext*) context
{
long bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.Width * 4);
long allocSize = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.Height * bytesPerRow);
NSDictionary* options = @{
(id)kIOSurfaceWidth: @(size.Width),
(id)kIOSurfaceHeight: @(size.Height),
(id)kIOSurfacePixelFormat: @((uint)'BGRA'),
(id)kIOSurfaceBytesPerElement: @(4),
(id)kIOSurfaceBytesPerRow: @(bytesPerRow),
(id)kIOSurfaceAllocSize: @(allocSize),
//(id)kIOSurfaceCacheMode: @(kIOMapWriteCombineCache),
(id)kIOSurfaceElementWidth: @(1),
(id)kIOSurfaceElementHeight: @(1)
};
surface = IOSurfaceCreate((CFDictionaryRef)options);
self->scale = scale;
self->size = size;
self->_context = context;
return self;
}
-(HRESULT) prepareForGlRender
{
if(_context == nil)
return E_FAIL;
if(CGLGetCurrentContext() != _context->GetNativeHandle())
return E_FAIL;
if(_framebuffer == 0)
glGenFramebuffersEXT(1, &_framebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _framebuffer);
if(_texture == 0)
{
glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, _texture);
CGLError res = CGLTexImageIOSurface2D((CGLContextObj)_context->GetNativeHandle(),
GL_TEXTURE_RECTANGLE_EXT, GL_RGBA8,
size.Width, size.Height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, surface, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
if(res != 0)
{
glDeleteTextures(1, &_texture);
_texture = 0;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return E_FAIL;
}
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, _texture, 0);
}
if(_renderbuffer == 0)
{
glGenRenderbuffers(1, &_renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.Width, size.Height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderbuffer);
}
return S_OK;
}
-(void) finishDraw
{
ComPtr<IUnknown> release;
_context->MakeCurrent(release.getPPV());
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glFlush();
}
-(void) dealloc
{
if(_framebuffer != 0)
{
ComPtr<IUnknown> release;
_context->MakeCurrent(release.getPPV());
glDeleteFramebuffers(1, &_framebuffer);
if(_texture != 0)
glDeleteTextures(1, &_texture);
if(_renderbuffer != 0)
glDeleteRenderbuffers(1, &_renderbuffer);
}
IOSurfaceDecrementUseCount(surface);
}
@end
static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* target);
@implementation IOSurfaceRenderTarget
{
CALayer* _layer;
@public IOSurfaceHolder* surface;
@public NSObject* lock;
ComPtr<IAvnGlContext> _glContext;
}
- (IOSurfaceRenderTarget*) initWithOpenGlContext: (IAvnGlContext*) context;
{
self = [super init];
_glContext = context;
lock = [NSObject new];
surface = nil;
[self resize:{1,1} withScale: 1];
return self;
}
- (AvnPixelSize) pixelSize {
return {1, 1};
}
- (CALayer *)layer {
return _layer;
}
- (void)resize:(AvnPixelSize)size withScale: (float) scale;{
@synchronized (lock) {
if(surface == nil
|| surface->size.Width != size.Width
|| surface->size.Height != size.Height
|| surface->scale != scale)
surface = [[IOSurfaceHolder alloc] initWithSize:size withScale:scale withOpenGlContext:_glContext.getRaw()];
}
}
- (void)updateLayer {
if ([NSThread isMainThread])
{
@synchronized (lock) {
if(_layer == nil)
return;
[_layer setContents: nil];
if(surface != nil)
{
[_layer setContentsScale: surface->scale];
[_layer setContents: (__bridge IOSurface*) surface->surface];
}
}
}
else
dispatch_async(dispatch_get_main_queue(), ^{
[self updateLayer];
});
}
- (void) setNewLayer:(CALayer *)layer {
_layer = layer;
[self updateLayer];
}
- (HRESULT)setSwFrame:(AvnFramebuffer *)fb {
@synchronized (lock) {
if(fb->PixelFormat == AvnPixelFormat::kAvnRgb565)
return E_INVALIDARG;
if(surface == nil)
return E_FAIL;
IOSurfaceRef surf = surface->surface;
if(IOSurfaceLock(surf, 0, nil))
return E_FAIL;
size_t w = MIN(fb->Width, IOSurfaceGetWidth(surf));
size_t h = MIN(fb->Height, IOSurfaceGetHeight(surf));
size_t wbytes = w*4;
size_t sstride = IOSurfaceGetBytesPerRow(surf);
size_t fstride = fb->Stride;
char*pSurface = (char*)IOSurfaceGetBaseAddress(surf);
char*pFb = (char*)fb->Data;
for(size_t y = 0; y < h; y++)
{
memcpy(pSurface + y*sstride, pFb + y*fstride, wbytes);
}
IOSurfaceUnlock(surf, 0, nil);
[self updateLayer];
return S_OK;
}
}
-(IAvnGlSurfaceRenderTarget*) createSurfaceRenderTarget
{
return CreateGlRenderTarget(self);
}
@end
class AvnGlRenderingSession : public ComSingleObject<IAvnGlSurfaceRenderingSession, &IID_IAvnGlSurfaceRenderingSession>
{
ComPtr<IUnknown> _releaseContext;
IOSurfaceRenderTarget* _target;
IOSurfaceHolder* _surface;
public:
FORWARD_IUNKNOWN()
AvnGlRenderingSession(IOSurfaceRenderTarget* target, ComPtr<IUnknown> releaseContext)
{
_target = target;
// This happens in a synchronized block set up by AvnRenderTarget, so we take the current surface for this
// particular render session
_surface = _target->surface;
_releaseContext = releaseContext;
}
virtual HRESULT GetPixelSize(AvnPixelSize* ret) override
{
if(!_surface)
return E_FAIL;
*ret = _surface->size;
return S_OK;
}
virtual HRESULT GetScaling(double* ret) override
{
if(!_surface)
return E_FAIL;
*ret = _surface->scale;
return S_OK;
}
virtual ~AvnGlRenderingSession()
{
[_surface finishDraw];
[_target updateLayer];
_releaseContext = nil;
}
};
class AvnGlRenderTarget : public ComSingleObject<IAvnGlSurfaceRenderTarget, &IID_IAvnGlSurfaceRenderTarget>
{
IOSurfaceRenderTarget* _target;
public:
FORWARD_IUNKNOWN()
AvnGlRenderTarget(IOSurfaceRenderTarget* target)
{
_target = target;
}
virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret) override
{
ComPtr<IUnknown> releaseContext;
@synchronized (_target->lock) {
if(_target->surface == nil)
return E_FAIL;
_target->_glContext->MakeCurrent(releaseContext.getPPV());
HRESULT res = [_target->surface prepareForGlRender];
if(res)
return res;
*ret = new AvnGlRenderingSession(_target, releaseContext);
return S_OK;
}
}
};
static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* target)
{
return new AvnGlRenderTarget(target);
}

11
native/Avalonia.Native/src/OSX/window.h

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#ifndef window_h #ifndef window_h
#define window_h #define window_h
@ -12,6 +9,7 @@ class WindowBaseImpl;
-(AvnPoint) translateLocalPoint:(AvnPoint)pt; -(AvnPoint) translateLocalPoint:(AvnPoint)pt;
-(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose; -(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose;
-(void) onClosed; -(void) onClosed;
-(AvnPixelSize) getPixelSize;
@end @end
@interface AvnWindow : NSWindow <NSWindowDelegate> @interface AvnWindow : NSWindow <NSWindowDelegate>
@ -21,7 +19,12 @@ class WindowBaseImpl;
-(void) pollModalSession: (NSModalSession _Nonnull) session; -(void) pollModalSession: (NSModalSession _Nonnull) session;
-(void) restoreParentWindow; -(void) restoreParentWindow;
-(bool) shouldTryToHandleEvents; -(bool) shouldTryToHandleEvents;
-(void) applyMenu:(NSMenu *)menu; -(bool) isModal;
-(void) setModal: (bool) isModal;
-(void) showAppMenuOnly;
-(void) showWindowMenuWithAppMenu;
-(void) applyMenu:(NSMenu* _Nullable)menu;
-(double) getScaling;
@end @end
struct INSWindowHolder struct INSWindowHolder

576
native/Avalonia.Native/src/OSX/window.mm

@ -1,50 +1,12 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#include "common.h" #include "common.h"
#include "window.h" #include "window.h"
#include "KeyTransform.h" #include "KeyTransform.h"
#include "cursor.h" #include "cursor.h"
#include "menu.h" #include "menu.h"
#include <OpenGL/gl.h> #include <OpenGL/gl.h>
#include "rendertarget.h"
class SoftwareDrawingOperation
{
public:
void* Data = 0;
AvnFramebuffer Desc;
void Alloc(NSView* view)
{
auto logicalSize = [view frame].size;
auto pixelSize = [view convertSizeToBacking:logicalSize];
int w = pixelSize.width;
int h = pixelSize.height;
int stride = w * 4;
Data = malloc(h * stride);
Desc = {
.Data = Data,
.Stride = stride,
.Width = w,
.Height = h,
.PixelFormat = kAvnRgba8888,
.Dpi = AvnVector { .X = w / logicalSize.width * 96, .Y = h / logicalSize.height * 96}
};
}
void Dealloc()
{
if(Data != NULL)
{
free(Data);
Data = NULL;
}
}
~SoftwareDrawingOperation()
{
Dealloc();
}
};
class WindowBaseImpl : public virtual ComSingleObject<IAvnWindowBase, &IID_IAvnWindowBase>, public INSWindowHolder class WindowBaseImpl : public virtual ComSingleObject<IAvnWindowBase, &IID_IAvnWindowBase>, public INSWindowHolder
{ {
@ -61,15 +23,20 @@ public:
AvnView* View; AvnView* View;
AvnWindow* Window; AvnWindow* Window;
ComPtr<IAvnWindowBaseEvents> BaseEvents; ComPtr<IAvnWindowBaseEvents> BaseEvents;
SoftwareDrawingOperation CurrentSwDrawingOperation; ComPtr<IAvnGlContext> _glContext;
NSObject<IRenderTarget>* renderTarget;
AvnPoint lastPositionSet; AvnPoint lastPositionSet;
NSString* _lastTitle; NSString* _lastTitle;
IAvnAppMenu* _mainMenu; IAvnMenu* _mainMenu;
bool _shown;
WindowBaseImpl(IAvnWindowBaseEvents* events) WindowBaseImpl(IAvnWindowBaseEvents* events, IAvnGlContext* gl)
{ {
_shown = false;
_mainMenu = nullptr; _mainMenu = nullptr;
BaseEvents = events; BaseEvents = events;
_glContext = gl;
renderTarget = [[IOSurfaceRenderTarget alloc] initWithOpenGlContext: gl];
View = [[AvnView alloc] initWithParent:this]; View = [[AvnView alloc] initWithParent:this];
Window = [[AvnWindow alloc] initWithParent:this]; Window = [[AvnWindow alloc] initWithParent:this];
@ -147,7 +114,8 @@ public:
[NSApp activateIgnoringOtherApps:YES]; [NSApp activateIgnoringOtherApps:YES];
[Window setTitle:_lastTitle]; [Window setTitle:_lastTitle];
[Window setTitleVisibility:NSWindowTitleVisible];
_shown = true;
return S_OK; return S_OK;
} }
@ -195,7 +163,11 @@ public:
{ {
@autoreleasepool @autoreleasepool
{ {
[Window close]; if (Window != nullptr)
{
[Window close];
}
return S_OK; return S_OK;
} }
} }
@ -262,7 +234,7 @@ public:
} }
} }
virtual HRESULT SetMainMenu(IAvnAppMenu* menu) override virtual HRESULT SetMainMenu(IAvnMenu* menu) override
{ {
_mainMenu = menu; _mainMenu = menu;
@ -272,37 +244,14 @@ public:
[Window applyMenu:nsmenu]; [Window applyMenu:nsmenu];
return S_OK; if ([Window isKeyWindow])
}
virtual HRESULT ObtainMainMenu(IAvnAppMenu** ret) override
{
if(ret == nullptr)
{ {
return E_POINTER; [Window showWindowMenuWithAppMenu];
} }
*ret = _mainMenu;
return S_OK; return S_OK;
} }
virtual bool TryLock() override
{
@autoreleasepool
{
return [View lockFocusIfCanDraw] == YES;
}
}
virtual void Unlock() override
{
@autoreleasepool
{
[View unlockFocus];
}
}
virtual HRESULT BeginMoveDrag () override virtual HRESULT BeginMoveDrag () override
{ {
@autoreleasepool @autoreleasepool
@ -397,16 +346,6 @@ public:
return S_OK; return S_OK;
} }
virtual HRESULT GetSoftwareFramebuffer(AvnFramebuffer*ret) override
{
if(![[NSThread currentThread] isMainThread])
return E_FAIL;
if(CurrentSwDrawingOperation.Data == NULL)
CurrentSwDrawingOperation.Alloc(View);
*ret = CurrentSwDrawingOperation.Desc;
return S_OK;
}
virtual HRESULT SetCursor(IAvnCursor* cursor) override virtual HRESULT SetCursor(IAvnCursor* cursor) override
{ {
@autoreleasepool @autoreleasepool
@ -440,8 +379,8 @@ public:
{ {
if(View == NULL) if(View == NULL)
return E_FAIL; return E_FAIL;
*ppv = ::CreateGlRenderTarget(Window, View); *ppv = [renderTarget createSurfaceRenderTarget];
return S_OK; return *ppv == nil ? E_FAIL : S_OK;
} }
protected: protected:
@ -455,6 +394,7 @@ protected:
[Window setStyleMask:GetStyle()]; [Window setStyleMask:GetStyle()];
} }
public:
virtual void OnResized () virtual void OnResized ()
{ {
@ -465,7 +405,7 @@ class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, pub
{ {
private: private:
bool _canResize = true; bool _canResize = true;
bool _hasDecorations = true; SystemDecorations _hasDecorations = SystemDecorationsFull;
CGRect _lastUndecoratedFrame; CGRect _lastUndecoratedFrame;
AvnWindowState _lastWindowState; AvnWindowState _lastWindowState;
@ -479,11 +419,13 @@ private:
} }
ComPtr<IAvnWindowEvents> WindowEvents; ComPtr<IAvnWindowEvents> WindowEvents;
WindowImpl(IAvnWindowEvents* events) : WindowBaseImpl(events) WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl)
{ {
_lastWindowState = Normal;
WindowEvents = events; WindowEvents = events;
[Window setCanBecomeKeyAndMain]; [Window setCanBecomeKeyAndMain];
[Window disableCursorRects]; [Window disableCursorRects];
[Window setTabbingMode:NSWindowTabbingModeDisallowed];
} }
virtual HRESULT Show () override virtual HRESULT Show () override
@ -492,9 +434,12 @@ private:
{ {
if([Window parentWindow] != nil) if([Window parentWindow] != nil)
[[Window parentWindow] removeChildWindow:Window]; [[Window parentWindow] removeChildWindow:Window];
[Window setModal:FALSE];
WindowBaseImpl::Show(); WindowBaseImpl::Show();
return SetWindowState(Normal); return SetWindowState(_lastWindowState);
} }
} }
@ -509,6 +454,8 @@ private:
if(cparent == nullptr) if(cparent == nullptr)
return E_INVALIDARG; return E_INVALIDARG;
[Window setModal:TRUE];
[cparent->Window addChildWindow:Window ordered:NSWindowAbove]; [cparent->Window addChildWindow:Window ordered:NSWindowAbove];
WindowBaseImpl::Show(); WindowBaseImpl::Show();
@ -530,23 +477,26 @@ private:
bool IsZoomed () bool IsZoomed ()
{ {
return _hasDecorations ? [Window isZoomed] : UndecoratedIsMaximized(); return _hasDecorations != SystemDecorationsNone ? [Window isZoomed] : UndecoratedIsMaximized();
} }
void DoZoom() void DoZoom()
{ {
if (_hasDecorations) switch (_hasDecorations)
{ {
[Window performZoom:Window]; case SystemDecorationsNone:
} if (!UndecoratedIsMaximized())
else {
{ _lastUndecoratedFrame = [Window frame];
if (!UndecoratedIsMaximized()) }
{
_lastUndecoratedFrame = [Window frame]; [Window zoom:Window];
} break;
[Window zoom:Window]; case SystemDecorationsBorderOnly:
case SystemDecorationsFull:
[Window performZoom:Window];
break;
} }
} }
@ -560,13 +510,35 @@ private:
} }
} }
virtual HRESULT SetHasDecorations(bool value) override virtual HRESULT SetHasDecorations(SystemDecorations value) override
{ {
@autoreleasepool @autoreleasepool
{ {
_hasDecorations = value; _hasDecorations = value;
UpdateStyle(); UpdateStyle();
switch (_hasDecorations)
{
case SystemDecorationsNone:
[Window setHasShadow:NO];
[Window setTitleVisibility:NSWindowTitleHidden];
[Window setTitlebarAppearsTransparent:YES];
break;
case SystemDecorationsBorderOnly:
[Window setHasShadow:YES];
[Window setTitleVisibility:NSWindowTitleHidden];
[Window setTitlebarAppearsTransparent:YES];
break;
case SystemDecorationsFull:
[Window setHasShadow:YES];
[Window setTitleVisibility:NSWindowTitleVisible];
[Window setTitlebarAppearsTransparent:NO];
[Window setTitle:_lastTitle];
break;
}
return S_OK; return S_OK;
} }
} }
@ -577,7 +549,6 @@ private:
{ {
_lastTitle = [NSString stringWithUTF8String:(const char*)utf8title]; _lastTitle = [NSString stringWithUTF8String:(const char*)utf8title];
[Window setTitle:_lastTitle]; [Window setTitle:_lastTitle];
[Window setTitleVisibility:NSWindowTitleVisible];
return S_OK; return S_OK;
} }
@ -645,64 +616,86 @@ private:
{ {
_lastWindowState = state; _lastWindowState = state;
switch (state) { if(_shown)
case Maximized: {
lastPositionSet.X = 0; switch (state) {
lastPositionSet.Y = 0; case Maximized:
lastPositionSet.X = 0;
if([Window isMiniaturized]) lastPositionSet.Y = 0;
{
[Window deminiaturize:Window]; if([Window isMiniaturized])
} {
[Window deminiaturize:Window];
if(!IsZoomed()) }
{
DoZoom(); if(!IsZoomed())
} {
break; DoZoom();
}
case Minimized: break;
[Window miniaturize:Window];
break; case Minimized:
[Window miniaturize:Window];
default: break;
if([Window isMiniaturized])
{ default:
[Window deminiaturize:Window]; if([Window isMiniaturized])
} {
[Window deminiaturize:Window];
if(IsZoomed()) }
{
DoZoom(); if(IsZoomed())
} {
break; DoZoom();
}
break;
}
} }
return S_OK; return S_OK;
} }
} }
protected:
virtual void OnResized () override virtual void OnResized () override
{ {
auto windowState = [Window isMiniaturized] ? Minimized if(_shown)
: (IsZoomed() ? Maximized : Normal);
if (windowState != _lastWindowState)
{ {
_lastWindowState = windowState; auto windowState = [Window isMiniaturized] ? Minimized
: (IsZoomed() ? Maximized : Normal);
WindowEvents->WindowStateChanged(windowState); if (windowState != _lastWindowState)
{
_lastWindowState = windowState;
WindowEvents->WindowStateChanged(windowState);
}
} }
} }
protected:
virtual NSWindowStyleMask GetStyle() override virtual NSWindowStyleMask GetStyle() override
{ {
unsigned long s = NSWindowStyleMaskBorderless; unsigned long s = NSWindowStyleMaskBorderless;
if(_hasDecorations)
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; switch (_hasDecorations)
if(_canResize) {
s = s | NSWindowStyleMaskResizable; case SystemDecorationsNone:
break;
case SystemDecorationsBorderOnly:
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView;
break;
case SystemDecorationsFull:
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskBorderless;
if(_canResize)
{
s = s | NSWindowStyleMaskResizable;
}
break;
}
return s; return s;
} }
}; };
@ -719,15 +712,21 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed, _isMouseOver; bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed, _isMouseOver;
NSEvent* _lastMouseDownEvent; NSEvent* _lastMouseDownEvent;
bool _lastKeyHandled; bool _lastKeyHandled;
AvnPixelSize _lastPixelSize;
NSObject<IRenderTarget>* _renderTarget;
} }
- (void)dealloc - (void)onClosed
{ {
@synchronized (self)
{
_parent = nullptr;
}
} }
- (void)onClosed -(AvnPixelSize) getPixelSize
{ {
_parent = NULL; return _lastPixelSize;
} }
- (NSEvent*) lastMouseDownEvent - (NSEvent*) lastMouseDownEvent
@ -735,16 +734,43 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
return _lastMouseDownEvent; return _lastMouseDownEvent;
} }
- (void) updateRenderTarget
{
[_renderTarget resize:_lastPixelSize withScale: [[self window] backingScaleFactor]];
[self setNeedsDisplayInRect:[self frame]];
}
-(AvnView*) initWithParent: (WindowBaseImpl*) parent -(AvnView*) initWithParent: (WindowBaseImpl*) parent
{ {
self = [super init]; self = [super init];
[self setWantsBestResolutionOpenGLSurface:true]; _renderTarget = parent->renderTarget;
[self setWantsLayer:YES]; [self setWantsLayer:YES];
[self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize];
_parent = parent; _parent = parent;
_area = nullptr; _area = nullptr;
_lastPixelSize.Height = 100;
_lastPixelSize.Width = 100;
return self; return self;
} }
- (BOOL)isFlipped
{
return YES;
}
- (BOOL)wantsUpdateLayer
{
return YES;
}
- (void)setLayer:(CALayer *)layer
{
[_renderTarget setNewLayer: layer];
[super setLayer: layer];
}
- (BOOL)isOpaque - (BOOL)isOpaque
{ {
return YES; return YES;
@ -774,7 +800,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[self removeTrackingArea:_area]; [self removeTrackingArea:_area];
_area = nullptr; _area = nullptr;
} }
if (_parent == nullptr)
{
return;
}
NSRect rect = NSZeroRect; NSRect rect = NSZeroRect;
rect.size = newSize; rect.size = newSize;
@ -783,81 +814,36 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[self addTrackingArea:_area]; [self addTrackingArea:_area];
_parent->UpdateCursor(); _parent->UpdateCursor();
auto fsize = [self convertSizeToBacking: [self frame].size];
_lastPixelSize.Width = (int)fsize.width;
_lastPixelSize.Height = (int)fsize.height;
[self updateRenderTarget];
_parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}); _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
} }
- (void) drawFb: (AvnFramebuffer*) fb
{
auto colorSpace = CGColorSpaceCreateDeviceRGB();
auto dataProvider = CGDataProviderCreateWithData(NULL, fb->Data, fb->Height*fb->Stride, NULL);
auto image = CGImageCreate(fb->Width, fb->Height, 8, 32, fb->Stride, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast,
dataProvider, nullptr, false, kCGRenderingIntentDefault);
auto ctx = [NSGraphicsContext currentContext];
[ctx saveGraphicsState];
auto cgc = [ctx CGContext];
CGContextDrawImage(cgc, CGRect{0,0, fb->Width/(fb->Dpi.X/96), fb->Height/(fb->Dpi.Y/96)}, image);
CGImageRelease(image);
CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(dataProvider);
[ctx restoreGraphicsState];
} - (void)updateLayer
- (void)drawRect:(NSRect)dirtyRect
{ {
_parent->BaseEvents->RunRenderPriorityJobs(); if (_parent == nullptr)
@synchronized (self) { {
if(_swRenderedFrame != NULL) return;
{
[self drawFb: &_swRenderedFrameBuffer];
return;
}
} }
auto swOp = &_parent->CurrentSwDrawingOperation; _parent->BaseEvents->RunRenderPriorityJobs();
_parent->BaseEvents->Paint(); _parent->BaseEvents->Paint();
if(swOp->Data != NULL)
[self drawFb: &swOp->Desc];
swOp->Dealloc();
return;
} }
-(void) redrawSelf - (void)drawRect:(NSRect)dirtyRect
{ {
@autoreleasepool return;
{
@synchronized(self)
{
if(!_queuedDisplayFromThread)
return;
_queuedDisplayFromThread = false;
}
[self setNeedsDisplayInRect:[self frame]];
[self display];
}
} }
-(void) setSwRenderedFrame: (AvnFramebuffer*) fb dispose: (IUnknown*) dispose -(void) setSwRenderedFrame: (AvnFramebuffer*) fb dispose: (IUnknown*) dispose
{ {
@autoreleasepool { @autoreleasepool {
@synchronized (self) { [_renderTarget setSwFrame:fb];
_swRenderedFrame = dispose; dispose->Release();
_swRenderedFrameBuffer = *fb;
if(!_queuedDisplayFromThread)
{
_queuedDisplayFromThread = true;
[self performSelector:@selector(redrawSelf) onThread:[NSThread mainThread] withObject:NULL waitUntilDone:false modes: AllLoopModes];
}
}
} }
} }
@ -879,7 +865,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
- (void) viewDidChangeBackingProperties - (void) viewDidChangeBackingProperties
{ {
auto fsize = [self convertSizeToBacking: [self frame].size];
_lastPixelSize.Width = (int)fsize.width;
_lastPixelSize.Height = (int)fsize.height;
[self updateRenderTarget];
_parent->BaseEvents->ScalingChanged([_parent->Window backingScaleFactor]); _parent->BaseEvents->ScalingChanged([_parent->Window backingScaleFactor]);
[super viewDidChangeBackingProperties]; [super viewDidChangeBackingProperties];
} }
@ -1159,8 +1150,14 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
ComPtr<WindowBaseImpl> _parent; ComPtr<WindowBaseImpl> _parent;
bool _canBecomeKeyAndMain; bool _canBecomeKeyAndMain;
bool _closed; bool _closed;
NSMenu* _menu; bool _isModal;
bool _isAppMenuApplied; AvnMenu* _menu;
double _lastScaling;
}
-(double) getScaling
{
return _lastScaling;
} }
+(void)closeAll +(void)closeAll
@ -1174,10 +1171,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
} }
} }
- (void)dealloc
{
}
- (void)pollModalSession:(nonnull NSModalSession)session - (void)pollModalSession:(nonnull NSModalSession)session
{ {
auto response = [NSApp runModalSession:session]; auto response = [NSApp runModalSession:session];
@ -1195,30 +1188,62 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
} }
} }
-(void) applyMenu:(NSMenu *)menu -(void) showWindowMenuWithAppMenu
{ {
if(menu == nullptr) if(_menu != nullptr)
{ {
menu = [NSMenu new]; auto appMenuItem = ::GetAppMenuItem();
if(appMenuItem != nullptr)
{
auto appMenu = [appMenuItem menu];
[appMenu removeItem:appMenuItem];
[_menu insertItem:appMenuItem atIndex:0];
[_menu setHasGlobalMenuItem:true];
}
[NSApp setMenu:_menu];
} }
}
-(void) showAppMenuOnly
{
auto appMenuItem = ::GetAppMenuItem();
_menu = menu; if(appMenuItem != nullptr)
if ([self isKeyWindow])
{ {
auto appMenu = ::GetAppMenuItem(); auto appMenu = ::GetAppMenu();
auto nativeAppMenu = dynamic_cast<AvnAppMenu*>(appMenu);
if(appMenu != nullptr) [[appMenuItem menu] removeItem:appMenuItem];
if(_menu != nullptr)
{ {
[[appMenu menu] removeItem:appMenu]; [_menu setHasGlobalMenuItem:false];
[_menu insertItem:appMenu atIndex:0];
_isAppMenuApplied = true;
} }
[NSApp setMenu:menu]; [nativeAppMenu->GetNative() addItem:appMenuItem];
[NSApp setMenu:nativeAppMenu->GetNative()];
}
else
{
[NSApp setMenu:nullptr];
}
}
-(void) applyMenu:(AvnMenu *)menu
{
if(menu == nullptr)
{
menu = [AvnMenu new];
} }
_menu = menu;
} }
-(void) setCanBecomeKeyAndMain -(void) setCanBecomeKeyAndMain
@ -1232,6 +1257,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[self setReleasedWhenClosed:false]; [self setReleasedWhenClosed:false];
_parent = parent; _parent = parent;
[self setDelegate:self]; [self setDelegate:self];
_closed = false;
_lastScaling = [self backingScaleFactor];
[self setOpaque:NO];
[self setBackgroundColor: [NSColor clearColor]];
[self invalidateShadow];
return self; return self;
} }
@ -1247,6 +1278,11 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
return true; return true;
} }
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
{
_lastScaling = [self backingScaleFactor];
}
- (void)windowWillClose:(NSNotification *)notification - (void)windowWillClose:(NSNotification *)notification
{ {
_closed = true; _closed = true;
@ -1257,9 +1293,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[self restoreParentWindow]; [self restoreParentWindow];
parent->BaseEvents->Closed(); parent->BaseEvents->Closed();
[parent->View onClosed]; [parent->View onClosed];
dispatch_async(dispatch_get_main_queue(), ^{
[self setContentView: nil];
});
} }
} }
@ -1296,11 +1329,25 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
auto ch = objc_cast<AvnWindow>(uch); auto ch = objc_cast<AvnWindow>(uch);
if(ch == nil) if(ch == nil)
continue; continue;
if(![ch isModal])
continue;
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
-(bool) isModal
{
return _isModal;
}
-(void) setModal: (bool) isModal
{
_isModal = isModal;
}
-(void)makeKeyWindow -(void)makeKeyWindow
{ {
if([self activateAppropriateChild: true]) if([self activateAppropriateChild: true])
@ -1313,23 +1360,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
{ {
if([self activateAppropriateChild: true]) if([self activateAppropriateChild: true])
{ {
if(_menu == nullptr) [self showWindowMenuWithAppMenu];
{
_menu = [NSMenu new];
}
auto appMenu = ::GetAppMenuItem();
if(appMenu != nullptr)
{
[[appMenu menu] removeItem:appMenu];
[_menu insertItem:appMenu atIndex:0];
_isAppMenuApplied = true;
}
[NSApp setMenu:_menu];
_parent->BaseEvents->Activated(); _parent->BaseEvents->Activated();
[super becomeKeyWindow]; [super becomeKeyWindow];
@ -1366,6 +1397,11 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
} }
} }
- (void)windowDidResize:(NSNotification *)notification
{
_parent->OnResized();
}
- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
{ {
return true; return true;
@ -1376,26 +1412,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
if(_parent) if(_parent)
_parent->BaseEvents->Deactivated(); _parent->BaseEvents->Deactivated();
auto appMenuItem = ::GetAppMenuItem(); [self showAppMenuOnly];
if(appMenuItem != nullptr)
{
auto appMenu = ::GetAppMenu();
auto nativeAppMenu = dynamic_cast<AvnAppMenu*>(appMenu);
[[appMenuItem menu] removeItem:appMenuItem];
[nativeAppMenu->GetNative() addItem:appMenuItem];
[NSApp setMenu:nativeAppMenu->GetNative()];
}
else
{
[NSApp setMenu:nullptr];
}
// remove window menu items from appmenu?
[super resignKeyWindow]; [super resignKeyWindow];
} }
@ -1406,18 +1423,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
_parent->GetPosition(&position); _parent->GetPosition(&position);
_parent->BaseEvents->PositionChanged(position); _parent->BaseEvents->PositionChanged(position);
} }
// TODO this breaks resizing.
/*- (void)windowDidResize:(NSNotification *)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
if(parent != nullptr)
{
parent->WindowStateChanged();
}
}*/
@end @end
class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup
@ -1429,7 +1434,7 @@ private:
END_INTERFACE_MAP() END_INTERFACE_MAP()
virtual ~PopupImpl(){} virtual ~PopupImpl(){}
ComPtr<IAvnWindowEvents> WindowEvents; ComPtr<IAvnWindowEvents> WindowEvents;
PopupImpl(IAvnWindowEvents* events) : WindowBaseImpl(events) PopupImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl)
{ {
WindowEvents = events; WindowEvents = events;
[Window setLevel:NSPopUpMenuWindowLevel]; [Window setLevel:NSPopUpMenuWindowLevel];
@ -1448,25 +1453,26 @@ protected:
[Window setContentSize:NSSize{x, y}]; [Window setContentSize:NSSize{x, y}];
[Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))]; [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))];
return S_OK; return S_OK;
} }
} }
}; };
extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events) extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events, IAvnGlContext* gl)
{ {
@autoreleasepool @autoreleasepool
{ {
IAvnPopup* ptr = dynamic_cast<IAvnPopup*>(new PopupImpl(events)); IAvnPopup* ptr = dynamic_cast<IAvnPopup*>(new PopupImpl(events, gl));
return ptr; return ptr;
} }
} }
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events) extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl)
{ {
@autoreleasepool @autoreleasepool
{ {
IAvnWindow* ptr = (IAvnWindow*)new WindowImpl(events); IAvnWindow* ptr = (IAvnWindow*)new WindowImpl(events, gl);
return ptr; return ptr;
} }
} }

165
nukebuild/Build.cs

@ -13,6 +13,7 @@ using Nuke.Common.Tooling;
using Nuke.Common.Tools.DotNet; using Nuke.Common.Tools.DotNet;
using Nuke.Common.Tools.MSBuild; using Nuke.Common.Tools.MSBuild;
using Nuke.Common.Utilities; using Nuke.Common.Utilities;
using Nuke.Common.Utilities.Collections;
using static Nuke.Common.EnvironmentInfo; using static Nuke.Common.EnvironmentInfo;
using static Nuke.Common.IO.FileSystemTasks; using static Nuke.Common.IO.FileSystemTasks;
using static Nuke.Common.IO.PathConstruction; using static Nuke.Common.IO.PathConstruction;
@ -26,11 +27,13 @@ using static Nuke.Common.Tools.VSWhere.VSWhereTasks;
running and debugging a particular target (optionally without deps) would be way easier running and debugging a particular target (optionally without deps) would be way easier
ReSharper/Rider - https://plugins.jetbrains.com/plugin/10803-nuke-support ReSharper/Rider - https://plugins.jetbrains.com/plugin/10803-nuke-support
VSCode - https://marketplace.visualstudio.com/items?itemName=nuke.support VSCode - https://marketplace.visualstudio.com/items?itemName=nuke.support
*/ */
partial class Build : NukeBuild partial class Build : NukeBuild
{ {
[Solution("Avalonia.sln")] readonly Solution Solution;
static Lazy<string> MsBuildExe = new Lazy<string>(() => static Lazy<string> MsBuildExe = new Lazy<string>(() =>
{ {
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@ -54,7 +57,7 @@ partial class Build : NukeBuild
protected override void OnBuildInitialized() protected override void OnBuildInitialized()
{ {
Parameters = new BuildParameters(this); Parameters = new BuildParameters(this);
Information("Building version {0} of Avalonia ({1}) using version {2} of Nuke.", Information("Building version {0} of Avalonia ({1}) using version {2} of Nuke.",
Parameters.Version, Parameters.Version,
Parameters.Configuration, Parameters.Configuration,
typeof(NukeBuild).Assembly.GetName().Version.ToString()); typeof(NukeBuild).Assembly.GetName().Version.ToString());
@ -93,29 +96,24 @@ partial class Build : NukeBuild
string projectFile, string projectFile,
Configure<MSBuildSettings> configurator = null) Configure<MSBuildSettings> configurator = null)
{ {
return MSBuild(projectFile, c => return MSBuild(c => c
{ .SetProjectFile(projectFile)
// This is required for VS2019 image on Azure Pipelines // This is required for VS2019 image on Azure Pipelines
if (Parameters.IsRunningOnWindows && Parameters.IsRunningOnAzure) .When(Parameters.IsRunningOnWindows &&
{ Parameters.IsRunningOnAzure, c => c
var javaSdk = Environment.GetEnvironmentVariable("JAVA_HOME_8_X64"); .AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_8_X64")))
if (javaSdk != null) .AddProperty("PackageVersion", Parameters.Version)
c = c.AddProperty("JavaSdkDirectory", javaSdk); .AddProperty("iOSRoslynPathHackRequired", true)
} .SetToolPath(MsBuildExe.Value)
.SetConfiguration(Parameters.Configuration)
c = c.AddProperty("PackageVersion", Parameters.Version) .SetVerbosity(MSBuildVerbosity.Minimal)
.AddProperty("iOSRoslynPathHackRequired", "true") .Apply(configurator));
.SetToolPath(MsBuildExe.Value)
.SetConfiguration(Parameters.Configuration)
.SetVerbosity(MSBuildVerbosity.Minimal);
c = configurator?.Invoke(c) ?? c;
return c;
});
} }
Target Clean => _ => _.Executes(() => Target Clean => _ => _.Executes(() =>
{ {
DeleteDirectories(Parameters.BuildDirs); Parameters.BuildDirs.ForEach(DeleteDirectory);
EnsureCleanDirectories(Parameters.BuildDirs); Parameters.BuildDirs.ForEach(EnsureCleanDirectory);
EnsureCleanDirectory(Parameters.ArtifactsDir); EnsureCleanDirectory(Parameters.ArtifactsDir);
EnsureCleanDirectory(Parameters.NugetIntermediateRoot); EnsureCleanDirectory(Parameters.NugetIntermediateRoot);
EnsureCleanDirectory(Parameters.NugetRoot); EnsureCleanDirectory(Parameters.NugetRoot);
@ -134,96 +132,84 @@ partial class Build : NukeBuild
); );
else else
DotNetBuild(Parameters.MSBuildSolution, c => c DotNetBuild(c => c
.SetProjectFile(Parameters.MSBuildSolution)
.AddProperty("PackageVersion", Parameters.Version) .AddProperty("PackageVersion", Parameters.Version)
.SetConfiguration(Parameters.Configuration) .SetConfiguration(Parameters.Configuration)
); );
}); });
void RunCoreTest(string project) void RunCoreTest(string projectName)
{ {
if(!project.EndsWith(".csproj")) Information($"Running tests from {projectName}");
project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj"); var project = Solution.GetProject(projectName).NotNull("project != null");
Information("Running tests from " + project);
XDocument xdoc; foreach (var fw in project.GetTargetFrameworks())
using (var s = File.OpenRead(project))
xdoc = XDocument.Load(s);
List<string> frameworks = null;
var targets = xdoc.Root.Descendants("TargetFrameworks").FirstOrDefault();
if (targets != null)
frameworks = targets.Value.Split(';').Where(f => !string.IsNullOrWhiteSpace(f)).ToList();
else
frameworks = new List<string> {xdoc.Root.Descendants("TargetFramework").First().Value};
foreach(var fw in frameworks)
{ {
if (fw.StartsWith("net4") if (fw.StartsWith("net4")
&& RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
&& Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1") && Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1")
{ {
Information($"Skipping {fw} tests on Linux - https://github.com/mono/mono/issues/13969"); Information($"Skipping {projectName} ({fw}) tests on Linux - https://github.com/mono/mono/issues/13969");
continue; continue;
} }
Information("Running for " + fw); Information($"Running for {projectName} ({fw}) ...");
DotNetTest(c =>
{ DotNetTest(c => c
c = c .SetProjectFile(project)
.SetProjectFile(project) .SetConfiguration(Parameters.Configuration)
.SetConfiguration(Parameters.Configuration) .SetFramework(fw)
.SetFramework(fw) .EnableNoBuild()
.EnableNoBuild() .EnableNoRestore()
.EnableNoRestore(); .When(Parameters.PublishTestResults, c => c
// NOTE: I can see that we could maybe add another extension method "Switch" or "If" to make this more convenient .SetLogger("trx")
if (Parameters.PublishTestResults) .SetResultsDirectory(Parameters.TestResultsRoot)));
c = c.SetLogger("trx").SetResultsDirectory(Parameters.TestResultsRoot);
return c;
});
} }
} }
Target RunCoreLibsTests => _ => _ Target RunCoreLibsTests => _ => _
.OnlyWhen(() => !Parameters.SkipTests) .OnlyWhenStatic(() => !Parameters.SkipTests)
.DependsOn(Compile) .DependsOn(Compile)
.Executes(() => .Executes(() =>
{ {
RunCoreTest("./tests/Avalonia.Animation.UnitTests"); RunCoreTest("Avalonia.Animation.UnitTests");
RunCoreTest("./tests/Avalonia.Base.UnitTests"); RunCoreTest("Avalonia.Base.UnitTests");
RunCoreTest("./tests/Avalonia.Controls.UnitTests"); RunCoreTest("Avalonia.Controls.UnitTests");
RunCoreTest("./tests/Avalonia.Input.UnitTests"); RunCoreTest("Avalonia.Controls.DataGrid.UnitTests");
RunCoreTest("./tests/Avalonia.Interactivity.UnitTests"); RunCoreTest("Avalonia.Input.UnitTests");
RunCoreTest("./tests/Avalonia.Layout.UnitTests"); RunCoreTest("Avalonia.Interactivity.UnitTests");
RunCoreTest("./tests/Avalonia.Markup.UnitTests"); RunCoreTest("Avalonia.Layout.UnitTests");
RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests"); RunCoreTest("Avalonia.Markup.UnitTests");
RunCoreTest("./tests/Avalonia.Styling.UnitTests"); RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
RunCoreTest("./tests/Avalonia.Visuals.UnitTests"); RunCoreTest("Avalonia.Styling.UnitTests");
RunCoreTest("./tests/Avalonia.Skia.UnitTests"); RunCoreTest("Avalonia.Visuals.UnitTests");
RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests"); RunCoreTest("Avalonia.Skia.UnitTests");
RunCoreTest("Avalonia.ReactiveUI.UnitTests");
}); });
Target RunRenderTests => _ => _ Target RunRenderTests => _ => _
.OnlyWhen(() => !Parameters.SkipTests) .OnlyWhenStatic(() => !Parameters.SkipTests)
.DependsOn(Compile) .DependsOn(Compile)
.Executes(() => .Executes(() =>
{ {
RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj"); RunCoreTest("Avalonia.Skia.RenderTests");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj"); RunCoreTest("Avalonia.Direct2D1.RenderTests");
}); });
Target RunDesignerTests => _ => _ Target RunDesignerTests => _ => _
.OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
.DependsOn(Compile) .DependsOn(Compile)
.Executes(() => .Executes(() =>
{ {
RunCoreTest("./tests/Avalonia.DesignerSupport.Tests"); RunCoreTest("Avalonia.DesignerSupport.Tests");
}); });
[PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit; [PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit;
Target RunLeakTests => _ => _ Target RunLeakTests => _ => _
.OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
.DependsOn(Compile) .DependsOn(Compile)
.Executes(() => .Executes(() =>
{ {
@ -234,7 +220,7 @@ partial class Build : NukeBuild
}); });
Target ZipFiles => _ => _ Target ZipFiles => _ => _
.After(CreateNugetPackages, Compile, RunCoreLibsTests, Package) .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package)
.Executes(() => .Executes(() =>
{ {
var data = Parameters; var data = Parameters;
@ -258,9 +244,10 @@ partial class Build : NukeBuild
MsBuildCommon(Parameters.MSBuildSolution, c => c MsBuildCommon(Parameters.MSBuildSolution, c => c
.AddTargets("Pack")); .AddTargets("Pack"));
else else
DotNetPack(Parameters.MSBuildSolution, c => DotNetPack(c => c
c.SetConfiguration(Parameters.Configuration) .SetProject(Parameters.MSBuildSolution)
.AddProperty("PackageVersion", Parameters.Version)); .SetConfiguration(Parameters.Configuration)
.AddProperty("PackageVersion", Parameters.Version));
}); });
Target CreateNugetPackages => _ => _ Target CreateNugetPackages => _ => _
@ -273,32 +260,40 @@ partial class Build : NukeBuild
new NumergeNukeLogger())) new NumergeNukeLogger()))
throw new Exception("Package merge failed"); throw new Exception("Package merge failed");
}); });
Target RunTests => _ => _ Target RunTests => _ => _
.DependsOn(RunCoreLibsTests) .DependsOn(RunCoreLibsTests)
.DependsOn(RunRenderTests) .DependsOn(RunRenderTests)
.DependsOn(RunDesignerTests) .DependsOn(RunDesignerTests)
.DependsOn(RunLeakTests); .DependsOn(RunLeakTests);
Target Package => _ => _ Target Package => _ => _
.DependsOn(RunTests) .DependsOn(RunTests)
.DependsOn(CreateNugetPackages); .DependsOn(CreateNugetPackages);
Target CiAzureLinux => _ => _ Target CiAzureLinux => _ => _
.DependsOn(RunTests); .DependsOn(RunTests);
Target CiAzureOSX => _ => _ Target CiAzureOSX => _ => _
.DependsOn(Package) .DependsOn(Package)
.DependsOn(ZipFiles); .DependsOn(ZipFiles);
Target CiAzureWindows => _ => _ Target CiAzureWindows => _ => _
.DependsOn(Package) .DependsOn(Package)
.DependsOn(ZipFiles); .DependsOn(ZipFiles);
public static int Main() => public static int Main() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? Execute<Build>(x => x.Package) ? Execute<Build>(x => x.Package)
: Execute<Build>(x => x.RunTests); : Execute<Build>(x => x.RunTests);
} }
public static class ToolSettingsExtensions
{
public static T Apply<T>(this T settings, Configure<T> configurator)
{
return configurator != null ? configurator(settings) : settings;
}
}

21
nukebuild/BuildParameters.cs

@ -4,24 +4,21 @@ using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Xml.Linq; using System.Xml.Linq;
using Nuke.Common; using Nuke.Common;
using Nuke.Common.BuildServers; using Nuke.Common.CI.AzurePipelines;
using Nuke.Common.Execution;
using Nuke.Common.IO; using Nuke.Common.IO;
using static Nuke.Common.IO.FileSystemTasks;
using static Nuke.Common.IO.PathConstruction; using static Nuke.Common.IO.PathConstruction;
using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
public partial class Build public partial class Build
{ {
[Parameter("configuration")] [Parameter("configuration")]
public string Configuration { get; set; } public string Configuration { get; set; }
[Parameter("skip-tests")] [Parameter("skip-tests")]
public bool SkipTests { get; set; } public bool SkipTests { get; set; }
[Parameter("force-nuget-version")] [Parameter("force-nuget-version")]
public string ForceNugetVersion { get; set; } public string ForceNugetVersion { get; set; }
public class BuildParameters public class BuildParameters
{ {
public string Configuration { get; } public string Configuration { get; }
@ -79,15 +76,15 @@ public partial class Build
IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix ||
Environment.OSVersion.Platform == PlatformID.MacOSX; Environment.OSVersion.Platform == PlatformID.MacOSX;
IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
IsRunningOnAzure = Host == HostType.TeamServices || IsRunningOnAzure = Host == HostType.AzurePipelines ||
Environment.GetEnvironmentVariable("LOGNAME") == "vsts"; Environment.GetEnvironmentVariable("LOGNAME") == "vsts";
if (IsRunningOnAzure) if (IsRunningOnAzure)
{ {
RepositoryName = TeamServices.Instance.RepositoryUri; RepositoryName = AzurePipelines.Instance.RepositoryUri;
RepositoryBranch = TeamServices.Instance.SourceBranch; RepositoryBranch = AzurePipelines.Instance.SourceBranch;
IsPullRequest = TeamServices.Instance.PullRequestId.HasValue; IsPullRequest = AzurePipelines.Instance.PullRequestId.HasValue;
IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, TeamServices.Instance.RepositoryUri); IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, AzurePipelines.Instance.RepositoryUri);
} }
IsMainRepo = IsMainRepo =
StringComparer.OrdinalIgnoreCase.Equals(MainRepo, StringComparer.OrdinalIgnoreCase.Equals(MainRepo,

8
nukebuild/Shims.cs

@ -19,9 +19,9 @@ public partial class Build
Logger.Info(info, args); Logger.Info(info, args);
} }
private void Zip(PathConstruction.AbsolutePath target, params string[] paths) => Zip(target, paths.AsEnumerable()); private void Zip(AbsolutePath target, params string[] paths) => Zip(target, paths.AsEnumerable());
private void Zip(PathConstruction.AbsolutePath target, IEnumerable<string> paths) private void Zip(AbsolutePath target, IEnumerable<string> paths)
{ {
var targetPath = target.ToString(); var targetPath = target.ToString();
bool finished = false, atLeastOneFileAdded = false; bool finished = false, atLeastOneFileAdded = false;
@ -38,7 +38,7 @@ public partial class Build
fileStream.CopyTo(entryStream); fileStream.CopyTo(entryStream);
atLeastOneFileAdded = true; atLeastOneFileAdded = true;
} }
foreach (var path in paths) foreach (var path in paths)
{ {
if (Directory.Exists(path)) if (Directory.Exists(path))
@ -64,7 +64,7 @@ public partial class Build
finished = true; finished = true;
} }
finally finally
{ {
try try
{ {

8
nukebuild/_build.csproj

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace></RootNamespace> <RootNamespace></RootNamespace>
<IsPackable>False</IsPackable> <IsPackable>False</IsPackable>
@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Nuke.Common" Version="0.12.3" /> <PackageReference Include="Nuke.Common" Version="0.24.0" />
<PackageReference Include="xunit.runner.console" Version="2.3.1" /> <PackageReference Include="xunit.runner.console" Version="2.3.1" />
<PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" /> <PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" />
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " /> <PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
@ -20,11 +20,11 @@
<NukeMetadata Include="**\*.json" Exclude="bin\**;obj\**" /> <NukeMetadata Include="**\*.json" Exclude="bin\**;obj\**" />
<NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" /> <NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" />
<None Remove="*.csproj.DotSettings;*.ref.*.txt" /> <None Remove="*.csproj.DotSettings;*.ref.*.txt" />
<!-- Common build related files --> <!-- Common build related files -->
<None Include="..\build.ps1" /> <None Include="..\build.ps1" />
<None Include="..\build.sh" /> <None Include="..\build.sh" />
<None Include="..\.nuke" /> <None Include="..\.nuke" />
<None Include="..\global.json" Condition="Exists('..\global.json')" /> <None Include="..\global.json" Condition="Exists('..\global.json')" />
<None Include="..\nuget.config" Condition="Exists('..\nuget.config')" /> <None Include="..\nuget.config" Condition="Exists('..\nuget.config')" />
<None Include="..\Jenkinsfile" Condition="Exists('..\Jenkinsfile')" /> <None Include="..\Jenkinsfile" Condition="Exists('..\Jenkinsfile')" />

52
readme.md

@ -8,21 +8,21 @@
## About ## About
**Avalonia** is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), macOS and with experimental support for Android and iOS. **Avalonia** is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), macOS.
**Avalonia** is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development. To see the status of some of our features, please see our [Roadmap here](https://github.com/AvaloniaUI/Avalonia/issues/2239). **Avalonia** is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development.
| Control catalog | Desktop platforms | Mobile platforms | To see the status of some of our features, please see our [Roadmap here](https://github.com/AvaloniaUI/Avalonia/issues/2239).
|---|---|---|
| <a href='https://youtu.be/wHcB3sGLVYg'><img width='300' src='http://avaloniaui.net/images/screen.png'></a> | <a href='https://www.youtube.com/watch?t=28&v=c_AB_XSILp0' target='_blank'><img width='300' src='http://avaloniaui.net/images/avalonia-video.png'></a> | <a href='https://www.youtube.com/watch?v=NJ9-hnmUbBM' target='_blank'><img width='300' src='https://i.ytimg.com/vi/NJ9-hnmUbBM/hqdefault.jpg'></a> |
## Getting Started You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been.
[Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started. After installing it, open "New Project" dialog in Visual Studio, choose "Avalonia" in "Visual C#" section, select "Avalonia .NET Core Application" and press OK (<a href="http://avaloniaui.net/docs/quickstart/images/new-project-dialog.png">screenshot</a>). Now you can write code and markup that will work on multiple platforms! ## Getting Started
For those without Visual Studio, a starter guide for .NET Core CLI can be found [here](http://avaloniaui.net/docs/quickstart/create-new-project#net-core). The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starer guide see our [documentation](http://avaloniaui.net/docs/quickstart/create-new-project).
Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: ([stable(ish)](https://www.nuget.org/packages/Avalonia/), [nightly](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed)) Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/
Use these commands in the Package Manager console to install Avalonia manually: Use these commands in the Package Manager console to install Avalonia manually:
``` ```
@ -30,40 +30,46 @@ Install-Package Avalonia
Install-Package Avalonia.Desktop Install-Package Avalonia.Desktop
``` ```
## Bleeding Edge Builds ## JetBrains Rider
or use nightly build feeds as described here: If you need to develop Avalonia app with JetBrains Rider, go and *vote* on [this issue](https://youtrack.jetbrains.com/issue/RIDER-39247) in their tracker. JetBrains won't do things without their users telling them that they want the feature, so only **YOU** can make it happen.
https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed
## Documentation ## Bleeding Edge Builds
You can take a look at the [getting started page](http://avaloniaui.net/docs/quickstart/) for an overview of how to get started but probably the best thing to do for now is to already know a little bit about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/AvaloniaUI/Avalonia). We also have a [nightly build](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) which tracks the current state of master. Although these packages are less stable than the release on NuGet.org, you'll get all the latest features and bugfixes right away and many of our users actually prefer this feed!
There's also a high-level [architecture document](http://avaloniaui.net/architecture/project-structure) that is currently a little bit out of date, and I've also started writing blog posts on Avalonia at http://grokys.github.io/. ## Documentation
Contributions for our docs are always welcome! Documentation can be found on our website at http://avaloniaui.net/docs/. We also have a [tutorial](http://avaloniaui.net/docs/tutorial/) over there for newcomers.
## Building and Using ## Building and Using
See the [build instructions here](http://avaloniaui.net/contributing/build). See the [build instructions here](Documentation/build.md).
## Contributing ## Contributing
Please read the [contribution guidelines](http://avaloniaui.net/contributing/contributing) before submitting a pull request. Please read the [contribution guidelines](CONTRIBUTING.md) before submitting a pull request.
## Code of Conduct
### Contributors This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
For more information see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
## Licence
Avalonia is licenced under the [MIT licence](licence.md).
## Contributors
This project exists thanks to all the people who contribute. [[Contribute](http://avaloniaui.net/contributing/contributing)]. This project exists thanks to all the people who contribute. [[Contribute](http://avaloniaui.net/contributing/contributing)].
<a href="https://github.com/AvaloniaUI/Avalonia/graphs/contributors"><img src="https://opencollective.com/Avalonia/contributors.svg?width=890&button=false" /></a> <a href="https://github.com/AvaloniaUI/Avalonia/graphs/contributors"><img src="https://opencollective.com/Avalonia/contributors.svg?width=890&button=false" /></a>
### Backers ### Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)] Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)]
<a href="https://opencollective.com/Avalonia#backers" target="_blank"><img src="https://opencollective.com/Avalonia/backers.svg?width=890"></a> <a href="https://opencollective.com/Avalonia#backers" target="_blank"><img src="https://opencollective.com/Avalonia/backers.svg?width=890"></a>
### Sponsors ### Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/Avalonia#sponsor)] Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/Avalonia#sponsor)]
@ -78,3 +84,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
<a href="https://opencollective.com/Avalonia/sponsor/7/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/Avalonia/sponsor/7/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/Avalonia/sponsor/8/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/Avalonia/sponsor/8/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a>
## .NET Foundation
This project is supported by the [.NET Foundation](https://dotnetfoundation.org).

3
samples/BindingDemo/BindingDemo.csproj

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks> <TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" /> <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" /> <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
</ItemGroup> </ItemGroup>

5
samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System.ComponentModel.DataAnnotations;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.ComponentModel.DataAnnotations;
namespace BindingDemo.ViewModels namespace BindingDemo.ViewModels
{ {

5
samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using ReactiveUI;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using ReactiveUI;
using System; using System;
namespace BindingDemo.ViewModels namespace BindingDemo.ViewModels

5
samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using ReactiveUI;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using ReactiveUI;
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Collections; using System.Collections;

2
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch> <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
</PropertyGroup> </PropertyGroup>

1
samples/ControlCatalog/ControlCatalog.csproj

@ -21,6 +21,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" /> <ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" /> <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
</ItemGroup> </ItemGroup>

18
samples/ControlCatalog/MainView.xaml

@ -32,7 +32,11 @@
<TabItem Header="DatePicker"><pages:DatePickerPage/></TabItem> <TabItem Header="DatePicker"><pages:DatePickerPage/></TabItem>
<TabItem Header="Drag+Drop"><pages:DragAndDropPage/></TabItem> <TabItem Header="Drag+Drop"><pages:DragAndDropPage/></TabItem>
<TabItem Header="Expander"><pages:ExpanderPage/></TabItem> <TabItem Header="Expander"><pages:ExpanderPage/></TabItem>
<TabItem Header="Image"><pages:ImagePage/></TabItem> <TabItem Header="Image"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<pages:ImagePage/>
</TabItem>
<TabItem Header="ItemsRepeater" <TabItem Header="ItemsRepeater"
ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"> ScrollViewer.HorizontalScrollBarVisibility="Disabled">
@ -50,14 +54,22 @@
<TabItem Header="TabControl"><pages:TabControlPage/></TabItem> <TabItem Header="TabControl"><pages:TabControlPage/></TabItem>
<TabItem Header="TabStrip"><pages:TabStripPage/></TabItem> <TabItem Header="TabStrip"><pages:TabStripPage/></TabItem>
<TabItem Header="TextBox"><pages:TextBoxPage/></TabItem> <TabItem Header="TextBox"><pages:TextBoxPage/></TabItem>
<TabItem Header="TextBlock"><pages:TextBlockPage/></TabItem>
<TabItem Header="ToolTip"><pages:ToolTipPage/></TabItem> <TabItem Header="ToolTip"><pages:ToolTipPage/></TabItem>
<TabItem Header="TreeView"><pages:TreeViewPage/></TabItem> <TabItem Header="TreeView"><pages:TreeViewPage/></TabItem>
<TabItem Header="Viewbox"><pages:ViewboxPage/></TabItem> <TabItem Header="Viewbox"><pages:ViewboxPage/></TabItem>
<TabControl.Tag> <TabControl.Tag>
<ComboBox x:Name="Themes" SelectedIndex="0" Width="100" Margin="8" HorizontalAlignment="Right" VerticalAlignment="Bottom"> <StackPanel Width="115" Margin="8" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<ComboBox x:Name="Decorations" SelectedIndex="0" Margin="0,0,0,8">
<ComboBoxItem>No Decorations</ComboBoxItem>
<ComboBoxItem>Border Only</ComboBoxItem>
<ComboBoxItem>Full Decorations</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="Themes" SelectedIndex="0">
<ComboBoxItem>Light</ComboBoxItem> <ComboBoxItem>Light</ComboBoxItem>
<ComboBoxItem>Dark</ComboBoxItem> <ComboBoxItem>Dark</ComboBoxItem>
</ComboBox> </ComboBox>
</StackPanel>
</TabControl.Tag> </TabControl.Tag>
</TabControl> </TabControl>
</Grid> </Grid>

15
samples/ControlCatalog/MainView.xaml.cs

@ -56,6 +56,21 @@ namespace ControlCatalog
} }
}; };
Styles.Add(light); Styles.Add(light);
var decorations = this.Find<ComboBox>("Decorations");
decorations.SelectionChanged += (sender, e) =>
{
if (VisualRoot is Window window)
window.SystemDecorations = (SystemDecorations)decorations.SelectedIndex;
};
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
var decorations = this.Find<ComboBox>("Decorations");
if (VisualRoot is Window window)
decorations.SelectedIndex = (int)window.SystemDecorations;
} }
} }
} }

26
samples/ControlCatalog/MainWindow.xaml

@ -14,15 +14,17 @@
<NativeMenuItem Header="File"> <NativeMenuItem Header="File">
<NativeMenuItem.Menu> <NativeMenuItem.Menu>
<NativeMenu> <NativeMenu>
<NativeMenuItem Header="Open" Clicked="OnOpenClicked"/> <NativeMenuItem Icon="/Assets/test_icon.ico" Header="Open" Clicked="OnOpenClicked" Gesture="Ctrl+O"/>
<NativeMenuItemSeperator/> <NativeMenuItemSeperator/>
<NativeMenuItem Header="Recent"> <NativeMenuItem Icon="/Assets/github_icon.png" Header="Recent">
<NativeMenuItem.Menu> <NativeMenuItem.Menu>
<NativeMenu/> <NativeMenu/>
</NativeMenuItem.Menu> </NativeMenuItem.Menu>
</NativeMenuItem> </NativeMenuItem>
<NativeMenuItemSeperator/> <NativeMenuItemSeperator/>
<NativeMenuItem Header="Quit Avalonia" Clicked="OnCloseClicked" Gesture="CMD+Q"/> <NativeMenuItem Header="{x:Static local:MainWindow.MenuQuitHeader}"
Gesture="{x:Static local:MainWindow.MenuQuitGesture}"
Clicked="OnCloseClicked" />
</NativeMenu> </NativeMenu>
</NativeMenuItem.Menu> </NativeMenuItem.Menu>
</NativeMenuItem> </NativeMenuItem>
@ -34,6 +36,24 @@
</NativeMenu> </NativeMenu>
</NativeMenuItem.Menu> </NativeMenuItem.Menu>
</NativeMenuItem> </NativeMenuItem>
<NativeMenuItem Header="Options">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Check Me (None)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="None"
IsChecked="{Binding IsMenuItemChecked}" />
<NativeMenuItem Header="Check Me (CheckBox)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="CheckBox"
IsChecked="{Binding IsMenuItemChecked}" />
<NativeMenuItem Header="Check Me (Radio)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="Radio"
IsChecked="{Binding IsMenuItemChecked}" />
</NativeMenu>
</NativeMenuItem.Menu>
</NativeMenuItem>
</NativeMenu> </NativeMenu>
</NativeMenu.Menu> </NativeMenu.Menu>

15
samples/ControlCatalog/MainWindow.xaml.cs

@ -1,13 +1,11 @@
using System;
using System.Runtime.InteropServices;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Notifications; using Avalonia.Controls.Notifications;
using Avalonia.Controls.Primitives; using Avalonia.Input;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using ControlCatalog.ViewModels; using ControlCatalog.ViewModels;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ControlCatalog namespace ControlCatalog
{ {
@ -31,10 +29,17 @@ namespace ControlCatalog
DataContext = new MainWindowViewModel(_notificationArea); DataContext = new MainWindowViewModel(_notificationArea);
_recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu; _recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu;
var mainMenu = this.FindControl<Menu>("MainMenu"); var mainMenu = this.FindControl<Menu>("MainMenu");
mainMenu.AttachedToVisualTree += MenuAttached; mainMenu.AttachedToVisualTree += MenuAttached;
} }
public static string MenuQuitHeader => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Quit Avalonia" : "E_xit";
public static KeyGesture MenuQuitGesture => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ?
new KeyGesture(Key.Q, KeyModifiers.Meta) :
new KeyGesture(Key.F4, KeyModifiers.Alt);
public void MenuAttached(object sender, VisualTreeAttachmentEventArgs e) public void MenuAttached(object sender, VisualTreeAttachmentEventArgs e)
{ {
if (NativeMenu.GetIsNativeMenuExported(this) && sender is Menu mainMenu) if (NativeMenu.GetIsNativeMenuExported(this) && sender is Menu mainMenu)

1
samples/ControlCatalog/Pages/DialogsPage.xaml

@ -9,5 +9,6 @@
<Button Name="DecoratedWindow">Decorated window</Button> <Button Name="DecoratedWindow">Decorated window</Button>
<Button Name="DecoratedWindowDialog">Decorated window (dialog)</Button> <Button Name="DecoratedWindowDialog">Decorated window (dialog)</Button>
<Button Name="Dialog">Dialog</Button> <Button Name="Dialog">Dialog</Button>
<Button Name="DialogNoTaskbar">Dialog (No taskbar icon)</Button>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

43
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -1,4 +1,7 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
#pragma warning disable 4014 #pragma warning disable 4014
@ -34,7 +37,9 @@ namespace ControlCatalog.Pages
new OpenFileDialog() new OpenFileDialog()
{ {
Title = "Open file", Title = "Open file",
Filters = GetFilters() Filters = GetFilters(),
// Almost guaranteed to exist
InitialFileName = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName
}.ShowAsync(GetWindow()); }.ShowAsync(GetWindow());
}; };
this.FindControl<Button>("SaveFile").Click += delegate this.FindControl<Button>("SaveFile").Click += delegate
@ -42,14 +47,15 @@ namespace ControlCatalog.Pages
new SaveFileDialog() new SaveFileDialog()
{ {
Title = "Save file", Title = "Save file",
Filters = GetFilters() Filters = GetFilters(),
InitialFileName = "test.txt"
}.ShowAsync(GetWindow()); }.ShowAsync(GetWindow());
}; };
this.FindControl<Button>("SelectFolder").Click += delegate this.FindControl<Button>("SelectFolder").Click += delegate
{ {
new OpenFolderDialog() new OpenFolderDialog()
{ {
Title = "Select folder" Title = "Select folder",
}.ShowAsync(GetWindow()); }.ShowAsync(GetWindow());
}; };
this.FindControl<Button>("DecoratedWindow").Click += delegate this.FindControl<Button>("DecoratedWindow").Click += delegate
@ -61,14 +67,29 @@ namespace ControlCatalog.Pages
new DecoratedWindow().ShowDialog(GetWindow()); new DecoratedWindow().ShowDialog(GetWindow());
}; };
this.FindControl<Button>("Dialog").Click += delegate this.FindControl<Button>("Dialog").Click += delegate
{ {
var window = new Window(); var window = CreateSampleWindow();
window.Height = 200; window.Height = 200;
window.Width = 200; window.ShowDialog(GetWindow());
window.Content = new TextBlock { Text = "Hello world!" }; };
window.WindowStartupLocation = WindowStartupLocation.CenterOwner; this.FindControl<Button>("DialogNoTaskbar").Click += delegate
window.ShowDialog(GetWindow()); {
}; var window = CreateSampleWindow();
window.Height = 200;
window.ShowInTaskbar = false;
window.ShowDialog(GetWindow());
};
}
private Window CreateSampleWindow()
{
var window = new Window();
window.Height = 200;
window.Width = 200;
window.Content = new TextBlock { Text = "Hello world!" };
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
return window;
} }
Window GetWindow() => (Window)this.VisualRoot; Window GetWindow() => (Window)this.VisualRoot;

100
samples/ControlCatalog/Pages/ImagePage.xaml

@ -1,45 +1,69 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ImagePage"> x:Class="ControlCatalog.Pages.ImagePage">
<StackPanel Orientation="Vertical" Spacing="4"> <DockPanel>
<TextBlock Classes="h1">Image</TextBlock> <StackPanel DockPanel.Dock="Top" Orientation="Vertical" Spacing="4">
<TextBlock Classes="h2">Displays an image</TextBlock> <TextBlock Classes="h1">Image</TextBlock>
<TextBlock Classes="h2">Displays an image</TextBlock>
<StackPanel Orientation="Horizontal" </StackPanel>
Margin="0,16,0,0"
HorizontalAlignment="Center"
Spacing="16">
<StackPanel Orientation="Vertical">
<TextBlock>No Stretch</TextBlock>
<Image Source="/Assets/delicate-arch-896885_640.jpg"
Width="100" Height="200"
Stretch="None"/>
</StackPanel>
<StackPanel Orientation="Vertical"> <Grid ColumnDefinitions="*,*,*" RowDefinitions="Auto,*" Margin="64">
<TextBlock>Fill</TextBlock>
<Image Source="/Assets/delicate-arch-896885_640.jpg" <DockPanel Grid.Column="0" Grid.Row="1" Margin="16">
Width="100" Height="200" <TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Bitmap</TextBlock>
Stretch="Fill"/> <ComboBox Name="bitmapStretch" DockPanel.Dock="Top" SelectedIndex="2" SelectionChanged="BitmapStretchChanged">
</StackPanel> <ComboBoxItem>None</ComboBoxItem>
<ComboBoxItem>Fill</ComboBoxItem>
<ComboBoxItem>Uniform</ComboBoxItem>
<ComboBoxItem>UniformToFill</ComboBoxItem>
</ComboBox>
<Image Name="bitmapImage"
Source="/Assets/delicate-arch-896885_640.jpg"/>
</DockPanel>
<StackPanel Orientation="Vertical"> <DockPanel Grid.Column="1" Grid.Row="1" Margin="16">
<TextBlock>Uniform</TextBlock> <TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Crop</TextBlock>
<Image Source="/Assets/delicate-arch-896885_640.jpg" <ComboBox Name="bitmapCrop" DockPanel.Dock="Top" SelectedIndex="2" SelectionChanged="BitmapCropChanged">
Width="100" Height="200" <ComboBoxItem>None</ComboBoxItem>
Stretch="Uniform"/> <ComboBoxItem>Center</ComboBoxItem>
</StackPanel> <ComboBoxItem>TopLeft</ComboBoxItem>
<ComboBoxItem>TopRight</ComboBoxItem>
<ComboBoxItem>BottomLeft</ComboBoxItem>
<ComboBoxItem>BottomRight</ComboBoxItem>
</ComboBox>
<Image Name="croppedImage">
<Image.Source>
<CroppedBitmap Source="/Assets/delicate-arch-896885_640.jpg" SourceRect="0 0 320 240"/>
</Image.Source>
</Image>
</DockPanel>
<StackPanel Orientation="Vertical"> <DockPanel Grid.Column="2" Grid.Row="1" Margin="16">
<TextBlock>UniformToFill</TextBlock> <TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Drawing</TextBlock>
<Image Source="/Assets/delicate-arch-896885_640.jpg" <ComboBox Name="drawingStretch" DockPanel.Dock="Top" SelectedIndex="2" SelectionChanged="DrawingStretchChanged">
Width="100" Height="200" <ComboBoxItem>None</ComboBoxItem>
Stretch="UniformToFill"/> <ComboBoxItem>Fill</ComboBoxItem>
</StackPanel> <ComboBoxItem>Uniform</ComboBoxItem>
</StackPanel> <ComboBoxItem>UniformToFill</ComboBoxItem>
<StackPanel Orientation="Vertical"> </ComboBox>
<TextBlock>Window Icon as an Image</TextBlock> <Image Name="drawingImage">
<Image Name="Icon" Width="100" Height="200" Stretch="None" /> <Image.Source>
</StackPanel> <DrawingImage>
</StackPanel> <GeometryDrawing Brush="Red">
<PathGeometry>
<PathFigure StartPoint="0,0" IsClosed="True">
<QuadraticBezierSegment Point1="50,0" Point2="50,-50" />
<QuadraticBezierSegment Point1="100,-50" Point2="100,0" />
<LineSegment Point="50,0" />
<LineSegment Point="50,50" />
</PathFigure>
</PathGeometry>
</GeometryDrawing>
</DrawingImage>
</Image.Source>
</Image>
</DockPanel>
</Grid>
</DockPanel>
</UserControl> </UserControl>

68
samples/ControlCatalog/Pages/ImagePage.xaml.cs

@ -1,41 +1,75 @@
using System.IO; using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Platform;
namespace ControlCatalog.Pages namespace ControlCatalog.Pages
{ {
public class ImagePage : UserControl public class ImagePage : UserControl
{ {
private Image iconImage; private readonly Image _bitmapImage;
private readonly Image _drawingImage;
private readonly Image _croppedImage;
public ImagePage() public ImagePage()
{ {
this.InitializeComponent(); InitializeComponent();
_bitmapImage = this.FindControl<Image>("bitmapImage");
_drawingImage = this.FindControl<Image>("drawingImage");
_croppedImage = this.FindControl<Image>("croppedImage");
} }
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
iconImage = this.Get<Image>("Icon");
} }
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) public void BitmapStretchChanged(object sender, SelectionChangedEventArgs e)
{
if (_bitmapImage != null)
{
var comboxBox = (ComboBox)sender;
_bitmapImage.Stretch = (Stretch)comboxBox.SelectedIndex;
}
}
public void DrawingStretchChanged(object sender, SelectionChangedEventArgs e)
{ {
base.OnAttachedToVisualTree(e); if (_drawingImage != null)
if (iconImage.Source == null)
{ {
var windowRoot = e.Root as Window; var comboxBox = (ComboBox)sender;
if (windowRoot != null) _drawingImage.Stretch = (Stretch)comboxBox.SelectedIndex;
{
using (var stream = new MemoryStream())
{
windowRoot.Icon.Save(stream);
stream.Seek(0, SeekOrigin.Begin);
iconImage.Source = new Bitmap(stream);
}
}
} }
} }
public void BitmapCropChanged(object sender, SelectionChangedEventArgs e)
{
if (_croppedImage != null)
{
var comboxBox = (ComboBox)sender;
var croppedBitmap = _croppedImage.Source as CroppedBitmap;
croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex);
}
}
private PixelRect GetCropRect(int index)
{
var bitmapWidth = 640;
var bitmapHeight = 426;
var cropSize = new PixelSize(320, 240);
return index switch
{
1 => new PixelRect(new PixelPoint((bitmapWidth - cropSize.Width) / 2, (bitmapHeight - cropSize.Width) / 2), cropSize),
2 => new PixelRect(new PixelPoint(0, 0), cropSize),
3 => new PixelRect(new PixelPoint(bitmapWidth - cropSize.Width, 0), cropSize),
4 => new PixelRect(new PixelPoint(0, bitmapHeight - cropSize.Height), cropSize),
5 => new PixelRect(new PixelPoint(bitmapWidth - cropSize.Width, bitmapHeight - cropSize.Height), cropSize),
_ => PixelRect.Empty
};
}
} }
} }

4
samples/ControlCatalog/Pages/MenuPage.xaml

@ -16,13 +16,13 @@
<TextBlock Classes="h3" Margin="4 8">Defined in XAML</TextBlock> <TextBlock Classes="h3" Margin="4 8">Defined in XAML</TextBlock>
<Menu> <Menu>
<MenuItem Header="_First"> <MenuItem Header="_First">
<MenuItem Header="Standard _Menu Item"/> <MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A"/>
<Separator/> <Separator/>
<MenuItem Header="Menu with _Submenu"> <MenuItem Header="Menu with _Submenu">
<MenuItem Header="Submenu _1"/> <MenuItem Header="Submenu _1"/>
<MenuItem Header="Submenu _2"/> <MenuItem Header="Submenu _2"/>
</MenuItem> </MenuItem>
<MenuItem Header="Menu Item with _Icon"> <MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B">
<MenuItem.Icon> <MenuItem.Icon>
<Image Source="/Assets/github_icon.png"/> <Image Source="/Assets/github_icon.png"/>
</MenuItem.Icon> </MenuItem.Icon>

8
samples/ControlCatalog/Pages/ProgressBarPage.xaml

@ -6,15 +6,19 @@
<TextBlock Classes="h2">A progress bar control</TextBlock> <TextBlock Classes="h2">A progress bar control</TextBlock>
<StackPanel> <StackPanel>
<CheckBox
x:Name="showProgress"
Margin="10,16,0,0"
Content="Show Progress Text" />
<StackPanel Orientation="Horizontal" <StackPanel Orientation="Horizontal"
Margin="0,16,0,0" Margin="0,16,0,0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
Spacing="16"> Spacing="16">
<StackPanel Spacing="16"> <StackPanel Spacing="16">
<ProgressBar Value="{Binding #hprogress.Value}" /> <ProgressBar ShowProgressText="{Binding #showProgress.IsChecked}" Value="{Binding #hprogress.Value}" />
<ProgressBar IsIndeterminate="True"/> <ProgressBar IsIndeterminate="True"/>
</StackPanel> </StackPanel>
<ProgressBar Value="{Binding #vprogress.Value}" Orientation="Vertical" /> <ProgressBar ShowProgressText="{Binding #showProgress.IsChecked}" Value="{Binding #vprogress.Value}" Orientation="Vertical" />
<ProgressBar Orientation="Vertical" IsIndeterminate="True" /> <ProgressBar Orientation="Vertical" IsIndeterminate="True" />
</StackPanel> </StackPanel>
<StackPanel Margin="16"> <StackPanel Margin="16">

134
samples/ControlCatalog/Pages/TextBlockPage.xaml

@ -0,0 +1,134 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.TextBlockPage">
<StackPanel>
<TextBlock Classes="h1">TextBlock</TextBlock>
<TextBlock Classes="h2">A control that can display text</TextBlock>
<StackPanel
Orientation="Horizontal"
Spacing="16"
HorizontalAlignment="Center"
Margin="0,16,0,0">
<StackPanel.Styles>
<Style Selector="Border">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="Padding" Value="2"/>
</Style>
</StackPanel.Styles>
<Border>
<StackPanel Width="200" Spacing="8">
<TextBlock TextTrimming="CharacterEllipsis" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
<TextBlock TextTrimming="WordEllipsis" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
<TextBlock Text="Left aligned text" TextAlignment="Left" />
<TextBlock Text="Center aligned text" TextAlignment="Center" />
<TextBlock Text="Right aligned text" TextAlignment="Right" />
</StackPanel>
</Border>
<Border>
<StackPanel Width="200" Spacing="8">
<TextBlock
TextWrapping="Wrap"
Text="Multiline TextBlock with TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." />
</StackPanel>
</Border>
<Border>
<StackPanel Width="200" Spacing="8">
<TextBlock Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBlock Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBlock Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="/Assets/Fonts/SourceSansPro-Italic.ttf#Source Sans Pro"/>
<TextBlock Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="/Assets/Fonts/SourceSansPro-*.ttf#Source Sans Pro"/>
</StackPanel>
</Border>
</StackPanel>
<StackPanel
Orientation="Horizontal"
Spacing="16"
HorizontalAlignment="Center"
Margin="0,16,0,0">
<StackPanel.Styles>
<Style Selector="Border">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="Padding" Value="2"/>
</Style>
</StackPanel.Styles>
<Border>
<StackPanel Width="200" Spacing="8">
<TextBlock TextDecorations="Underline" Text="Underline"/>
<TextBlock TextDecorations="Strikethrough" Text="Strikethrough"/>
<TextBlock TextDecorations="Overline" Text="Overline" />
<TextBlock TextDecorations="Baseline" Text="Baseline"/>
<TextBlock Text="Custom TextDecorations">
<TextBlock.TextDecorations>
<TextDecorationCollection>
<TextDecoration
Location="Overline"
PenThicknessUnit="Pixel">
<TextDecoration.Pen>
<Pen Thickness="2">
<Pen.Brush>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Green"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Pen.Brush>
</Pen>
</TextDecoration.Pen>
</TextDecoration>
<TextDecoration
Location="Strikethrough"
PenThicknessUnit="Pixel">
<TextDecoration.Pen>
<Pen Thickness="1">
<Pen.Brush>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="Green"/>
<GradientStop Offset="1" Color="Blue"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Pen.Brush>
</Pen>
</TextDecoration.Pen>
</TextDecoration>
<TextDecoration
Location="Underline"
PenThicknessUnit="Pixel">
<TextDecoration.Pen>
<Pen Thickness="2">
<Pen.Brush>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="Blue"/>
<GradientStop Offset="1" Color="Red"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Pen.Brush>
</Pen>
</TextDecoration.Pen>
</TextDecoration>
</TextDecorationCollection>
</TextBlock.TextDecorations>
</TextBlock>
</StackPanel>
</Border>
<Border>
<StackPanel Width="200" Spacing="8">
<TextBlock Text="🏻 👌🏻"/>
<TextBlock Text="🏼 👌🏼" />
<TextBlock Text="🏽 👌🏽"/>
<TextBlock Text="🏾 👌🏾"/>
<TextBlock Text="🏿 👌🏿"/>
</StackPanel>
</Border>
<Border>
<StackPanel Width="200" Spacing="8">
<TextBlock Text="👪 👨‍👩‍👧 👨‍👩‍👧‍👦"/>
</StackPanel>
</Border>
</StackPanel>
</StackPanel>
</UserControl>

18
samples/ControlCatalog/Pages/TextBlockPage.xaml.cs

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

15
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -10,6 +10,8 @@ namespace ControlCatalog.ViewModels
{ {
private IManagedNotificationManager _notificationManager; private IManagedNotificationManager _notificationManager;
private bool _isMenuItemChecked = true;
public MainWindowViewModel(IManagedNotificationManager notificationManager) public MainWindowViewModel(IManagedNotificationManager notificationManager)
{ {
_notificationManager = notificationManager; _notificationManager = notificationManager;
@ -42,6 +44,11 @@ namespace ControlCatalog.ViewModels
{ {
(App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown(); (App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown();
}); });
ToggleMenuItemCheckedCommand = ReactiveCommand.Create(() =>
{
IsMenuItemChecked = !IsMenuItemChecked;
});
} }
public IManagedNotificationManager NotificationManager public IManagedNotificationManager NotificationManager
@ -50,6 +57,12 @@ namespace ControlCatalog.ViewModels
set { this.RaiseAndSetIfChanged(ref _notificationManager, value); } set { this.RaiseAndSetIfChanged(ref _notificationManager, value); }
} }
public bool IsMenuItemChecked
{
get { return _isMenuItemChecked; }
set { this.RaiseAndSetIfChanged(ref _isMenuItemChecked, value); }
}
public ReactiveCommand<Unit, Unit> ShowCustomManagedNotificationCommand { get; } public ReactiveCommand<Unit, Unit> ShowCustomManagedNotificationCommand { get; }
public ReactiveCommand<Unit, Unit> ShowManagedNotificationCommand { get; } public ReactiveCommand<Unit, Unit> ShowManagedNotificationCommand { get; }
@ -59,5 +72,7 @@ namespace ControlCatalog.ViewModels
public ReactiveCommand<Unit, Unit> AboutCommand { get; } public ReactiveCommand<Unit, Unit> AboutCommand { get; }
public ReactiveCommand<Unit, Unit> ExitCommand { get; } public ReactiveCommand<Unit, Unit> ExitCommand { get; }
public ReactiveCommand<Unit, Unit> ToggleMenuItemCheckedCommand { get; }
} }
} }

2
samples/PlatformSanityChecks/PlatformSanityChecks.csproj

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
samples/Previewer/Previewer.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Update="**\*.xaml.cs"> <Compile Update="**\*.xaml.cs">

2
samples/RemoteDemo/RemoteDemo.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" /> <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />

3
samples/RenderDemo/App.xaml.cs

@ -1,6 +1,3 @@
// 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 Avalonia; using Avalonia;
using Avalonia.Logging.Serilog; using Avalonia.Logging.Serilog;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;

3
samples/RenderDemo/MainWindow.xaml.cs

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;

2
samples/RenderDemo/Pages/RenderTargetBitmapPage.cs

@ -39,7 +39,7 @@ namespace RenderDemo.Pages
ctx.FillRectangle(Brushes.Fuchsia, new Rect(50, 50, 100, 100)); ctx.FillRectangle(Brushes.Fuchsia, new Rect(50, 50, 100, 100));
} }
context.DrawImage(_bitmap, 1, context.DrawImage(_bitmap,
new Rect(0, 0, 200, 200), new Rect(0, 0, 200, 200),
new Rect(0, 0, 200, 200)); new Rect(0, 0, 200, 200));
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background); Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);

3
samples/RenderDemo/RenderDemo.csproj

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks> <TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" /> <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" /> <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
</ItemGroup> </ItemGroup>

3
samples/VirtualizationDemo/App.xaml.cs

@ -1,6 +1,3 @@
// 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 Avalonia; using Avalonia;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;

3
samples/VirtualizationDemo/MainWindow.xaml.cs

@ -1,6 +1,3 @@
// 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 Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;

5
samples/VirtualizationDemo/Program.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Logging.Serilog; using Avalonia.Logging.Serilog;

5
samples/VirtualizationDemo/ViewModels/ItemViewModel.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using ReactiveUI; using ReactiveUI;
namespace VirtualizationDemo.ViewModels namespace VirtualizationDemo.ViewModels

5
samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// 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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive; using System.Reactive;

3
samples/VirtualizationDemo/VirtualizationDemo.csproj

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks> <TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" /> <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" /> <ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
</ItemGroup> </ItemGroup>

5
samples/interop/Direct3DInteropSample/MainWindow.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;

8
scripts/ReplaceNugetCache.sh

@ -1,8 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp2.0/ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp3.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp3.1/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp3.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.skia/$1/lib/netstandard2.0/ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp3.1/Avalonia**.dll ~/.nuget/packages/avalonia.skia/$1/lib/netstandard2.0/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.native/$1/lib/netstandard2.0/ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp3.1/Avalonia**.dll ~/.nuget/packages/avalonia.native/$1/lib/netstandard2.0/

64
scripts/avalonia-rename.ps1

@ -1,64 +0,0 @@
function Get-NewDirectoryName {
param ([System.IO.DirectoryInfo]$item)
$name = $item.Name.Replace("perspex", "avalonia")
$name = $name.Replace("Perspex", "Avalonia")
Join-Path $item.Parent.FullName $name
}
function Get-NewFileName {
param ([System.IO.FileInfo]$item)
$name = $item.Name.Replace("perspex", "avalonia")
$name = $name.Replace("Perspex", "Avalonia")
Join-Path $item.DirectoryName $name
}
function Rename-Contents {
param ([System.IO.FileInfo] $file)
$extensions = @(".cs",".xaml",".csproj",".sln",".md",".json",".yml",".partial",".ps1",".nuspec",".htm",".html",".gitmodules".".xml",".plist",".targets",".projitems",".shproj",".xib")
if ($extensions.Contains($file.Extension)) {
$text = [IO.File]::ReadAllText($file.FullName)
$text = $text.Replace("github.com/perspex", "github.com/avaloniaui")
$text = $text.Replace("github.com/Perspex", "github.com/AvaloniaUI")
$text = $text.Replace("perspex", "avalonia")
$text = $text.Replace("Perspex", "Avalonia")
$text = $text.Replace("PERSPEX", "AVALONIA")
[IO.File]::WriteAllText($file.FullName, $text)
}
}
function Process-Files {
param ([System.IO.DirectoryInfo] $item)
$dirs = Get-ChildItem -Path $item.FullName -Directory
$files = Get-ChildItem -Path $item.FullName -File
foreach ($dir in $dirs) {
Process-Files $dir.FullName
}
foreach ($file in $files) {
Rename-Contents $file
$renamed = Get-NewFileName $file
if ($file.FullName -ne $renamed) {
Write-Host git mv $file.FullName $renamed
& git mv $file.FullName $renamed
}
}
$renamed = Get-NewDirectoryName $item
if ($item.FullName -ne $renamed) {
Write-Host git mv $item.FullName $renamed
& git mv $item.FullName $renamed
}
}
& git submodule deinit .
& git clean -xdf
Process-Files .

29
src/Avalonia.Animation/Animatable.cs

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -65,26 +62,30 @@ namespace Avalonia.Animation
} }
} }
/// <summary> protected override void OnPropertyChanged<T>(
/// Reacts to a change in a <see cref="AvaloniaProperty"/> value in AvaloniaProperty<T> property,
/// order to animate the change if a <see cref="ITransition"/> is set for the property. Optional<T> oldValue,
/// </summary> BindingValue<T> newValue,
/// <param name="e">The event args.</param> BindingPriority priority)
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
if (_transitions is null || _previousTransitions is null || e.Priority == BindingPriority.Animation) return; if (_transitions is null || _previousTransitions is null || priority == BindingPriority.Animation)
return;
// PERF-SENSITIVE: Called on every property change. Don't use LINQ here (too many allocations). // PERF-SENSITIVE: Called on every property change. Don't use LINQ here (too many allocations).
foreach (var transition in _transitions) foreach (var transition in _transitions)
{ {
if (transition.Property == e.Property) if (transition.Property == property)
{ {
if (_previousTransitions.TryGetValue(e.Property, out var dispose)) if (_previousTransitions.TryGetValue(property, out var dispose))
dispose.Dispose(); dispose.Dispose();
var instance = transition.Apply(this, Clock ?? Avalonia.Animation.Clock.GlobalClock, e.OldValue, e.NewValue); var instance = transition.Apply(
this,
Clock ?? Avalonia.Animation.Clock.GlobalClock,
oldValue.GetValueOrDefault(),
newValue.GetValueOrDefault());
_previousTransitions[e.Property] = instance; _previousTransitions[property] = instance;
return; return;
} }
} }

7
src/Avalonia.Animation/Animation.cs

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -254,10 +251,10 @@ namespace Avalonia.Animation
if (keyframe.TimingMode == KeyFrameTimingMode.TimeSpan) if (keyframe.TimingMode == KeyFrameTimingMode.TimeSpan)
{ {
cue = new Cue(keyframe.KeyTime.Ticks / Duration.Ticks); cue = new Cue(keyframe.KeyTime.TotalSeconds / Duration.TotalSeconds);
} }
var newKF = new AnimatorKeyFrame(handler, cue); var newKF = new AnimatorKeyFrame(handler, cue, keyframe.KeySpline);
subscriptions.Add(newKF.BindSetter(setter, control)); subscriptions.Add(newKF.BindSetter(setter, control));

9
src/Avalonia.Animation/AnimatorKeyFrame.cs

@ -24,11 +24,20 @@ namespace Avalonia.Animation
{ {
AnimatorType = animatorType; AnimatorType = animatorType;
Cue = cue; Cue = cue;
KeySpline = null;
}
public AnimatorKeyFrame(Type animatorType, Cue cue, KeySpline keySpline)
{
AnimatorType = animatorType;
Cue = cue;
KeySpline = keySpline;
} }
internal bool isNeutral; internal bool isNeutral;
public Type AnimatorType { get; } public Type AnimatorType { get; }
public Cue Cue { get; } public Cue Cue { get; }
public KeySpline KeySpline { get; }
public AvaloniaProperty Property { get; private set; } public AvaloniaProperty Property { get; private set; }
private object _value; private object _value;

8
src/Avalonia.Animation/Animators/Animator`1.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// 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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
@ -92,6 +89,9 @@ namespace Avalonia.Animation.Animators
else else
newValue = (T)lastKeyframe.Value; newValue = (T)lastKeyframe.Value;
if (lastKeyframe.KeySpline != null)
progress = lastKeyframe.KeySpline.GetSplineProgress(progress);
return Interpolate(progress, oldValue, newValue); return Interpolate(progress, oldValue, newValue);
} }

5
src/Avalonia.Animation/Animators/BoolAnimator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. namespace Avalonia.Animation.Animators
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation.Animators
{ {
/// <summary> /// <summary>
/// Animator that handles <see cref="bool"/> properties. /// Animator that handles <see cref="bool"/> properties.

5
src/Avalonia.Animation/Animators/ByteAnimator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Animation.Animators namespace Avalonia.Animation.Animators
{ {

5
src/Avalonia.Animation/Animators/DecimalAnimator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. namespace Avalonia.Animation.Animators
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation.Animators
{ {
/// <summary> /// <summary>
/// Animator that handles <see cref="decimal"/> properties. /// Animator that handles <see cref="decimal"/> properties.

5
src/Avalonia.Animation/Animators/DoubleAnimator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. namespace Avalonia.Animation.Animators
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation.Animators
{ {
/// <summary> /// <summary>
/// Animator that handles <see cref="double"/> properties. /// Animator that handles <see cref="double"/> properties.

5
src/Avalonia.Animation/Animators/FloatAnimator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. namespace Avalonia.Animation.Animators
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation.Animators
{ {
/// <summary> /// <summary>
/// Animator that handles <see cref="float"/> properties. /// Animator that handles <see cref="float"/> properties.

5
src/Avalonia.Animation/Animators/Int16Animator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Animation.Animators namespace Avalonia.Animation.Animators
{ {

5
src/Avalonia.Animation/Animators/Int32Animator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Animation.Animators namespace Avalonia.Animation.Animators
{ {

5
src/Avalonia.Animation/Animators/Int64Animator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Animation.Animators namespace Avalonia.Animation.Animators
{ {

5
src/Avalonia.Animation/Animators/UInt16Animator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Animation.Animators namespace Avalonia.Animation.Animators
{ {

5
src/Avalonia.Animation/Animators/UInt32Animator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Animation.Animators namespace Avalonia.Animation.Animators
{ {

5
src/Avalonia.Animation/Animators/UInt64Animator.cs

@ -1,7 +1,4 @@
// Copyright (c) The Avalonia Project. All rights reserved. using System;
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Animation.Animators namespace Avalonia.Animation.Animators
{ {

3
src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using Avalonia.Animation.Animators; using Avalonia.Animation.Animators;

3
src/Avalonia.Animation/Easing/BackEaseIn.cs

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
namespace Avalonia.Animation.Easings namespace Avalonia.Animation.Easings

3
src/Avalonia.Animation/Easing/BackEaseInOut.cs

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
namespace Avalonia.Animation.Easings namespace Avalonia.Animation.Easings

3
src/Avalonia.Animation/Easing/BackEaseOut.cs

@ -1,6 +1,3 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
namespace Avalonia.Animation.Easings namespace Avalonia.Animation.Easings

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

Loading…
Cancel
Save