diff --git a/.ncrunch/BindingDemo.v3.ncrunchproject b/.ncrunch/BindingDemo.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/BindingDemo.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/RenderDemo.v3.ncrunchproject b/.ncrunch/RenderDemo.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/RenderDemo.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/VirtualizationDemo.v3.ncrunchproject b/.ncrunch/VirtualizationDemo.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/VirtualizationDemo.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/Avalonia.sln b/Avalonia.sln index 810ba5c12f..38f8e5f720 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -204,16 +204,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Dialogs", "src\Ava EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.FreeDesktop", "src\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj", "{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Controls.DataGrid.UnitTests", "tests\Avalonia.Controls.DataGrid.UnitTests\Avalonia.Controls.DataGrid.UnitTests.csproj", "{351337F5-D66F-461B-A957-4EF60BDB4BA6}" +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 GlobalSection(SharedMSBuildProjectFiles) = preSolution 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*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4 - src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4 - tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{dabfd304-d6a4-4752-8123-c2ccf7ac7831}*SharedItemsImports = 4 + src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 5 + src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 5 src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index dc57a73f48..fde2931bf9 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,76 +1,130 @@ + # Contributor Covenant Code of Conduct ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + 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 - advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission +* Publishing others' private information, such as a physical or email + address, without their explicit permission * 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 -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, 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 -further defined and clarified by project maintainers. +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at steven@avaloniaui.net. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +reported to the community leaders responsible for enforcement at +steven@avaloniaui.net. +All complaints will be reviewed and investigated promptly and fairly. + +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 -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +**Community Impact**: A violation through a single incident or series +of actions. + +**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 -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +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 -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..dcf95ce33c --- /dev/null +++ b/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) diff --git a/Documentation/build.md b/Documentation/build.md new file mode 100644 index 0000000000..56b028206d --- /dev/null +++ b/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 +``` diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 0000000000..0e1d792e84 --- /dev/null +++ b/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 Hgsberg +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 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 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 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index accad63faa..54645e461e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,7 +14,7 @@ jobs: displayName: 'Install Nuke' inputs: script: | - dotnet tool install --global Nuke.GlobalTool --version 0.12.3 + dotnet tool install --global Nuke.GlobalTool --version 0.24.0 - task: CmdLine@2 displayName: 'Run Nuke' inputs: @@ -35,16 +35,16 @@ jobs: vmImage: 'macOS-10.14' steps: - task: UseDotNet@2 - displayName: 'Use .NET Core SDK 3.0.x' + displayName: 'Use .NET Core SDK 3.1.101' inputs: packageType: sdk - version: 3.0.x + version: 3.1.101 - task: UseDotNet@2 - displayName: 'Use .NET Core Runtime 2.1.x' + displayName: 'Use .NET Core Runtime 3.1.1' inputs: packageType: runtime - version: 2.1.x + version: 3.1.1 - task: CmdLine@2 displayName: 'Install Mono 5.18' @@ -68,13 +68,13 @@ jobs: inputs: script: | brew update - brew install castxml + brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8a004a91a7fcd3f6620d5b01b6541ff0a640ffba/Formula/castxml.rb - task: CmdLine@2 displayName: 'Install Nuke' inputs: script: | - dotnet tool install --global Nuke.GlobalTool --version 0.12.3 + dotnet tool install --global Nuke.GlobalTool --version 0.24.0 - task: CmdLine@2 displayName: 'Run Nuke' @@ -116,7 +116,7 @@ jobs: displayName: 'Install Nuke' inputs: script: | - dotnet tool install --global Nuke.GlobalTool --version 0.12.3 + dotnet tool install --global Nuke.GlobalTool --version 0.24.0 - task: CmdLine@2 displayName: 'Run Nuke' diff --git a/build/Rx.props b/build/Rx.props index edff0af160..8a15ccd6a9 100644 --- a/build/Rx.props +++ b/build/Rx.props @@ -1,5 +1,5 @@  - + diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props index 08a9aa3ceb..4f69f39e02 100644 --- a/build/SkiaSharp.props +++ b/build/SkiaSharp.props @@ -1,6 +1,6 @@  - - + + diff --git a/global.json b/global.json index 1e599211d4..a3fdca9bed 100644 --- a/global.json +++ b/global.json @@ -1,4 +1,7 @@ { + "sdk": { + "version": "3.1.101" + }, "msbuild-sdks": { "Microsoft.Build.Traversal": "1.0.43", "MSBuild.Sdk.Extras": "2.0.46", diff --git a/licence.md b/licence.md index d730e936db..d18aef99ad 100644 --- a/licence.md +++ b/licence.md @@ -1,6 +1,7 @@ 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 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 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. \ No newline at end of file +SOFTWARE. diff --git a/native/Avalonia.Native/inc/avalonia-native-guids.h b/native/Avalonia.Native/inc/avalonia-native-guids.h index 439008fd4b..64fec729a2 100644 --- a/native/Avalonia.Native/inc/avalonia-native-guids.h +++ b/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 #include "avalonia-native.h" diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 4a960d47a1..b10db08adc 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/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 "key.h" +#include "stddef.h" #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 IAvnGlSurfaceRenderTarget; struct IAvnGlSurfaceRenderingSession; -struct IAvnAppMenu; -struct IAvnAppMenuItem; +struct IAvnMenu; +struct IAvnMenuItem; +struct IAvnMenuEvents; + +enum SystemDecorations { + SystemDecorationsNone = 0, + SystemDecorationsBorderOnly = 1, + SystemDecorationsFull = 2, +}; struct AvnSize { @@ -172,6 +177,13 @@ enum AvnWindowEdge WindowEdgeSouthEast }; +enum AvnMenuItemToggleType +{ + None, + CheckMark, + Radio +}; + AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown { public: @@ -185,11 +197,10 @@ public: virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0; virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0; virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) = 0; - virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) = 0; - virtual HRESULT SetAppMenu(IAvnAppMenu* menu) = 0; - virtual HRESULT CreateMenu (IAvnAppMenu** ppv) = 0; - virtual HRESULT CreateMenuItem (IAvnAppMenuItem** ppv) = 0; - virtual HRESULT CreateMenuItemSeperator (IAvnAppMenuItem** ppv) = 0; + virtual HRESULT SetAppMenu(IAvnMenu* menu) = 0; + virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) = 0; + virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) = 0; + virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) = 0; }; AVNCOM(IAvnString, 17) : IUnknown @@ -219,8 +230,7 @@ AVNCOM(IAvnWindowBase, 02) : IUnknown virtual HRESULT SetTopMost (bool value) = 0; virtual HRESULT SetCursor(IAvnCursor* cursor) = 0; virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0; - virtual HRESULT SetMainMenu(IAvnAppMenu* menu) = 0; - virtual HRESULT ObtainMainMenu(IAvnAppMenu** retOut) = 0; + virtual HRESULT SetMainMenu(IAvnMenu* menu) = 0; virtual HRESULT ObtainNSWindowHandle(void** retOut) = 0; virtual HRESULT ObtainNSWindowHandleRetained(void** retOut) = 0; virtual HRESULT ObtainNSViewHandle(void** retOut) = 0; @@ -236,7 +246,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase { virtual HRESULT ShowDialog (IAvnWindow* parent) = 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 SetTitleBarColor (AvnColor color) = 0; virtual HRESULT SetWindowState(AvnWindowState state) = 0; @@ -385,10 +395,10 @@ AVNCOM(IAvnGlSurfaceRenderingSession, 16) : IUnknown virtual HRESULT GetScaling(double* ret) = 0; }; -AVNCOM(IAvnAppMenu, 17) : IUnknown +AVNCOM(IAvnMenu, 17) : IUnknown { - virtual HRESULT AddItem (IAvnAppMenuItem* item) = 0; - virtual HRESULT RemoveItem (IAvnAppMenuItem* item) = 0; + virtual HRESULT InsertItem (int index, IAvnMenuItem* item) = 0; + virtual HRESULT RemoveItem (IAvnMenuItem* item) = 0; virtual HRESULT SetTitle (void* utf8String) = 0; virtual HRESULT Clear () = 0; }; @@ -398,12 +408,23 @@ AVNCOM(IAvnPredicateCallback, 18) : IUnknown 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 SetGesture (void* utf8String, AvnInputModifiers modifiers) = 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(); diff --git a/native/Avalonia.Native/inc/com.h b/native/Avalonia.Native/inc/com.h index 22fb4a11a3..df251514ef 100644 --- a/native/Avalonia.Native/inc/com.h +++ b/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 ide diagnostic ignored "OCUnusedGlobalDeclarationInspection" #ifndef COM_H_INCLUDED diff --git a/native/Avalonia.Native/inc/key.h b/native/Avalonia.Native/inc/key.h index cdc9658e29..12d283cc17 100644 --- a/native/Avalonia.Native/inc/key.h +++ b/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_ #define _KEY_H_ diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme index 1a665d3ea5..5d20a135b9 100644 --- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme +++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme @@ -29,8 +29,6 @@ shouldUseLaunchSchemeArgsEnv = "YES"> - - - - diff --git a/native/Avalonia.Native/src/OSX/SystemDialogs.mm b/native/Avalonia.Native/src/OSX/SystemDialogs.mm index 567dd7f747..a47221056b 100644 --- a/native/Avalonia.Native/src/OSX/SystemDialogs.mm +++ b/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 "window.h" @@ -23,6 +20,7 @@ public: if(title != nullptr) { + panel.message = [NSString stringWithUTF8String:title]; panel.title = [NSString stringWithUTF8String:title]; } @@ -97,6 +95,7 @@ public: if(title != nullptr) { + panel.message = [NSString stringWithUTF8String:title]; panel.title = [NSString stringWithUTF8String:title]; } @@ -185,6 +184,7 @@ public: if(title != nullptr) { + panel.message = [NSString stringWithUTF8String:title]; panel.title = [NSString stringWithUTF8String:title]; } diff --git a/native/Avalonia.Native/src/OSX/app.mm b/native/Avalonia.Native/src/OSX/app.mm index 5c50aad4cc..1e74a70e66 100644 --- a/native/Avalonia.Native/src/OSX/app.mm +++ b/native/Avalonia.Native/src/OSX/app.mm @@ -2,7 +2,8 @@ @interface AvnAppDelegate : NSObject @end -extern NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular; +NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular; + @implementation AvnAppDelegate - (void)applicationWillFinishLaunching:(NSNotification *)notification { @@ -14,6 +15,10 @@ extern NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationA } [[NSApplication sharedApplication] setActivationPolicy: AvnDesiredActivationPolicy]; + + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; + + [[NSApplication sharedApplication] setHelpMenu: [[NSMenu new] initWithTitle:@""]]; } } diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index 6e4d3ce668..c2cf1f1f61 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/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 "AvnString.h" diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h index d7eda20f65..7a433bfd9f 100644 --- a/native/Avalonia.Native/src/OSX/common.h +++ b/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 #define common_h #include "comimpl.h" @@ -18,11 +15,11 @@ extern IAvnScreens* CreateScreens(); extern IAvnClipboard* CreateClipboard(); extern IAvnCursorFactory* CreateCursorFactory(); extern IAvnGlDisplay* GetGlDisplay(); -extern IAvnAppMenu* CreateAppMenu(); -extern IAvnAppMenuItem* CreateAppMenuItem(); -extern IAvnAppMenuItem* CreateAppMenuItemSeperator(); -extern void SetAppMenu (NSString* appName, IAvnAppMenu* appMenu); -extern IAvnAppMenu* GetAppMenu (); +extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* events); +extern IAvnMenuItem* CreateAppMenuItem(); +extern IAvnMenuItem* CreateAppMenuItemSeperator(); +extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu); +extern IAvnMenu* GetAppMenu (); extern NSMenuItem* GetAppMenuItem (); extern void InitializeAvnApp(); diff --git a/native/Avalonia.Native/src/OSX/cursor.h b/native/Avalonia.Native/src/OSX/cursor.h index cfe91955d8..75a9c3d2ad 100644 --- a/native/Avalonia.Native/src/OSX/cursor.h +++ b/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 #define cursor_h diff --git a/native/Avalonia.Native/src/OSX/cursor.mm b/native/Avalonia.Native/src/OSX/cursor.mm index 799fa9e8e6..b6f9ed5071 100644 --- a/native/Avalonia.Native/src/OSX/cursor.mm +++ b/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 "cursor.h" #include diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm index 2b6b24cfda..a63353bc0a 100644 --- a/native/Avalonia.Native/src/OSX/main.mm +++ b/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 #define COM_GUIDS_MATERIALIZE #include "common.h" @@ -95,12 +92,11 @@ void SetProcessName(NSString* appTitle) { PrivateLSASN asn = ls_get_current_application_asn_func(); // Constant used by WebKit; what exactly it means is unknown. const int magic_session_constant = -2; - OSErr err = + ls_set_application_information_item_func(magic_session_constant, asn, ls_display_name_key, process_name, NULL /* optional out param */); - //LOG_IF(ERROR, err) << "Call to set process name failed, err " << err; } class MacOptions : public ComSingleObject @@ -231,41 +227,29 @@ public: 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; } - virtual HRESULT CreateMenuItem (IAvnAppMenuItem** ppv) override + virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) override { *ppv = ::CreateAppMenuItem(); return S_OK; } - virtual HRESULT CreateMenuItemSeperator (IAvnAppMenuItem** ppv) override + virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) override { *ppv = ::CreateAppMenuItemSeperator(); return S_OK; } - virtual HRESULT SetAppMenu (IAvnAppMenu* appMenu) override + virtual HRESULT SetAppMenu (IAvnMenu* appMenu) override { ::SetAppMenu(s_appTitle, appMenu); return S_OK; } - - virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) override - { - if(retOut == nullptr) - { - return E_POINTER; - } - - *retOut = ::GetAppMenu(); - - return S_OK; - } }; extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative() diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h index befbe6a7e0..bfbc6801f8 100644 --- a/native/Avalonia.Native/src/OSX/menu.h +++ b/native/Avalonia.Native/src/OSX/menu.h @@ -14,8 +14,10 @@ class AvnAppMenuItem; class AvnAppMenu; -@interface AvnMenu : NSMenu // for some reason it doesnt detect nsmenu here but compiler doesnt complain -- (void)setMenu:(NSMenu*) menu; +@interface AvnMenu : NSMenu +- (id) initWithDelegate: (NSObject*) del; +- (void) setHasGlobalMenuItem: (bool) value; +- (bool) hasGlobalMenuItem; @end @interface AvnMenuItem : NSMenuItem @@ -23,13 +25,14 @@ class AvnAppMenu; - (void)didSelectItem:(id)sender; @end -class AvnAppMenuItem : public ComSingleObject +class AvnAppMenuItem : public ComSingleObject { private: NSMenuItem* _native; // here we hold a pointer to an AvnMenuItem IAvnActionCallback* _callback; IAvnPredicateCallback* _predicate; bool _isSeperator; + bool _isCheckable; public: FORWARD_IUNKNOWN() @@ -38,7 +41,7 @@ public: NSMenuItem* GetNative(); - virtual HRESULT SetSubMenu (IAvnAppMenu* menu) override; + virtual HRESULT SetSubMenu (IAvnMenu* menu) override; virtual HRESULT SetTitle (void* utf8String) override; @@ -46,29 +49,36 @@ public: 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(); void RaiseOnClicked(); }; -class AvnAppMenu : public ComSingleObject +class AvnAppMenu : public ComSingleObject { private: AvnMenu* _native; + ComPtr _baseEvents; public: FORWARD_IUNKNOWN() - AvnAppMenu(); - - AvnAppMenu(AvnMenu* native); - + AvnAppMenu(IAvnMenuEvents* events); + 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; @@ -76,5 +86,9 @@ public: }; +@interface AvnMenuDelegate : NSObject +- (id) initWithParent: (AvnAppMenu*) parent; +@end + #endif diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index 1d2f075ccb..dc1245cd23 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -4,6 +4,30 @@ #include "window.h" @implementation AvnMenu +{ + bool _isReparented; + NSObject* _wtf; +} + +- (id) initWithDelegate: (NSObject*)del +{ + self = [super init]; + self.delegate = del; + _wtf = del; + _isReparented = false; + return self; +} + +- (bool)hasGlobalMenuItem +{ + return _isReparented; +} + +- (void)setHasGlobalMenuItem:(bool)value +{ + _isReparented = value; +} + @end @implementation AvnMenuItem @@ -46,6 +70,7 @@ AvnAppMenuItem::AvnAppMenuItem(bool isSeperator) { + _isCheckable = false; _isSeperator = isSeperator; if(isSeperator) @@ -65,49 +90,134 @@ NSMenuItem* AvnAppMenuItem::GetNative() return _native; } -HRESULT AvnAppMenuItem::SetSubMenu (IAvnAppMenu* menu) +HRESULT AvnAppMenuItem::SetSubMenu (IAvnMenu* menu) { - auto nsMenu = dynamic_cast(menu)->GetNative(); - - [_native setSubmenu: nsMenu]; - - return S_OK; + @autoreleasepool + { + if(menu != nullptr) + { + auto nsMenu = dynamic_cast(menu)->GetNative(); + + [_native setSubmenu: nsMenu]; + } + else + { + [_native setSubmenu: nullptr]; + } + + return S_OK; + } } 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) { - NSEventModifierFlags flags = 0; - - if (modifiers & Control) - flags |= NSEventModifierFlagControl; - if (modifiers & Shift) - flags |= NSEventModifierFlagShift; - if (modifiers & Alt) - flags |= NSEventModifierFlagOption; - if (modifiers & Windows) - flags |= NSEventModifierFlagCommand; - - [_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]]; - [_native setKeyEquivalentModifierMask:flags]; - - return S_OK; + @autoreleasepool + { + NSEventModifierFlags flags = 0; + + if (modifiers & Control) + flags |= NSEventModifierFlagControl; + if (modifiers & Shift) + flags |= NSEventModifierFlagShift; + if (modifiers & Alt) + flags |= NSEventModifierFlagOption; + if (modifiers & Windows) + flags |= NSEventModifierFlagCommand; + + [_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]]; + [_native setKeyEquivalentModifierMask:flags]; + + return S_OK; + } } HRESULT AvnAppMenuItem::SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) { - _predicate = predicate; - _callback = callback; - return S_OK; + @autoreleasepool + { + _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() @@ -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() { return _native; } -HRESULT AvnAppMenu::AddItem (IAvnAppMenuItem* item) +void AvnAppMenu::RaiseNeedsUpdate() { - auto avnMenuItem = dynamic_cast(item); - - if(avnMenuItem != nullptr) + if(_baseEvents != 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(item); - - if(avnMenuItem != nullptr) + @autoreleasepool { - [_native removeItem:avnMenuItem->GetNative()]; + if([_native hasGlobalMenuItem]) + { + index++; + } + + auto avnMenuItem = dynamic_cast(item); + + if(avnMenuItem != nullptr) + { + [_native insertItem: avnMenuItem->GetNative() atIndex:index]; + } + + return S_OK; + } +} + +HRESULT AvnAppMenu::RemoveItem (IAvnMenuItem* item) +{ + @autoreleasepool + { + auto avnMenuItem = dynamic_cast(item); + + if(avnMenuItem != nullptr) + { + [_native removeItem:avnMenuItem->GetNative()]; + } + + return S_OK; } - - return S_OK; } 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() { - [_native removeAllItems]; - return S_OK; + @autoreleasepool + { + [_native removeAllItems]; + return S_OK; + } +} + +@implementation AvnMenuDelegate +{ + ComPtr _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 { - id menuBar = [NSMenu new]; - return new AvnAppMenu(menuBar); + return new AvnAppMenu(cb); } } -extern IAvnAppMenuItem* CreateAppMenuItem() +extern IAvnMenuItem* CreateAppMenuItem() { @autoreleasepool { @@ -202,7 +364,7 @@ extern IAvnAppMenuItem* CreateAppMenuItem() } } -extern IAvnAppMenuItem* CreateAppMenuItemSeperator() +extern IAvnMenuItem* CreateAppMenuItemSeperator() { @autoreleasepool { @@ -210,10 +372,10 @@ extern IAvnAppMenuItem* CreateAppMenuItemSeperator() } } -static IAvnAppMenu* s_appMenu = nullptr; +static IAvnMenu* s_appMenu = nullptr; static NSMenuItem* s_appMenuItem = nullptr; -extern void SetAppMenu (NSString* appName, IAvnAppMenu* menu) +extern void SetAppMenu (NSString* appName, IAvnMenu* menu) { s_appMenu = menu; @@ -294,7 +456,7 @@ extern void SetAppMenu (NSString* appName, IAvnAppMenu* menu) } } -extern IAvnAppMenu* GetAppMenu () +extern IAvnMenu* GetAppMenu () { return s_appMenu; } diff --git a/native/Avalonia.Native/src/OSX/platformthreading.mm b/native/Avalonia.Native/src/OSX/platformthreading.mm index ed00f8c5e1..f93436d157 100644 --- a/native/Avalonia.Native/src/OSX/platformthreading.mm +++ b/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" class PlatformThreadingInterface; @@ -57,9 +54,11 @@ private: { public: FORWARD_IUNKNOWN() + bool Running = false; bool Cancelled = false; - virtual void Cancel() + + virtual void Cancel() override { Cancelled = true; if(Running) diff --git a/native/Avalonia.Native/src/OSX/window.h b/native/Avalonia.Native/src/OSX/window.h index 3e626675d2..8092db3663 100644 --- a/native/Avalonia.Native/src/OSX/window.h +++ b/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 #define window_h @@ -22,7 +19,11 @@ class WindowBaseImpl; -(void) pollModalSession: (NSModalSession _Nonnull) session; -(void) restoreParentWindow; -(bool) shouldTryToHandleEvents; --(void) applyMenu:(NSMenu *)menu; +-(bool) isModal; +-(void) setModal: (bool) isModal; +-(void) showAppMenuOnly; +-(void) showWindowMenuWithAppMenu; +-(void) applyMenu:(NSMenu* _Nullable)menu; -(double) getScaling; @end diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index b6ce172ffa..68899df9f0 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.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 "window.h" #include "KeyTransform.h" @@ -30,10 +27,12 @@ public: NSObject* renderTarget; AvnPoint lastPositionSet; NSString* _lastTitle; - IAvnAppMenu* _mainMenu; + IAvnMenu* _mainMenu; + bool _shown; WindowBaseImpl(IAvnWindowBaseEvents* events, IAvnGlContext* gl) { + _shown = false; _mainMenu = nullptr; BaseEvents = events; _glContext = gl; @@ -115,7 +114,8 @@ public: [NSApp activateIgnoringOtherApps:YES]; [Window setTitle:_lastTitle]; - [Window setTitleVisibility:NSWindowTitleVisible]; + + _shown = true; return S_OK; } @@ -234,7 +234,7 @@ public: } } - virtual HRESULT SetMainMenu(IAvnAppMenu* menu) override + virtual HRESULT SetMainMenu(IAvnMenu* menu) override { _mainMenu = menu; @@ -244,18 +244,11 @@ public: [Window applyMenu:nsmenu]; - return S_OK; - } - - virtual HRESULT ObtainMainMenu(IAvnAppMenu** ret) override - { - if(ret == nullptr) + if ([Window isKeyWindow]) { - return E_POINTER; + [Window showWindowMenuWithAppMenu]; } - *ret = _mainMenu; - return S_OK; } @@ -401,6 +394,7 @@ protected: [Window setStyleMask:GetStyle()]; } +public: virtual void OnResized () { @@ -411,7 +405,7 @@ class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, pub { private: bool _canResize = true; - bool _hasDecorations = true; + SystemDecorations _hasDecorations = SystemDecorationsFull; CGRect _lastUndecoratedFrame; AvnWindowState _lastWindowState; @@ -427,9 +421,11 @@ private: ComPtr WindowEvents; WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl) { + _lastWindowState = Normal; WindowEvents = events; [Window setCanBecomeKeyAndMain]; [Window disableCursorRects]; + [Window setTabbingMode:NSWindowTabbingModeDisallowed]; } virtual HRESULT Show () override @@ -438,9 +434,12 @@ private: { if([Window parentWindow] != nil) [[Window parentWindow] removeChildWindow:Window]; + + [Window setModal:FALSE]; + WindowBaseImpl::Show(); - return SetWindowState(Normal); + return SetWindowState(_lastWindowState); } } @@ -455,6 +454,8 @@ private: if(cparent == nullptr) return E_INVALIDARG; + [Window setModal:TRUE]; + [cparent->Window addChildWindow:Window ordered:NSWindowAbove]; WindowBaseImpl::Show(); @@ -476,23 +477,26 @@ private: bool IsZoomed () { - return _hasDecorations ? [Window isZoomed] : UndecoratedIsMaximized(); + return _hasDecorations != SystemDecorationsNone ? [Window isZoomed] : UndecoratedIsMaximized(); } void DoZoom() { - if (_hasDecorations) + switch (_hasDecorations) { - [Window performZoom:Window]; - } - else - { - if (!UndecoratedIsMaximized()) - { - _lastUndecoratedFrame = [Window frame]; - } - - [Window zoom:Window]; + case SystemDecorationsNone: + if (!UndecoratedIsMaximized()) + { + _lastUndecoratedFrame = [Window frame]; + } + + [Window zoom:Window]; + break; + + case SystemDecorationsBorderOnly: + case SystemDecorationsFull: + [Window performZoom:Window]; + break; } } @@ -506,13 +510,35 @@ private: } } - virtual HRESULT SetHasDecorations(bool value) override + virtual HRESULT SetHasDecorations(SystemDecorations value) override { @autoreleasepool { _hasDecorations = value; 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; } } @@ -523,7 +549,6 @@ private: { _lastTitle = [NSString stringWithUTF8String:(const char*)utf8title]; [Window setTitle:_lastTitle]; - [Window setTitleVisibility:NSWindowTitleVisible]; return S_OK; } @@ -591,64 +616,86 @@ private: { _lastWindowState = state; - switch (state) { - case Maximized: - lastPositionSet.X = 0; - lastPositionSet.Y = 0; - - if([Window isMiniaturized]) - { - [Window deminiaturize:Window]; - } - - if(!IsZoomed()) - { - DoZoom(); - } - break; - - case Minimized: - [Window miniaturize:Window]; - break; - - default: - if([Window isMiniaturized]) - { - [Window deminiaturize:Window]; - } - - if(IsZoomed()) - { - DoZoom(); - } - break; + if(_shown) + { + switch (state) { + case Maximized: + lastPositionSet.X = 0; + lastPositionSet.Y = 0; + + if([Window isMiniaturized]) + { + [Window deminiaturize:Window]; + } + + if(!IsZoomed()) + { + DoZoom(); + } + break; + + case Minimized: + [Window miniaturize:Window]; + break; + + default: + if([Window isMiniaturized]) + { + [Window deminiaturize:Window]; + } + + if(IsZoomed()) + { + DoZoom(); + } + break; + } } return S_OK; } } - -protected: + virtual void OnResized () override { - auto windowState = [Window isMiniaturized] ? Minimized - : (IsZoomed() ? Maximized : Normal); - - if (windowState != _lastWindowState) + if(_shown) { - _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 { unsigned long s = NSWindowStyleMaskBorderless; - if(_hasDecorations) - s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; - if(_canResize) - s = s | NSWindowStyleMaskResizable; + + switch (_hasDecorations) + { + 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; } }; @@ -1103,8 +1150,8 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent ComPtr _parent; bool _canBecomeKeyAndMain; bool _closed; - NSMenu* _menu; - bool _isAppMenuApplied; + bool _isModal; + AvnMenu* _menu; double _lastScaling; } @@ -1141,32 +1188,64 @@ 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 ([self isKeyWindow]) + if(appMenuItem != nullptr) { - auto appMenu = ::GetAppMenuItem(); + auto appMenu = ::GetAppMenu(); - if(appMenu != nullptr) + auto nativeAppMenu = dynamic_cast(appMenu); + + [[appMenuItem menu] removeItem:appMenuItem]; + + if(_menu != nullptr) { - [[appMenu menu] removeItem:appMenu]; - - [_menu insertItem:appMenu atIndex:0]; - - _isAppMenuApplied = true; + [_menu setHasGlobalMenuItem:false]; } - [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 { _canBecomeKeyAndMain = true; @@ -1250,11 +1329,25 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent auto ch = objc_cast(uch); if(ch == nil) continue; + + if(![ch isModal]) + continue; + return FALSE; } return TRUE; } +-(bool) isModal +{ + return _isModal; +} + +-(void) setModal: (bool) isModal +{ + _isModal = isModal; +} + -(void)makeKeyWindow { if([self activateAppropriateChild: true]) @@ -1267,23 +1360,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent { if([self activateAppropriateChild: true]) { - if(_menu == nullptr) - { - _menu = [NSMenu new]; - } - - auto appMenu = ::GetAppMenuItem(); - - if(appMenu != nullptr) - { - [[appMenu menu] removeItem:appMenu]; - - [_menu insertItem:appMenu atIndex:0]; - - _isAppMenuApplied = true; - } - - [NSApp setMenu:_menu]; + [self showWindowMenuWithAppMenu]; _parent->BaseEvents->Activated(); [super becomeKeyWindow]; @@ -1320,6 +1397,11 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent } } +- (void)windowDidResize:(NSNotification *)notification +{ + _parent->OnResized(); +} + - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame { return true; @@ -1330,26 +1412,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent if(_parent) _parent->BaseEvents->Deactivated(); - auto appMenuItem = ::GetAppMenuItem(); - - if(appMenuItem != nullptr) - { - auto appMenu = ::GetAppMenu(); - - auto nativeAppMenu = dynamic_cast(appMenu); - - [[appMenuItem menu] removeItem:appMenuItem]; - - [nativeAppMenu->GetNative() addItem:appMenuItem]; - - [NSApp setMenu:nativeAppMenu->GetNative()]; - } - else - { - [NSApp setMenu:nullptr]; - } - - // remove window menu items from appmenu? + [self showAppMenuOnly]; [super resignKeyWindow]; } @@ -1390,6 +1453,7 @@ protected: [Window setContentSize:NSSize{x, y}]; [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))]; + return S_OK; } } diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index 7b3b8465ce..358846a14e 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -13,6 +13,7 @@ using Nuke.Common.Tooling; using Nuke.Common.Tools.DotNet; using Nuke.Common.Tools.MSBuild; using Nuke.Common.Utilities; +using Nuke.Common.Utilities.Collections; using static Nuke.Common.EnvironmentInfo; using static Nuke.Common.IO.FileSystemTasks; 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 ReSharper/Rider - https://plugins.jetbrains.com/plugin/10803-nuke-support VSCode - https://marketplace.visualstudio.com/items?itemName=nuke.support - + */ partial class Build : NukeBuild { + [Solution("Avalonia.sln")] readonly Solution Solution; + static Lazy MsBuildExe = new Lazy(() => { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -54,7 +57,7 @@ partial class Build : NukeBuild protected override void OnBuildInitialized() { 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.Configuration, typeof(NukeBuild).Assembly.GetName().Version.ToString()); @@ -93,29 +96,24 @@ partial class Build : NukeBuild string projectFile, Configure configurator = null) { - return MSBuild(projectFile, c => - { + return MSBuild(c => c + .SetProjectFile(projectFile) // This is required for VS2019 image on Azure Pipelines - if (Parameters.IsRunningOnWindows && Parameters.IsRunningOnAzure) - { - var javaSdk = Environment.GetEnvironmentVariable("JAVA_HOME_8_X64"); - if (javaSdk != null) - c = c.AddProperty("JavaSdkDirectory", javaSdk); - } - - c = c.AddProperty("PackageVersion", Parameters.Version) - .AddProperty("iOSRoslynPathHackRequired", "true") - .SetToolPath(MsBuildExe.Value) - .SetConfiguration(Parameters.Configuration) - .SetVerbosity(MSBuildVerbosity.Minimal); - c = configurator?.Invoke(c) ?? c; - return c; - }); + .When(Parameters.IsRunningOnWindows && + Parameters.IsRunningOnAzure, c => c + .AddProperty("JavaSdkDirectory", GetVariable("JAVA_HOME_8_X64"))) + .AddProperty("PackageVersion", Parameters.Version) + .AddProperty("iOSRoslynPathHackRequired", true) + .SetToolPath(MsBuildExe.Value) + .SetConfiguration(Parameters.Configuration) + .SetVerbosity(MSBuildVerbosity.Minimal) + .Apply(configurator)); } + Target Clean => _ => _.Executes(() => { - DeleteDirectories(Parameters.BuildDirs); - EnsureCleanDirectories(Parameters.BuildDirs); + Parameters.BuildDirs.ForEach(DeleteDirectory); + Parameters.BuildDirs.ForEach(EnsureCleanDirectory); EnsureCleanDirectory(Parameters.ArtifactsDir); EnsureCleanDirectory(Parameters.NugetIntermediateRoot); EnsureCleanDirectory(Parameters.NugetRoot); @@ -134,97 +132,84 @@ partial class Build : NukeBuild ); else - DotNetBuild(Parameters.MSBuildSolution, c => c + DotNetBuild(c => c + .SetProjectFile(Parameters.MSBuildSolution) .AddProperty("PackageVersion", Parameters.Version) .SetConfiguration(Parameters.Configuration) ); }); - - void RunCoreTest(string project) + + void RunCoreTest(string projectName) { - if(!project.EndsWith(".csproj")) - project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj"); - Information("Running tests from " + project); - XDocument xdoc; - using (var s = File.OpenRead(project)) - xdoc = XDocument.Load(s); - - List 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 {xdoc.Root.Descendants("TargetFramework").First().Value}; - - foreach(var fw in frameworks) + Information($"Running tests from {projectName}"); + var project = Solution.GetProject(projectName).NotNull("project != null"); + + foreach (var fw in project.GetTargetFrameworks()) { if (fw.StartsWith("net4") - && RuntimeInformation.IsOSPlatform(OSPlatform.Linux) + && RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && 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; } - Information("Running for " + fw); - DotNetTest(c => - { - c = c - .SetProjectFile(project) - .SetConfiguration(Parameters.Configuration) - .SetFramework(fw) - .EnableNoBuild() - .EnableNoRestore(); - // NOTE: I can see that we could maybe add another extension method "Switch" or "If" to make this more convenient - if (Parameters.PublishTestResults) - c = c.SetLogger("trx").SetResultsDirectory(Parameters.TestResultsRoot); - return c; - }); + Information($"Running for {projectName} ({fw}) ..."); + + DotNetTest(c => c + .SetProjectFile(project) + .SetConfiguration(Parameters.Configuration) + .SetFramework(fw) + .EnableNoBuild() + .EnableNoRestore() + .When(Parameters.PublishTestResults, c => c + .SetLogger("trx") + .SetResultsDirectory(Parameters.TestResultsRoot))); } } Target RunCoreLibsTests => _ => _ - .OnlyWhen(() => !Parameters.SkipTests) + .OnlyWhenStatic(() => !Parameters.SkipTests) .DependsOn(Compile) .Executes(() => { - RunCoreTest("./tests/Avalonia.Animation.UnitTests"); - RunCoreTest("./tests/Avalonia.Base.UnitTests"); - RunCoreTest("./tests/Avalonia.Controls.UnitTests"); - RunCoreTest("./tests/Avalonia.Controls.DataGrid.UnitTests"); - RunCoreTest("./tests/Avalonia.Input.UnitTests"); - RunCoreTest("./tests/Avalonia.Interactivity.UnitTests"); - RunCoreTest("./tests/Avalonia.Layout.UnitTests"); - RunCoreTest("./tests/Avalonia.Markup.UnitTests"); - RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests"); - RunCoreTest("./tests/Avalonia.Styling.UnitTests"); - RunCoreTest("./tests/Avalonia.Visuals.UnitTests"); - RunCoreTest("./tests/Avalonia.Skia.UnitTests"); - RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests"); + RunCoreTest("Avalonia.Animation.UnitTests"); + RunCoreTest("Avalonia.Base.UnitTests"); + RunCoreTest("Avalonia.Controls.UnitTests"); + RunCoreTest("Avalonia.Controls.DataGrid.UnitTests"); + RunCoreTest("Avalonia.Input.UnitTests"); + RunCoreTest("Avalonia.Interactivity.UnitTests"); + RunCoreTest("Avalonia.Layout.UnitTests"); + RunCoreTest("Avalonia.Markup.UnitTests"); + RunCoreTest("Avalonia.Markup.Xaml.UnitTests"); + RunCoreTest("Avalonia.Styling.UnitTests"); + RunCoreTest("Avalonia.Visuals.UnitTests"); + RunCoreTest("Avalonia.Skia.UnitTests"); + RunCoreTest("Avalonia.ReactiveUI.UnitTests"); }); Target RunRenderTests => _ => _ - .OnlyWhen(() => !Parameters.SkipTests) + .OnlyWhenStatic(() => !Parameters.SkipTests) .DependsOn(Compile) .Executes(() => { - RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj"); + RunCoreTest("Avalonia.Skia.RenderTests"); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj"); + RunCoreTest("Avalonia.Direct2D1.RenderTests"); }); - + Target RunDesignerTests => _ => _ - .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) + .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) .DependsOn(Compile) .Executes(() => { - RunCoreTest("./tests/Avalonia.DesignerSupport.Tests"); + RunCoreTest("Avalonia.DesignerSupport.Tests"); }); [PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit; Target RunLeakTests => _ => _ - .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) + .OnlyWhenStatic(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) .DependsOn(Compile) .Executes(() => { @@ -235,7 +220,7 @@ partial class Build : NukeBuild }); Target ZipFiles => _ => _ - .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package) + .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package) .Executes(() => { var data = Parameters; @@ -259,9 +244,10 @@ partial class Build : NukeBuild MsBuildCommon(Parameters.MSBuildSolution, c => c .AddTargets("Pack")); else - DotNetPack(Parameters.MSBuildSolution, c => - c.SetConfiguration(Parameters.Configuration) - .AddProperty("PackageVersion", Parameters.Version)); + DotNetPack(c => c + .SetProject(Parameters.MSBuildSolution) + .SetConfiguration(Parameters.Configuration) + .AddProperty("PackageVersion", Parameters.Version)); }); Target CreateNugetPackages => _ => _ @@ -274,32 +260,40 @@ partial class Build : NukeBuild new NumergeNukeLogger())) throw new Exception("Package merge failed"); }); - + Target RunTests => _ => _ .DependsOn(RunCoreLibsTests) .DependsOn(RunRenderTests) .DependsOn(RunDesignerTests) .DependsOn(RunLeakTests); - + Target Package => _ => _ .DependsOn(RunTests) .DependsOn(CreateNugetPackages); - + Target CiAzureLinux => _ => _ .DependsOn(RunTests); - + Target CiAzureOSX => _ => _ .DependsOn(Package) .DependsOn(ZipFiles); - + Target CiAzureWindows => _ => _ .DependsOn(Package) .DependsOn(ZipFiles); - + public static int Main() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Execute(x => x.Package) : Execute(x => x.RunTests); } + +public static class ToolSettingsExtensions +{ + public static T Apply(this T settings, Configure configurator) + { + return configurator != null ? configurator(settings) : settings; + } +} diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs index 65ba5e9756..149716b416 100644 --- a/nukebuild/BuildParameters.cs +++ b/nukebuild/BuildParameters.cs @@ -4,24 +4,21 @@ using System.Linq; using System.Runtime.InteropServices; using System.Xml.Linq; using Nuke.Common; -using Nuke.Common.BuildServers; -using Nuke.Common.Execution; +using Nuke.Common.CI.AzurePipelines; using Nuke.Common.IO; -using static Nuke.Common.IO.FileSystemTasks; using static Nuke.Common.IO.PathConstruction; -using static Nuke.Common.Tools.MSBuild.MSBuildTasks; public partial class Build { [Parameter("configuration")] public string Configuration { get; set; } - + [Parameter("skip-tests")] public bool SkipTests { get; set; } - + [Parameter("force-nuget-version")] public string ForceNugetVersion { get; set; } - + public class BuildParameters { public string Configuration { get; } @@ -79,15 +76,15 @@ public partial class Build IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - IsRunningOnAzure = Host == HostType.TeamServices || + IsRunningOnAzure = Host == HostType.AzurePipelines || Environment.GetEnvironmentVariable("LOGNAME") == "vsts"; if (IsRunningOnAzure) { - RepositoryName = TeamServices.Instance.RepositoryUri; - RepositoryBranch = TeamServices.Instance.SourceBranch; - IsPullRequest = TeamServices.Instance.PullRequestId.HasValue; - IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, TeamServices.Instance.RepositoryUri); + RepositoryName = AzurePipelines.Instance.RepositoryUri; + RepositoryBranch = AzurePipelines.Instance.SourceBranch; + IsPullRequest = AzurePipelines.Instance.PullRequestId.HasValue; + IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, AzurePipelines.Instance.RepositoryUri); } IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, diff --git a/nukebuild/Shims.cs b/nukebuild/Shims.cs index 461d617643..1ac14bf622 100644 --- a/nukebuild/Shims.cs +++ b/nukebuild/Shims.cs @@ -19,9 +19,9 @@ public partial class Build 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 paths) + private void Zip(AbsolutePath target, IEnumerable paths) { var targetPath = target.ToString(); bool finished = false, atLeastOneFileAdded = false; @@ -38,7 +38,7 @@ public partial class Build fileStream.CopyTo(entryStream); atLeastOneFileAdded = true; } - + foreach (var path in paths) { if (Directory.Exists(path)) @@ -64,7 +64,7 @@ public partial class Build finished = true; } - finally + finally { try { diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index 2a736e4653..584c36d033 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + netcoreapp3.1 false False @@ -10,7 +10,7 @@ - + @@ -20,11 +20,11 @@ - + - + diff --git a/readme.md b/readme.md index 42b1e52205..8ae3f1ad66 100644 --- a/readme.md +++ b/readme.md @@ -8,25 +8,21 @@ ## 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](https://github.com/AvaloniaUI/Avalonia/wiki/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). -[Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is curated list of awesome Avalonia UI tools, libraries, projects and resources. +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. -## Getting Started - -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 (screenshot). Now you can write code and markup that will work on multiple platforms! +[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! -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). +## Getting Started -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. +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 NuGet package manager. You can find the packages here: [stable(ish)](https://www.nuget.org/packages/Avalonia/) +Avalonia is delivered via NuGet 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: ``` @@ -34,40 +30,46 @@ Install-Package Avalonia Install-Package Avalonia.Desktop ``` -## Bleeding Edge Builds +## JetBrains Rider -or use nightly build feeds as described here: -https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed +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. -## 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 -See the [build instructions here](http://avaloniaui.net/contributing/build). +See the [build instructions here](Documentation/build.md). ## 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)]. - ### Backers Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)] - ### 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)] @@ -82,3 +84,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l + +## .NET Foundation + +This project is supported by the [.NET Foundation](https://dotnetfoundation.org). diff --git a/samples/BindingDemo/BindingDemo.csproj b/samples/BindingDemo/BindingDemo.csproj index a3f16dc222..ce33f42143 100644 --- a/samples/BindingDemo/BindingDemo.csproj +++ b/samples/BindingDemo/BindingDemo.csproj @@ -1,7 +1,7 @@  Exe - netcoreapp2.0;net461 + netcoreapp3.1 diff --git a/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs b/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs index e274f9180e..391d1791d3 100644 --- a/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs +++ b/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs @@ -1,7 +1,4 @@ -// 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.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace BindingDemo.ViewModels { diff --git a/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs b/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs index df80931367..0fe12a8ef7 100644 --- a/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs +++ b/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs @@ -1,7 +1,4 @@ -// 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 ReactiveUI; +using ReactiveUI; using System; namespace BindingDemo.ViewModels diff --git a/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs b/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs index bb3b4d64e9..caf75c846c 100644 --- a/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs +++ b/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs @@ -1,7 +1,4 @@ -// 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 ReactiveUI; +using ReactiveUI; using System; using System.ComponentModel; using System.Collections; diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj index 7919c3ac5a..772af9eacd 100644 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + netcoreapp3.1 true diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index bbfa3be4ab..3a7a2a186f 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -60,10 +60,17 @@ - + + + No Decorations + Border Only + Full Decorations + + Light Dark - + + diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs index acb9bc5bc6..7c17b125d6 100644 --- a/samples/ControlCatalog/MainView.xaml.cs +++ b/samples/ControlCatalog/MainView.xaml.cs @@ -56,6 +56,21 @@ namespace ControlCatalog } }; Styles.Add(light); + + var decorations = this.Find("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("Decorations"); + if (VisualRoot is Window window) + decorations.SelectedIndex = (int)window.SystemDecorations; } } } diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 248f94082d..bea751ad4c 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -14,15 +14,17 @@ - + - + - + @@ -34,6 +36,24 @@ + + + + + + + + + diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs index 38cbde9d92..d97325ef8d 100644 --- a/samples/ControlCatalog/MainWindow.xaml.cs +++ b/samples/ControlCatalog/MainWindow.xaml.cs @@ -1,13 +1,11 @@ +using System; +using System.Runtime.InteropServices; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Notifications; -using Avalonia.Controls.Primitives; +using Avalonia.Input; using Avalonia.Markup.Xaml; -using Avalonia.Threading; using ControlCatalog.ViewModels; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; namespace ControlCatalog { @@ -31,10 +29,17 @@ namespace ControlCatalog DataContext = new MainWindowViewModel(_notificationArea); _recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu; + var mainMenu = this.FindControl("MainMenu"); 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) { if (NativeMenu.GetIsNativeMenuExported(this) && sender is Menu mainMenu) diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml b/samples/ControlCatalog/Pages/DialogsPage.xaml index 60f8e3656e..1ed5c0cbfd 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml @@ -9,5 +9,6 @@ + diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index d207689223..ba1921a185 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -1,4 +1,7 @@ +using System; using System.Collections.Generic; +using System.Linq; +using System.Reflection; using Avalonia.Controls; using Avalonia.Markup.Xaml; #pragma warning disable 4014 @@ -34,7 +37,9 @@ namespace ControlCatalog.Pages new OpenFileDialog() { Title = "Open file", - Filters = GetFilters() + Filters = GetFilters(), + // Almost guaranteed to exist + InitialFileName = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName }.ShowAsync(GetWindow()); }; this.FindControl