diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 9a0da4aa9b..78b9cff039 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,16 +1,31 @@
-This template is not intended to be prescriptive, but to help us review pull requests it would be useful if you included as much of the following information as possible:
+## What does the pull request do?
-- What does the pull request do?
-- What is the current behavior?
-- What is the updated/expected behavior with this PR?
-- How was the solution implemented (if it's not obvious)?
+Give a bit of background on the PR here, together with links to with related issues etc.
-Checklist:
+## What is the current behavior?
+
+If the PR is a fix, describe the current incorrect behavior, otherwise delete this section.
+
+## What is the updated/expected behavior with this PR?
+
+Describe how to test the PR.
+
+## How was the solution implemented (if it's not obvious)?
+
+Include any information that might be of use to a reviewer here.
+
+## Checklist
- [ ] Added unit tests (if possible)?
- [ ] Added XML documentation to any related classes?
- [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Avaloniaui.net with user documentation
+## Breaking changes
+
+List any breaking changes here. When the PR is merged please add an entry to https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes
+
+## Fixed issues
+
If the pull request fixes issue(s) list them like this:
Fixes #123
diff --git a/.ncrunch/Avalonia.Desktop.v3.ncrunchproject b/.ncrunch/Avalonia.Desktop.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.Desktop.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.net461.v3.ncrunchproject b/.ncrunch/Avalonia.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/Avalonia.sln b/Avalonia.sln
index cf440972b2..d6472503fe 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -196,6 +196,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "nukebuild\_build.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Animation.UnitTests", "tests\Avalonia.Animation.UnitTests\Avalonia.Animation.UnitTests.csproj", "{AF227847-E65C-4BE9-BCE9-B551357788E0}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.X11", "src\Avalonia.X11\Avalonia.X11.csproj", "{41B02319-965D-4945-8005-C1A3D1224165}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.UnitTests", "tests\Avalonia.ReactiveUI.UnitTests\Avalonia.ReactiveUI.UnitTests.csproj", "{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@@ -1767,6 +1773,78 @@ Global
{AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhone.Build.0 = Release|Any CPU
{AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.Build.0 = Release|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhone.Build.0 = Release|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhone.Build.0 = Release|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhone.Build.0 = Release|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1821,6 +1899,9 @@ Global
{D49233F8-F29C-47DD-9975-C4C9E4502720} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
{3C471044-3640-45E3-B1B2-16D2FF8399EE} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
{AF227847-E65C-4BE9-BCE9-B551357788E0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+ {41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
+ {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
diff --git a/Avalonia.v3.ncrunchsolution b/Avalonia.v3.ncrunchsolution
index 1b5b0c8930..a2208a9a91 100644
--- a/Avalonia.v3.ncrunchsolution
+++ b/Avalonia.v3.ncrunchsolution
@@ -2,6 +2,7 @@
tests\TestFiles\**.*
+ src\Avalonia.Build.Tasks\bin\Debug\netstandard2.0\Avalonia.Build.Tasks.dll
True
.ncrunch
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index fd40118888..39333f37ba 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -92,13 +92,13 @@ jobs:
inputs:
pathToPublish: '$(Build.SourcesDirectory)/Build/Products/Release/'
artifactName: 'Avalonia.Native.OSX'
- condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false))
+ condition: succeeded()
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget'
artifactName: 'NuGetOSX'
- condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false))
+ condition: succeeded()
- job: Windows
pool:
@@ -127,10 +127,10 @@ jobs:
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget'
artifactName: 'NuGet'
- condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false))
+ condition: succeeded()
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: '$(Build.SourcesDirectory)/artifacts/zip'
artifactName: 'Samples'
- condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false))
+ condition: succeeded()
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index a43c99e978..cf8e0fd13a 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,6 +1,6 @@
-
+
diff --git a/readme.md b/readme.md
index 9280125323..12f683bd55 100644
--- a/readme.md
+++ b/readme.md
@@ -2,9 +2,9 @@
# Avalonia
-| Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective |
-|---|---|---|
-| [](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [](#backers) [](#sponsors) |
+| Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective | NuGet | MyGet |
+|---|---|---|---|---|
+| [](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [](#backers) [](#sponsors) | [](https://www.nuget.org/packages/Avalonia) | [](https://www.myget.org/gallery/avalonia-ci) |
## About
diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
index 7e2c707e91..589f41c06b 100644
--- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
+++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
@@ -9,6 +9,7 @@
+
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 0f7f2e80a8..2ddb5887e5 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -32,10 +32,10 @@
+
-
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml b/samples/ControlCatalog/Pages/DialogsPage.xaml
index 1e4e9fef1c..2bd9a39300 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml
@@ -6,6 +6,7 @@
Save File
Select Folder
Decorated window
+ Decorated window (dialog)
Dialog
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
index e380c677c9..e2e9fbd21c 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
@@ -31,15 +31,22 @@ namespace ControlCatalog.Pages
}.ShowAsync(GetWindow());
};
this.FindControl("DecoratedWindow").Click += delegate
- {
- new DecoratedWindow().ShowDialog(GetWindow());
- };
+ {
+ new DecoratedWindow().Show();
+ };
+ this.FindControl("DecoratedWindowDialog").Click += delegate
+ {
+ new DecoratedWindow().ShowDialog(GetWindow());
+ };
this.FindControl("Dialog").Click += delegate
{
- new MainWindow().ShowDialog(GetWindow());
+ var window = new Window();
+ window.Height = 200;
+ window.Width = 200;
+ window.Content = new TextBlock { Text = "Hello world!" };
+ window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
+ window.ShowDialog(GetWindow());
};
-
-
}
Window GetWindow() => (Window)this.VisualRoot;
diff --git a/samples/ControlCatalog/Pages/DropDownPage.xaml b/samples/ControlCatalog/Pages/DropDownPage.xaml
index 864d2be49c..7673294e46 100644
--- a/samples/ControlCatalog/Pages/DropDownPage.xaml
+++ b/samples/ControlCatalog/Pages/DropDownPage.xaml
@@ -27,6 +27,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/DropDownPage.xaml.cs b/samples/ControlCatalog/Pages/DropDownPage.xaml.cs
index edab5f1ceb..397f9f21e1 100644
--- a/samples/ControlCatalog/Pages/DropDownPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DropDownPage.xaml.cs
@@ -13,6 +13,9 @@ namespace ControlCatalog.Pages
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
+ var fontDropDown = this.Find("fontDropDown");
+ fontDropDown.Items = Avalonia.Media.FontFamily.SystemFontFamilies;
+ fontDropDown.SelectedIndex = 0;
}
}
}
diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs
index fd66185832..b5c6892885 100644
--- a/samples/ControlCatalog/Pages/ScreenPage.cs
+++ b/samples/ControlCatalog/Pages/ScreenPage.cs
@@ -4,6 +4,7 @@ using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Platform;
+using Avalonia.Rendering;
namespace ControlCatalog.Pages
{
@@ -23,6 +24,7 @@ namespace ControlCatalog.Pages
base.Render(context);
Window w = (Window)VisualRoot;
Screen[] screens = w.Screens.All;
+ var scaling = ((IRenderRoot)w).RenderScaling;
Pen p = new Pen(Brushes.Black);
if (screens != null)
@@ -56,7 +58,7 @@ namespace ControlCatalog.Pages
text.Text = $"Primary: {screen.Primary}";
context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text);
- text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new Rect(w.Position, w.Bounds.Size)))}";
+ text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}";
context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text);
}
diff --git a/samples/ControlCatalog/SideBar.xaml b/samples/ControlCatalog/SideBar.xaml
index f97a3064e7..625b344b8c 100644
--- a/samples/ControlCatalog/SideBar.xaml
+++ b/samples/ControlCatalog/SideBar.xaml
@@ -26,7 +26,7 @@
+
+
+
+
+
diff --git a/samples/PlatformSanityChecks/App.xaml.cs b/samples/PlatformSanityChecks/App.xaml.cs
new file mode 100644
index 0000000000..508fc1e34b
--- /dev/null
+++ b/samples/PlatformSanityChecks/App.xaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Markup.Xaml;
+
+namespace PlatformSanityChecks
+{
+ public class App : Application
+ {
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj
new file mode 100644
index 0000000000..2adef5f64e
--- /dev/null
+++ b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj
@@ -0,0 +1,13 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
+
diff --git a/samples/PlatformSanityChecks/Program.cs b/samples/PlatformSanityChecks/Program.cs
new file mode 100644
index 0000000000..99474bd0ab
--- /dev/null
+++ b/samples/PlatformSanityChecks/Program.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Diagnostics;
+using System.Reactive.Disposables;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using Avalonia;
+using Avalonia.Platform;
+using Avalonia.Threading;
+using Avalonia.X11;
+
+namespace PlatformSanityChecks
+{
+ public class Program
+ {
+ static Thread UiThread;
+
+ static void Main(string[] args)
+ {
+ UiThread = Thread.CurrentThread;
+ AppBuilder.Configure().RuntimePlatformServicesInitializer();
+ var app = new App();
+
+ AvaloniaX11PlatformExtensions.InitializeX11Platform();
+
+ CheckPlatformThreading();
+ }
+
+ static bool CheckAccess() => UiThread == Thread.CurrentThread;
+
+ static void VerifyAccess()
+ {
+ if (!CheckAccess())
+ Die("Call from invalid thread");
+ }
+
+ static Exception Die(string error)
+ {
+ Console.Error.WriteLine(error);
+ Console.Error.WriteLine(Environment.StackTrace);
+ Process.GetCurrentProcess().Kill();
+ throw new Exception(error);
+ }
+
+ static IDisposable Enter([CallerMemberName] string caller = null)
+ {
+ Console.WriteLine("Entering " + caller);
+ return Disposable.Create(() => { Console.WriteLine("Leaving " + caller); });
+ }
+
+ static void EnterLoop(Action cb, [CallerMemberName] string caller = null)
+ {
+ using (Enter(caller))
+ {
+ var cts = new CancellationTokenSource();
+ cb(cts);
+ Dispatcher.UIThread.MainLoop(cts.Token);
+ if (!cts.IsCancellationRequested)
+ Die("Unexpected loop exit");
+ }
+ }
+
+ static void CheckTimerOrdering() => EnterLoop(cts =>
+ {
+ bool firstFired = false, secondFired = false;
+ DispatcherTimer.Run(() =>
+ {
+ Console.WriteLine("Second tick");
+ VerifyAccess();
+ if (!firstFired)
+ throw Die("Invalid timer ordering");
+ if (secondFired)
+ throw Die("Invocation of finished timer");
+ secondFired = true;
+ cts.Cancel();
+ return false;
+ }, TimeSpan.FromSeconds(2));
+ DispatcherTimer.Run(() =>
+ {
+ Console.WriteLine("First tick");
+ VerifyAccess();
+ if (secondFired)
+ throw Die("Invalid timer ordering");
+ if (firstFired)
+ throw Die("Invocation of finished timer");
+ firstFired = true;
+ return false;
+ }, TimeSpan.FromSeconds(1));
+ });
+
+ static void CheckTimerTicking() => EnterLoop(cts =>
+ {
+ int ticks = 0;
+ var st = Stopwatch.StartNew();
+ DispatcherTimer.Run(() =>
+ {
+ ticks++;
+ Console.WriteLine($"Tick {ticks} at {st.Elapsed}");
+ if (ticks == 5)
+ {
+ if (st.Elapsed.TotalSeconds < 4.5)
+ Die("Timer is too fast");
+ if (st.Elapsed.TotalSeconds > 6)
+ Die("Timer is too slow");
+ cts.Cancel();
+ return false;
+ }
+
+ return true;
+ }, TimeSpan.FromSeconds(1));
+ });
+
+ static void CheckSignaling() => EnterLoop(cts =>
+ {
+ ThreadPool.QueueUserWorkItem(_ =>
+ {
+ Thread.Sleep(100);
+ Dispatcher.UIThread.Post(() =>
+ {
+ VerifyAccess();
+ cts.Cancel();
+ });
+ });
+ });
+
+ static void CheckPlatformThreading()
+ {
+ CheckSignaling();
+ CheckTimerOrdering();
+ CheckTimerTicking();
+ }
+ }
+}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs
index d55755d6e3..e89414d1f8 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs
@@ -10,10 +10,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
class PopupImpl : TopLevelImpl, IPopupImpl
{
- private Point _position;
+ private PixelPoint _position;
private bool _isAdded;
Action IWindowBaseImpl.Activated { get; set; }
- public Action PositionChanged { get; set; }
+ public Action PositionChanged { get; set; }
public Action Deactivated { get; set; }
public PopupImpl() : base(ActivityTracker.Current, true)
@@ -36,7 +36,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IScreenImpl Screen { get; }
- public Point Position
+ public PixelPoint Position
{
get { return _position; }
set
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 8e8886269c..f42faeaa63 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -99,14 +99,14 @@ namespace Avalonia.Android.Platform.SkiaPlatform
if (_view.Holder?.Surface?.IsValid == true) _view.Invalidate();
}
- public Point PointToClient(Point point)
+ public Point PointToClient(PixelPoint point)
{
- return point;
+ return point.ToPoint(1);
}
- public Point PointToScreen(Point point)
+ public PixelPoint PointToScreen(Point point)
{
- return point;
+ return PixelPoint.FromPoint(point, 1);
}
public void SetCursor(IPlatformHandle cursor)
diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Animation/AnimationInstance`1.cs
index bc7e106a2a..6f601a3e13 100644
--- a/src/Avalonia.Animation/AnimationInstance`1.cs
+++ b/src/Avalonia.Animation/AnimationInstance`1.cs
@@ -19,6 +19,7 @@ namespace Avalonia.Animation
private ulong? _iterationCount;
private ulong _currentIteration;
private bool _gotFirstKFValue;
+ private bool _playbackReversed;
private FillMode _fillMode;
private PlaybackDirection _playbackDirection;
private Animator _animator;
@@ -160,9 +161,14 @@ namespace Avalonia.Animation
_currentIteration = (ulong)(opsTime / iterationTime);
- // Stop animation when the current iteration is beyond the iteration count.
+ // Stop animation when the current iteration is beyond the iteration count
+ // and snap the last iteration value to exact values.
if ((_currentIteration + 1) > _iterationCount)
+ {
+ var easedTime = _easeFunc.Ease(_playbackReversed ? 0.0 : 1.0);
+ _lastInterpValue = _interpolator(easedTime, _neutralValue);
DoComplete();
+ }
if (playbackTime <= iterDuration)
{
@@ -170,27 +176,26 @@ namespace Avalonia.Animation
var normalizedTime = playbackTime / iterDuration;
// Check if normalized time needs to be reversed according to PlaybackDirection
-
- bool playbackReversed;
+
switch (_playbackDirection)
{
case PlaybackDirection.Normal:
- playbackReversed = false;
+ _playbackReversed = false;
break;
case PlaybackDirection.Reverse:
- playbackReversed = true;
+ _playbackReversed = true;
break;
case PlaybackDirection.Alternate:
- playbackReversed = (_currentIteration % 2 == 0) ? false : true;
+ _playbackReversed = (_currentIteration % 2 == 0) ? false : true;
break;
case PlaybackDirection.AlternateReverse:
- playbackReversed = (_currentIteration % 2 == 0) ? true : false;
+ _playbackReversed = (_currentIteration % 2 == 0) ? true : false;
break;
default:
throw new InvalidOperationException($"Animation direction value is unknown: {_playbackDirection}");
}
- if (playbackReversed)
+ if (_playbackReversed)
normalizedTime = 1 - normalizedTime;
// Ease and interpolate
diff --git a/src/Avalonia.Base/Data/Converters/ObjectConverters.cs b/src/Avalonia.Base/Data/Converters/ObjectConverters.cs
new file mode 100644
index 0000000000..3cadfd5b47
--- /dev/null
+++ b/src/Avalonia.Base/Data/Converters/ObjectConverters.cs
@@ -0,0 +1,24 @@
+// 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.
+
+
+namespace Avalonia.Data.Converters
+{
+ ///
+ /// Provides a set of useful s for working with objects.
+ ///
+ public static class ObjectConverters
+ {
+ ///
+ /// A value converter that returns true if the input object is a null reference.
+ ///
+ public static readonly IValueConverter IsNull =
+ new FuncValueConverter(x => x is null);
+
+ ///
+ /// A value converter that returns true if the input object is not null.
+ ///
+ public static readonly IValueConverter IsNotNull =
+ new FuncValueConverter(x => !(x is null));
+ }
+}
diff --git a/src/Avalonia.Base/Data/Converters/StringConverters.cs b/src/Avalonia.Base/Data/Converters/StringConverters.cs
index 0101cf5d29..42eb8e1d81 100644
--- a/src/Avalonia.Base/Data/Converters/StringConverters.cs
+++ b/src/Avalonia.Base/Data/Converters/StringConverters.cs
@@ -12,13 +12,13 @@ namespace Avalonia.Data.Converters
///
/// A value converter that returns true if the input string is null or an empty string.
///
- public static readonly IValueConverter NullOrEmpty =
+ public static readonly IValueConverter IsNullOrEmpty =
new FuncValueConverter(string.IsNullOrEmpty);
///
/// A value converter that returns true if the input string is not null or empty.
///
- public static readonly IValueConverter NotNullOrEmpty =
+ public static readonly IValueConverter IsNotNullOrEmpty =
new FuncValueConverter(x => !string.IsNullOrEmpty(x));
}
}
diff --git a/src/Avalonia.Controls/ContentControl.cs b/src/Avalonia.Controls/ContentControl.cs
index 20ec581108..6da6da54a5 100644
--- a/src/Avalonia.Controls/ContentControl.cs
+++ b/src/Avalonia.Controls/ContentControl.cs
@@ -45,8 +45,6 @@ namespace Avalonia.Controls
static ContentControl()
{
ContentControlMixin.Attach(ContentProperty, x => x.LogicalChildren);
- PseudoClass(ContentProperty, x => x != null, ":valid");
- PseudoClass(ContentProperty, x => x == null, ":invalid");
}
///
diff --git a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
index 37bb72e75a..d328e1ee88 100644
--- a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
+++ b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
@@ -49,9 +49,9 @@ namespace Avalonia.Controls.Embedding.Offscreen
public Action ScalingChanged { get; set; }
public void SetInputRoot(IInputRoot inputRoot) => InputRoot = inputRoot;
- public virtual Point PointToClient(Point point) => point;
+ public virtual Point PointToClient(PixelPoint point) => point.ToPoint(1);
- public virtual Point PointToScreen(Point point) => point;
+ public virtual PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, 1);
public virtual void SetCursor(IPlatformHandle cursor)
{
diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
index 57db1e19bb..18cef7d64e 100644
--- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
+++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
@@ -287,6 +287,13 @@ namespace Avalonia.Controls
ValueProperty.Changed.Subscribe(OnValueChanged);
}
+ ///
+ protected override void OnLostFocus(RoutedEventArgs e)
+ {
+ CommitInput();
+ base.OnLostFocus(e);
+ }
+
///
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
@@ -812,7 +819,7 @@ namespace Avalonia.Controls
///
/// Raised when the changes.
///
- public event EventHandler ValueChanged
+ public event EventHandler ValueChanged
{
add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
diff --git a/src/Avalonia.Controls/PixelPointEventArgs.cs b/src/Avalonia.Controls/PixelPointEventArgs.cs
new file mode 100644
index 0000000000..55a3d5601f
--- /dev/null
+++ b/src/Avalonia.Controls/PixelPointEventArgs.cs
@@ -0,0 +1,27 @@
+// 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;
+
+namespace Avalonia.Controls
+{
+ ///
+ /// Provides data for events.
+ ///
+ public class PixelPointEventArgs : EventArgs
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The data.
+ public PixelPointEventArgs(PixelPoint point)
+ {
+ Point = point;
+ }
+
+ ///
+ /// Gets the data.
+ ///
+ public PixelPoint Point { get; }
+ }
+}
diff --git a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
index 60e25d2be6..8d8ce35c38 100644
--- a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
+++ b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
@@ -82,14 +82,14 @@ namespace Avalonia.Platform
///
/// The point in screen coordinates.
/// The point in client coordinates.
- Point PointToClient(Point point);
+ Point PointToClient(PixelPoint point);
///
/// Converts a point from client to screen coordinates.
///
/// The point in client coordinates.
/// The point in screen coordinates.
- Point PointToScreen(Point point);
+ PixelPoint PointToScreen(Point point);
///
/// Sets the cursor associated with the toplevel.
diff --git a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs
index e788b3c73e..b37521de30 100644
--- a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs
@@ -27,14 +27,14 @@ namespace Avalonia.Platform
void BeginResizeDrag(WindowEdge edge);
///
- /// Gets position of the window relatively to the screen
+ /// Gets the position of the window in device pixels.
///
- Point Position { get; set; }
+ PixelPoint Position { get; set; }
///
/// Gets or sets a method called when the window's position changes.
///
- Action PositionChanged { get; set; }
+ Action PositionChanged { get; set; }
///
/// Activates the window.
diff --git a/src/Avalonia.Controls/Platform/Screen.cs b/src/Avalonia.Controls/Platform/Screen.cs
index 5aa8c2c392..e7c811235c 100644
--- a/src/Avalonia.Controls/Platform/Screen.cs
+++ b/src/Avalonia.Controls/Platform/Screen.cs
@@ -2,17 +2,17 @@
{
public class Screen
{
- public Rect Bounds { get; }
+ public PixelRect Bounds { get; }
- public Rect WorkingArea { get; }
+ public PixelRect WorkingArea { get; }
public bool Primary { get; }
- public Screen(Rect bounds, Rect workingArea, bool primary)
+ public Screen(PixelRect bounds, PixelRect workingArea, bool primary)
{
this.Bounds = bounds;
this.WorkingArea = workingArea;
this.Primary = primary;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Controls/PointEventArgs.cs b/src/Avalonia.Controls/PointEventArgs.cs
deleted file mode 100644
index 4173d367d0..0000000000
--- a/src/Avalonia.Controls/PointEventArgs.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
-
-namespace Avalonia.Controls
-{
- ///
- /// Provides data for events.
- ///
- public class PointEventArgs : EventArgs
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The data.
- public PointEventArgs(Point point)
- {
- Point = point;
- }
-
- ///
- /// Gets the data.
- ///
- public Point Point { get; }
- }
-}
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index 5e79711f5a..d9070197b6 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -380,7 +380,7 @@ namespace Avalonia.Controls.Primitives
/// Gets the position for the popup based on the placement properties.
///
/// The popup's position in screen coordinates.
- protected virtual Point GetPosition()
+ protected virtual PixelPoint GetPosition()
{
var result = GetPosition(PlacementTarget ?? this.GetVisualParent(), PlacementMode, PopupRoot,
HorizontalOffset, VerticalOffset);
@@ -388,35 +388,31 @@ namespace Avalonia.Controls.Primitives
return result;
}
- internal static Point GetPosition(Control target, PlacementMode placement, PopupRoot popupRoot, double horizontalOffset, double verticalOffset)
+ internal static PixelPoint GetPosition(Control target, PlacementMode placement, PopupRoot popupRoot, double horizontalOffset, double verticalOffset)
{
- var zero = default(Point);
- var mode = placement;
-
- if (target?.GetVisualRoot() == null)
- {
- mode = PlacementMode.Pointer;
- }
+ var root = target?.GetVisualRoot();
+ var mode = root != null ? placement : PlacementMode.Pointer;
+ var scaling = root?.RenderScaling ?? 1;
switch (mode)
{
case PlacementMode.Pointer:
if (popupRoot != null)
{
- // Scales the Horizontal and Vertical offset to screen co-ordinates.
- var screenOffset = new Point(horizontalOffset * (popupRoot as ILayoutRoot).LayoutScaling,
- verticalOffset * (popupRoot as ILayoutRoot).LayoutScaling);
- return (((IInputRoot)popupRoot)?.MouseDevice?.Position ?? default(Point)) + screenOffset;
+ var screenOffset = PixelPoint.FromPoint(new Point(horizontalOffset, verticalOffset), scaling);
+ var mouseOffset = ((IInputRoot)popupRoot)?.MouseDevice?.Position ?? default;
+ return new PixelPoint(
+ screenOffset.X + mouseOffset.X,
+ screenOffset.Y + mouseOffset.Y);
}
- return default(Point);
+ return default;
case PlacementMode.Bottom:
- return target?.PointToScreen(new Point(0 + horizontalOffset, target.Bounds.Height + verticalOffset)) ??
- zero;
+ return target?.PointToScreen(new Point(0 + horizontalOffset, target.Bounds.Height + verticalOffset)) ?? default;
case PlacementMode.Right:
- return target?.PointToScreen(new Point(target.Bounds.Width + horizontalOffset, 0 + verticalOffset)) ?? zero;
+ return target?.PointToScreen(new Point(target.Bounds.Width + horizontalOffset, 0 + verticalOffset)) ?? default;
default:
throw new InvalidOperationException("Invalid value for Popup.PlacementMode");
diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs
index 286f7df3b9..59a8933b4b 100644
--- a/src/Avalonia.Controls/Primitives/PopupRoot.cs
+++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs
@@ -85,18 +85,18 @@ namespace Avalonia.Controls.Primitives
if (screen != null)
{
var scaling = VisualRoot.RenderScaling;
-
- var screenX = Position.X + (Bounds.Width * scaling) - screen.Bounds.X;
- var screenY = Position.Y + (Bounds.Height * scaling) - screen.Bounds.Y;
+ var bounds = PixelRect.FromRect(Bounds, scaling);
+ var screenX = Position.X + bounds.Width - screen.Bounds.X;
+ var screenY = Position.Y + bounds.Height - screen.Bounds.Y;
if (screenX > screen.Bounds.Width)
{
- Position = Position.WithX(Position.X - (screenX - screen.Bounds.Width));
+ Position = Position.WithX(Position.X - screenX - bounds.Width);
}
if (screenY > screen.Bounds.Height)
{
- Position = Position.WithY(Position.Y - (screenY - screen.Bounds.Height));
+ Position = Position.WithY(Position.Y - screenY - bounds.Height);
}
}
}
diff --git a/src/Avalonia.Controls/Screens.cs b/src/Avalonia.Controls/Screens.cs
index 2bfddc048b..5a90adadbd 100644
--- a/src/Avalonia.Controls/Screens.cs
+++ b/src/Avalonia.Controls/Screens.cs
@@ -18,7 +18,7 @@ namespace Avalonia.Controls
_iScreenImpl = iScreenImpl;
}
- public Screen ScreenFromBounds(Rect bounds){
+ public Screen ScreenFromBounds(PixelRect bounds){
Screen currMaxScreen = null;
double maxAreaSize = 0;
@@ -39,16 +39,16 @@ namespace Avalonia.Controls
return currMaxScreen;
}
- public Screen ScreenFromPoint(Point point)
+ public Screen ScreenFromPoint(PixelPoint point)
{
- return All.FirstOrDefault(x=>x.Bounds.Contains(point));
+ return All.FirstOrDefault(x => x.Bounds.Contains(point));
}
public Screen ScreenFromVisual(IVisual visual)
{
- Point tl = visual.PointToScreen(visual.Bounds.TopLeft);
- Point br = visual.PointToScreen(visual.Bounds.BottomRight);
- return ScreenFromBounds(new Rect(tl,br));
+ var tl = visual.PointToScreen(visual.Bounds.TopLeft);
+ var br = visual.PointToScreen(visual.Bounds.BottomRight);
+ return ScreenFromBounds(new PixelRect(tl, br));
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Controls/TabControl.cs b/src/Avalonia.Controls/TabControl.cs
index 8eaf166f57..d6537ebbca 100644
--- a/src/Avalonia.Controls/TabControl.cs
+++ b/src/Avalonia.Controls/TabControl.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Controls.Generators;
+using Avalonia.Controls.Mixins;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
@@ -65,6 +66,10 @@ namespace Avalonia.Controls
SelectionModeProperty.OverrideDefaultValue(SelectionMode.AlwaysSelected);
ItemsPanelProperty.OverrideDefaultValue(DefaultPanel);
AffectsMeasure(TabStripPlacementProperty);
+ ContentControlMixin.Attach(
+ SelectedContentProperty,
+ x => x.LogicalChildren,
+ "PART_SelectedContentHost");
}
///
@@ -142,7 +147,7 @@ namespace Avalonia.Controls
ItemsPresenterPart = e.NameScope.Get("PART_ItemsPresenter");
- ContentPart = e.NameScope.Get("PART_Content");
+ ContentPart = e.NameScope.Get("PART_SelectedContentHost");
}
///
diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index 5443baf225..32c40847c5 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -98,6 +98,11 @@ namespace Avalonia.Controls
Renderer = impl.CreateRenderer(this);
+ if (Renderer != null)
+ {
+ Renderer.SceneInvalidated += SceneInvalidated;
+ }
+
impl.SetInputRoot(this);
impl.Closed = HandleClosed;
@@ -131,6 +136,11 @@ namespace Avalonia.Controls
}
}
+ ///
+ /// Fired when the window is opened.
+ ///
+ public event EventHandler Opened;
+
///
/// Fired when the window is closed.
///
@@ -231,17 +241,17 @@ namespace Avalonia.Controls
{
PlatformImpl?.Invalidate(rect);
}
-
+
///
- Point IRenderRoot.PointToClient(Point p)
+ Point IRenderRoot.PointToClient(PixelPoint p)
{
- return PlatformImpl?.PointToClient(p) ?? default(Point);
+ return PlatformImpl?.PointToClient(p) ?? default;
}
///
- Point IRenderRoot.PointToScreen(Point p)
+ PixelPoint IRenderRoot.PointToScreen(Point p)
{
- return PlatformImpl?.PointToScreen(p) ?? default(Point);
+ return PlatformImpl?.PointToScreen(p) ?? default;
}
///
@@ -306,6 +316,12 @@ namespace Avalonia.Controls
$"Control '{GetType().Name}' is a top level control and cannot be added as a child.");
}
+ ///
+ /// Raises the event.
+ ///
+ /// The event args.
+ protected virtual void OnOpened(EventArgs e) => Opened?.Invoke(this, e);
+
///
/// Tries to get a service from an , logging a
/// warning if not found.
@@ -349,5 +365,10 @@ namespace Avalonia.Controls
{
_inputManager.ProcessInput(e);
}
+
+ private void SceneInvalidated(object sender, SceneInvalidatedEventArgs e)
+ {
+ (this as IInputRoot).MouseDevice.SceneInvalidated(this, e.DirtyRect);
+ }
}
}
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index 46916efc1d..f5af6774b5 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -388,45 +388,49 @@ namespace Avalonia.Controls
PlatformImpl?.Show();
Renderer?.Start();
}
- SetWindowStartupLocation();
+ SetWindowStartupLocation(Owner?.PlatformImpl);
+ OnOpened(EventArgs.Empty);
}
///
/// Shows the window as a dialog.
///
+ /// The dialog's owner window.
///
/// A task that can be used to track the lifetime of the dialog.
///
- public Task ShowDialog(Window parent)
+ public Task ShowDialog(Window owner)
{
- return ShowDialog(parent);
+ return ShowDialog(owner);
}
-
///
/// Shows the window as a dialog.
///
///
/// The type of the result produced by the dialog.
///
+ /// The dialog's owner window.
/// .
/// A task that can be used to retrieve the result of the dialog when it closes.
///
- public Task ShowDialog(Window parent) => ShowDialog(parent.PlatformImpl);
-
+ public Task ShowDialog(Window owner) => ShowDialog(owner.PlatformImpl);
+
///
/// Shows the window as a dialog.
///
///
/// The type of the result produced by the dialog.
///
+ /// The dialog's owner window.
/// .
/// A task that can be used to retrieve the result of the dialog when it closes.
///
- public Task ShowDialog(IWindowImpl parent)
+ public Task ShowDialog(IWindowImpl owner)
{
- if(parent == null)
- throw new ArgumentNullException(nameof(parent));
+ if(owner == null)
+ throw new ArgumentNullException(nameof(owner));
+
if (IsVisible)
{
throw new InvalidOperationException("The window is already being shown.");
@@ -435,15 +439,15 @@ namespace Avalonia.Controls
AddWindow(this);
EnsureInitialized();
- SetWindowStartupLocation();
IsVisible = true;
LayoutManager.ExecuteInitialLayoutPass(this);
+ var result = new TaskCompletionSource();
+
using (BeginAutoSizing())
{
- PlatformImpl?.ShowDialog(parent);
- var result = new TaskCompletionSource();
+ PlatformImpl?.ShowDialog(owner);
Renderer?.Start();
Observable.FromEventPattern(
@@ -452,29 +456,43 @@ namespace Avalonia.Controls
.Take(1)
.Subscribe(_ =>
{
- parent.Activate();
+ owner.Activate();
result.SetResult((TResult)(_dialogResult ?? default(TResult)));
});
-
- return result.Task;
+ OnOpened(EventArgs.Empty);
}
+
+ SetWindowStartupLocation(owner);
+ return result.Task;
}
- void SetWindowStartupLocation()
+ private void SetWindowStartupLocation(IWindowBaseImpl owner = null)
{
+ var scaling = owner?.Scaling ?? PlatformImpl?.Scaling ?? 1;
+
+ // TODO: We really need non-client size here.
+ var rect = new PixelRect(
+ PixelPoint.Origin,
+ PixelSize.FromSize(ClientSize, scaling));
+
if (WindowStartupLocation == WindowStartupLocation.CenterScreen)
{
- var screen = Screens.ScreenFromPoint(Bounds.Position);
+ var screen = Screens.ScreenFromPoint(owner?.Position ?? Position);
if (screen != null)
- Position = screen.WorkingArea.CenterRect(new Rect(ClientSize)).Position;
+ {
+ Position = screen.WorkingArea.CenterRect(rect).Position;
+ }
}
else if (WindowStartupLocation == WindowStartupLocation.CenterOwner)
{
- if (Owner != null)
+ if (owner != null)
{
- var positionAsSize = Owner.ClientSize / 2 - ClientSize / 2;
- Position = Owner.Position + new Point(positionAsSize.Width, positionAsSize.Height);
+ // TODO: We really need non-client size here.
+ var ownerRect = new PixelRect(
+ owner.Position,
+ PixelSize.FromSize(owner.ClientSize, scaling));
+ Position = ownerRect.CenterRect(rect).Position;
}
}
}
diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs
index f609432545..56ffd315f1 100644
--- a/src/Avalonia.Controls/WindowBase.cs
+++ b/src/Avalonia.Controls/WindowBase.cs
@@ -81,7 +81,7 @@ namespace Avalonia.Controls
///
/// Fired when the window position is changed.
///
- public event EventHandler PositionChanged;
+ public event EventHandler PositionChanged;
[CanBeNull]
public new IWindowBaseImpl PlatformImpl => (IWindowBaseImpl) base.PlatformImpl;
@@ -98,9 +98,9 @@ namespace Avalonia.Controls
///
/// Gets or sets the window position in screen coordinates.
///
- public Point Position
+ public PixelPoint Position
{
- get { return PlatformImpl?.Position ?? default(Point); }
+ get { return PlatformImpl?.Position ?? PixelPoint.Origin; }
set
{
if (PlatformImpl is IWindowBaseImpl impl)
@@ -163,7 +163,7 @@ namespace Avalonia.Controls
}
///
- /// Shows the popup.
+ /// Shows the window.
///
public virtual void Show()
{
@@ -181,6 +181,7 @@ namespace Avalonia.Controls
}
PlatformImpl?.Show();
Renderer?.Start();
+ OnOpened(EventArgs.Empty);
}
finally
{
@@ -267,9 +268,9 @@ namespace Avalonia.Controls
/// .
///
/// The window position.
- private void HandlePositionChanged(Point pos)
+ private void HandlePositionChanged(PixelPoint pos)
{
- PositionChanged?.Invoke(this, new PointEventArgs(pos));
+ PositionChanged?.Invoke(this, new PixelPointEventArgs(pos));
}
///
diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
index cff59f2f8b..dc01bcb07e 100644
--- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
+++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
@@ -35,8 +35,8 @@ namespace Avalonia.DesignerSupport.Remote
{
}
- public Point Position { get; set; }
- public Action PositionChanged { get; set; }
+ public PixelPoint Position { get; set; }
+ public Action PositionChanged { get; set; }
public Action Deactivated { get; set; }
public Action Activated { get; set; }
public Func Closing { get; set; }
diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
index 8f5b97af41..d849bfc021 100644
--- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs
+++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
@@ -29,8 +29,8 @@ namespace Avalonia.DesignerSupport.Remote
public Func Closing { get; set; }
public Action Closed { get; set; }
public IMouseDevice MouseDevice { get; } = new MouseDevice();
- public Point Position { get; set; }
- public Action PositionChanged { get; set; }
+ public PixelPoint Position { get; set; }
+ public Action PositionChanged { get; set; }
public WindowState WindowState { get; set; }
public Action WindowStateChanged { get; set; }
public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
@@ -45,9 +45,9 @@ namespace Avalonia.DesignerSupport.Remote
{
}
- public Point PointToClient(Point point) => point;
+ public Point PointToClient(PixelPoint p) => p.ToPoint(1);
- public Point PointToScreen(Point point) => point;
+ public PixelPoint PointToScreen(Point p) => PixelPoint.FromPoint(p, 1);
public void SetCursor(IPlatformHandle cursor)
{
@@ -157,6 +157,6 @@ namespace Avalonia.DesignerSupport.Remote
public int ScreenCount => 1;
public Screen[] AllScreens { get; } =
- {new Screen(new Rect(0, 0, 4000, 4000), new Rect(0, 0, 4000, 4000), true)};
+ {new Screen(new PixelRect(0, 0, 4000, 4000), new PixelRect(0, 0, 4000, 4000), true)};
}
}
diff --git a/src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs b/src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs
index 4db6de353f..36f762d625 100644
--- a/src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs
+++ b/src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs
@@ -29,7 +29,7 @@ namespace Avalonia
}
else
{
- LoadGtk3(builder);
+ LoadX11(builder);
LoadSkia(builder);
}
return builder;
@@ -42,9 +42,9 @@ namespace Avalonia
where TAppBuilder : AppBuilderBase, new()
=> builder.UseWin32();
- static void LoadGtk3(TAppBuilder builder)
+ static void LoadX11(TAppBuilder builder)
where TAppBuilder : AppBuilderBase, new()
- => builder.UseGtk3();
+ => builder.UseX11();
static void LoadDirect2D1(TAppBuilder builder)
where TAppBuilder : AppBuilderBase, new()
diff --git a/src/Avalonia.Desktop/Avalonia.Desktop.csproj b/src/Avalonia.Desktop/Avalonia.Desktop.csproj
index 3fc20150a7..f7c06306f5 100644
--- a/src/Avalonia.Desktop/Avalonia.Desktop.csproj
+++ b/src/Avalonia.Desktop/Avalonia.Desktop.csproj
@@ -1,14 +1,14 @@
- netstandard2.0
+ netstandard2.0
-
+
diff --git a/src/Avalonia.Input/IMouseDevice.cs b/src/Avalonia.Input/IMouseDevice.cs
index 58e2222295..a1d1bb3eb8 100644
--- a/src/Avalonia.Input/IMouseDevice.cs
+++ b/src/Avalonia.Input/IMouseDevice.cs
@@ -11,6 +11,6 @@ namespace Avalonia.Input
///
/// Gets the mouse position, in screen coordinates.
///
- Point Position { get; }
+ PixelPoint Position { get; }
}
}
diff --git a/src/Avalonia.Input/IPointerDevice.cs b/src/Avalonia.Input/IPointerDevice.cs
index 8613717f60..932cbc989f 100644
--- a/src/Avalonia.Input/IPointerDevice.cs
+++ b/src/Avalonia.Input/IPointerDevice.cs
@@ -12,5 +12,7 @@ namespace Avalonia.Input
void Capture(IInputElement control);
Point GetPosition(IVisual relativeTo);
+
+ void SceneInvalidated(IInputRoot root, Rect rect);
}
}
diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs
index e581772978..7945ee8ee4 100644
--- a/src/Avalonia.Input/MouseDevice.cs
+++ b/src/Avalonia.Input/MouseDevice.cs
@@ -18,7 +18,7 @@ namespace Avalonia.Input
{
private int _clickCount;
private Rect _lastClickRect;
- private uint _lastClickTime;
+ private ulong _lastClickTime;
private IInputElement _captured;
private IDisposable _capturedSubscription;
@@ -54,7 +54,7 @@ namespace Avalonia.Input
///
/// Gets the mouse position, in screen coordinates.
///
- public Point Position
+ public PixelPoint Position
{
get;
protected set;
@@ -104,6 +104,23 @@ namespace Avalonia.Input
ProcessRawEvent(margs);
}
+ public void SceneInvalidated(IInputRoot root, Rect rect)
+ {
+ var clientPoint = root.PointToClient(Position);
+
+ if (rect.Contains(clientPoint))
+ {
+ if (Captured == null)
+ {
+ SetPointerOver(this, root, clientPoint);
+ }
+ else
+ {
+ SetPointerOver(this, root, Captured);
+ }
+ }
+ }
+
private void ProcessRawEvent(RawMouseEventArgs e)
{
Contract.Requires(e != null);
@@ -152,7 +169,7 @@ namespace Avalonia.Input
ClearPointerOver(this, root);
}
- private bool MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers)
+ private bool MouseDown(IMouseDevice device, ulong timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers)
{
Contract.Requires(device != null);
Contract.Requires(root != null);
@@ -305,16 +322,41 @@ namespace Avalonia.Input
Device = device,
};
+ if (element!=null && !element.IsAttachedToVisualTree)
+ {
+ // element has been removed from visual tree so do top down cleanup
+ if (root.IsPointerOver)
+ ClearChildrenPointerOver(e, root,true);
+ }
while (element != null)
{
e.Source = element;
+ e.Handled = false;
element.RaiseEvent(e);
element = (IInputElement)element.VisualParent;
}
-
+
root.PointerOverElement = null;
}
+ private void ClearChildrenPointerOver(PointerEventArgs e, IInputElement element,bool clearRoot)
+ {
+ foreach (IInputElement el in element.VisualChildren)
+ {
+ if (el.IsPointerOver)
+ {
+ ClearChildrenPointerOver(e, el, true);
+ break;
+ }
+ }
+ if(clearRoot)
+ {
+ e.Source = element;
+ e.Handled = false;
+ element.RaiseEvent(e);
+ }
+ }
+
private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, Point p)
{
Contract.Requires(device != null);
@@ -361,13 +403,18 @@ namespace Avalonia.Input
el = root.PointerOverElement;
e.RoutedEvent = InputElement.PointerLeaveEvent;
+ if (el!=null && branch!=null && !el.IsAttachedToVisualTree)
+ {
+ ClearChildrenPointerOver(e,branch,false);
+ }
+
while (el != null && el != branch)
{
e.Source = el;
e.Handled = false;
el.RaiseEvent(e);
el = (IInputElement)el.VisualParent;
- }
+ }
el = root.PointerOverElement = element;
e.RoutedEvent = InputElement.PointerEnterEvent;
diff --git a/src/Avalonia.Input/Raw/RawDragEvent.cs b/src/Avalonia.Input/Raw/RawDragEvent.cs
index d251fe8640..208d898a8a 100644
--- a/src/Avalonia.Input/Raw/RawDragEvent.cs
+++ b/src/Avalonia.Input/Raw/RawDragEvent.cs
@@ -3,7 +3,7 @@
public class RawDragEvent : RawInputEventArgs
{
public IInputElement InputRoot { get; }
- public Point Location { get; }
+ public Point Location { get; set; }
public IDataObject Data { get; }
public DragDropEffects Effects { get; set; }
public RawDragEventType Type { get; }
diff --git a/src/Avalonia.Input/Raw/RawInputEventArgs.cs b/src/Avalonia.Input/Raw/RawInputEventArgs.cs
index 041c361d30..78c1b58624 100644
--- a/src/Avalonia.Input/Raw/RawInputEventArgs.cs
+++ b/src/Avalonia.Input/Raw/RawInputEventArgs.cs
@@ -21,7 +21,7 @@ namespace Avalonia.Input.Raw
///
/// The associated device.
/// The event timestamp.
- public RawInputEventArgs(IInputDevice device, uint timestamp)
+ public RawInputEventArgs(IInputDevice device, ulong timestamp)
{
Contract.Requires(device != null);
@@ -47,6 +47,6 @@ namespace Avalonia.Input.Raw
///
/// Gets the timestamp associated with the event.
///
- public uint Timestamp { get; private set; }
+ public ulong Timestamp { get; private set; }
}
}
diff --git a/src/Avalonia.Input/Raw/RawKeyEventArgs.cs b/src/Avalonia.Input/Raw/RawKeyEventArgs.cs
index 0c208b4596..044f244138 100644
--- a/src/Avalonia.Input/Raw/RawKeyEventArgs.cs
+++ b/src/Avalonia.Input/Raw/RawKeyEventArgs.cs
@@ -13,7 +13,7 @@ namespace Avalonia.Input.Raw
{
public RawKeyEventArgs(
IKeyboardDevice device,
- uint timestamp,
+ ulong timestamp,
RawKeyEventType type,
Key key, InputModifiers modifiers)
: base(device, timestamp)
diff --git a/src/Avalonia.Input/Raw/RawMouseEventArgs.cs b/src/Avalonia.Input/Raw/RawMouseEventArgs.cs
index 914833624f..c5637d66cc 100644
--- a/src/Avalonia.Input/Raw/RawMouseEventArgs.cs
+++ b/src/Avalonia.Input/Raw/RawMouseEventArgs.cs
@@ -35,7 +35,7 @@ namespace Avalonia.Input.Raw
/// The input modifiers.
public RawMouseEventArgs(
IInputDevice device,
- uint timestamp,
+ ulong timestamp,
IInputRoot root,
RawMouseEventType type,
Point position,
diff --git a/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs b/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs
index f4078af9e1..d2e5faab6c 100644
--- a/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs
+++ b/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs
@@ -8,7 +8,7 @@ namespace Avalonia.Input.Raw
{
public RawMouseWheelEventArgs(
IInputDevice device,
- uint timestamp,
+ ulong timestamp,
IInputRoot root,
Point position,
Vector delta, InputModifiers inputModifiers)
diff --git a/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs b/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs
index 6e427c3751..0d1e5d2422 100644
--- a/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs
+++ b/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs
@@ -7,7 +7,7 @@ namespace Avalonia.Input.Raw
{
public string Text { get; set; }
- public RawTextInputEventArgs(IKeyboardDevice device, uint timestamp, string text) : base(device, timestamp)
+ public RawTextInputEventArgs(IKeyboardDevice device, ulong timestamp, string text) : base(device, timestamp)
{
Text = text;
}
diff --git a/src/Avalonia.Native/Helpers.cs b/src/Avalonia.Native/Helpers.cs
index c9d1256e91..a77e7d4ff8 100644
--- a/src/Avalonia.Native/Helpers.cs
+++ b/src/Avalonia.Native/Helpers.cs
@@ -12,11 +12,21 @@ namespace Avalonia.Native
return new Point(pt.X, pt.Y);
}
+ public static PixelPoint ToAvaloniaPixelPoint(this AvnPoint pt)
+ {
+ return new PixelPoint((int)pt.X, (int)pt.Y);
+ }
+
public static AvnPoint ToAvnPoint (this Point pt)
{
return new AvnPoint { X = pt.X, Y = pt.Y };
}
+ public static AvnPoint ToAvnPoint(this PixelPoint pt)
+ {
+ return new AvnPoint { X = pt.X, Y = pt.Y };
+ }
+
public static AvnSize ToAvnSize (this Size size)
{
return new AvnSize { Height = size.Height, Width = size.Width };
@@ -31,5 +41,10 @@ namespace Avalonia.Native
{
return new Rect(rect.X, rect.Y, rect.Width, rect.Height);
}
+
+ public static PixelRect ToAvaloniaPixelRect(this AvnRect rect)
+ {
+ return new PixelRect((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
+ }
}
}
diff --git a/src/Avalonia.Native/ScreenImpl.cs b/src/Avalonia.Native/ScreenImpl.cs
index 079062c254..c1edd6c846 100644
--- a/src/Avalonia.Native/ScreenImpl.cs
+++ b/src/Avalonia.Native/ScreenImpl.cs
@@ -29,7 +29,10 @@ namespace Avalonia.Native
{
var screen = _native.GetScreen(i);
- result[i] = new Screen(screen.Bounds.ToAvaloniaRect(), screen.WorkingArea.ToAvaloniaRect(), screen.Primary);
+ result[i] = new Screen(
+ screen.Bounds.ToAvaloniaPixelRect(),
+ screen.WorkingArea.ToAvaloniaPixelRect(),
+ screen.Primary);
}
return result;
diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs
index 629c91a2e8..3c8d8b597f 100644
--- a/src/Avalonia.Native/WindowImplBase.cs
+++ b/src/Avalonia.Native/WindowImplBase.cs
@@ -159,7 +159,7 @@ namespace Avalonia.Native
void IAvnWindowBaseEvents.PositionChanged(AvnPoint position)
{
- _parent.PositionChanged?.Invoke(position.ToAvaloniaPoint());
+ _parent.PositionChanged?.Invoke(position.ToAvaloniaPixelPoint());
}
void IAvnWindowBaseEvents.RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)
@@ -275,20 +275,20 @@ namespace Avalonia.Native
}
- public Point Position
+ public PixelPoint Position
{
- get => _native.GetPosition().ToAvaloniaPoint();
+ get => _native.GetPosition().ToAvaloniaPixelPoint();
set => _native.SetPosition(value.ToAvnPoint());
}
- public Point PointToClient(Point point)
+ public Point PointToClient(PixelPoint point)
{
return _native.PointToClient(point.ToAvnPoint()).ToAvaloniaPoint();
}
- public Point PointToScreen(Point point)
+ public PixelPoint PointToScreen(Point point)
{
- return _native.PointToScreen(point.ToAvnPoint()).ToAvaloniaPoint();
+ return _native.PointToScreen(point.ToAvnPoint()).ToAvaloniaPixelPoint();
}
public void Hide()
@@ -320,7 +320,7 @@ namespace Avalonia.Native
_native.Cursor = newCursor.Cursor;
}
- public Action PositionChanged { get; set; }
+ public Action PositionChanged { get; set; }
public Action Input { get; set; }
diff --git a/src/Avalonia.OpenGL/EglContext.cs b/src/Avalonia.OpenGL/EglContext.cs
index 27b1abe411..17caf84179 100644
--- a/src/Avalonia.OpenGL/EglContext.cs
+++ b/src/Avalonia.OpenGL/EglContext.cs
@@ -31,14 +31,14 @@ namespace Avalonia.OpenGL
public void MakeCurrent()
{
if (!_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, Context))
- throw new OpenGlException("eglMakeCurrent failed");
+ throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
}
public void MakeCurrent(EglSurface surface)
{
- var surf = ((EglSurface)surface)?.DangerousGetHandle() ?? OffscreenSurface;
+ var surf = surface?.DangerousGetHandle() ?? OffscreenSurface;
if (!_egl.MakeCurrent(_disp.Handle, surf, surf, Context))
- throw new OpenGlException("eglMakeCurrent failed");
+ throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
}
}
}
diff --git a/src/Avalonia.OpenGL/EglDisplay.cs b/src/Avalonia.OpenGL/EglDisplay.cs
index 90a70adcb7..b14932acfe 100644
--- a/src/Avalonia.OpenGL/EglDisplay.cs
+++ b/src/Avalonia.OpenGL/EglDisplay.cs
@@ -1,5 +1,4 @@
using System;
-using System.ComponentModel;
using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
using static Avalonia.OpenGL.EglConsts;
@@ -34,11 +33,11 @@ namespace Avalonia.OpenGL
if (_display == IntPtr.Zero)
_display = _egl.GetDisplay(IntPtr.Zero);
- if(_display == IntPtr.Zero)
- throw new OpenGlException("eglGetDisplay failed");
-
+ if (_display == IntPtr.Zero)
+ throw OpenGlException.GetFormattedException("eglGetDisplay", _egl);
+
if (!_egl.Initialize(_display, out var major, out var minor))
- throw new OpenGlException("eglInitialize failed");
+ throw OpenGlException.GetFormattedException("eglInitialize", _egl);
foreach (var cfg in new[]
{
@@ -87,18 +86,8 @@ namespace Avalonia.OpenGL
if (_contextAttributes == null)
throw new OpenGlException("No suitable EGL config was found");
-
- GlInterface = new GlInterface((proc, optional) =>
- {
- using (var u = new Utf8Buffer(proc))
- {
- var rv = _egl.GetProcAddress(u);
- if (rv == IntPtr.Zero && !optional)
- throw new OpenGlException("Missing function " + proc);
- return rv;
- }
- });
+ GlInterface = GlInterface.FromNativeUtf8GetProcAddress(b => _egl.GetProcAddress(b));
}
public EglDisplay() : this(new EglInterface())
@@ -113,7 +102,7 @@ namespace Avalonia.OpenGL
var shareCtx = (EglContext)share;
var ctx = _egl.CreateContext(_display, _config, shareCtx?.Context ?? IntPtr.Zero, _contextAttributes);
if (ctx == IntPtr.Zero)
- throw new OpenGlException("eglCreateContext failed");
+ throw OpenGlException.GetFormattedException("eglCreateContext", _egl);
var surf = _egl.CreatePBufferSurface(_display, _config, new[]
{
EGL_WIDTH, 1,
@@ -121,7 +110,7 @@ namespace Avalonia.OpenGL
EGL_NONE
});
if (surf == IntPtr.Zero)
- throw new OpenGlException("eglCreatePbufferSurface failed");
+ throw OpenGlException.GetFormattedException("eglCreatePBufferSurface", _egl);
var rv = new EglContext(this, _egl, ctx, surf);
rv.MakeCurrent(null);
return rv;
@@ -130,14 +119,14 @@ namespace Avalonia.OpenGL
public void ClearContext()
{
if (!_egl.MakeCurrent(_display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
- throw new OpenGlException("eglMakeCurrent failed");
+ throw OpenGlException.GetFormattedException("eglMakeCurrent", _egl);
}
public EglSurface CreateWindowSurface(IntPtr window)
{
var s = _egl.CreateWindowSurface(_display, _config, window, new[] {EGL_NONE, EGL_NONE});
if (s == IntPtr.Zero)
- throw new OpenGlException("eglCreateWindowSurface failed");
+ throw OpenGlException.GetFormattedException("eglCreateWindowSurface", _egl);
return new EglSurface(this, _egl, s);
}
diff --git a/src/Avalonia.OpenGL/EglErrors.cs b/src/Avalonia.OpenGL/EglErrors.cs
new file mode 100644
index 0000000000..bfe46f2b69
--- /dev/null
+++ b/src/Avalonia.OpenGL/EglErrors.cs
@@ -0,0 +1,21 @@
+namespace Avalonia.OpenGL
+{
+ public enum EglErrors
+ {
+ EGL_SUCCESS = EglConsts.EGL_SUCCESS,
+ EGL_NOT_INITIALIZED = EglConsts.EGL_NOT_INITIALIZED,
+ EGL_BAD_ACCESS = EglConsts.EGL_BAD_ACCESS,
+ EGL_BAD_ALLOC = EglConsts.EGL_BAD_ALLOC,
+ EGL_BAD_ATTRIBUTE = EglConsts.EGL_BAD_ATTRIBUTE,
+ EGL_BAD_CONTEXT = EglConsts.EGL_BAD_CONTEXT,
+ EGL_BAD_CONFIG = EglConsts.EGL_BAD_CONFIG,
+ EGL_BAD_CURRENT_SURFACE = EglConsts.EGL_BAD_CURRENT_SURFACE,
+ EGL_BAD_DISPLAY = EglConsts.EGL_BAD_DISPLAY,
+ EGL_BAD_SURFACE = EglConsts.EGL_BAD_SURFACE,
+ EGL_BAD_MATCH = EglConsts.EGL_BAD_MATCH,
+ EGL_BAD_PARAMETER = EglConsts.EGL_BAD_PARAMETER,
+ EGL_BAD_NATIVE_PIXMAP = EglConsts.EGL_BAD_NATIVE_PIXMAP,
+ EGL_BAD_NATIVE_WINDOW = EglConsts.EGL_BAD_NATIVE_WINDOW,
+ EGL_CONTEXT_LOST = EglConsts.EGL_CONTEXT_LOST
+ }
+}
diff --git a/src/Avalonia.OpenGL/EglInterface.cs b/src/Avalonia.OpenGL/EglInterface.cs
index 535f66ee1f..00fcd97af0 100644
--- a/src/Avalonia.OpenGL/EglInterface.cs
+++ b/src/Avalonia.OpenGL/EglInterface.cs
@@ -1,7 +1,6 @@
using System;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
-using static Avalonia.OpenGL.EglConsts;
namespace Avalonia.OpenGL
{
@@ -32,60 +31,64 @@ namespace Avalonia.OpenGL
var lib = dyn.LoadLibrary(library);
return (s, o) => dyn.GetProcAddress(lib, s, o);
}
-
+
// ReSharper disable UnassignedGetOnlyAutoProperty
+ public delegate int EglGetError();
+ [GlEntryPoint("eglGetError")]
+ public EglGetError GetError { get; }
+
public delegate IntPtr EglGetDisplay(IntPtr nativeDisplay);
- [EntryPoint("eglGetDisplay")]
+ [GlEntryPoint("eglGetDisplay")]
public EglGetDisplay GetDisplay { get; }
public delegate IntPtr EglGetPlatformDisplayEXT(int platform, IntPtr nativeDisplay, int[] attrs);
- [EntryPoint("eglGetPlatformDisplayEXT", true)]
+ [GlEntryPoint("eglGetPlatformDisplayEXT", true)]
public EglGetPlatformDisplayEXT GetPlatformDisplayEXT { get; }
public delegate bool EglInitialize(IntPtr display, out int major, out int minor);
- [EntryPoint("eglInitialize")]
+ [GlEntryPoint("eglInitialize")]
public EglInitialize Initialize { get; }
public delegate IntPtr EglGetProcAddress(Utf8Buffer proc);
- [EntryPoint("eglGetProcAddress")]
+ [GlEntryPoint("eglGetProcAddress")]
public EglGetProcAddress GetProcAddress { get; }
public delegate bool EglBindApi(int api);
- [EntryPoint("eglBindAPI")]
+ [GlEntryPoint("eglBindAPI")]
public EglBindApi BindApi { get; }
public delegate bool EglChooseConfig(IntPtr display, int[] attribs,
out IntPtr surfaceConfig, int numConfigs, out int choosenConfig);
- [EntryPoint("eglChooseConfig")]
+ [GlEntryPoint("eglChooseConfig")]
public EglChooseConfig ChooseConfig { get; }
public delegate IntPtr EglCreateContext(IntPtr display, IntPtr config,
IntPtr share, int[] attrs);
- [EntryPoint("eglCreateContext")]
+ [GlEntryPoint("eglCreateContext")]
public EglCreateContext CreateContext { get; }
public delegate IntPtr EglCreatePBufferSurface(IntPtr display, IntPtr config, int[] attrs);
- [EntryPoint("eglCreatePbufferSurface")]
+ [GlEntryPoint("eglCreatePbufferSurface")]
public EglCreatePBufferSurface CreatePBufferSurface { get; }
public delegate bool EglMakeCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
- [EntryPoint("eglMakeCurrent")]
+ [GlEntryPoint("eglMakeCurrent")]
public EglMakeCurrent MakeCurrent { get; }
public delegate void EglDisplaySurfaceVoidDelegate(IntPtr display, IntPtr surface);
- [EntryPoint("eglDestroySurface")]
+ [GlEntryPoint("eglDestroySurface")]
public EglDisplaySurfaceVoidDelegate DestroySurface { get; }
- [EntryPoint("eglSwapBuffers")]
+ [GlEntryPoint("eglSwapBuffers")]
public EglDisplaySurfaceVoidDelegate SwapBuffers { get; }
public delegate IntPtr
EglCreateWindowSurface(IntPtr display, IntPtr config, IntPtr window, int[] attrs);
- [EntryPoint("eglCreateWindowSurface")]
+ [GlEntryPoint("eglCreateWindowSurface")]
public EglCreateWindowSurface CreateWindowSurface { get; }
public delegate bool EglGetConfigAttrib(IntPtr display, IntPtr config, int attr, out int rv);
- [EntryPoint("eglGetConfigAttrib")]
+ [GlEntryPoint("eglGetConfigAttrib")]
public EglGetConfigAttrib GetConfigAttrib { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty
diff --git a/src/Avalonia.OpenGL/GlConsts.cs b/src/Avalonia.OpenGL/GlConsts.cs
index 3084a6f958..275f351e3e 100644
--- a/src/Avalonia.OpenGL/GlConsts.cs
+++ b/src/Avalonia.OpenGL/GlConsts.cs
@@ -456,12 +456,15 @@ namespace Avalonia.OpenGL
public const int GL_RENDERER = 0x1F01;
public const int GL_VERSION = 0x1F02;
public const int GL_EXTENSIONS = 0x1F03;
+ public const int GL_NO_ERROR = 0;
public const int GL_INVALID_ENUM = 0x0500;
public const int GL_INVALID_VALUE = 0x0501;
public const int GL_INVALID_OPERATION = 0x0502;
public const int GL_STACK_OVERFLOW = 0x0503;
public const int GL_STACK_UNDERFLOW = 0x0504;
public const int GL_OUT_OF_MEMORY = 0x0505;
+ public const int GL_INVALID_FRAMEBUFFER_OPERATION = 0x0506;
+ public const int GL_CONTEXT_LOST = 0x0507;
public const int GL_CURRENT_BIT = 0x00000001;
public const int GL_POINT_BIT = 0x00000002;
public const int GL_LINE_BIT = 0x00000004;
diff --git a/src/Avalonia.OpenGL/EntryPointAttribute.cs b/src/Avalonia.OpenGL/GlEntryPointAttribute.cs
similarity index 56%
rename from src/Avalonia.OpenGL/EntryPointAttribute.cs
rename to src/Avalonia.OpenGL/GlEntryPointAttribute.cs
index 241f517df9..016c3d0af9 100644
--- a/src/Avalonia.OpenGL/EntryPointAttribute.cs
+++ b/src/Avalonia.OpenGL/GlEntryPointAttribute.cs
@@ -2,12 +2,13 @@ using System;
namespace Avalonia.OpenGL
{
- class EntryPointAttribute : Attribute
+ [AttributeUsage(AttributeTargets.Property)]
+ public class GlEntryPointAttribute : Attribute
{
public string EntryPoint { get; }
public bool Optional { get; }
- public EntryPointAttribute(string entryPoint, bool optional = false)
+ public GlEntryPointAttribute(string entryPoint, bool optional = false)
{
EntryPoint = entryPoint;
Optional = optional;
diff --git a/src/Avalonia.OpenGL/GlErrors.cs b/src/Avalonia.OpenGL/GlErrors.cs
new file mode 100644
index 0000000000..ecc7d21c7a
--- /dev/null
+++ b/src/Avalonia.OpenGL/GlErrors.cs
@@ -0,0 +1,15 @@
+namespace Avalonia.OpenGL
+{
+ public enum GlErrors
+ {
+ GL_NO_ERROR = GlConsts.GL_NO_ERROR,
+ GL_INVALID_ENUM = GlConsts.GL_INVALID_ENUM,
+ GL_INVALID_VALUE = GlConsts.GL_INVALID_VALUE,
+ GL_INVALID_OPERATION = GlConsts.GL_INVALID_OPERATION,
+ GL_INVALID_FRAMEBUFFER_OPERATION = GlConsts.GL_INVALID_FRAMEBUFFER_OPERATION,
+ GL_STACK_OVERFLOW = GlConsts.GL_STACK_OVERFLOW,
+ GL_STACK_UNDERFLOW = GlConsts.GL_STACK_UNDERFLOW,
+ GL_OUT_OF_MEMORY = GlConsts.GL_OUT_OF_MEMORY,
+ GL_CONTEXT_LOST = GlConsts.GL_CONTEXT_LOST
+ }
+}
diff --git a/src/Avalonia.OpenGL/GlInterface.cs b/src/Avalonia.OpenGL/GlInterface.cs
index 60dc5381d4..718afc4a94 100644
--- a/src/Avalonia.OpenGL/GlInterface.cs
+++ b/src/Avalonia.OpenGL/GlInterface.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
+using Avalonia.Platform.Interop;
namespace Avalonia.OpenGL
{
@@ -7,40 +8,56 @@ namespace Avalonia.OpenGL
public class GlInterface : GlInterfaceBase
{
- private readonly Func _getProcAddress;
+ public string Version { get; }
public GlInterface(Func getProcAddress) : base(getProcAddress)
{
- _getProcAddress = getProcAddress;
+ var versionPtr = GetString(GlConsts.GL_VERSION);
+ if (versionPtr != IntPtr.Zero)
+ Version = Marshal.PtrToStringAnsi(versionPtr);
}
- public IntPtr GetProcAddress(string proc) => _getProcAddress(proc, true);
+ public GlInterface(Func n) : this(ConvertNative(n))
+ {
+
+ }
+ public static GlInterface FromNativeUtf8GetProcAddress(Func getProcAddress) =>
+ new GlInterface(getProcAddress);
+
+
public T GetProcAddress(string proc) => Marshal.GetDelegateForFunctionPointer(GetProcAddress(proc));
// ReSharper disable UnassignedGetOnlyAutoProperty
-
+ public delegate int GlGetError();
+ [GlEntryPoint("glGetError")]
+ public GlGetError GetError { get; }
+
public delegate void GlClearStencil(int s);
- [EntryPoint("glClearStencil")]
+ [GlEntryPoint("glClearStencil")]
public GlClearStencil ClearStencil { get; }
public delegate void GlClearColor(int r, int g, int b, int a);
- [EntryPoint("glClearColor")]
+ [GlEntryPoint("glClearColor")]
public GlClearColor ClearColor { get; }
public delegate void GlClear(int bits);
- [EntryPoint("glClear")]
+ [GlEntryPoint("glClear")]
public GlClear Clear { get; }
public delegate void GlViewport(int x, int y, int width, int height);
- [EntryPoint("glViewport")]
+ [GlEntryPoint("glViewport")]
public GlViewport Viewport { get; }
- [EntryPoint("glFlush")]
+ [GlEntryPoint("glFlush")]
public Action Flush { get; }
+ public delegate IntPtr GlGetString(int v);
+ [GlEntryPoint("glGetString")]
+ public GlGetString GetString { get; }
+
public delegate void GlGetIntegerv(int name, out int rv);
- [EntryPoint("glGetIntegerv")]
+ [GlEntryPoint("glGetIntegerv")]
public GlGetIntegerv GetIntegerv { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty
diff --git a/src/Avalonia.OpenGL/GlInterfaceBase.cs b/src/Avalonia.OpenGL/GlInterfaceBase.cs
index 33191a6567..89ec0e77d4 100644
--- a/src/Avalonia.OpenGL/GlInterfaceBase.cs
+++ b/src/Avalonia.OpenGL/GlInterfaceBase.cs
@@ -1,16 +1,20 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
+using Avalonia.Platform.Interop;
namespace Avalonia.OpenGL
{
public class GlInterfaceBase
{
+
+ private readonly Func _getProcAddress;
public GlInterfaceBase(Func getProcAddress)
{
+ _getProcAddress = getProcAddress;
foreach (var prop in this.GetType().GetProperties())
{
- var a = prop.GetCustomAttribute();
+ var a = prop.GetCustomAttribute();
if (a != null)
{
var fieldName = $"<{prop.Name}>k__BackingField";
@@ -24,5 +28,26 @@ namespace Avalonia.OpenGL
}
}
}
+
+ protected static Func ConvertNative(Func func) =>
+ (proc, optional) =>
+ {
+ using (var u = new Utf8Buffer(proc))
+ {
+ var rv = func(u);
+ if (rv == IntPtr.Zero && !optional)
+ throw new OpenGlException("Missing function " + proc);
+ return rv;
+ }
+ };
+
+ public GlInterfaceBase(Func nativeGetProcAddress) : this(ConvertNative(nativeGetProcAddress))
+ {
+
+ }
+
+ public IntPtr GetProcAddress(string proc) => _getProcAddress(proc, true);
+ public IntPtr GetProcAddress(string proc, bool optional) => _getProcAddress(proc, optional);
+
}
}
diff --git a/src/Avalonia.OpenGL/OpenGlException.cs b/src/Avalonia.OpenGL/OpenGlException.cs
index 7ba539a2b2..d3cd7d059e 100644
--- a/src/Avalonia.OpenGL/OpenGlException.cs
+++ b/src/Avalonia.OpenGL/OpenGlException.cs
@@ -4,9 +4,39 @@ namespace Avalonia.OpenGL
{
public class OpenGlException : Exception
{
+ public int? ErrorCode { get; private set; }
+
public OpenGlException(string message) : base(message)
{
+ }
+
+ private OpenGlException(string message, int errorCode) : base(message)
+ {
+ ErrorCode = errorCode;
+ }
+
+ public static OpenGlException GetFormattedException(string funcName, EglInterface egl)
+ {
+ return GetFormattedException(typeof(EglErrors), funcName, egl.GetError());
+ }
+
+ public static OpenGlException GetFormattedException(string funcName, GlInterface gl)
+ {
+ return GetFormattedException(typeof(GlErrors), funcName, gl.GetError());
+ }
+ private static OpenGlException GetFormattedException(Type consts, string funcName, int errorCode)
+ {
+ try
+ {
+ string errorName = Enum.GetName(consts, errorCode);
+ return new OpenGlException(
+ $"{funcName} failed with error {errorName} (0x{errorCode.ToString("X")})", errorCode);
+ }
+ catch (ArgumentException)
+ {
+ return new OpenGlException($"{funcName} failed with error 0x{errorCode.ToString("X")}", errorCode);
+ }
}
}
}
diff --git a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs
index cf386a235e..e1db604e95 100644
--- a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs
+++ b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs
@@ -29,8 +29,8 @@ namespace Avalonia
{
var windowLoaded = Observable
.FromEventPattern(
- x => window.Initialized += x,
- x => window.Initialized -= x)
+ x => window.Opened += x,
+ x => window.Opened -= x)
.Select(args => true);
var windowUnloaded = Observable
.FromEventPattern(
@@ -59,4 +59,4 @@ namespace Avalonia
.DistinctUntilChanged();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs
index 04c6f100a6..43e2ef93b6 100644
--- a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs
+++ b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs
@@ -16,7 +16,7 @@ namespace Avalonia
public class ReactiveUserControl : UserControl, IViewFor where TViewModel : class
{
public static readonly AvaloniaProperty ViewModelProperty = AvaloniaProperty
- .Register, TViewModel>(nameof(ViewModel));
+ .Register, TViewModel>(nameof(ViewModel));
///
/// Initializes a new instance of the class.
@@ -41,4 +41,4 @@ namespace Avalonia
set => ViewModel = (TViewModel)value;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Styling/Styling/NotSelector.cs b/src/Avalonia.Styling/Styling/NotSelector.cs
new file mode 100644
index 0000000000..bcf76620be
--- /dev/null
+++ b/src/Avalonia.Styling/Styling/NotSelector.cs
@@ -0,0 +1,72 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Reactive.Linq;
+
+namespace Avalonia.Styling
+{
+ ///
+ /// The `:not()` style selector.
+ ///
+ internal class NotSelector : Selector
+ {
+ private readonly Selector _previous;
+ private readonly Selector _argument;
+ private string _selectorString;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The previous selector.
+ /// The selector to be not-ed.
+ public NotSelector(Selector previous, Selector argument)
+ {
+ _previous = previous;
+ _argument = argument ?? throw new InvalidOperationException("Not selector must have a selector argument.");
+ }
+
+ ///
+ public override bool InTemplate => _argument.InTemplate;
+
+ ///
+ public override bool IsCombinator => false;
+
+ ///
+ public override Type TargetType => _previous?.TargetType;
+
+ ///
+ public override string ToString()
+ {
+ if (_selectorString == null)
+ {
+ _selectorString = ":not(" + _argument.ToString() + ")";
+ }
+
+ return _selectorString;
+ }
+
+ protected override SelectorMatch Evaluate(IStyleable control, bool subscribe)
+ {
+ var innerResult = _argument.Match(control, subscribe);
+
+ switch (innerResult.Result)
+ {
+ case SelectorMatchResult.AlwaysThisInstance:
+ return SelectorMatch.NeverThisInstance;
+ case SelectorMatchResult.AlwaysThisType:
+ return SelectorMatch.NeverThisType;
+ case SelectorMatchResult.NeverThisInstance:
+ return SelectorMatch.AlwaysThisInstance;
+ case SelectorMatchResult.NeverThisType:
+ return SelectorMatch.AlwaysThisType;
+ case SelectorMatchResult.Sometimes:
+ return new SelectorMatch(innerResult.Activator.Select(x => !x));
+ default:
+ throw new InvalidOperationException("Invalid SelectorMatchResult.");
+ }
+ }
+
+ protected override Selector MovePrevious() => _previous;
+ }
+}
diff --git a/src/Avalonia.Styling/Styling/Selectors.cs b/src/Avalonia.Styling/Styling/Selectors.cs
index c91cc7af04..4284c7e798 100644
--- a/src/Avalonia.Styling/Styling/Selectors.cs
+++ b/src/Avalonia.Styling/Styling/Selectors.cs
@@ -94,6 +94,17 @@ namespace Avalonia.Styling
}
}
+ ///
+ /// Returns a selector which inverts the results of selector argument.
+ ///
+ /// The previous selector.
+ /// The selector to be not-ed.
+ /// The selector.
+ public static Selector Not(this Selector previous, Func argument)
+ {
+ return new NotSelector(previous, argument(null));
+ }
+
///
/// Returns a selector which matches a type.
///
diff --git a/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs b/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs
index cd019e6535..362ac86e50 100644
--- a/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs
+++ b/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs
@@ -116,11 +116,9 @@ namespace Avalonia.Styling
}
}
- if (Name != null)
+ if (Name != null && control.Name != Name)
{
- return control.Name == Name ?
- SelectorMatch.AlwaysThisInstance :
- SelectorMatch.NeverThisInstance;
+ return SelectorMatch.NeverThisInstance;
}
if (_classes.IsValueCreated && _classes.Value.Count > 0)
@@ -130,17 +128,13 @@ namespace Avalonia.Styling
var observable = new ClassObserver(control.Classes, _classes.Value);
return new SelectorMatch(observable);
}
- else
+ else if (!Matches(control.Classes))
{
- return Matches(control.Classes) ?
- SelectorMatch.AlwaysThisInstance :
- SelectorMatch.NeverThisInstance;
+ return SelectorMatch.NeverThisInstance;
}
}
- else
- {
- return SelectorMatch.AlwaysThisType;
- }
+
+ return Name == null ? SelectorMatch.AlwaysThisType : SelectorMatch.AlwaysThisInstance;
}
protected override Selector MovePrevious() => _previous;
diff --git a/src/Avalonia.Themes.Default/CheckBox.xaml b/src/Avalonia.Themes.Default/CheckBox.xaml
index e2301b9b09..f87ae2674f 100644
--- a/src/Avalonia.Themes.Default/CheckBox.xaml
+++ b/src/Avalonia.Themes.Default/CheckBox.xaml
@@ -1,9 +1,10 @@
-
+
-
diff --git a/src/Avalonia.Themes.Default/TabControl.xaml b/src/Avalonia.Themes.Default/TabControl.xaml
index a492698feb..60c70ebfda 100644
--- a/src/Avalonia.Themes.Default/TabControl.xaml
+++ b/src/Avalonia.Themes.Default/TabControl.xaml
@@ -18,7 +18,7 @@
MemberSelector="{TemplateBinding MemberSelector}" >
+ Converter="{x:Static StringConverters.IsNotNullOrEmpty}"/>
@@ -36,7 +36,7 @@
+ IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}"/>
public static FontFamily Default => new FontFamily(String.Empty);
+ ///
+ /// Represents all font families in the system. This can be an expensive call depending on platform implementation.
+ ///
+ public static IEnumerable SystemFontFamilies =>
+ AvaloniaLocator.Current.GetService().InstalledFontNames.Select(name => new FontFamily(name));
+
///
/// Gets the primary family name of the font family.
///
diff --git a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs
index 0ad826f5a9..8dd75d2374 100644
--- a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs
+++ b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs
@@ -75,7 +75,7 @@ namespace Avalonia.Media.Imaging
public Vector Dpi => PlatformImpl.Item.Dpi;
///
- public Size Size => PlatformImpl.Item.PixelSize.ToSize(Dpi);
+ public Size Size => PlatformImpl.Item.PixelSize.ToSizeWithDpi(Dpi);
///
public PixelSize PixelSize => PlatformImpl.Item.PixelSize;
diff --git a/src/Avalonia.Visuals/Media/PixelPoint.cs b/src/Avalonia.Visuals/Media/PixelPoint.cs
new file mode 100644
index 0000000000..995781ee9f
--- /dev/null
+++ b/src/Avalonia.Visuals/Media/PixelPoint.cs
@@ -0,0 +1,201 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Globalization;
+using Avalonia.Utilities;
+
+namespace Avalonia
+{
+ ///
+ /// Represents a point in device pixels.
+ ///
+ public readonly struct PixelPoint
+ {
+ ///
+ /// A point representing 0,0.
+ ///
+ public static readonly PixelPoint Origin = new PixelPoint(0, 0);
+
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// The X co-ordinate.
+ /// The Y co-ordinate.
+ public PixelPoint(int x, int y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ ///
+ /// Gets the X co-ordinate.
+ ///
+ public int X { get; }
+
+ ///
+ /// Gets the Y co-ordinate.
+ ///
+ public int Y { get; }
+
+ ///
+ /// Checks for equality between two s.
+ ///
+ /// The first point.
+ /// The second point.
+ /// True if the points are equal; otherwise false.
+ public static bool operator ==(PixelPoint left, PixelPoint right)
+ {
+ return left.X == right.X && left.Y == right.Y;
+ }
+
+ ///
+ /// Checks for inequality between two s.
+ ///
+ /// The first point.
+ /// The second point.
+ /// True if the points are unequal; otherwise false.
+ public static bool operator !=(PixelPoint left, PixelPoint right)
+ {
+ return !(left == right);
+ }
+
+ ///
+ /// Parses a string.
+ ///
+ /// The string.
+ /// The .
+ public static PixelPoint Parse(string s)
+ {
+ using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelPoint"))
+ {
+ return new PixelPoint(
+ tokenizer.ReadInt32(),
+ tokenizer.ReadInt32());
+ }
+ }
+
+ ///
+ /// Checks for equality between a point and an object.
+ ///
+ /// The object.
+ ///
+ /// True if is a point that equals the current point.
+ ///
+ public override bool Equals(object obj)
+ {
+ if (obj is PixelPoint other)
+ {
+ return this == other;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Returns a hash code for a .
+ ///
+ /// The hash code.
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hash = 17;
+ hash = (hash * 23) + X.GetHashCode();
+ hash = (hash * 23) + Y.GetHashCode();
+ return hash;
+ }
+ }
+
+ ///
+ /// Returns a new with the same Y co-ordinate and the specified X co-ordinate.
+ ///
+ /// The X co-ordinate.
+ /// The new .
+ public PixelPoint WithX(int x) => new PixelPoint(x, Y);
+
+ ///
+ /// Returns a new with the same X co-ordinate and the specified Y co-ordinate.
+ ///
+ /// The Y co-ordinate.
+ /// The new .
+ public PixelPoint WithY(int y) => new PixelPoint(X, y);
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified scaling factor.
+ ///
+ /// The scaling factor.
+ /// The device-independent point.
+ public Point ToPoint(double scale) => new Point(X / scale, Y / scale);
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified scaling factor.
+ ///
+ /// The scaling factor.
+ /// The device-independent point.
+ public Point ToPoint(Vector scale) => new Point(X / scale.X, Y / scale.Y);
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified dots per inch (DPI).
+ ///
+ /// The dots per inch of the device.
+ /// The device-independent point.
+ public Point ToPointWithDpi(double dpi) => ToPoint(dpi / 96);
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified dots per inch (DPI).
+ ///
+ /// The dots per inch of the device.
+ /// The device-independent point.
+ public Point ToPointWithDpi(Vector dpi) => ToPoint(new Vector(dpi.X / 96, dpi.Y / 96));
+
+ ///
+ /// Converts a to device pixels using the specified scaling factor.
+ ///
+ /// The point.
+ /// The scaling factor.
+ /// The device-independent point.
+ public static PixelPoint FromPoint(Point point, double scale) => new PixelPoint(
+ (int)(point.X * scale),
+ (int)(point.Y * scale));
+
+ ///
+ /// Converts a to device pixels using the specified scaling factor.
+ ///
+ /// The point.
+ /// The scaling factor.
+ /// The device-independent point.
+ public static PixelPoint FromPoint(Point point, Vector scale) => new PixelPoint(
+ (int)(point.X * scale.X),
+ (int)(point.Y * scale.Y));
+
+ ///
+ /// Converts a to device pixels using the specified dots per inch (DPI).
+ ///
+ /// The point.
+ /// The dots per inch of the device.
+ /// The device-independent point.
+ public static PixelPoint FromPointWithDpi(Point point, double dpi) => FromPoint(point, dpi / 96);
+
+ ///
+ /// Converts a to device pixels using the specified dots per inch (DPI).
+ ///
+ /// The point.
+ /// The dots per inch of the device.
+ /// The device-independent point.
+ public static PixelPoint FromPointWithDpi(Point point, Vector dpi) => FromPoint(point, new Vector(dpi.X / 96, dpi.Y / 96));
+
+ ///
+ /// Returns the string representation of the point.
+ ///
+ /// The string representation of the point.
+ public override string ToString()
+ {
+ return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", X, Y);
+ }
+ }
+}
diff --git a/src/Avalonia.Visuals/Media/PixelRect.cs b/src/Avalonia.Visuals/Media/PixelRect.cs
new file mode 100644
index 0000000000..9c8e5ad1c4
--- /dev/null
+++ b/src/Avalonia.Visuals/Media/PixelRect.cs
@@ -0,0 +1,436 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Globalization;
+using Avalonia.Utilities;
+
+namespace Avalonia
+{
+ ///
+ /// Represents a rectangle in device pixels.
+ ///
+ public readonly struct PixelRect
+ {
+ ///
+ /// An empty rectangle.
+ ///
+ public static readonly PixelRect Empty = default;
+
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// The X position.
+ /// The Y position.
+ /// The width.
+ /// The height.
+ public PixelRect(int x, int y, int width, int height)
+ {
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ }
+
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// The size of the rectangle.
+ public PixelRect(PixelSize size)
+ {
+ X = 0;
+ Y = 0;
+ Width = size.Width;
+ Height = size.Height;
+ }
+
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// The position of the rectangle.
+ /// The size of the rectangle.
+ public PixelRect(PixelPoint position, PixelSize size)
+ {
+ X = position.X;
+ Y = position.Y;
+ Width = size.Width;
+ Height = size.Height;
+ }
+
+ ///
+ /// Initializes a new instance of the structure.
+ ///
+ /// The top left position of the rectangle.
+ /// The bottom right position of the rectangle.
+ public PixelRect(PixelPoint topLeft, PixelPoint bottomRight)
+ {
+ X = topLeft.X;
+ Y = topLeft.Y;
+ Width = bottomRight.X - topLeft.X;
+ Height = bottomRight.Y - topLeft.Y;
+ }
+
+ ///
+ /// Gets the X position.
+ ///
+ public int X { get; }
+
+ ///
+ /// Gets the Y position.
+ ///
+ public int Y { get; }
+
+ ///
+ /// Gets the width.
+ ///
+ public int Width { get; }
+
+ ///
+ /// Gets the height.
+ ///
+ public int Height { get; }
+
+ ///
+ /// Gets the position of the rectangle.
+ ///
+ public PixelPoint Position => new PixelPoint(X, Y);
+
+ ///
+ /// Gets the size of the rectangle.
+ ///
+ public PixelSize Size => new PixelSize(Width, Height);
+
+ ///
+ /// Gets the right position of the rectangle.
+ ///
+ public int Right => X + Width;
+
+ ///
+ /// Gets the bottom position of the rectangle.
+ ///
+ public int Bottom => Y + Height;
+
+ ///
+ /// Gets the top left point of the rectangle.
+ ///
+ public PixelPoint TopLeft => new PixelPoint(X, Y);
+
+ ///
+ /// Gets the top right point of the rectangle.
+ ///
+ public PixelPoint TopRight => new PixelPoint(Right, Y);
+
+ ///
+ /// Gets the bottom left point of the rectangle.
+ ///
+ public PixelPoint BottomLeft => new PixelPoint(X, Bottom);
+
+ ///
+ /// Gets the bottom right point of the rectangle.
+ ///
+ public PixelPoint BottomRight => new PixelPoint(Right, Bottom);
+
+ ///
+ /// Gets the center point of the rectangle.
+ ///
+ public PixelPoint Center => new PixelPoint(X + (Width / 2), Y + (Height / 2));
+
+ ///
+ /// Gets a value that indicates whether the rectangle is empty.
+ ///
+ public bool IsEmpty => Width == 0 && Height == 0;
+
+ ///
+ /// Checks for equality between two s.
+ ///
+ /// The first rect.
+ /// The second rect.
+ /// True if the rects are equal; otherwise false.
+ public static bool operator ==(PixelRect left, PixelRect right)
+ {
+ return left.Position == right.Position && left.Size == right.Size;
+ }
+
+ ///
+ /// Checks for inequality between two s.
+ ///
+ /// The first rect.
+ /// The second rect.
+ /// True if the rects are unequal; otherwise false.
+ public static bool operator !=(PixelRect left, PixelRect right)
+ {
+ return !(left == right);
+ }
+
+ ///
+ /// Determines whether a point in in the bounds of the rectangle.
+ ///
+ /// The point.
+ /// true if the point is in the bounds of the rectangle; otherwise false.
+ public bool Contains(PixelPoint p)
+ {
+ return p.X >= X && p.X <= Right && p.Y >= Y && p.Y <= Bottom;
+ }
+
+ ///
+ /// Determines whether the rectangle fully contains another rectangle.
+ ///
+ /// The rectangle.
+ /// true if the rectangle is fully contained; otherwise false.
+ public bool Contains(PixelRect r)
+ {
+ return Contains(r.TopLeft) && Contains(r.BottomRight);
+ }
+
+ ///
+ /// Centers another rectangle in this rectangle.
+ ///
+ /// The rectangle to center.
+ /// The centered rectangle.
+ public PixelRect CenterRect(PixelRect rect)
+ {
+ return new PixelRect(
+ X + ((Width - rect.Width) / 2),
+ Y + ((Height - rect.Height) / 2),
+ rect.Width,
+ rect.Height);
+ }
+
+ ///
+ /// Returns a boolean indicating whether the given object is equal to this rectangle.
+ ///
+ /// The object to compare against.
+ /// True if the object is equal to this rectangle; false otherwise.
+ public override bool Equals(object obj)
+ {
+ if (obj is PixelRect other)
+ {
+ return this == other;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Returns the hash code for this instance.
+ ///
+ /// The hash code.
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hash = 17;
+ hash = (hash * 23) + X.GetHashCode();
+ hash = (hash * 23) + Y.GetHashCode();
+ hash = (hash * 23) + Width.GetHashCode();
+ hash = (hash * 23) + Height.GetHashCode();
+ return hash;
+ }
+ }
+
+ ///
+ /// Gets the intersection of two rectangles.
+ ///
+ /// The other rectangle.
+ /// The intersection.
+ public PixelRect Intersect(PixelRect rect)
+ {
+ var newLeft = (rect.X > X) ? rect.X : X;
+ var newTop = (rect.Y > Y) ? rect.Y : Y;
+ var newRight = (rect.Right < Right) ? rect.Right : Right;
+ var newBottom = (rect.Bottom < Bottom) ? rect.Bottom : Bottom;
+
+ if ((newRight > newLeft) && (newBottom > newTop))
+ {
+ return new PixelRect(newLeft, newTop, newRight - newLeft, newBottom - newTop);
+ }
+ else
+ {
+ return Empty;
+ }
+ }
+
+ ///
+ /// Determines whether a rectangle intersects with this rectangle.
+ ///
+ /// The other rectangle.
+ ///
+ /// True if the specified rectangle intersects with this one; otherwise false.
+ ///
+ public bool Intersects(PixelRect rect)
+ {
+ return (rect.X < Right) && (X < rect.Right) && (rect.Y < Bottom) && (Y < rect.Bottom);
+ }
+
+ ///
+ /// Gets the union of two rectangles.
+ ///
+ /// The other rectangle.
+ /// The union.
+ public PixelRect Union(PixelRect rect)
+ {
+ if (IsEmpty)
+ {
+ return rect;
+ }
+ else if (rect.IsEmpty)
+ {
+ return this;
+ }
+ else
+ {
+ var x1 = Math.Min(X, rect.X);
+ var x2 = Math.Max(Right, rect.Right);
+ var y1 = Math.Min(Y, rect.Y);
+ var y2 = Math.Max(Bottom, rect.Bottom);
+
+ return new PixelRect(new PixelPoint(x1, y1), new PixelPoint(x2, y2));
+ }
+ }
+
+ ///
+ /// Returns a new with the specified X position.
+ ///
+ /// The x position.
+ /// The new .
+ public PixelRect WithX(int x)
+ {
+ return new PixelRect(x, Y, Width, Height);
+ }
+
+ ///
+ /// Returns a new with the specified Y position.
+ ///
+ /// The y position.
+ /// The new .
+ public PixelRect WithY(int y)
+ {
+ return new PixelRect(X, y, Width, Height);
+ }
+
+ ///
+ /// Returns a new with the specified width.
+ ///
+ /// The width.
+ /// The new .
+ public PixelRect WithWidth(int width)
+ {
+ return new PixelRect(X, Y, width, Height);
+ }
+
+ ///
+ /// Returns a new with the specified height.
+ ///
+ /// The height.
+ /// The new .
+ public PixelRect WithHeight(int height)
+ {
+ return new PixelRect(X, Y, Width, Height);
+ }
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified scaling factor.
+ ///
+ /// The scaling factor.
+ /// The device-independent rect.
+ public Rect ToRect(double scale) => new Rect(Position.ToPoint(scale), Size.ToSize(scale));
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified scaling factor.
+ ///
+ /// The scaling factor.
+ /// The device-independent rect.
+ public Rect ToRect(Vector scale) => new Rect(Position.ToPoint(scale), Size.ToSize(scale));
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified dots per inch (DPI).
+ ///
+ /// The dots per inch of the device.
+ /// The device-independent rect.
+ public Rect ToRectWithDpi(double dpi) => new Rect(Position.ToPointWithDpi(dpi), Size.ToSizeWithDpi(dpi));
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified dots per inch (DPI).
+ ///
+ /// The dots per inch of the device.
+ /// The device-independent rect.
+ public Rect ToRectWithDpi(Vector dpi) => new Rect(Position.ToPointWithDpi(dpi), Size.ToSizeWithDpi(dpi));
+
+ ///
+ /// Converts a to device pixels using the specified scaling factor.
+ ///
+ /// The rect.
+ /// The scaling factor.
+ /// The device-independent rect.
+ public static PixelRect FromRect(Rect rect, double scale) => new PixelRect(
+ PixelPoint.FromPoint(rect.Position, scale),
+ PixelSize.FromSize(rect.Size, scale));
+
+ ///
+ /// Converts a to device pixels using the specified scaling factor.
+ ///
+ /// The rect.
+ /// The scaling factor.
+ /// The device-independent point.
+ public static PixelRect FromRect(Rect rect, Vector scale) => new PixelRect(
+ PixelPoint.FromPoint(rect.Position, scale),
+ PixelSize.FromSize(rect.Size, scale));
+
+ ///
+ /// Converts a to device pixels using the specified dots per inch (DPI).
+ ///
+ /// The rect.
+ /// The dots per inch of the device.
+ /// The device-independent point.
+ public static PixelRect FromRectWithDpi(Rect rect, double dpi) => new PixelRect(
+ PixelPoint.FromPointWithDpi(rect.Position, dpi),
+ PixelSize.FromSizeWithDpi(rect.Size, dpi));
+
+ ///
+ /// Converts a to device pixels using the specified dots per inch (DPI).
+ ///
+ /// The rect.
+ /// The dots per inch of the device.
+ /// The device-independent point.
+ public static PixelRect FromRectWithDpi(Rect rect, Vector dpi) => new PixelRect(
+ PixelPoint.FromPointWithDpi(rect.Position, dpi),
+ PixelSize.FromSizeWithDpi(rect.Size, dpi));
+
+ ///
+ /// Returns the string representation of the rectangle.
+ ///
+ /// The string representation of the rectangle.
+ public override string ToString()
+ {
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "{0}, {1}, {2}, {3}",
+ X,
+ Y,
+ Width,
+ Height);
+ }
+
+ ///
+ /// Parses a string.
+ ///
+ /// The string.
+ /// The parsed .
+ public static PixelRect Parse(string s)
+ {
+ using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelRect"))
+ {
+ return new PixelRect(
+ tokenizer.ReadInt32(),
+ tokenizer.ReadInt32(),
+ tokenizer.ReadInt32(),
+ tokenizer.ReadInt32()
+ );
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.Visuals/Media/PixelSize.cs b/src/Avalonia.Visuals/Media/PixelSize.cs
index 6785b51716..b903b804f9 100644
--- a/src/Avalonia.Visuals/Media/PixelSize.cs
+++ b/src/Avalonia.Visuals/Media/PixelSize.cs
@@ -72,7 +72,7 @@ namespace Avalonia
/// The .
public static PixelSize Parse(string s)
{
- using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Size"))
+ using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelSize"))
{
return new PixelSize(
tokenizer.ReadInt32(),
@@ -126,13 +126,29 @@ namespace Avalonia
/// The new .
public PixelSize WithHeight(int height) => new PixelSize(Width, height);
+ ///
+ /// Converts the to a device-independent using the
+ /// specified scaling factor.
+ ///
+ /// The scaling factor.
+ /// The device-independent size.
+ public Size ToSize(double scale) => new Size(Width / scale, Height / scale);
+
+ ///
+ /// Converts the to a device-independent using the
+ /// specified scaling factor.
+ ///
+ /// The scaling factor.
+ /// The device-independent size.
+ public Size ToSize(Vector scale) => new Size(Width / scale.X, Height / scale.Y);
+
///
/// Converts the to a device-independent using the
/// specified dots per inch (DPI).
///
/// The dots per inch.
/// The device-independent size.
- public Size ToSize(double dpi) => new Size(Width / (dpi / 96), Height / (dpi / 96));
+ public Size ToSizeWithDpi(double dpi) => ToSize(dpi / 96);
///
/// Converts the to a device-independent using the
@@ -140,7 +156,27 @@ namespace Avalonia
///
/// The dots per inch.
/// The device-independent size.
- public Size ToSize(Vector dpi) => new Size(Width / (dpi.X / 96), Height / (dpi.Y / 96));
+ public Size ToSizeWithDpi(Vector dpi) => ToSize(new Vector(dpi.X / 96, dpi.Y / 96));
+
+ ///
+ /// Converts a to device pixels using the specified scaling factor.
+ ///
+ /// The size.
+ /// The scaling factor.
+ /// The device-independent size.
+ public static PixelSize FromSize(Size size, double scale) => new PixelSize(
+ (int)Math.Ceiling(size.Width * scale),
+ (int)Math.Ceiling(size.Height * scale));
+
+ ///
+ /// Converts a to device pixels using the specified scaling factor.
+ ///
+ /// The size.
+ /// The scaling factor.
+ /// The device-independent size.
+ public static PixelSize FromSize(Size size, Vector scale) => new PixelSize(
+ (int)Math.Ceiling(size.Width * scale.X),
+ (int)Math.Ceiling(size.Height * scale.Y));
///
/// Converts a to device pixels using the specified dots per inch (DPI).
@@ -148,9 +184,7 @@ namespace Avalonia
/// The size.
/// The dots per inch.
/// The device-independent size.
- public static PixelSize FromSize(Size size, double dpi) => new PixelSize(
- (int)(size.Width * (dpi / 96)),
- (int)(size.Height * (dpi / 96)));
+ public static PixelSize FromSizeWithDpi(Size size, double dpi) => FromSize(size, dpi / 96);
///
/// Converts a to device pixels using the specified dots per inch (DPI).
@@ -158,9 +192,7 @@ namespace Avalonia
/// The size.
/// The dots per inch.
/// The device-independent size.
- public static PixelSize FromSize(Size size, Vector dpi) => new PixelSize(
- (int)Math.Ceiling(size.Width * (dpi.X / 96)),
- (int)Math.Ceiling(size.Height * (dpi.Y / 96)));
+ public static PixelSize FromSizeWithDpi(Size size, Vector dpi) => FromSize(size, new Vector(dpi.X / 96, dpi.Y / 96));
///
/// Returns the string representation of the size.
diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
index aacdef0538..3a1f79e32a 100644
--- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
+++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
@@ -13,6 +13,11 @@ namespace Avalonia.Platform
///
public interface IPlatformRenderInterface
{
+ ///
+ /// Get all installed fonts in the system
+ ///
+ IEnumerable InstalledFontNames { get; }
+
///
/// Creates a formatted text implementation.
///
diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
index b48efaa34e..60e624948e 100644
--- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
@@ -29,6 +29,7 @@ namespace Avalonia.Rendering
private readonly ISceneBuilder _sceneBuilder;
private bool _running;
+ private bool _disposed;
private volatile IRef _scene;
private DirtyVisuals _dirty;
private IRef _overlay;
@@ -99,6 +100,9 @@ namespace Avalonia.Rendering
///
public string DebugFramesPath { get; set; }
+ ///
+ public event EventHandler SceneInvalidated;
+
///
/// Gets the render layers.
///
@@ -122,15 +126,34 @@ namespace Avalonia.Rendering
{
lock (_sceneLock)
{
+ if (_disposed)
+ return;
+ _disposed = true;
var scene = _scene;
_scene = null;
scene?.Dispose();
}
Stop();
+ DisposeRenderTarget();
+ }
+
+ void DisposeRenderTarget()
+ {
+ using (var l = _lock.TryLock())
+ {
+ if(l == null)
+ {
+ // We are still trying to render on the render thread, try again a bit later
+ DispatcherTimer.RunOnce(DisposeRenderTarget, TimeSpan.FromMilliseconds(50),
+ DispatcherPriority.Background);
+ return;
+ }
- Layers.Clear();
- RenderTarget?.Dispose();
+ Layers.Clear();
+ RenderTarget?.Dispose();
+ RenderTarget = null;
+ }
}
///
@@ -152,7 +175,8 @@ namespace Avalonia.Rendering
var t = (IRenderLoopTask)this;
if(t.NeedsUpdate)
UpdateScene();
- Render(true);
+ if(_scene?.Item != null)
+ Render(true);
}
///
@@ -336,16 +360,34 @@ namespace Avalonia.Rendering
private void RenderToLayers(Scene scene)
{
- if (scene.Layers.HasDirty)
+ foreach (var layer in scene.Layers)
{
- foreach (var layer in scene.Layers)
- {
- var renderTarget = Layers[layer.LayerRoot].Bitmap;
- var node = (VisualNode)scene.FindNode(layer.LayerRoot);
+ var renderLayer = Layers[layer.LayerRoot];
+ if (layer.Dirty.IsEmpty && !renderLayer.IsEmpty)
+ continue;
+ var renderTarget = renderLayer.Bitmap;
+ var node = (VisualNode)scene.FindNode(layer.LayerRoot);
- if (node != null)
+ if (node != null)
+ {
+ using (var context = renderTarget.Item.CreateDrawingContext(this))
{
- using (var context = renderTarget.Item.CreateDrawingContext(this))
+ if (renderLayer.IsEmpty)
+ {
+ // Render entire layer root node
+ context.Clear(Colors.Transparent);
+ context.Transform = Matrix.Identity;
+ context.PushClip(node.ClipBounds);
+ Render(context, node, layer.LayerRoot, node.ClipBounds);
+ context.PopClip();
+ if (DrawDirtyRects)
+ {
+ _dirtyRectsDisplay.Add(node.ClipBounds);
+ }
+
+ renderLayer.IsEmpty = false;
+ }
+ else
{
foreach (var rect in layer.Dirty)
{
@@ -364,6 +406,7 @@ namespace Avalonia.Rendering
}
}
}
+
}
private void RenderOverlay(Scene scene, IDrawingContextImpl parentContent)
@@ -442,6 +485,8 @@ namespace Avalonia.Rendering
Dispatcher.UIThread.VerifyAccess();
lock (_sceneLock)
{
+ if (_disposed)
+ return;
if (_scene?.Item.Generation > _lastSceneId)
return;
}
@@ -470,6 +515,21 @@ namespace Avalonia.Rendering
oldScene?.Dispose();
}
+ if (SceneInvalidated != null)
+ {
+ var rect = new Rect();
+
+ foreach (var layer in scene.Layers)
+ {
+ foreach (var dirty in layer.Dirty)
+ {
+ rect = rect.Union(dirty);
+ }
+ }
+
+ SceneInvalidated(this, new SceneInvalidatedEventArgs((IRenderRoot)_root, rect));
+ }
+
_dirty.Clear();
}
else
diff --git a/src/Avalonia.Visuals/Rendering/IRenderRoot.cs b/src/Avalonia.Visuals/Rendering/IRenderRoot.cs
index 2b364e5d22..044911ca95 100644
--- a/src/Avalonia.Visuals/Rendering/IRenderRoot.cs
+++ b/src/Avalonia.Visuals/Rendering/IRenderRoot.cs
@@ -41,15 +41,15 @@ namespace Avalonia.Rendering
///
/// Converts a point from screen to client coordinates.
///
- /// The point in screen coordinates.
+ /// The point in screen device coordinates.
/// The point in client coordinates.
- Point PointToClient(Point point);
+ Point PointToClient(PixelPoint point);
///
/// Converts a point from client to screen coordinates.
///
/// The point in client coordinates.
- /// The point in screen coordinates.
- Point PointToScreen(Point point);
+ /// The point in screen device coordinates.
+ PixelPoint PointToScreen(Point point);
}
}
diff --git a/src/Avalonia.Visuals/Rendering/IRenderer.cs b/src/Avalonia.Visuals/Rendering/IRenderer.cs
index 9085e63aa9..36a1f7d220 100644
--- a/src/Avalonia.Visuals/Rendering/IRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/IRenderer.cs
@@ -18,11 +18,20 @@ namespace Avalonia.Rendering
bool DrawFps { get; set; }
///
- /// Gets or sets a value indicating whether the renderer should a visual representation
+ /// Gets or sets a value indicating whether the renderer should draw a visual representation
/// of its dirty rectangles.
///
bool DrawDirtyRects { get; set; }
+ ///
+ /// Raised when a portion of the scene has been invalidated.
+ ///
+ ///
+ /// Indicates that the underlying low-level scene information has been updated. Used to
+ /// signal that an update to the current pointer-over state may be required.
+ ///
+ event EventHandler SceneInvalidated;
+
///
/// Mark a visual as dirty and needing re-rendering.
///
@@ -63,4 +72,4 @@ namespace Avalonia.Rendering
///
void Stop();
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
index 03ac004fd5..21129e38af 100644
--- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
@@ -42,6 +42,9 @@ namespace Avalonia.Rendering
///
public bool DrawDirtyRects { get; set; }
+ ///
+ public event EventHandler SceneInvalidated;
+
///
public void Paint(Rect rect)
{
@@ -81,6 +84,8 @@ namespace Avalonia.Rendering
_renderTarget.Dispose();
_renderTarget = null;
}
+
+ SceneInvalidated?.Invoke(this, new SceneInvalidatedEventArgs((IRenderRoot)_root, rect));
}
///
diff --git a/src/Avalonia.Visuals/Rendering/RenderLayer.cs b/src/Avalonia.Visuals/Rendering/RenderLayer.cs
index cd09bdee10..d6676e25ff 100644
--- a/src/Avalonia.Visuals/Rendering/RenderLayer.cs
+++ b/src/Avalonia.Visuals/Rendering/RenderLayer.cs
@@ -7,39 +7,39 @@ namespace Avalonia.Rendering
{
public class RenderLayer
{
- private readonly IDrawingContextImpl _drawingContext;
-
public RenderLayer(
IDrawingContextImpl drawingContext,
Size size,
double scaling,
IVisual layerRoot)
{
- _drawingContext = drawingContext;
Bitmap = RefCountable.Create(drawingContext.CreateLayer(size));
Size = size;
Scaling = scaling;
LayerRoot = layerRoot;
+ IsEmpty = true;
}
public IRef Bitmap { get; private set; }
+ public bool IsEmpty { get; set; }
public double Scaling { get; private set; }
public Size Size { get; private set; }
public IVisual LayerRoot { get; }
- public void ResizeBitmap(Size size, double scaling)
+ public void RecreateBitmap(IDrawingContextImpl drawingContext, Size size, double scaling)
{
if (Size != size || Scaling != scaling)
{
- var resized = RefCountable.Create(_drawingContext.CreateLayer(size));
+ var resized = RefCountable.Create(drawingContext.CreateLayer(size));
using (var context = resized.Item.CreateDrawingContext(null))
{
context.Clear(Colors.Transparent);
- context.DrawImage(Bitmap, 1, new Rect(Size), new Rect(Size));
Bitmap.Dispose();
Bitmap = resized;
+ Scaling = scaling;
Size = size;
+ IsEmpty = true;
}
}
}
diff --git a/src/Avalonia.Visuals/Rendering/RenderLayers.cs b/src/Avalonia.Visuals/Rendering/RenderLayers.cs
index 9b0ce944e7..0ff7862ab6 100644
--- a/src/Avalonia.Visuals/Rendering/RenderLayers.cs
+++ b/src/Avalonia.Visuals/Rendering/RenderLayers.cs
@@ -29,11 +29,11 @@ namespace Avalonia.Rendering
}
else
{
- layer.ResizeBitmap(scene.Size, scene.Scaling);
+ layer.RecreateBitmap(context, scene.Size, scene.Scaling);
}
}
- for (var i = _inner.Count - 1; i >= 0; --i)
+ for (var i = 0; i < _inner.Count;)
{
var layer = _inner[i];
@@ -43,6 +43,8 @@ namespace Avalonia.Rendering
_inner.RemoveAt(i);
_index.Remove(layer.LayerRoot);
}
+ else
+ i++;
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
index ffa0b0bcc5..ad4c475d89 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
@@ -160,7 +160,7 @@ namespace Avalonia.Rendering.SceneGraph
private IEnumerable HitTest(IVisualNode node, Point p, Rect? clip, Func filter)
{
- if (filter?.Invoke(node.Visual) != false)
+ if (filter?.Invoke(node.Visual) != false && node.Visual.IsAttachedToVisualTree)
{
var clipped = false;
@@ -186,7 +186,7 @@ namespace Avalonia.Rendering.SceneGraph
}
}
- if (node.HitTest(p) && node.Visual.IsAttachedToVisualTree)
+ if (node.HitTest(p))
{
yield return node.Visual;
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs b/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs
new file mode 100644
index 0000000000..40cb9f3356
--- /dev/null
+++ b/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs
@@ -0,0 +1,36 @@
+// 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;
+
+namespace Avalonia.Rendering
+{
+ ///
+ /// Provides data for the event.
+ ///
+ public class SceneInvalidatedEventArgs : EventArgs
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The render root that has been updated.
+ /// The updated area.
+ public SceneInvalidatedEventArgs(
+ IRenderRoot root,
+ Rect dirtyRect)
+ {
+ RenderRoot = root;
+ DirtyRect = dirtyRect;
+ }
+
+ ///
+ /// Gets the invalidated area.
+ ///
+ public Rect DirtyRect { get; }
+
+ ///
+ /// Gets the render root that has been invalidated.
+ ///
+ public IRenderRoot RenderRoot { get; }
+ }
+}
diff --git a/src/Avalonia.Visuals/VisualExtensions.cs b/src/Avalonia.Visuals/VisualExtensions.cs
index 7c5d011ce8..650921a985 100644
--- a/src/Avalonia.Visuals/VisualExtensions.cs
+++ b/src/Avalonia.Visuals/VisualExtensions.cs
@@ -18,10 +18,12 @@ namespace Avalonia
/// The visual.
/// The point in screen coordinates.
/// The point in client coordinates.
- public static Point PointToClient(this IVisual visual, Point point)
+ public static Point PointToClient(this IVisual visual, PixelPoint point)
{
- var p = GetRootAndPosition(visual);
- return p.Item1.PointToClient(point - p.Item2);
+ var (root, offset) = GetRootAndPosition(visual);
+ var screenOffset = PixelPoint.FromPoint((Point)offset, root.RenderScaling);
+ var screenPoint = new PixelPoint(point.X - screenOffset.X, point.Y - screenOffset.Y);
+ return root.PointToClient(screenPoint);
}
///
@@ -30,7 +32,7 @@ namespace Avalonia
/// The visual.
/// The point in client coordinates.
/// The point in screen coordinates.
- public static Point PointToScreen(this IVisual visual, Point point)
+ public static PixelPoint PointToScreen(this IVisual visual, Point point)
{
var p = GetRootAndPosition(visual);
return p.Item1.PointToScreen(point + p.Item2);
diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj
new file mode 100644
index 0000000000..087ba017ae
--- /dev/null
+++ b/src/Avalonia.X11/Avalonia.X11.csproj
@@ -0,0 +1,14 @@
+
+
+
+ netstandard2.0
+ true
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.X11/Glx/Glx.cs b/src/Avalonia.X11/Glx/Glx.cs
new file mode 100644
index 0000000000..c3a2fd2050
--- /dev/null
+++ b/src/Avalonia.X11/Glx/Glx.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using Avalonia.OpenGL;
+using Avalonia.Platform.Interop;
+// ReSharper disable UnassignedGetOnlyAutoProperty
+
+namespace Avalonia.X11.Glx
+{
+ unsafe class GlxInterface : GlInterfaceBase
+ {
+ private const string libGL = "libGL.so.1";
+ [GlEntryPointAttribute("glXMakeContextCurrent")]
+ public GlxMakeContextCurrent MakeContextCurrent { get; }
+ public delegate bool GlxMakeContextCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
+
+ [GlEntryPoint("glXCreatePbuffer")]
+ public GlxCreatePbuffer CreatePbuffer { get; }
+
+ public delegate IntPtr GlxCreatePbuffer(IntPtr dpy, IntPtr fbc, int[] attrib_list);
+
+ [GlEntryPointAttribute("glXChooseVisual")]
+ public GlxChooseVisual ChooseVisual { get; }
+ public delegate XVisualInfo* GlxChooseVisual(IntPtr dpy, int screen, int[] attribList);
+
+
+ [GlEntryPointAttribute("glXCreateContext")]
+ public GlxCreateContext CreateContext { get; }
+ public delegate IntPtr GlxCreateContext(IntPtr dpy, XVisualInfo* vis, IntPtr shareList, bool direct);
+
+
+ [GlEntryPointAttribute("glXCreateContextAttribsARB")]
+ public GlxCreateContextAttribsARB CreateContextAttribsARB { get; }
+ public delegate IntPtr GlxCreateContextAttribsARB(IntPtr dpy, IntPtr fbconfig, IntPtr shareList,
+ bool direct, int[] attribs);
+
+
+ [DllImport(libGL, EntryPoint = "glXGetProcAddress")]
+ public static extern IntPtr GlxGetProcAddress(Utf8Buffer buffer);
+
+
+ [GlEntryPointAttribute("glXDestroyContext")]
+ public GlxDestroyContext DestroyContext { get; }
+ public delegate void GlxDestroyContext(IntPtr dpy, IntPtr ctx);
+
+
+ [GlEntryPointAttribute("glXChooseFBConfig")]
+ public GlxChooseFBConfig ChooseFBConfig { get; }
+ public delegate IntPtr* GlxChooseFBConfig(IntPtr dpy, int screen, int[] attrib_list, out int nelements);
+
+
+ public IntPtr* GlxChooseFbConfig(IntPtr dpy, int screen, IEnumerable attribs, out int nelements)
+ {
+ var arr = attribs.Concat(new[]{0}).ToArray();
+ return ChooseFBConfig(dpy, screen, arr, out nelements);
+ }
+
+ [GlEntryPointAttribute("glXGetVisualFromFBConfig")]
+ public GlxGetVisualFromFBConfig GetVisualFromFBConfig { get; }
+ public delegate XVisualInfo * GlxGetVisualFromFBConfig(IntPtr dpy, IntPtr config);
+
+
+ [GlEntryPointAttribute("glXGetFBConfigAttrib")]
+ public GlxGetFBConfigAttrib GetFBConfigAttrib { get; }
+ public delegate int GlxGetFBConfigAttrib(IntPtr dpy, IntPtr config, int attribute, out int value);
+
+
+ [GlEntryPointAttribute("glXSwapBuffers")]
+ public GlxSwapBuffers SwapBuffers { get; }
+ public delegate void GlxSwapBuffers(IntPtr dpy, IntPtr drawable);
+
+
+ [GlEntryPointAttribute("glXWaitX")]
+ public GlxWaitX WaitX { get; }
+ public delegate void GlxWaitX();
+
+
+ [GlEntryPointAttribute("glXWaitGL")]
+ public GlxWaitGL WaitGL { get; }
+ public delegate void GlxWaitGL();
+
+ public delegate int GlGetError();
+ [GlEntryPoint("glGetError")]
+ public GlGetError GetError { get; }
+
+ public GlxInterface() : base(GlxGetProcAddress)
+ {
+ }
+ }
+}
diff --git a/src/Avalonia.X11/Glx/GlxConsts.cs b/src/Avalonia.X11/Glx/GlxConsts.cs
new file mode 100644
index 0000000000..65f253696a
--- /dev/null
+++ b/src/Avalonia.X11/Glx/GlxConsts.cs
@@ -0,0 +1,106 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable IdentifierTypo
+// ReSharper disable UnusedMember.Global
+#pragma warning disable 414
+namespace Avalonia.X11.Glx
+{
+ class GlxConsts
+ {
+ public const int GLX_USE_GL = 1;
+ public const int GLX_BUFFER_SIZE = 2;
+ public const int GLX_LEVEL = 3;
+ public const int GLX_RGBA = 4;
+ public const int GLX_DOUBLEBUFFER = 5;
+ public const int GLX_STEREO = 6;
+ public const int GLX_AUX_BUFFERS = 7;
+ public const int GLX_RED_SIZE = 8;
+ public const int GLX_GREEN_SIZE = 9;
+ public const int GLX_BLUE_SIZE = 10;
+ public const int GLX_ALPHA_SIZE = 11;
+ public const int GLX_DEPTH_SIZE = 12;
+ public const int GLX_STENCIL_SIZE = 13;
+ public const int GLX_ACCUM_RED_SIZE = 14;
+ public const int GLX_ACCUM_GREEN_SIZE = 15;
+ public const int GLX_ACCUM_BLUE_SIZE = 16;
+ public const int GLX_ACCUM_ALPHA_SIZE = 17;
+ public const int GLX_BAD_SCREEN = 1;
+ public const int GLX_BAD_ATTRIBUTE = 2;
+ public const int GLX_NO_EXTENSION = 3;
+ public const int GLX_BAD_VISUAL = 4;
+ public const int GLX_BAD_CONTEXT = 5;
+ public const int GLX_BAD_VALUE = 6;
+ public const int GLX_BAD_ENUM = 7;
+ public const int GLX_VENDOR = 1;
+ public const int GLX_VERSION = 2;
+ public const int GLX_EXTENSIONS= 3;
+ public const int GLX_CONFIG_CAVEAT = 0x20;
+ public const int GLX_DONT_CARE = unchecked((int)0xFFFFFFFF);
+ public const int GLX_X_VISUAL_TYPE = 0x22;
+ public const int GLX_TRANSPARENT_TYPE = 0x23;
+ public const int GLX_TRANSPARENT_INDEX_VALUE = 0x24;
+ public const int GLX_TRANSPARENT_RED_VALUE = 0x25;
+ public const int GLX_TRANSPARENT_GREEN_VALUE = 0x26;
+ public const int GLX_TRANSPARENT_BLUE_VALUE = 0x27;
+ public const int GLX_TRANSPARENT_ALPHA_VALUE = 0x28;
+ public const int GLX_WINDOW_BIT = 0x00000001;
+ public const int GLX_PIXMAP_BIT = 0x00000002;
+ public const int GLX_PBUFFER_BIT = 0x00000004;
+ public const int GLX_AUX_BUFFERS_BIT = 0x00000010;
+ public const int GLX_FRONT_LEFT_BUFFER_BIT = 0x00000001;
+ public const int GLX_FRONT_RIGHT_BUFFER_BIT = 0x00000002;
+ public const int GLX_BACK_LEFT_BUFFER_BIT = 0x00000004;
+ public const int GLX_BACK_RIGHT_BUFFER_BIT = 0x00000008;
+ public const int GLX_DEPTH_BUFFER_BIT = 0x00000020;
+ public const int GLX_STENCIL_BUFFER_BIT = 0x00000040;
+ public const int GLX_ACCUM_BUFFER_BIT = 0x00000080;
+ public const int GLX_NONE = 0x8000;
+ public const int GLX_SLOW_CONFIG = 0x8001;
+ public const int GLX_TRUE_COLOR = 0x8002;
+ public const int GLX_DIRECT_COLOR = 0x8003;
+ public const int GLX_PSEUDO_COLOR = 0x8004;
+ public const int GLX_STATIC_COLOR = 0x8005;
+ public const int GLX_GRAY_SCALE = 0x8006;
+ public const int GLX_STATIC_GRAY = 0x8007;
+ public const int GLX_TRANSPARENT_RGB = 0x8008;
+ public const int GLX_TRANSPARENT_INDEX = 0x8009;
+ public const int GLX_VISUAL_ID = 0x800B;
+ public const int GLX_SCREEN = 0x800C;
+ public const int GLX_NON_CONFORMANT_CONFIG = 0x800D;
+ public const int GLX_DRAWABLE_TYPE = 0x8010;
+ public const int GLX_RENDER_TYPE = 0x8011;
+ public const int GLX_X_RENDERABLE = 0x8012;
+ public const int GLX_FBCONFIG_ID = 0x8013;
+ public const int GLX_RGBA_TYPE = 0x8014;
+ public const int GLX_COLOR_INDEX_TYPE = 0x8015;
+ public const int GLX_MAX_PBUFFER_WIDTH = 0x8016;
+ public const int GLX_MAX_PBUFFER_HEIGHT = 0x8017;
+ public const int GLX_MAX_PBUFFER_PIXELS = 0x8018;
+ public const int GLX_PRESERVED_CONTENTS = 0x801B;
+ public const int GLX_LARGEST_PBUFFER = 0x801C;
+ public const int GLX_WIDTH = 0x801D;
+ public const int GLX_HEIGHT = 0x801E;
+ public const int GLX_EVENT_MASK = 0x801F;
+ public const int GLX_DAMAGED = 0x8020;
+ public const int GLX_SAVED = 0x8021;
+ public const int GLX_WINDOW = 0x8022;
+ public const int GLX_PBUFFER = 0x8023;
+ public const int GLX_PBUFFER_HEIGHT = 0x8040;
+ public const int GLX_PBUFFER_WIDTH = 0x8041;
+ public const int GLX_RGBA_BIT = 0x00000001;
+ public const int GLX_COLOR_INDEX_BIT = 0x00000002;
+ public const int GLX_PBUFFER_CLOBBER_MASK = 0x08000000;
+ public const int GLX_SAMPLE_BUFFERS = 0x186a0 /*100000*/;
+ public const int GLX_SAMPLES = 0x186a1 /*100001*/;
+ public const int GLX_PbufferClobber = 0;
+ public const int GLX_BufferSwapComplete = 1;
+ public const int GLX_CONTEXT_DEBUG_BIT_ARB = 0x00000001;
+ public const int GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x00000002;
+ public const int GLX_CONTEXT_MAJOR_VERSION_ARB = 0x2091;
+ public const int GLX_CONTEXT_MINOR_VERSION_ARB = 0x2092;
+ public const int GLX_CONTEXT_FLAGS_ARB = 0x2094;
+ public const int GLX_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001;
+ public const int GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002;
+ public const int GLX_CONTEXT_PROFILE_MASK_ARB = 0x9126;
+
+ }
+}
diff --git a/src/Avalonia.X11/Glx/GlxContext.cs b/src/Avalonia.X11/Glx/GlxContext.cs
new file mode 100644
index 0000000000..dd95841d57
--- /dev/null
+++ b/src/Avalonia.X11/Glx/GlxContext.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Reactive.Disposables;
+using System.Threading;
+using Avalonia.OpenGL;
+namespace Avalonia.X11.Glx
+{
+ class GlxContext : IGlContext
+ {
+ public IntPtr Handle { get; }
+ public GlxInterface Glx { get; }
+ private readonly X11Info _x11;
+ private readonly IntPtr _defaultXid;
+ private readonly object _lock = new object();
+
+ public GlxContext(GlxInterface glx, IntPtr handle, GlxDisplay display, X11Info x11, IntPtr defaultXid)
+ {
+ Handle = handle;
+ Glx = glx;
+ _x11 = x11;
+ _defaultXid = defaultXid;
+ Display = display;
+ }
+
+ public GlxDisplay Display { get; }
+ IGlDisplay IGlContext.Display => Display;
+
+ public IDisposable Lock()
+ {
+ Monitor.Enter(_lock);
+ return Disposable.Create(() => Monitor.Exit(_lock));
+ }
+
+ public void MakeCurrent() => MakeCurrent(_defaultXid);
+
+ public void MakeCurrent(IntPtr xid)
+ {
+ if (!Glx.MakeContextCurrent(_x11.Display, xid, xid, Handle))
+ throw new OpenGlException("glXMakeContextCurrent failed ");
+ }
+ }
+}
diff --git a/src/Avalonia.X11/Glx/GlxDisplay.cs b/src/Avalonia.X11/Glx/GlxDisplay.cs
new file mode 100644
index 0000000000..5602b33280
--- /dev/null
+++ b/src/Avalonia.X11/Glx/GlxDisplay.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Linq;
+using Avalonia.OpenGL;
+using static Avalonia.X11.Glx.GlxConsts;
+
+namespace Avalonia.X11.Glx
+{
+ unsafe class GlxDisplay : IGlDisplay
+ {
+ private readonly X11Info _x11;
+ private readonly IntPtr _fbconfig;
+ private readonly XVisualInfo* _visual;
+ public GlDisplayType Type => GlDisplayType.OpenGL2;
+ public GlInterface GlInterface { get; }
+
+ public XVisualInfo* VisualInfo => _visual;
+ public int SampleCount { get; }
+ public int StencilSize { get; }
+
+ public GlxContext ImmediateContext { get; }
+ public GlxContext DeferredContext { get; }
+ public GlxInterface Glx { get; } = new GlxInterface();
+ public GlxDisplay(X11Info x11)
+ {
+ _x11 = x11;
+
+ var baseAttribs = new[]
+ {
+ GLX_X_RENDERABLE, 1,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT,
+ GLX_DOUBLEBUFFER, 1,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, 8,
+ GLX_DEPTH_SIZE, 1,
+ GLX_STENCIL_SIZE, 8,
+
+ };
+
+ foreach (var attribs in new[]
+ {
+ //baseAttribs.Concat(multiattribs),
+ baseAttribs,
+ })
+ {
+ var ptr = Glx.ChooseFBConfig(_x11.Display, x11.DefaultScreen,
+ attribs, out var count);
+ for (var c = 0 ; c < count; c++)
+ {
+
+ var visual = Glx.GetVisualFromFBConfig(_x11.Display, ptr[c]);
+ // We prefer 32 bit visuals
+ if (_fbconfig == IntPtr.Zero || visual->depth == 32)
+ {
+ _fbconfig = ptr[c];
+ _visual = visual;
+ if(visual->depth == 32)
+ break;
+ }
+ }
+
+ if (_fbconfig != IntPtr.Zero)
+ break;
+ }
+
+ if (_fbconfig == IntPtr.Zero)
+ throw new OpenGlException("Unable to choose FBConfig");
+
+ if (_visual == null)
+ throw new OpenGlException("Unable to get visual info from FBConfig");
+ if (Glx.GetFBConfigAttrib(_x11.Display, _fbconfig, GLX_SAMPLES, out var samples) == 0)
+ SampleCount = samples;
+ if (Glx.GetFBConfigAttrib(_x11.Display, _fbconfig, GLX_STENCIL_SIZE, out var stencil) == 0)
+ StencilSize = stencil;
+
+ var pbuffers = Enumerable.Range(0, 2).Select(_ => Glx.CreatePbuffer(_x11.Display, _fbconfig, new[]
+ {
+ GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, 0
+ })).ToList();
+
+ XLib.XFlush(_x11.Display);
+
+ ImmediateContext = CreateContext(pbuffers[0],null);
+ DeferredContext = CreateContext(pbuffers[1], ImmediateContext);
+ ImmediateContext.MakeCurrent();
+ var err = Glx.GetError();
+
+ GlInterface = new GlInterface(GlxInterface.GlxGetProcAddress);
+ if (GlInterface.Version == null)
+ throw new OpenGlException("GL version string is null, aborting");
+ }
+
+ public void ClearContext() => Glx.MakeContextCurrent(_x11.Display,
+ IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+
+ public GlxContext CreateContext(IGlContext share) => CreateContext(IntPtr.Zero, share);
+ public GlxContext CreateContext(IntPtr defaultXid, IGlContext share)
+ {
+ var sharelist = ((GlxContext)share)?.Handle ?? IntPtr.Zero;
+ IntPtr handle = default;
+ foreach (var ver in new[]
+ {
+ new Version(4, 0), new Version(3, 2),
+ new Version(3, 0), new Version(2, 0)
+ })
+ {
+
+ var attrs = new[]
+ {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, ver.Major,
+ GLX_CONTEXT_MINOR_VERSION_ARB, ver.Minor,
+ GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+ 0
+ };
+ try
+ {
+ handle = Glx.CreateContextAttribsARB(_x11.Display, _fbconfig, sharelist, true, attrs);
+ if (handle != IntPtr.Zero)
+ break;
+ }
+ catch
+ {
+ break;
+ }
+ }
+
+ if (handle == IntPtr.Zero)
+ throw new OpenGlException("Unable to create direct GLX context");
+ return new GlxContext(new GlxInterface(), handle, this, _x11, defaultXid);
+ }
+
+ public void SwapBuffers(IntPtr xid) => Glx.SwapBuffers(_x11.Display, xid);
+ }
+}
diff --git a/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs b/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
new file mode 100644
index 0000000000..45a46bd6f5
--- /dev/null
+++ b/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
@@ -0,0 +1,86 @@
+using System;
+using Avalonia.OpenGL;
+
+namespace Avalonia.X11.Glx
+{
+ class GlxGlPlatformSurface: IGlPlatformSurface
+ {
+
+ private readonly GlxDisplay _display;
+ private readonly GlxContext _context;
+ private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
+
+ public GlxGlPlatformSurface(GlxDisplay display, GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info)
+ {
+ _display = display;
+ _context = context;
+ _info = info;
+ }
+
+ public IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
+ {
+ return new RenderTarget(_context, _info);
+ }
+
+ class RenderTarget : IGlPlatformSurfaceRenderTarget
+ {
+ private readonly GlxContext _context;
+ private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
+
+ public RenderTarget(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info)
+ {
+ _context = context;
+ _info = info;
+ }
+
+ public void Dispose()
+ {
+ // No-op
+ }
+
+ public IGlPlatformSurfaceRenderingSession BeginDraw()
+ {
+ var l = _context.Lock();
+ try
+ {
+ _context.MakeCurrent(_info.Handle);
+ return new Session(_context, _info, l);
+ }
+ catch
+ {
+ l.Dispose();
+ throw;
+ }
+ }
+
+ class Session : IGlPlatformSurfaceRenderingSession
+ {
+ private readonly GlxContext _context;
+ private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
+ private IDisposable _lock;
+
+ public Session(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info,
+ IDisposable @lock)
+ {
+ _context = context;
+ _info = info;
+ _lock = @lock;
+ }
+
+ public void Dispose()
+ {
+ _context.Display.GlInterface.Flush();
+ _context.Glx.WaitGL();
+ _context.Display.SwapBuffers(_info.Handle);
+ _context.Glx.WaitX();
+ _context.Display.ClearContext();
+ _lock.Dispose();
+ }
+
+ public IGlDisplay Display => _context.Display;
+ public PixelSize Size => _info.Size;
+ public double Scaling => _info.Scaling;
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.X11/Glx/GlxPlatformFeature.cs b/src/Avalonia.X11/Glx/GlxPlatformFeature.cs
new file mode 100644
index 0000000000..d15b5fe4b8
--- /dev/null
+++ b/src/Avalonia.X11/Glx/GlxPlatformFeature.cs
@@ -0,0 +1,44 @@
+using System;
+using Avalonia.Logging;
+using Avalonia.OpenGL;
+
+namespace Avalonia.X11.Glx
+{
+ class GlxGlPlatformFeature : IWindowingPlatformGlFeature
+ {
+ public GlxDisplay Display { get; private set; }
+ public IGlContext ImmediateContext { get; private set; }
+ public GlxContext DeferredContext { get; private set; }
+
+ public static bool TryInitialize(X11Info x11)
+ {
+ var feature = TryCreate(x11);
+ if (feature != null)
+ {
+ AvaloniaLocator.CurrentMutable.Bind().ToConstant(feature);
+ return true;
+ }
+
+ return false;
+ }
+
+ public static GlxGlPlatformFeature TryCreate(X11Info x11)
+ {
+ try
+ {
+ var disp = new GlxDisplay(x11);
+ return new GlxGlPlatformFeature
+ {
+ Display = disp,
+ ImmediateContext = disp.ImmediateContext,
+ DeferredContext = disp.DeferredContext
+ };
+ }
+ catch(Exception e)
+ {
+ Logger.Error("OpenGL", null, "Unable to initialize GLX-based rendering: {0}", e);
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.X11/Keysyms.cs b/src/Avalonia.X11/Keysyms.cs
new file mode 100644
index 0000000000..651a06f574
--- /dev/null
+++ b/src/Avalonia.X11/Keysyms.cs
@@ -0,0 +1,2108 @@
+// ReSharper disable UnusedMember.Global
+// ReSharper disable IdentifierTypo
+// ReSharper disable CommentTypo
+namespace Avalonia.X11
+{
+ enum X11Key
+ {
+ VoidSymbol = 0xffffff /* Void symbol */,
+ BackSpace = 0xff08 /* Back space, back char */,
+ Tab = 0xff09,
+ Linefeed = 0xff0a /* Linefeed, LF */,
+ Clear = 0xff0b,
+ Return = 0xff0d /* Return, enter */,
+ Pause = 0xff13 /* Pause, hold */,
+ Scroll_Lock = 0xff14,
+ Sys_Req = 0xff15,
+ Escape = 0xff1b,
+ Delete = 0xffff /* Delete, rubout */,
+ Multi_key = 0xff20 /* Multi-key character compose */,
+ Codeinput = 0xff37,
+ SingleCandidate = 0xff3c,
+ MultipleCandidate = 0xff3d,
+ PreviousCandidate = 0xff3e,
+ Kanji = 0xff21 /* Kanji, Kanji convert */,
+ Muhenkan = 0xff22 /* Cancel Conversion */,
+ Henkan_Mode = 0xff23 /* Start/Stop Conversion */,
+ Henkan = 0xff23 /* Alias for Henkan_Mode */,
+ Romaji = 0xff24 /* to Romaji */,
+ Hiragana = 0xff25 /* to Hiragana */,
+ Katakana = 0xff26 /* to Katakana */,
+ Hiragana_Katakana = 0xff27 /* Hiragana/Katakana toggle */,
+ Zenkaku = 0xff28 /* to Zenkaku */,
+ Hankaku = 0xff29 /* to Hankaku */,
+ Zenkaku_Hankaku = 0xff2a /* Zenkaku/Hankaku toggle */,
+ Touroku = 0xff2b /* Add to Dictionary */,
+ Massyo = 0xff2c /* Delete from Dictionary */,
+ Kana_Lock = 0xff2d /* Kana Lock */,
+ Kana_Shift = 0xff2e /* Kana Shift */,
+ Eisu_Shift = 0xff2f /* Alphanumeric Shift */,
+ Eisu_toggle = 0xff30 /* Alphanumeric toggle */,
+ Kanji_Bangou = 0xff37 /* Codeinput */,
+ Zen_Koho = 0xff3d /* Multiple/All Candidate(s) */,
+ Mae_Koho = 0xff3e /* Previous Candidate */,
+ Home = 0xff50,
+ Left = 0xff51 /* Move left, left arrow */,
+ Up = 0xff52 /* Move up, up arrow */,
+ Right = 0xff53 /* Move right, right arrow */,
+ Down = 0xff54 /* Move down, down arrow */,
+ Prior = 0xff55 /* Prior, previous */,
+ Page_Up = 0xff55,
+ Next = 0xff56 /* Next */,
+ Page_Down = 0xff56,
+ End = 0xff57 /* EOL */,
+ Begin = 0xff58 /* BOL */,
+ Select = 0xff60 /* Select, mark */,
+ Print = 0xff61,
+ Execute = 0xff62 /* Execute, run, do */,
+ Insert = 0xff63 /* Insert, insert here */,
+ Undo = 0xff65,
+ Redo = 0xff66 /* Redo, again */,
+ Menu = 0xff67,
+ Find = 0xff68 /* Find, search */,
+ Cancel = 0xff69 /* Cancel, stop, abort, exit */,
+ Help = 0xff6a /* Help */,
+ Break = 0xff6b,
+ Mode_switch = 0xff7e /* Character set switch */,
+ script_switch = 0xff7e /* Alias for mode_switch */,
+ Num_Lock = 0xff7f,
+ KP_Space = 0xff80 /* Space */,
+ KP_Tab = 0xff89,
+ KP_Enter = 0xff8d /* Enter */,
+ KP_F1 = 0xff91 /* PF1, KP_A, ... */,
+ KP_F2 = 0xff92,
+ KP_F3 = 0xff93,
+ KP_F4 = 0xff94,
+ KP_Home = 0xff95,
+ KP_Left = 0xff96,
+ KP_Up = 0xff97,
+ KP_Right = 0xff98,
+ KP_Down = 0xff99,
+ KP_Prior = 0xff9a,
+ KP_Page_Up = 0xff9a,
+ KP_Next = 0xff9b,
+ KP_Page_Down = 0xff9b,
+ KP_End = 0xff9c,
+ KP_Begin = 0xff9d,
+ KP_Insert = 0xff9e,
+ KP_Delete = 0xff9f,
+ KP_Equal = 0xffbd /* Equals */,
+ KP_Multiply = 0xffaa,
+ KP_Add = 0xffab,
+ KP_Separator = 0xffac /* Separator, often comma */,
+ KP_Subtract = 0xffad,
+ KP_Decimal = 0xffae,
+ KP_Divide = 0xffaf,
+ KP_0 = 0xffb0,
+ KP_1 = 0xffb1,
+ KP_2 = 0xffb2,
+ KP_3 = 0xffb3,
+ KP_4 = 0xffb4,
+ KP_5 = 0xffb5,
+ KP_6 = 0xffb6,
+ KP_7 = 0xffb7,
+ KP_8 = 0xffb8,
+ KP_9 = 0xffb9,
+ F1 = 0xffbe,
+ F2 = 0xffbf,
+ F3 = 0xffc0,
+ F4 = 0xffc1,
+ F5 = 0xffc2,
+ F6 = 0xffc3,
+ F7 = 0xffc4,
+ F8 = 0xffc5,
+ F9 = 0xffc6,
+ F10 = 0xffc7,
+ F11 = 0xffc8,
+ L1 = 0xffc8,
+ F12 = 0xffc9,
+ L2 = 0xffc9,
+ F13 = 0xffca,
+ L3 = 0xffca,
+ F14 = 0xffcb,
+ L4 = 0xffcb,
+ F15 = 0xffcc,
+ L5 = 0xffcc,
+ F16 = 0xffcd,
+ L6 = 0xffcd,
+ F17 = 0xffce,
+ L7 = 0xffce,
+ F18 = 0xffcf,
+ L8 = 0xffcf,
+ F19 = 0xffd0,
+ L9 = 0xffd0,
+ F20 = 0xffd1,
+ L10 = 0xffd1,
+ F21 = 0xffd2,
+ R1 = 0xffd2,
+ F22 = 0xffd3,
+ R2 = 0xffd3,
+ F23 = 0xffd4,
+ R3 = 0xffd4,
+ F24 = 0xffd5,
+ R4 = 0xffd5,
+ F25 = 0xffd6,
+ R5 = 0xffd6,
+ F26 = 0xffd7,
+ R6 = 0xffd7,
+ F27 = 0xffd8,
+ R7 = 0xffd8,
+ F28 = 0xffd9,
+ R8 = 0xffd9,
+ F29 = 0xffda,
+ R9 = 0xffda,
+ F30 = 0xffdb,
+ R10 = 0xffdb,
+ F31 = 0xffdc,
+ R11 = 0xffdc,
+ F32 = 0xffdd,
+ R12 = 0xffdd,
+ F33 = 0xffde,
+ R13 = 0xffde,
+ F34 = 0xffdf,
+ R14 = 0xffdf,
+ F35 = 0xffe0,
+ R15 = 0xffe0,
+ Shift_L = 0xffe1 /* Left shift */,
+ Shift_R = 0xffe2 /* Right shift */,
+ Control_L = 0xffe3 /* Left control */,
+ Control_R = 0xffe4 /* Right control */,
+ Caps_Lock = 0xffe5 /* Caps lock */,
+ Shift_Lock = 0xffe6 /* Shift lock */,
+ Meta_L = 0xffe7 /* Left meta */,
+ Meta_R = 0xffe8 /* Right meta */,
+ Alt_L = 0xffe9 /* Left alt */,
+ Alt_R = 0xffea /* Right alt */,
+ Super_L = 0xffeb /* Left super */,
+ Super_R = 0xffec /* Right super */,
+ Hyper_L = 0xffed /* Left hyper */,
+ Hyper_R = 0xffee /* Right hyper */,
+ ISO_Lock = 0xfe01,
+ ISO_Level2_Latch = 0xfe02,
+ ISO_Level3_Shift = 0xfe03,
+ ISO_Level3_Latch = 0xfe04,
+ ISO_Level3_Lock = 0xfe05,
+ ISO_Level5_Shift = 0xfe11,
+ ISO_Level5_Latch = 0xfe12,
+ ISO_Level5_Lock = 0xfe13,
+ ISO_Group_Shift = 0xff7e /* Alias for mode_switch */,
+ ISO_Group_Latch = 0xfe06,
+ ISO_Group_Lock = 0xfe07,
+ ISO_Next_Group = 0xfe08,
+ ISO_Next_Group_Lock = 0xfe09,
+ ISO_Prev_Group = 0xfe0a,
+ ISO_Prev_Group_Lock = 0xfe0b,
+ ISO_First_Group = 0xfe0c,
+ ISO_First_Group_Lock = 0xfe0d,
+ ISO_Last_Group = 0xfe0e,
+ ISO_Last_Group_Lock = 0xfe0f,
+ ISO_Left_Tab = 0xfe20,
+ ISO_Move_Line_Up = 0xfe21,
+ ISO_Move_Line_Down = 0xfe22,
+ ISO_Partial_Line_Up = 0xfe23,
+ ISO_Partial_Line_Down = 0xfe24,
+ ISO_Partial_Space_Left = 0xfe25,
+ ISO_Partial_Space_Right = 0xfe26,
+ ISO_Set_Margin_Left = 0xfe27,
+ ISO_Set_Margin_Right = 0xfe28,
+ ISO_Release_Margin_Left = 0xfe29,
+ ISO_Release_Margin_Right = 0xfe2a,
+ ISO_Release_Both_Margins = 0xfe2b,
+ ISO_Fast_Cursor_Left = 0xfe2c,
+ ISO_Fast_Cursor_Right = 0xfe2d,
+ ISO_Fast_Cursor_Up = 0xfe2e,
+ ISO_Fast_Cursor_Down = 0xfe2f,
+ ISO_Continuous_Underline = 0xfe30,
+ ISO_Discontinuous_Underline = 0xfe31,
+ ISO_Emphasize = 0xfe32,
+ ISO_Center_Object = 0xfe33,
+ ISO_Enter = 0xfe34,
+ dead_grave = 0xfe50,
+ dead_acute = 0xfe51,
+ dead_circumflex = 0xfe52,
+ dead_tilde = 0xfe53,
+ dead_perispomeni = 0xfe53 /* alias for dead_tilde */,
+ dead_macron = 0xfe54,
+ dead_breve = 0xfe55,
+ dead_abovedot = 0xfe56,
+ dead_diaeresis = 0xfe57,
+ dead_abovering = 0xfe58,
+ dead_doubleacute = 0xfe59,
+ dead_caron = 0xfe5a,
+ dead_cedilla = 0xfe5b,
+ dead_ogonek = 0xfe5c,
+ dead_iota = 0xfe5d,
+ dead_voiced_sound = 0xfe5e,
+ dead_semivoiced_sound = 0xfe5f,
+ dead_belowdot = 0xfe60,
+ dead_hook = 0xfe61,
+ dead_horn = 0xfe62,
+ dead_stroke = 0xfe63,
+ dead_abovecomma = 0xfe64,
+ dead_psili = 0xfe64 /* alias for dead_abovecomma */,
+ dead_abovereversedcomma = 0xfe65,
+ dead_dasia = 0xfe65 /* alias for dead_abovereversedcomma */,
+ dead_doublegrave = 0xfe66,
+ dead_belowring = 0xfe67,
+ dead_belowmacron = 0xfe68,
+ dead_belowcircumflex = 0xfe69,
+ dead_belowtilde = 0xfe6a,
+ dead_belowbreve = 0xfe6b,
+ dead_belowdiaeresis = 0xfe6c,
+ dead_invertedbreve = 0xfe6d,
+ dead_belowcomma = 0xfe6e,
+ dead_currency = 0xfe6f,
+ dead_lowline = 0xfe90,
+ dead_aboveverticalline = 0xfe91,
+ dead_belowverticalline = 0xfe92,
+ dead_longsolidusoverlay = 0xfe93,
+ dead_a = 0xfe80,
+ dead_A = 0xfe81,
+ dead_e = 0xfe82,
+ dead_E = 0xfe83,
+ dead_i = 0xfe84,
+ dead_I = 0xfe85,
+ dead_o = 0xfe86,
+ dead_O = 0xfe87,
+ dead_u = 0xfe88,
+ dead_U = 0xfe89,
+ dead_small_schwa = 0xfe8a,
+ dead_capital_schwa = 0xfe8b,
+ dead_greek = 0xfe8c,
+ First_Virtual_Screen = 0xfed0,
+ Prev_Virtual_Screen = 0xfed1,
+ Next_Virtual_Screen = 0xfed2,
+ Last_Virtual_Screen = 0xfed4,
+ Terminate_Server = 0xfed5,
+ AccessX_Enable = 0xfe70,
+ AccessX_Feedback_Enable = 0xfe71,
+ RepeatKeys_Enable = 0xfe72,
+ SlowKeys_Enable = 0xfe73,
+ BounceKeys_Enable = 0xfe74,
+ StickyKeys_Enable = 0xfe75,
+ MouseKeys_Enable = 0xfe76,
+ MouseKeys_Accel_Enable = 0xfe77,
+ Overlay1_Enable = 0xfe78,
+ Overlay2_Enable = 0xfe79,
+ AudibleBell_Enable = 0xfe7a,
+ Pointer_Left = 0xfee0,
+ Pointer_Right = 0xfee1,
+ Pointer_Up = 0xfee2,
+ Pointer_Down = 0xfee3,
+ Pointer_UpLeft = 0xfee4,
+ Pointer_UpRight = 0xfee5,
+ Pointer_DownLeft = 0xfee6,
+ Pointer_DownRight = 0xfee7,
+ Pointer_Button_Dflt = 0xfee8,
+ Pointer_Button1 = 0xfee9,
+ Pointer_Button2 = 0xfeea,
+ Pointer_Button3 = 0xfeeb,
+ Pointer_Button4 = 0xfeec,
+ Pointer_Button5 = 0xfeed,
+ Pointer_DblClick_Dflt = 0xfeee,
+ Pointer_DblClick1 = 0xfeef,
+ Pointer_DblClick2 = 0xfef0,
+ Pointer_DblClick3 = 0xfef1,
+ Pointer_DblClick4 = 0xfef2,
+ Pointer_DblClick5 = 0xfef3,
+ Pointer_Drag_Dflt = 0xfef4,
+ Pointer_Drag1 = 0xfef5,
+ Pointer_Drag2 = 0xfef6,
+ Pointer_Drag3 = 0xfef7,
+ Pointer_Drag4 = 0xfef8,
+ Pointer_Drag5 = 0xfefd,
+ Pointer_EnableKeys = 0xfef9,
+ Pointer_Accelerate = 0xfefa,
+ Pointer_DfltBtnNext = 0xfefb,
+ Pointer_DfltBtnPrev = 0xfefc,
+ ch = 0xfea0,
+ Ch = 0xfea1,
+ CH = 0xfea2,
+ c_h = 0xfea3,
+ C_h = 0xfea4,
+ C_H = 0xfea5,
+ XK_3270_Duplicate = 0xfd01,
+ XK_3270_FieldMark = 0xfd02,
+ XK_3270_Right2 = 0xfd03,
+ XK_3270_Left2 = 0xfd04,
+ XK_3270_BackTab = 0xfd05,
+ XK_3270_EraseEOF = 0xfd06,
+ XK_3270_EraseInput = 0xfd07,
+ XK_3270_Reset = 0xfd08,
+ XK_3270_Quit = 0xfd09,
+ XK_3270_PA1 = 0xfd0a,
+ XK_3270_PA2 = 0xfd0b,
+ XK_3270_PA3 = 0xfd0c,
+ XK_3270_Test = 0xfd0d,
+ XK_3270_Attn = 0xfd0e,
+ XK_3270_CursorBlink = 0xfd0f,
+ XK_3270_AltCursor = 0xfd10,
+ XK_3270_KeyClick = 0xfd11,
+ XK_3270_Jump = 0xfd12,
+ XK_3270_Ident = 0xfd13,
+ XK_3270_Rule = 0xfd14,
+ XK_3270_Copy = 0xfd15,
+ XK_3270_Play = 0xfd16,
+ XK_3270_Setup = 0xfd17,
+ XK_3270_Record = 0xfd18,
+ XK_3270_ChangeScreen = 0xfd19,
+ XK_3270_DeleteWord = 0xfd1a,
+ XK_3270_ExSelect = 0xfd1b,
+ XK_3270_CursorSelect = 0xfd1c,
+ XK_3270_PrintScreen = 0xfd1d,
+ XK_3270_Enter = 0xfd1e,
+ space = 0x0020 /* U+0020 SPACE */,
+ exclam = 0x0021 /* U+0021 EXCLAMATION MARK */,
+ quotedbl = 0x0022 /* U+0022 QUOTATION MARK */,
+ numbersign = 0x0023 /* U+0023 NUMBER SIGN */,
+ dollar = 0x0024 /* U+0024 DOLLAR SIGN */,
+ percent = 0x0025 /* U+0025 PERCENT SIGN */,
+ ampersand = 0x0026 /* U+0026 AMPERSAND */,
+ apostrophe = 0x0027 /* U+0027 APOSTROPHE */,
+ quoteright = 0x0027 /* deprecated */,
+ parenleft = 0x0028 /* U+0028 LEFT PARENTHESIS */,
+ parenright = 0x0029 /* U+0029 RIGHT PARENTHESIS */,
+ asterisk = 0x002a /* U+002A ASTERISK */,
+ plus = 0x002b /* U+002B PLUS SIGN */,
+ comma = 0x002c /* U+002C COMMA */,
+ minus = 0x002d /* U+002D HYPHEN-MINUS */,
+ period = 0x002e /* U+002E FULL STOP */,
+ slash = 0x002f /* U+002F SOLIDUS */,
+ XK_0 = 0x0030 /* U+0030 DIGIT ZERO */,
+ XK_1 = 0x0031 /* U+0031 DIGIT ONE */,
+ XK_2 = 0x0032 /* U+0032 DIGIT TWO */,
+ XK_3 = 0x0033 /* U+0033 DIGIT THREE */,
+ XK_4 = 0x0034 /* U+0034 DIGIT FOUR */,
+ XK_5 = 0x0035 /* U+0035 DIGIT FIVE */,
+ XK_6 = 0x0036 /* U+0036 DIGIT SIX */,
+ XK_7 = 0x0037 /* U+0037 DIGIT SEVEN */,
+ XK_8 = 0x0038 /* U+0038 DIGIT EIGHT */,
+ XK_9 = 0x0039 /* U+0039 DIGIT NINE */,
+ colon = 0x003a /* U+003A COLON */,
+ semicolon = 0x003b /* U+003B SEMICOLON */,
+ less = 0x003c /* U+003C LESS-THAN SIGN */,
+ equal = 0x003d /* U+003D EQUALS SIGN */,
+ greater = 0x003e /* U+003E GREATER-THAN SIGN */,
+ question = 0x003f /* U+003F QUESTION MARK */,
+ at = 0x0040 /* U+0040 COMMERCIAL AT */,
+ A = 0x0041 /* U+0041 LATIN CAPITAL LETTER A */,
+ B = 0x0042 /* U+0042 LATIN CAPITAL LETTER B */,
+ C = 0x0043 /* U+0043 LATIN CAPITAL LETTER C */,
+ D = 0x0044 /* U+0044 LATIN CAPITAL LETTER D */,
+ E = 0x0045 /* U+0045 LATIN CAPITAL LETTER E */,
+ F = 0x0046 /* U+0046 LATIN CAPITAL LETTER F */,
+ G = 0x0047 /* U+0047 LATIN CAPITAL LETTER G */,
+ H = 0x0048 /* U+0048 LATIN CAPITAL LETTER H */,
+ I = 0x0049 /* U+0049 LATIN CAPITAL LETTER I */,
+ J = 0x004a /* U+004A LATIN CAPITAL LETTER J */,
+ K = 0x004b /* U+004B LATIN CAPITAL LETTER K */,
+ L = 0x004c /* U+004C LATIN CAPITAL LETTER L */,
+ M = 0x004d /* U+004D LATIN CAPITAL LETTER M */,
+ N = 0x004e /* U+004E LATIN CAPITAL LETTER N */,
+ O = 0x004f /* U+004F LATIN CAPITAL LETTER O */,
+ P = 0x0050 /* U+0050 LATIN CAPITAL LETTER P */,
+ Q = 0x0051 /* U+0051 LATIN CAPITAL LETTER Q */,
+ R = 0x0052 /* U+0052 LATIN CAPITAL LETTER R */,
+ S = 0x0053 /* U+0053 LATIN CAPITAL LETTER S */,
+ T = 0x0054 /* U+0054 LATIN CAPITAL LETTER T */,
+ U = 0x0055 /* U+0055 LATIN CAPITAL LETTER U */,
+ V = 0x0056 /* U+0056 LATIN CAPITAL LETTER V */,
+ W = 0x0057 /* U+0057 LATIN CAPITAL LETTER W */,
+ X = 0x0058 /* U+0058 LATIN CAPITAL LETTER X */,
+ Y = 0x0059 /* U+0059 LATIN CAPITAL LETTER Y */,
+ Z = 0x005a /* U+005A LATIN CAPITAL LETTER Z */,
+ bracketleft = 0x005b /* U+005B LEFT SQUARE BRACKET */,
+ backslash = 0x005c /* U+005C REVERSE SOLIDUS */,
+ bracketright = 0x005d /* U+005D RIGHT SQUARE BRACKET */,
+ asciicircum = 0x005e /* U+005E CIRCUMFLEX ACCENT */,
+ underscore = 0x005f /* U+005F LOW LINE */,
+ grave = 0x0060 /* U+0060 GRAVE ACCENT */,
+ quoteleft = 0x0060 /* deprecated */,
+ a = 0x0061 /* U+0061 LATIN SMALL LETTER A */,
+ b = 0x0062 /* U+0062 LATIN SMALL LETTER B */,
+ c = 0x0063 /* U+0063 LATIN SMALL LETTER C */,
+ d = 0x0064 /* U+0064 LATIN SMALL LETTER D */,
+ e = 0x0065 /* U+0065 LATIN SMALL LETTER E */,
+ f = 0x0066 /* U+0066 LATIN SMALL LETTER F */,
+ g = 0x0067 /* U+0067 LATIN SMALL LETTER G */,
+ h = 0x0068 /* U+0068 LATIN SMALL LETTER H */,
+ i = 0x0069 /* U+0069 LATIN SMALL LETTER I */,
+ j = 0x006a /* U+006A LATIN SMALL LETTER J */,
+ k = 0x006b /* U+006B LATIN SMALL LETTER K */,
+ l = 0x006c /* U+006C LATIN SMALL LETTER L */,
+ m = 0x006d /* U+006D LATIN SMALL LETTER M */,
+ n = 0x006e /* U+006E LATIN SMALL LETTER N */,
+ o = 0x006f /* U+006F LATIN SMALL LETTER O */,
+ p = 0x0070 /* U+0070 LATIN SMALL LETTER P */,
+ q = 0x0071 /* U+0071 LATIN SMALL LETTER Q */,
+ r = 0x0072 /* U+0072 LATIN SMALL LETTER R */,
+ s = 0x0073 /* U+0073 LATIN SMALL LETTER S */,
+ t = 0x0074 /* U+0074 LATIN SMALL LETTER T */,
+ u = 0x0075 /* U+0075 LATIN SMALL LETTER U */,
+ v = 0x0076 /* U+0076 LATIN SMALL LETTER V */,
+ w = 0x0077 /* U+0077 LATIN SMALL LETTER W */,
+ x = 0x0078 /* U+0078 LATIN SMALL LETTER X */,
+ y = 0x0079 /* U+0079 LATIN SMALL LETTER Y */,
+ z = 0x007a /* U+007A LATIN SMALL LETTER Z */,
+ braceleft = 0x007b /* U+007B LEFT CURLY BRACKET */,
+ bar = 0x007c /* U+007C VERTICAL LINE */,
+ braceright = 0x007d /* U+007D RIGHT CURLY BRACKET */,
+ asciitilde = 0x007e /* U+007E TILDE */,
+ nobreakspace = 0x00a0 /* U+00A0 NO-BREAK SPACE */,
+ exclamdown = 0x00a1 /* U+00A1 INVERTED EXCLAMATION MARK */,
+ cent = 0x00a2 /* U+00A2 CENT SIGN */,
+ sterling = 0x00a3 /* U+00A3 POUND SIGN */,
+ currency = 0x00a4 /* U+00A4 CURRENCY SIGN */,
+ yen = 0x00a5 /* U+00A5 YEN SIGN */,
+ brokenbar = 0x00a6 /* U+00A6 BROKEN BAR */,
+ section = 0x00a7 /* U+00A7 SECTION SIGN */,
+ diaeresis = 0x00a8 /* U+00A8 DIAERESIS */,
+ copyright = 0x00a9 /* U+00A9 COPYRIGHT SIGN */,
+ ordfeminine = 0x00aa /* U+00AA FEMININE ORDINAL INDICATOR */,
+ guillemotleft = 0x00ab /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */,
+ notsign = 0x00ac /* U+00AC NOT SIGN */,
+ hyphen = 0x00ad /* U+00AD SOFT HYPHEN */,
+ registered = 0x00ae /* U+00AE REGISTERED SIGN */,
+ macron = 0x00af /* U+00AF MACRON */,
+ degree = 0x00b0 /* U+00B0 DEGREE SIGN */,
+ plusminus = 0x00b1 /* U+00B1 PLUS-MINUS SIGN */,
+ twosuperior = 0x00b2 /* U+00B2 SUPERSCRIPT TWO */,
+ threesuperior = 0x00b3 /* U+00B3 SUPERSCRIPT THREE */,
+ acute = 0x00b4 /* U+00B4 ACUTE ACCENT */,
+ mu = 0x00b5 /* U+00B5 MICRO SIGN */,
+ paragraph = 0x00b6 /* U+00B6 PILCROW SIGN */,
+ periodcentered = 0x00b7 /* U+00B7 MIDDLE DOT */,
+ cedilla = 0x00b8 /* U+00B8 CEDILLA */,
+ onesuperior = 0x00b9 /* U+00B9 SUPERSCRIPT ONE */,
+ masculine = 0x00ba /* U+00BA MASCULINE ORDINAL INDICATOR */,
+ guillemotright = 0x00bb /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */,
+ onequarter = 0x00bc /* U+00BC VULGAR FRACTION ONE QUARTER */,
+ onehalf = 0x00bd /* U+00BD VULGAR FRACTION ONE HALF */,
+ threequarters = 0x00be /* U+00BE VULGAR FRACTION THREE QUARTERS */,
+ questiondown = 0x00bf /* U+00BF INVERTED QUESTION MARK */,
+ Agrave = 0x00c0 /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */,
+ Aacute = 0x00c1 /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */,
+ Acircumflex = 0x00c2 /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */,
+ Atilde = 0x00c3 /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */,
+ Adiaeresis = 0x00c4 /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */,
+ Aring = 0x00c5 /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */,
+ AE = 0x00c6 /* U+00C6 LATIN CAPITAL LETTER AE */,
+ Ccedilla = 0x00c7 /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */,
+ Egrave = 0x00c8 /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */,
+ Eacute = 0x00c9 /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */,
+ Ecircumflex = 0x00ca /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */,
+ Ediaeresis = 0x00cb /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */,
+ Igrave = 0x00cc /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */,
+ Iacute = 0x00cd /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */,
+ Icircumflex = 0x00ce /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */,
+ Idiaeresis = 0x00cf /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */,
+ ETH = 0x00d0 /* U+00D0 LATIN CAPITAL LETTER ETH */,
+ Eth = 0x00d0 /* deprecated */,
+ Ntilde = 0x00d1 /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */,
+ Ograve = 0x00d2 /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */,
+ Oacute = 0x00d3 /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */,
+ Ocircumflex = 0x00d4 /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */,
+ Otilde = 0x00d5 /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */,
+ Odiaeresis = 0x00d6 /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */,
+ multiply = 0x00d7 /* U+00D7 MULTIPLICATION SIGN */,
+ Oslash = 0x00d8 /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */,
+ Ooblique = 0x00d8 /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */,
+ Ugrave = 0x00d9 /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */,
+ Uacute = 0x00da /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */,
+ Ucircumflex = 0x00db /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */,
+ Udiaeresis = 0x00dc /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */,
+ Yacute = 0x00dd /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */,
+ THORN = 0x00de /* U+00DE LATIN CAPITAL LETTER THORN */,
+ Thorn = 0x00de /* deprecated */,
+ ssharp = 0x00df /* U+00DF LATIN SMALL LETTER SHARP S */,
+ agrave = 0x00e0 /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */,
+ aacute = 0x00e1 /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */,
+ acircumflex = 0x00e2 /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */,
+ atilde = 0x00e3 /* U+00E3 LATIN SMALL LETTER A WITH TILDE */,
+ adiaeresis = 0x00e4 /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */,
+ aring = 0x00e5 /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */,
+ ae = 0x00e6 /* U+00E6 LATIN SMALL LETTER AE */,
+ ccedilla = 0x00e7 /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */,
+ egrave = 0x00e8 /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */,
+ eacute = 0x00e9 /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */,
+ ecircumflex = 0x00ea /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */,
+ ediaeresis = 0x00eb /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */,
+ igrave = 0x00ec /* U+00EC LATIN SMALL LETTER I WITH GRAVE */,
+ iacute = 0x00ed /* U+00ED LATIN SMALL LETTER I WITH ACUTE */,
+ icircumflex = 0x00ee /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */,
+ idiaeresis = 0x00ef /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */,
+ eth = 0x00f0 /* U+00F0 LATIN SMALL LETTER ETH */,
+ ntilde = 0x00f1 /* U+00F1 LATIN SMALL LETTER N WITH TILDE */,
+ ograve = 0x00f2 /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */,
+ oacute = 0x00f3 /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */,
+ ocircumflex = 0x00f4 /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */,
+ otilde = 0x00f5 /* U+00F5 LATIN SMALL LETTER O WITH TILDE */,
+ odiaeresis = 0x00f6 /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */,
+ division = 0x00f7 /* U+00F7 DIVISION SIGN */,
+ oslash = 0x00f8 /* U+00F8 LATIN SMALL LETTER O WITH STROKE */,
+ ooblique = 0x00f8 /* U+00F8 LATIN SMALL LETTER O WITH STROKE */,
+ ugrave = 0x00f9 /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */,
+ uacute = 0x00fa /* U+00FA LATIN SMALL LETTER U WITH ACUTE */,
+ ucircumflex = 0x00fb /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */,
+ udiaeresis = 0x00fc /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */,
+ yacute = 0x00fd /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */,
+ thorn = 0x00fe /* U+00FE LATIN SMALL LETTER THORN */,
+ ydiaeresis = 0x00ff /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */,
+ Aogonek = 0x01a1 /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK */,
+ breve = 0x01a2 /* U+02D8 BREVE */,
+ Lstroke = 0x01a3 /* U+0141 LATIN CAPITAL LETTER L WITH STROKE */,
+ Lcaron = 0x01a5 /* U+013D LATIN CAPITAL LETTER L WITH CARON */,
+ Sacute = 0x01a6 /* U+015A LATIN CAPITAL LETTER S WITH ACUTE */,
+ Scaron = 0x01a9 /* U+0160 LATIN CAPITAL LETTER S WITH CARON */,
+ Scedilla = 0x01aa /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA */,
+ Tcaron = 0x01ab /* U+0164 LATIN CAPITAL LETTER T WITH CARON */,
+ Zacute = 0x01ac /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE */,
+ Zcaron = 0x01ae /* U+017D LATIN CAPITAL LETTER Z WITH CARON */,
+ Zabovedot = 0x01af /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE */,
+ aogonek = 0x01b1 /* U+0105 LATIN SMALL LETTER A WITH OGONEK */,
+ ogonek = 0x01b2 /* U+02DB OGONEK */,
+ lstroke = 0x01b3 /* U+0142 LATIN SMALL LETTER L WITH STROKE */,
+ lcaron = 0x01b5 /* U+013E LATIN SMALL LETTER L WITH CARON */,
+ sacute = 0x01b6 /* U+015B LATIN SMALL LETTER S WITH ACUTE */,
+ caron = 0x01b7 /* U+02C7 CARON */,
+ scaron = 0x01b9 /* U+0161 LATIN SMALL LETTER S WITH CARON */,
+ scedilla = 0x01ba /* U+015F LATIN SMALL LETTER S WITH CEDILLA */,
+ tcaron = 0x01bb /* U+0165 LATIN SMALL LETTER T WITH CARON */,
+ zacute = 0x01bc /* U+017A LATIN SMALL LETTER Z WITH ACUTE */,
+ doubleacute = 0x01bd /* U+02DD DOUBLE ACUTE ACCENT */,
+ zcaron = 0x01be /* U+017E LATIN SMALL LETTER Z WITH CARON */,
+ zabovedot = 0x01bf /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE */,
+ Racute = 0x01c0 /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE */,
+ Abreve = 0x01c3 /* U+0102 LATIN CAPITAL LETTER A WITH BREVE */,
+ Lacute = 0x01c5 /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE */,
+ Cacute = 0x01c6 /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE */,
+ Ccaron = 0x01c8 /* U+010C LATIN CAPITAL LETTER C WITH CARON */,
+ Eogonek = 0x01ca /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK */,
+ Ecaron = 0x01cc /* U+011A LATIN CAPITAL LETTER E WITH CARON */,
+ Dcaron = 0x01cf /* U+010E LATIN CAPITAL LETTER D WITH CARON */,
+ Dstroke = 0x01d0 /* U+0110 LATIN CAPITAL LETTER D WITH STROKE */,
+ Nacute = 0x01d1 /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE */,
+ Ncaron = 0x01d2 /* U+0147 LATIN CAPITAL LETTER N WITH CARON */,
+ Odoubleacute = 0x01d5 /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */,
+ Rcaron = 0x01d8 /* U+0158 LATIN CAPITAL LETTER R WITH CARON */,
+ Uring = 0x01d9 /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE */,
+ Udoubleacute = 0x01db /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */,
+ Tcedilla = 0x01de /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA */,
+ racute = 0x01e0 /* U+0155 LATIN SMALL LETTER R WITH ACUTE */,
+ abreve = 0x01e3 /* U+0103 LATIN SMALL LETTER A WITH BREVE */,
+ lacute = 0x01e5 /* U+013A LATIN SMALL LETTER L WITH ACUTE */,
+ cacute = 0x01e6 /* U+0107 LATIN SMALL LETTER C WITH ACUTE */,
+ ccaron = 0x01e8 /* U+010D LATIN SMALL LETTER C WITH CARON */,
+ eogonek = 0x01ea /* U+0119 LATIN SMALL LETTER E WITH OGONEK */,
+ ecaron = 0x01ec /* U+011B LATIN SMALL LETTER E WITH CARON */,
+ dcaron = 0x01ef /* U+010F LATIN SMALL LETTER D WITH CARON */,
+ dstroke = 0x01f0 /* U+0111 LATIN SMALL LETTER D WITH STROKE */,
+ nacute = 0x01f1 /* U+0144 LATIN SMALL LETTER N WITH ACUTE */,
+ ncaron = 0x01f2 /* U+0148 LATIN SMALL LETTER N WITH CARON */,
+ odoubleacute = 0x01f5 /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE */,
+ rcaron = 0x01f8 /* U+0159 LATIN SMALL LETTER R WITH CARON */,
+ uring = 0x01f9 /* U+016F LATIN SMALL LETTER U WITH RING ABOVE */,
+ udoubleacute = 0x01fb /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE */,
+ tcedilla = 0x01fe /* U+0163 LATIN SMALL LETTER T WITH CEDILLA */,
+ abovedot = 0x01ff /* U+02D9 DOT ABOVE */,
+ Hstroke = 0x02a1 /* U+0126 LATIN CAPITAL LETTER H WITH STROKE */,
+ Hcircumflex = 0x02a6 /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX */,
+ Iabovedot = 0x02a9 /* U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE */,
+ Gbreve = 0x02ab /* U+011E LATIN CAPITAL LETTER G WITH BREVE */,
+ Jcircumflex = 0x02ac /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX */,
+ hstroke = 0x02b1 /* U+0127 LATIN SMALL LETTER H WITH STROKE */,
+ hcircumflex = 0x02b6 /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX */,
+ idotless = 0x02b9 /* U+0131 LATIN SMALL LETTER DOTLESS I */,
+ gbreve = 0x02bb /* U+011F LATIN SMALL LETTER G WITH BREVE */,
+ jcircumflex = 0x02bc /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX */,
+ Cabovedot = 0x02c5 /* U+010A LATIN CAPITAL LETTER C WITH DOT ABOVE */,
+ Ccircumflex = 0x02c6 /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX */,
+ Gabovedot = 0x02d5 /* U+0120 LATIN CAPITAL LETTER G WITH DOT ABOVE */,
+ Gcircumflex = 0x02d8 /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX */,
+ Ubreve = 0x02dd /* U+016C LATIN CAPITAL LETTER U WITH BREVE */,
+ Scircumflex = 0x02de /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX */,
+ cabovedot = 0x02e5 /* U+010B LATIN SMALL LETTER C WITH DOT ABOVE */,
+ ccircumflex = 0x02e6 /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX */,
+ gabovedot = 0x02f5 /* U+0121 LATIN SMALL LETTER G WITH DOT ABOVE */,
+ gcircumflex = 0x02f8 /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX */,
+ ubreve = 0x02fd /* U+016D LATIN SMALL LETTER U WITH BREVE */,
+ scircumflex = 0x02fe /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX */,
+ kra = 0x03a2 /* U+0138 LATIN SMALL LETTER KRA */,
+ kappa = 0x03a2 /* deprecated */,
+ Rcedilla = 0x03a3 /* U+0156 LATIN CAPITAL LETTER R WITH CEDILLA */,
+ Itilde = 0x03a5 /* U+0128 LATIN CAPITAL LETTER I WITH TILDE */,
+ Lcedilla = 0x03a6 /* U+013B LATIN CAPITAL LETTER L WITH CEDILLA */,
+ Emacron = 0x03aa /* U+0112 LATIN CAPITAL LETTER E WITH MACRON */,
+ Gcedilla = 0x03ab /* U+0122 LATIN CAPITAL LETTER G WITH CEDILLA */,
+ Tslash = 0x03ac /* U+0166 LATIN CAPITAL LETTER T WITH STROKE */,
+ rcedilla = 0x03b3 /* U+0157 LATIN SMALL LETTER R WITH CEDILLA */,
+ itilde = 0x03b5 /* U+0129 LATIN SMALL LETTER I WITH TILDE */,
+ lcedilla = 0x03b6 /* U+013C LATIN SMALL LETTER L WITH CEDILLA */,
+ emacron = 0x03ba /* U+0113 LATIN SMALL LETTER E WITH MACRON */,
+ gcedilla = 0x03bb /* U+0123 LATIN SMALL LETTER G WITH CEDILLA */,
+ tslash = 0x03bc /* U+0167 LATIN SMALL LETTER T WITH STROKE */,
+ ENG = 0x03bd /* U+014A LATIN CAPITAL LETTER ENG */,
+ eng = 0x03bf /* U+014B LATIN SMALL LETTER ENG */,
+ Amacron = 0x03c0 /* U+0100 LATIN CAPITAL LETTER A WITH MACRON */,
+ Iogonek = 0x03c7 /* U+012E LATIN CAPITAL LETTER I WITH OGONEK */,
+ Eabovedot = 0x03cc /* U+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE */,
+ Imacron = 0x03cf /* U+012A LATIN CAPITAL LETTER I WITH MACRON */,
+ Ncedilla = 0x03d1 /* U+0145 LATIN CAPITAL LETTER N WITH CEDILLA */,
+ Omacron = 0x03d2 /* U+014C LATIN CAPITAL LETTER O WITH MACRON */,
+ Kcedilla = 0x03d3 /* U+0136 LATIN CAPITAL LETTER K WITH CEDILLA */,
+ Uogonek = 0x03d9 /* U+0172 LATIN CAPITAL LETTER U WITH OGONEK */,
+ Utilde = 0x03dd /* U+0168 LATIN CAPITAL LETTER U WITH TILDE */,
+ Umacron = 0x03de /* U+016A LATIN CAPITAL LETTER U WITH MACRON */,
+ amacron = 0x03e0 /* U+0101 LATIN SMALL LETTER A WITH MACRON */,
+ iogonek = 0x03e7 /* U+012F LATIN SMALL LETTER I WITH OGONEK */,
+ eabovedot = 0x03ec /* U+0117 LATIN SMALL LETTER E WITH DOT ABOVE */,
+ imacron = 0x03ef /* U+012B LATIN SMALL LETTER I WITH MACRON */,
+ ncedilla = 0x03f1 /* U+0146 LATIN SMALL LETTER N WITH CEDILLA */,
+ omacron = 0x03f2 /* U+014D LATIN SMALL LETTER O WITH MACRON */,
+ kcedilla = 0x03f3 /* U+0137 LATIN SMALL LETTER K WITH CEDILLA */,
+ uogonek = 0x03f9 /* U+0173 LATIN SMALL LETTER U WITH OGONEK */,
+ utilde = 0x03fd /* U+0169 LATIN SMALL LETTER U WITH TILDE */,
+ umacron = 0x03fe /* U+016B LATIN SMALL LETTER U WITH MACRON */,
+ Wcircumflex = 0x1000174 /* U+0174 LATIN CAPITAL LETTER W WITH CIRCUMFLEX */,
+ wcircumflex = 0x1000175 /* U+0175 LATIN SMALL LETTER W WITH CIRCUMFLEX */,
+ Ycircumflex = 0x1000176 /* U+0176 LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */,
+ ycircumflex = 0x1000177 /* U+0177 LATIN SMALL LETTER Y WITH CIRCUMFLEX */,
+ Babovedot = 0x1001e02 /* U+1E02 LATIN CAPITAL LETTER B WITH DOT ABOVE */,
+ babovedot = 0x1001e03 /* U+1E03 LATIN SMALL LETTER B WITH DOT ABOVE */,
+ Dabovedot = 0x1001e0a /* U+1E0A LATIN CAPITAL LETTER D WITH DOT ABOVE */,
+ dabovedot = 0x1001e0b /* U+1E0B LATIN SMALL LETTER D WITH DOT ABOVE */,
+ Fabovedot = 0x1001e1e /* U+1E1E LATIN CAPITAL LETTER F WITH DOT ABOVE */,
+ fabovedot = 0x1001e1f /* U+1E1F LATIN SMALL LETTER F WITH DOT ABOVE */,
+ Mabovedot = 0x1001e40 /* U+1E40 LATIN CAPITAL LETTER M WITH DOT ABOVE */,
+ mabovedot = 0x1001e41 /* U+1E41 LATIN SMALL LETTER M WITH DOT ABOVE */,
+ Pabovedot = 0x1001e56 /* U+1E56 LATIN CAPITAL LETTER P WITH DOT ABOVE */,
+ pabovedot = 0x1001e57 /* U+1E57 LATIN SMALL LETTER P WITH DOT ABOVE */,
+ Sabovedot = 0x1001e60 /* U+1E60 LATIN CAPITAL LETTER S WITH DOT ABOVE */,
+ sabovedot = 0x1001e61 /* U+1E61 LATIN SMALL LETTER S WITH DOT ABOVE */,
+ Tabovedot = 0x1001e6a /* U+1E6A LATIN CAPITAL LETTER T WITH DOT ABOVE */,
+ tabovedot = 0x1001e6b /* U+1E6B LATIN SMALL LETTER T WITH DOT ABOVE */,
+ Wgrave = 0x1001e80 /* U+1E80 LATIN CAPITAL LETTER W WITH GRAVE */,
+ wgrave = 0x1001e81 /* U+1E81 LATIN SMALL LETTER W WITH GRAVE */,
+ Wacute = 0x1001e82 /* U+1E82 LATIN CAPITAL LETTER W WITH ACUTE */,
+ wacute = 0x1001e83 /* U+1E83 LATIN SMALL LETTER W WITH ACUTE */,
+ Wdiaeresis = 0x1001e84 /* U+1E84 LATIN CAPITAL LETTER W WITH DIAERESIS */,
+ wdiaeresis = 0x1001e85 /* U+1E85 LATIN SMALL LETTER W WITH DIAERESIS */,
+ Ygrave = 0x1001ef2 /* U+1EF2 LATIN CAPITAL LETTER Y WITH GRAVE */,
+ ygrave = 0x1001ef3 /* U+1EF3 LATIN SMALL LETTER Y WITH GRAVE */,
+ OE = 0x13bc /* U+0152 LATIN CAPITAL LIGATURE OE */,
+ oe = 0x13bd /* U+0153 LATIN SMALL LIGATURE OE */,
+ Ydiaeresis = 0x13be /* U+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS */,
+ overline = 0x047e /* U+203E OVERLINE */,
+ kana_fullstop = 0x04a1 /* U+3002 IDEOGRAPHIC FULL STOP */,
+ kana_openingbracket = 0x04a2 /* U+300C LEFT CORNER BRACKET */,
+ kana_closingbracket = 0x04a3 /* U+300D RIGHT CORNER BRACKET */,
+ kana_comma = 0x04a4 /* U+3001 IDEOGRAPHIC COMMA */,
+ kana_conjunctive = 0x04a5 /* U+30FB KATAKANA MIDDLE DOT */,
+ kana_middledot = 0x04a5 /* deprecated */,
+ kana_WO = 0x04a6 /* U+30F2 KATAKANA LETTER WO */,
+ kana_a = 0x04a7 /* U+30A1 KATAKANA LETTER SMALL A */,
+ kana_i = 0x04a8 /* U+30A3 KATAKANA LETTER SMALL I */,
+ kana_u = 0x04a9 /* U+30A5 KATAKANA LETTER SMALL U */,
+ kana_e = 0x04aa /* U+30A7 KATAKANA LETTER SMALL E */,
+ kana_o = 0x04ab /* U+30A9 KATAKANA LETTER SMALL O */,
+ kana_ya = 0x04ac /* U+30E3 KATAKANA LETTER SMALL YA */,
+ kana_yu = 0x04ad /* U+30E5 KATAKANA LETTER SMALL YU */,
+ kana_yo = 0x04ae /* U+30E7 KATAKANA LETTER SMALL YO */,
+ kana_tsu = 0x04af /* U+30C3 KATAKANA LETTER SMALL TU */,
+ kana_tu = 0x04af /* deprecated */,
+ prolongedsound = 0x04b0 /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */,
+ kana_A = 0x04b1 /* U+30A2 KATAKANA LETTER A */,
+ kana_I = 0x04b2 /* U+30A4 KATAKANA LETTER I */,
+ kana_U = 0x04b3 /* U+30A6 KATAKANA LETTER U */,
+ kana_E = 0x04b4 /* U+30A8 KATAKANA LETTER E */,
+ kana_O = 0x04b5 /* U+30AA KATAKANA LETTER O */,
+ kana_KA = 0x04b6 /* U+30AB KATAKANA LETTER KA */,
+ kana_KI = 0x04b7 /* U+30AD KATAKANA LETTER KI */,
+ kana_KU = 0x04b8 /* U+30AF KATAKANA LETTER KU */,
+ kana_KE = 0x04b9 /* U+30B1 KATAKANA LETTER KE */,
+ kana_KO = 0x04ba /* U+30B3 KATAKANA LETTER KO */,
+ kana_SA = 0x04bb /* U+30B5 KATAKANA LETTER SA */,
+ kana_SHI = 0x04bc /* U+30B7 KATAKANA LETTER SI */,
+ kana_SU = 0x04bd /* U+30B9 KATAKANA LETTER SU */,
+ kana_SE = 0x04be /* U+30BB KATAKANA LETTER SE */,
+ kana_SO = 0x04bf /* U+30BD KATAKANA LETTER SO */,
+ kana_TA = 0x04c0 /* U+30BF KATAKANA LETTER TA */,
+ kana_CHI = 0x04c1 /* U+30C1 KATAKANA LETTER TI */,
+ kana_TI = 0x04c1 /* deprecated */,
+ kana_TSU = 0x04c2 /* U+30C4 KATAKANA LETTER TU */,
+ kana_TU = 0x04c2 /* deprecated */,
+ kana_TE = 0x04c3 /* U+30C6 KATAKANA LETTER TE */,
+ kana_TO = 0x04c4 /* U+30C8 KATAKANA LETTER TO */,
+ kana_NA = 0x04c5 /* U+30CA KATAKANA LETTER NA */,
+ kana_NI = 0x04c6 /* U+30CB KATAKANA LETTER NI */,
+ kana_NU = 0x04c7 /* U+30CC KATAKANA LETTER NU */,
+ kana_NE = 0x04c8 /* U+30CD KATAKANA LETTER NE */,
+ kana_NO = 0x04c9 /* U+30CE KATAKANA LETTER NO */,
+ kana_HA = 0x04ca /* U+30CF KATAKANA LETTER HA */,
+ kana_HI = 0x04cb /* U+30D2 KATAKANA LETTER HI */,
+ kana_FU = 0x04cc /* U+30D5 KATAKANA LETTER HU */,
+ kana_HU = 0x04cc /* deprecated */,
+ kana_HE = 0x04cd /* U+30D8 KATAKANA LETTER HE */,
+ kana_HO = 0x04ce /* U+30DB KATAKANA LETTER HO */,
+ kana_MA = 0x04cf /* U+30DE KATAKANA LETTER MA */,
+ kana_MI = 0x04d0 /* U+30DF KATAKANA LETTER MI */,
+ kana_MU = 0x04d1 /* U+30E0 KATAKANA LETTER MU */,
+ kana_ME = 0x04d2 /* U+30E1 KATAKANA LETTER ME */,
+ kana_MO = 0x04d3 /* U+30E2 KATAKANA LETTER MO */,
+ kana_YA = 0x04d4 /* U+30E4 KATAKANA LETTER YA */,
+ kana_YU = 0x04d5 /* U+30E6 KATAKANA LETTER YU */,
+ kana_YO = 0x04d6 /* U+30E8 KATAKANA LETTER YO */,
+ kana_RA = 0x04d7 /* U+30E9 KATAKANA LETTER RA */,
+ kana_RI = 0x04d8 /* U+30EA KATAKANA LETTER RI */,
+ kana_RU = 0x04d9 /* U+30EB KATAKANA LETTER RU */,
+ kana_RE = 0x04da /* U+30EC KATAKANA LETTER RE */,
+ kana_RO = 0x04db /* U+30ED KATAKANA LETTER RO */,
+ kana_WA = 0x04dc /* U+30EF KATAKANA LETTER WA */,
+ kana_N = 0x04dd /* U+30F3 KATAKANA LETTER N */,
+ voicedsound = 0x04de /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */,
+ semivoicedsound = 0x04df /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */,
+ kana_switch = 0xff7e /* Alias for mode_switch */,
+ Farsi_0 = 0x10006f0 /* U+06F0 EXTENDED ARABIC-INDIC DIGIT ZERO */,
+ Farsi_1 = 0x10006f1 /* U+06F1 EXTENDED ARABIC-INDIC DIGIT ONE */,
+ Farsi_2 = 0x10006f2 /* U+06F2 EXTENDED ARABIC-INDIC DIGIT TWO */,
+ Farsi_3 = 0x10006f3 /* U+06F3 EXTENDED ARABIC-INDIC DIGIT THREE */,
+ Farsi_4 = 0x10006f4 /* U+06F4 EXTENDED ARABIC-INDIC DIGIT FOUR */,
+ Farsi_5 = 0x10006f5 /* U+06F5 EXTENDED ARABIC-INDIC DIGIT FIVE */,
+ Farsi_6 = 0x10006f6 /* U+06F6 EXTENDED ARABIC-INDIC DIGIT SIX */,
+ Farsi_7 = 0x10006f7 /* U+06F7 EXTENDED ARABIC-INDIC DIGIT SEVEN */,
+ Farsi_8 = 0x10006f8 /* U+06F8 EXTENDED ARABIC-INDIC DIGIT EIGHT */,
+ Farsi_9 = 0x10006f9 /* U+06F9 EXTENDED ARABIC-INDIC DIGIT NINE */,
+ Arabic_percent = 0x100066a /* U+066A ARABIC PERCENT SIGN */,
+ Arabic_superscript_alef = 0x1000670 /* U+0670 ARABIC LETTER SUPERSCRIPT ALEF */,
+ Arabic_tteh = 0x1000679 /* U+0679 ARABIC LETTER TTEH */,
+ Arabic_peh = 0x100067e /* U+067E ARABIC LETTER PEH */,
+ Arabic_tcheh = 0x1000686 /* U+0686 ARABIC LETTER TCHEH */,
+ Arabic_ddal = 0x1000688 /* U+0688 ARABIC LETTER DDAL */,
+ Arabic_rreh = 0x1000691 /* U+0691 ARABIC LETTER RREH */,
+ Arabic_comma = 0x05ac /* U+060C ARABIC COMMA */,
+ Arabic_fullstop = 0x10006d4 /* U+06D4 ARABIC FULL STOP */,
+ Arabic_0 = 0x1000660 /* U+0660 ARABIC-INDIC DIGIT ZERO */,
+ Arabic_1 = 0x1000661 /* U+0661 ARABIC-INDIC DIGIT ONE */,
+ Arabic_2 = 0x1000662 /* U+0662 ARABIC-INDIC DIGIT TWO */,
+ Arabic_3 = 0x1000663 /* U+0663 ARABIC-INDIC DIGIT THREE */,
+ Arabic_4 = 0x1000664 /* U+0664 ARABIC-INDIC DIGIT FOUR */,
+ Arabic_5 = 0x1000665 /* U+0665 ARABIC-INDIC DIGIT FIVE */,
+ Arabic_6 = 0x1000666 /* U+0666 ARABIC-INDIC DIGIT SIX */,
+ Arabic_7 = 0x1000667 /* U+0667 ARABIC-INDIC DIGIT SEVEN */,
+ Arabic_8 = 0x1000668 /* U+0668 ARABIC-INDIC DIGIT EIGHT */,
+ Arabic_9 = 0x1000669 /* U+0669 ARABIC-INDIC DIGIT NINE */,
+ Arabic_semicolon = 0x05bb /* U+061B ARABIC SEMICOLON */,
+ Arabic_question_mark = 0x05bf /* U+061F ARABIC QUESTION MARK */,
+ Arabic_hamza = 0x05c1 /* U+0621 ARABIC LETTER HAMZA */,
+ Arabic_maddaonalef = 0x05c2 /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */,
+ Arabic_hamzaonalef = 0x05c3 /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */,
+ Arabic_hamzaonwaw = 0x05c4 /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */,
+ Arabic_hamzaunderalef = 0x05c5 /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */,
+ Arabic_hamzaonyeh = 0x05c6 /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */,
+ Arabic_alef = 0x05c7 /* U+0627 ARABIC LETTER ALEF */,
+ Arabic_beh = 0x05c8 /* U+0628 ARABIC LETTER BEH */,
+ Arabic_tehmarbuta = 0x05c9 /* U+0629 ARABIC LETTER TEH MARBUTA */,
+ Arabic_teh = 0x05ca /* U+062A ARABIC LETTER TEH */,
+ Arabic_theh = 0x05cb /* U+062B ARABIC LETTER THEH */,
+ Arabic_jeem = 0x05cc /* U+062C ARABIC LETTER JEEM */,
+ Arabic_hah = 0x05cd /* U+062D ARABIC LETTER HAH */,
+ Arabic_khah = 0x05ce /* U+062E ARABIC LETTER KHAH */,
+ Arabic_dal = 0x05cf /* U+062F ARABIC LETTER DAL */,
+ Arabic_thal = 0x05d0 /* U+0630 ARABIC LETTER THAL */,
+ Arabic_ra = 0x05d1 /* U+0631 ARABIC LETTER REH */,
+ Arabic_zain = 0x05d2 /* U+0632 ARABIC LETTER ZAIN */,
+ Arabic_seen = 0x05d3 /* U+0633 ARABIC LETTER SEEN */,
+ Arabic_sheen = 0x05d4 /* U+0634 ARABIC LETTER SHEEN */,
+ Arabic_sad = 0x05d5 /* U+0635 ARABIC LETTER SAD */,
+ Arabic_dad = 0x05d6 /* U+0636 ARABIC LETTER DAD */,
+ Arabic_tah = 0x05d7 /* U+0637 ARABIC LETTER TAH */,
+ Arabic_zah = 0x05d8 /* U+0638 ARABIC LETTER ZAH */,
+ Arabic_ain = 0x05d9 /* U+0639 ARABIC LETTER AIN */,
+ Arabic_ghain = 0x05da /* U+063A ARABIC LETTER GHAIN */,
+ Arabic_tatweel = 0x05e0 /* U+0640 ARABIC TATWEEL */,
+ Arabic_feh = 0x05e1 /* U+0641 ARABIC LETTER FEH */,
+ Arabic_qaf = 0x05e2 /* U+0642 ARABIC LETTER QAF */,
+ Arabic_kaf = 0x05e3 /* U+0643 ARABIC LETTER KAF */,
+ Arabic_lam = 0x05e4 /* U+0644 ARABIC LETTER LAM */,
+ Arabic_meem = 0x05e5 /* U+0645 ARABIC LETTER MEEM */,
+ Arabic_noon = 0x05e6 /* U+0646 ARABIC LETTER NOON */,
+ Arabic_ha = 0x05e7 /* U+0647 ARABIC LETTER HEH */,
+ Arabic_heh = 0x05e7 /* deprecated */,
+ Arabic_waw = 0x05e8 /* U+0648 ARABIC LETTER WAW */,
+ Arabic_alefmaksura = 0x05e9 /* U+0649 ARABIC LETTER ALEF MAKSURA */,
+ Arabic_yeh = 0x05ea /* U+064A ARABIC LETTER YEH */,
+ Arabic_fathatan = 0x05eb /* U+064B ARABIC FATHATAN */,
+ Arabic_dammatan = 0x05ec /* U+064C ARABIC DAMMATAN */,
+ Arabic_kasratan = 0x05ed /* U+064D ARABIC KASRATAN */,
+ Arabic_fatha = 0x05ee /* U+064E ARABIC FATHA */,
+ Arabic_damma = 0x05ef /* U+064F ARABIC DAMMA */,
+ Arabic_kasra = 0x05f0 /* U+0650 ARABIC KASRA */,
+ Arabic_shadda = 0x05f1 /* U+0651 ARABIC SHADDA */,
+ Arabic_sukun = 0x05f2 /* U+0652 ARABIC SUKUN */,
+ Arabic_madda_above = 0x1000653 /* U+0653 ARABIC MADDAH ABOVE */,
+ Arabic_hamza_above = 0x1000654 /* U+0654 ARABIC HAMZA ABOVE */,
+ Arabic_hamza_below = 0x1000655 /* U+0655 ARABIC HAMZA BELOW */,
+ Arabic_jeh = 0x1000698 /* U+0698 ARABIC LETTER JEH */,
+ Arabic_veh = 0x10006a4 /* U+06A4 ARABIC LETTER VEH */,
+ Arabic_keheh = 0x10006a9 /* U+06A9 ARABIC LETTER KEHEH */,
+ Arabic_gaf = 0x10006af /* U+06AF ARABIC LETTER GAF */,
+ Arabic_noon_ghunna = 0x10006ba /* U+06BA ARABIC LETTER NOON GHUNNA */,
+ Arabic_heh_doachashmee = 0x10006be /* U+06BE ARABIC LETTER HEH DOACHASHMEE */,
+ Farsi_yeh = 0x10006cc /* U+06CC ARABIC LETTER FARSI YEH */,
+ Arabic_farsi_yeh = 0x10006cc /* U+06CC ARABIC LETTER FARSI YEH */,
+ Arabic_yeh_baree = 0x10006d2 /* U+06D2 ARABIC LETTER YEH BARREE */,
+ Arabic_heh_goal = 0x10006c1 /* U+06C1 ARABIC LETTER HEH GOAL */,
+ Arabic_switch = 0xff7e /* Alias for mode_switch */,
+ Cyrillic_GHE_bar = 0x1000492 /* U+0492 CYRILLIC CAPITAL LETTER GHE WITH STROKE */,
+ Cyrillic_ghe_bar = 0x1000493 /* U+0493 CYRILLIC SMALL LETTER GHE WITH STROKE */,
+ Cyrillic_ZHE_descender = 0x1000496 /* U+0496 CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */,
+ Cyrillic_zhe_descender = 0x1000497 /* U+0497 CYRILLIC SMALL LETTER ZHE WITH DESCENDER */,
+ Cyrillic_KA_descender = 0x100049a /* U+049A CYRILLIC CAPITAL LETTER KA WITH DESCENDER */,
+ Cyrillic_ka_descender = 0x100049b /* U+049B CYRILLIC SMALL LETTER KA WITH DESCENDER */,
+ Cyrillic_KA_vertstroke = 0x100049c /* U+049C CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */,
+ Cyrillic_ka_vertstroke = 0x100049d /* U+049D CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE */,
+ Cyrillic_EN_descender = 0x10004a2 /* U+04A2 CYRILLIC CAPITAL LETTER EN WITH DESCENDER */,
+ Cyrillic_en_descender = 0x10004a3 /* U+04A3 CYRILLIC SMALL LETTER EN WITH DESCENDER */,
+ Cyrillic_U_straight = 0x10004ae /* U+04AE CYRILLIC CAPITAL LETTER STRAIGHT U */,
+ Cyrillic_u_straight = 0x10004af /* U+04AF CYRILLIC SMALL LETTER STRAIGHT U */,
+ Cyrillic_U_straight_bar = 0x10004b0 /* U+04B0 CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */,
+ Cyrillic_u_straight_bar = 0x10004b1 /* U+04B1 CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE */,
+ Cyrillic_HA_descender = 0x10004b2 /* U+04B2 CYRILLIC CAPITAL LETTER HA WITH DESCENDER */,
+ Cyrillic_ha_descender = 0x10004b3 /* U+04B3 CYRILLIC SMALL LETTER HA WITH DESCENDER */,
+ Cyrillic_CHE_descender = 0x10004b6 /* U+04B6 CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */,
+ Cyrillic_che_descender = 0x10004b7 /* U+04B7 CYRILLIC SMALL LETTER CHE WITH DESCENDER */,
+ Cyrillic_CHE_vertstroke = 0x10004b8 /* U+04B8 CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */,
+ Cyrillic_che_vertstroke = 0x10004b9 /* U+04B9 CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE */,
+ Cyrillic_SHHA = 0x10004ba /* U+04BA CYRILLIC CAPITAL LETTER SHHA */,
+ Cyrillic_shha = 0x10004bb /* U+04BB CYRILLIC SMALL LETTER SHHA */,
+ Cyrillic_SCHWA = 0x10004d8 /* U+04D8 CYRILLIC CAPITAL LETTER SCHWA */,
+ Cyrillic_schwa = 0x10004d9 /* U+04D9 CYRILLIC SMALL LETTER SCHWA */,
+ Cyrillic_I_macron = 0x10004e2 /* U+04E2 CYRILLIC CAPITAL LETTER I WITH MACRON */,
+ Cyrillic_i_macron = 0x10004e3 /* U+04E3 CYRILLIC SMALL LETTER I WITH MACRON */,
+ Cyrillic_O_bar = 0x10004e8 /* U+04E8 CYRILLIC CAPITAL LETTER BARRED O */,
+ Cyrillic_o_bar = 0x10004e9 /* U+04E9 CYRILLIC SMALL LETTER BARRED O */,
+ Cyrillic_U_macron = 0x10004ee /* U+04EE CYRILLIC CAPITAL LETTER U WITH MACRON */,
+ Cyrillic_u_macron = 0x10004ef /* U+04EF CYRILLIC SMALL LETTER U WITH MACRON */,
+ Serbian_dje = 0x06a1 /* U+0452 CYRILLIC SMALL LETTER DJE */,
+ Macedonia_gje = 0x06a2 /* U+0453 CYRILLIC SMALL LETTER GJE */,
+ Cyrillic_io = 0x06a3 /* U+0451 CYRILLIC SMALL LETTER IO */,
+ Ukrainian_ie = 0x06a4 /* U+0454 CYRILLIC SMALL LETTER UKRAINIAN IE */,
+ Ukranian_je = 0x06a4 /* deprecated */,
+ Macedonia_dse = 0x06a5 /* U+0455 CYRILLIC SMALL LETTER DZE */,
+ Ukrainian_i = 0x06a6 /* U+0456 CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */,
+ Ukranian_i = 0x06a6 /* deprecated */,
+ Ukrainian_yi = 0x06a7 /* U+0457 CYRILLIC SMALL LETTER YI */,
+ Ukranian_yi = 0x06a7 /* deprecated */,
+ Cyrillic_je = 0x06a8 /* U+0458 CYRILLIC SMALL LETTER JE */,
+ Serbian_je = 0x06a8 /* deprecated */,
+ Cyrillic_lje = 0x06a9 /* U+0459 CYRILLIC SMALL LETTER LJE */,
+ Serbian_lje = 0x06a9 /* deprecated */,
+ Cyrillic_nje = 0x06aa /* U+045A CYRILLIC SMALL LETTER NJE */,
+ Serbian_nje = 0x06aa /* deprecated */,
+ Serbian_tshe = 0x06ab /* U+045B CYRILLIC SMALL LETTER TSHE */,
+ Macedonia_kje = 0x06ac /* U+045C CYRILLIC SMALL LETTER KJE */,
+ Ukrainian_ghe_with_upturn = 0x06ad /* U+0491 CYRILLIC SMALL LETTER GHE WITH UPTURN */,
+ Byelorussian_shortu = 0x06ae /* U+045E CYRILLIC SMALL LETTER SHORT U */,
+ Cyrillic_dzhe = 0x06af /* U+045F CYRILLIC SMALL LETTER DZHE */,
+ Serbian_dze = 0x06af /* deprecated */,
+ numerosign = 0x06b0 /* U+2116 NUMERO SIGN */,
+ Serbian_DJE = 0x06b1 /* U+0402 CYRILLIC CAPITAL LETTER DJE */,
+ Macedonia_GJE = 0x06b2 /* U+0403 CYRILLIC CAPITAL LETTER GJE */,
+ Cyrillic_IO = 0x06b3 /* U+0401 CYRILLIC CAPITAL LETTER IO */,
+ Ukrainian_IE = 0x06b4 /* U+0404 CYRILLIC CAPITAL LETTER UKRAINIAN IE */,
+ Ukranian_JE = 0x06b4 /* deprecated */,
+ Macedonia_DSE = 0x06b5 /* U+0405 CYRILLIC CAPITAL LETTER DZE */,
+ Ukrainian_I = 0x06b6 /* U+0406 CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */,
+ Ukranian_I = 0x06b6 /* deprecated */,
+ Ukrainian_YI = 0x06b7 /* U+0407 CYRILLIC CAPITAL LETTER YI */,
+ Ukranian_YI = 0x06b7 /* deprecated */,
+ Cyrillic_JE = 0x06b8 /* U+0408 CYRILLIC CAPITAL LETTER JE */,
+ Serbian_JE = 0x06b8 /* deprecated */,
+ Cyrillic_LJE = 0x06b9 /* U+0409 CYRILLIC CAPITAL LETTER LJE */,
+ Serbian_LJE = 0x06b9 /* deprecated */,
+ Cyrillic_NJE = 0x06ba /* U+040A CYRILLIC CAPITAL LETTER NJE */,
+ Serbian_NJE = 0x06ba /* deprecated */,
+ Serbian_TSHE = 0x06bb /* U+040B CYRILLIC CAPITAL LETTER TSHE */,
+ Macedonia_KJE = 0x06bc /* U+040C CYRILLIC CAPITAL LETTER KJE */,
+ Ukrainian_GHE_WITH_UPTURN = 0x06bd /* U+0490 CYRILLIC CAPITAL LETTER GHE WITH UPTURN */,
+ Byelorussian_SHORTU = 0x06be /* U+040E CYRILLIC CAPITAL LETTER SHORT U */,
+ Cyrillic_DZHE = 0x06bf /* U+040F CYRILLIC CAPITAL LETTER DZHE */,
+ Serbian_DZE = 0x06bf /* deprecated */,
+ Cyrillic_yu = 0x06c0 /* U+044E CYRILLIC SMALL LETTER YU */,
+ Cyrillic_a = 0x06c1 /* U+0430 CYRILLIC SMALL LETTER A */,
+ Cyrillic_be = 0x06c2 /* U+0431 CYRILLIC SMALL LETTER BE */,
+ Cyrillic_tse = 0x06c3 /* U+0446 CYRILLIC SMALL LETTER TSE */,
+ Cyrillic_de = 0x06c4 /* U+0434 CYRILLIC SMALL LETTER DE */,
+ Cyrillic_ie = 0x06c5 /* U+0435 CYRILLIC SMALL LETTER IE */,
+ Cyrillic_ef = 0x06c6 /* U+0444 CYRILLIC SMALL LETTER EF */,
+ Cyrillic_ghe = 0x06c7 /* U+0433 CYRILLIC SMALL LETTER GHE */,
+ Cyrillic_ha = 0x06c8 /* U+0445 CYRILLIC SMALL LETTER HA */,
+ Cyrillic_i = 0x06c9 /* U+0438 CYRILLIC SMALL LETTER I */,
+ Cyrillic_shorti = 0x06ca /* U+0439 CYRILLIC SMALL LETTER SHORT I */,
+ Cyrillic_ka = 0x06cb /* U+043A CYRILLIC SMALL LETTER KA */,
+ Cyrillic_el = 0x06cc /* U+043B CYRILLIC SMALL LETTER EL */,
+ Cyrillic_em = 0x06cd /* U+043C CYRILLIC SMALL LETTER EM */,
+ Cyrillic_en = 0x06ce /* U+043D CYRILLIC SMALL LETTER EN */,
+ Cyrillic_o = 0x06cf /* U+043E CYRILLIC SMALL LETTER O */,
+ Cyrillic_pe = 0x06d0 /* U+043F CYRILLIC SMALL LETTER PE */,
+ Cyrillic_ya = 0x06d1 /* U+044F CYRILLIC SMALL LETTER YA */,
+ Cyrillic_er = 0x06d2 /* U+0440 CYRILLIC SMALL LETTER ER */,
+ Cyrillic_es = 0x06d3 /* U+0441 CYRILLIC SMALL LETTER ES */,
+ Cyrillic_te = 0x06d4 /* U+0442 CYRILLIC SMALL LETTER TE */,
+ Cyrillic_u = 0x06d5 /* U+0443 CYRILLIC SMALL LETTER U */,
+ Cyrillic_zhe = 0x06d6 /* U+0436 CYRILLIC SMALL LETTER ZHE */,
+ Cyrillic_ve = 0x06d7 /* U+0432 CYRILLIC SMALL LETTER VE */,
+ Cyrillic_softsign = 0x06d8 /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */,
+ Cyrillic_yeru = 0x06d9 /* U+044B CYRILLIC SMALL LETTER YERU */,
+ Cyrillic_ze = 0x06da /* U+0437 CYRILLIC SMALL LETTER ZE */,
+ Cyrillic_sha = 0x06db /* U+0448 CYRILLIC SMALL LETTER SHA */,
+ Cyrillic_e = 0x06dc /* U+044D CYRILLIC SMALL LETTER E */,
+ Cyrillic_shcha = 0x06dd /* U+0449 CYRILLIC SMALL LETTER SHCHA */,
+ Cyrillic_che = 0x06de /* U+0447 CYRILLIC SMALL LETTER CHE */,
+ Cyrillic_hardsign = 0x06df /* U+044A CYRILLIC SMALL LETTER HARD SIGN */,
+ Cyrillic_YU = 0x06e0 /* U+042E CYRILLIC CAPITAL LETTER YU */,
+ Cyrillic_A = 0x06e1 /* U+0410 CYRILLIC CAPITAL LETTER A */,
+ Cyrillic_BE = 0x06e2 /* U+0411 CYRILLIC CAPITAL LETTER BE */,
+ Cyrillic_TSE = 0x06e3 /* U+0426 CYRILLIC CAPITAL LETTER TSE */,
+ Cyrillic_DE = 0x06e4 /* U+0414 CYRILLIC CAPITAL LETTER DE */,
+ Cyrillic_IE = 0x06e5 /* U+0415 CYRILLIC CAPITAL LETTER IE */,
+ Cyrillic_EF = 0x06e6 /* U+0424 CYRILLIC CAPITAL LETTER EF */,
+ Cyrillic_GHE = 0x06e7 /* U+0413 CYRILLIC CAPITAL LETTER GHE */,
+ Cyrillic_HA = 0x06e8 /* U+0425 CYRILLIC CAPITAL LETTER HA */,
+ Cyrillic_I = 0x06e9 /* U+0418 CYRILLIC CAPITAL LETTER I */,
+ Cyrillic_SHORTI = 0x06ea /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */,
+ Cyrillic_KA = 0x06eb /* U+041A CYRILLIC CAPITAL LETTER KA */,
+ Cyrillic_EL = 0x06ec /* U+041B CYRILLIC CAPITAL LETTER EL */,
+ Cyrillic_EM = 0x06ed /* U+041C CYRILLIC CAPITAL LETTER EM */,
+ Cyrillic_EN = 0x06ee /* U+041D CYRILLIC CAPITAL LETTER EN */,
+ Cyrillic_O = 0x06ef /* U+041E CYRILLIC CAPITAL LETTER O */,
+ Cyrillic_PE = 0x06f0 /* U+041F CYRILLIC CAPITAL LETTER PE */,
+ Cyrillic_YA = 0x06f1 /* U+042F CYRILLIC CAPITAL LETTER YA */,
+ Cyrillic_ER = 0x06f2 /* U+0420 CYRILLIC CAPITAL LETTER ER */,
+ Cyrillic_ES = 0x06f3 /* U+0421 CYRILLIC CAPITAL LETTER ES */,
+ Cyrillic_TE = 0x06f4 /* U+0422 CYRILLIC CAPITAL LETTER TE */,
+ Cyrillic_U = 0x06f5 /* U+0423 CYRILLIC CAPITAL LETTER U */,
+ Cyrillic_ZHE = 0x06f6 /* U+0416 CYRILLIC CAPITAL LETTER ZHE */,
+ Cyrillic_VE = 0x06f7 /* U+0412 CYRILLIC CAPITAL LETTER VE */,
+ Cyrillic_SOFTSIGN = 0x06f8 /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */,
+ Cyrillic_YERU = 0x06f9 /* U+042B CYRILLIC CAPITAL LETTER YERU */,
+ Cyrillic_ZE = 0x06fa /* U+0417 CYRILLIC CAPITAL LETTER ZE */,
+ Cyrillic_SHA = 0x06fb /* U+0428 CYRILLIC CAPITAL LETTER SHA */,
+ Cyrillic_E = 0x06fc /* U+042D CYRILLIC CAPITAL LETTER E */,
+ Cyrillic_SHCHA = 0x06fd /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */,
+ Cyrillic_CHE = 0x06fe /* U+0427 CYRILLIC CAPITAL LETTER CHE */,
+ Cyrillic_HARDSIGN = 0x06ff /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */,
+ Greek_ALPHAaccent = 0x07a1 /* U+0386 GREEK CAPITAL LETTER ALPHA WITH TONOS */,
+ Greek_EPSILONaccent = 0x07a2 /* U+0388 GREEK CAPITAL LETTER EPSILON WITH TONOS */,
+ Greek_ETAaccent = 0x07a3 /* U+0389 GREEK CAPITAL LETTER ETA WITH TONOS */,
+ Greek_IOTAaccent = 0x07a4 /* U+038A GREEK CAPITAL LETTER IOTA WITH TONOS */,
+ Greek_IOTAdieresis = 0x07a5 /* U+03AA GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */,
+ Greek_IOTAdiaeresis = 0x07a5 /* old typo */,
+ Greek_OMICRONaccent = 0x07a7 /* U+038C GREEK CAPITAL LETTER OMICRON WITH TONOS */,
+ Greek_UPSILONaccent = 0x07a8 /* U+038E GREEK CAPITAL LETTER UPSILON WITH TONOS */,
+ Greek_UPSILONdieresis = 0x07a9 /* U+03AB GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */,
+ Greek_OMEGAaccent = 0x07ab /* U+038F GREEK CAPITAL LETTER OMEGA WITH TONOS */,
+ Greek_accentdieresis = 0x07ae /* U+0385 GREEK DIALYTIKA TONOS */,
+ Greek_horizbar = 0x07af /* U+2015 HORIZONTAL BAR */,
+ Greek_alphaaccent = 0x07b1 /* U+03AC GREEK SMALL LETTER ALPHA WITH TONOS */,
+ Greek_epsilonaccent = 0x07b2 /* U+03AD GREEK SMALL LETTER EPSILON WITH TONOS */,
+ Greek_etaaccent = 0x07b3 /* U+03AE GREEK SMALL LETTER ETA WITH TONOS */,
+ Greek_iotaaccent = 0x07b4 /* U+03AF GREEK SMALL LETTER IOTA WITH TONOS */,
+ Greek_iotadieresis = 0x07b5 /* U+03CA GREEK SMALL LETTER IOTA WITH DIALYTIKA */,
+ Greek_iotaaccentdieresis = 0x07b6 /* U+0390 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */,
+ Greek_omicronaccent = 0x07b7 /* U+03CC GREEK SMALL LETTER OMICRON WITH TONOS */,
+ Greek_upsilonaccent = 0x07b8 /* U+03CD GREEK SMALL LETTER UPSILON WITH TONOS */,
+ Greek_upsilondieresis = 0x07b9 /* U+03CB GREEK SMALL LETTER UPSILON WITH DIALYTIKA */,
+ Greek_upsilonaccentdieresis = 0x07ba /* U+03B0 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */,
+ Greek_omegaaccent = 0x07bb /* U+03CE GREEK SMALL LETTER OMEGA WITH TONOS */,
+ Greek_ALPHA = 0x07c1 /* U+0391 GREEK CAPITAL LETTER ALPHA */,
+ Greek_BETA = 0x07c2 /* U+0392 GREEK CAPITAL LETTER BETA */,
+ Greek_GAMMA = 0x07c3 /* U+0393 GREEK CAPITAL LETTER GAMMA */,
+ Greek_DELTA = 0x07c4 /* U+0394 GREEK CAPITAL LETTER DELTA */,
+ Greek_EPSILON = 0x07c5 /* U+0395 GREEK CAPITAL LETTER EPSILON */,
+ Greek_ZETA = 0x07c6 /* U+0396 GREEK CAPITAL LETTER ZETA */,
+ Greek_ETA = 0x07c7 /* U+0397 GREEK CAPITAL LETTER ETA */,
+ Greek_THETA = 0x07c8 /* U+0398 GREEK CAPITAL LETTER THETA */,
+ Greek_IOTA = 0x07c9 /* U+0399 GREEK CAPITAL LETTER IOTA */,
+ Greek_KAPPA = 0x07ca /* U+039A GREEK CAPITAL LETTER KAPPA */,
+ Greek_LAMDA = 0x07cb /* U+039B GREEK CAPITAL LETTER LAMDA */,
+ Greek_LAMBDA = 0x07cb /* U+039B GREEK CAPITAL LETTER LAMDA */,
+ Greek_MU = 0x07cc /* U+039C GREEK CAPITAL LETTER MU */,
+ Greek_NU = 0x07cd /* U+039D GREEK CAPITAL LETTER NU */,
+ Greek_XI = 0x07ce /* U+039E GREEK CAPITAL LETTER XI */,
+ Greek_OMICRON = 0x07cf /* U+039F GREEK CAPITAL LETTER OMICRON */,
+ Greek_PI = 0x07d0 /* U+03A0 GREEK CAPITAL LETTER PI */,
+ Greek_RHO = 0x07d1 /* U+03A1 GREEK CAPITAL LETTER RHO */,
+ Greek_SIGMA = 0x07d2 /* U+03A3 GREEK CAPITAL LETTER SIGMA */,
+ Greek_TAU = 0x07d4 /* U+03A4 GREEK CAPITAL LETTER TAU */,
+ Greek_UPSILON = 0x07d5 /* U+03A5 GREEK CAPITAL LETTER UPSILON */,
+ Greek_PHI = 0x07d6 /* U+03A6 GREEK CAPITAL LETTER PHI */,
+ Greek_CHI = 0x07d7 /* U+03A7 GREEK CAPITAL LETTER CHI */,
+ Greek_PSI = 0x07d8 /* U+03A8 GREEK CAPITAL LETTER PSI */,
+ Greek_OMEGA = 0x07d9 /* U+03A9 GREEK CAPITAL LETTER OMEGA */,
+ Greek_alpha = 0x07e1 /* U+03B1 GREEK SMALL LETTER ALPHA */,
+ Greek_beta = 0x07e2 /* U+03B2 GREEK SMALL LETTER BETA */,
+ Greek_gamma = 0x07e3 /* U+03B3 GREEK SMALL LETTER GAMMA */,
+ Greek_delta = 0x07e4 /* U+03B4 GREEK SMALL LETTER DELTA */,
+ Greek_epsilon = 0x07e5 /* U+03B5 GREEK SMALL LETTER EPSILON */,
+ Greek_zeta = 0x07e6 /* U+03B6 GREEK SMALL LETTER ZETA */,
+ Greek_eta = 0x07e7 /* U+03B7 GREEK SMALL LETTER ETA */,
+ Greek_theta = 0x07e8 /* U+03B8 GREEK SMALL LETTER THETA */,
+ Greek_iota = 0x07e9 /* U+03B9 GREEK SMALL LETTER IOTA */,
+ Greek_kappa = 0x07ea /* U+03BA GREEK SMALL LETTER KAPPA */,
+ Greek_lamda = 0x07eb /* U+03BB GREEK SMALL LETTER LAMDA */,
+ Greek_lambda = 0x07eb /* U+03BB GREEK SMALL LETTER LAMDA */,
+ Greek_mu = 0x07ec /* U+03BC GREEK SMALL LETTER MU */,
+ Greek_nu = 0x07ed /* U+03BD GREEK SMALL LETTER NU */,
+ Greek_xi = 0x07ee /* U+03BE GREEK SMALL LETTER XI */,
+ Greek_omicron = 0x07ef /* U+03BF GREEK SMALL LETTER OMICRON */,
+ Greek_pi = 0x07f0 /* U+03C0 GREEK SMALL LETTER PI */,
+ Greek_rho = 0x07f1 /* U+03C1 GREEK SMALL LETTER RHO */,
+ Greek_sigma = 0x07f2 /* U+03C3 GREEK SMALL LETTER SIGMA */,
+ Greek_finalsmallsigma = 0x07f3 /* U+03C2 GREEK SMALL LETTER FINAL SIGMA */,
+ Greek_tau = 0x07f4 /* U+03C4 GREEK SMALL LETTER TAU */,
+ Greek_upsilon = 0x07f5 /* U+03C5 GREEK SMALL LETTER UPSILON */,
+ Greek_phi = 0x07f6 /* U+03C6 GREEK SMALL LETTER PHI */,
+ Greek_chi = 0x07f7 /* U+03C7 GREEK SMALL LETTER CHI */,
+ Greek_psi = 0x07f8 /* U+03C8 GREEK SMALL LETTER PSI */,
+ Greek_omega = 0x07f9 /* U+03C9 GREEK SMALL LETTER OMEGA */,
+ Greek_switch = 0xff7e /* Alias for mode_switch */,
+ leftradical = 0x08a1 /* U+23B7 RADICAL SYMBOL BOTTOM */,
+ topleftradical = 0x08a2 /*(U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT)*/,
+ horizconnector = 0x08a3 /*(U+2500 BOX DRAWINGS LIGHT HORIZONTAL)*/,
+ topintegral = 0x08a4 /* U+2320 TOP HALF INTEGRAL */,
+ botintegral = 0x08a5 /* U+2321 BOTTOM HALF INTEGRAL */,
+ vertconnector = 0x08a6 /*(U+2502 BOX DRAWINGS LIGHT VERTICAL)*/,
+ topleftsqbracket = 0x08a7 /* U+23A1 LEFT SQUARE BRACKET UPPER CORNER */,
+ botleftsqbracket = 0x08a8 /* U+23A3 LEFT SQUARE BRACKET LOWER CORNER */,
+ toprightsqbracket = 0x08a9 /* U+23A4 RIGHT SQUARE BRACKET UPPER CORNER */,
+ botrightsqbracket = 0x08aa /* U+23A6 RIGHT SQUARE BRACKET LOWER CORNER */,
+ topleftparens = 0x08ab /* U+239B LEFT PARENTHESIS UPPER HOOK */,
+ botleftparens = 0x08ac /* U+239D LEFT PARENTHESIS LOWER HOOK */,
+ toprightparens = 0x08ad /* U+239E RIGHT PARENTHESIS UPPER HOOK */,
+ botrightparens = 0x08ae /* U+23A0 RIGHT PARENTHESIS LOWER HOOK */,
+ leftmiddlecurlybrace = 0x08af /* U+23A8 LEFT CURLY BRACKET MIDDLE PIECE */,
+ rightmiddlecurlybrace = 0x08b0 /* U+23AC RIGHT CURLY BRACKET MIDDLE PIECE */,
+ topleftsummation = 0x08b1,
+ botleftsummation = 0x08b2,
+ topvertsummationconnector = 0x08b3,
+ botvertsummationconnector = 0x08b4,
+ toprightsummation = 0x08b5,
+ botrightsummation = 0x08b6,
+ rightmiddlesummation = 0x08b7,
+ lessthanequal = 0x08bc /* U+2264 LESS-THAN OR EQUAL TO */,
+ notequal = 0x08bd /* U+2260 NOT EQUAL TO */,
+ greaterthanequal = 0x08be /* U+2265 GREATER-THAN OR EQUAL TO */,
+ integral = 0x08bf /* U+222B INTEGRAL */,
+ therefore = 0x08c0 /* U+2234 THEREFORE */,
+ variation = 0x08c1 /* U+221D PROPORTIONAL TO */,
+ infinity = 0x08c2 /* U+221E INFINITY */,
+ nabla = 0x08c5 /* U+2207 NABLA */,
+ approximate = 0x08c8 /* U+223C TILDE OPERATOR */,
+ similarequal = 0x08c9 /* U+2243 ASYMPTOTICALLY EQUAL TO */,
+ ifonlyif = 0x08cd /* U+21D4 LEFT RIGHT DOUBLE ARROW */,
+ implies = 0x08ce /* U+21D2 RIGHTWARDS DOUBLE ARROW */,
+ identical = 0x08cf /* U+2261 IDENTICAL TO */,
+ radical = 0x08d6 /* U+221A SQUARE ROOT */,
+ includedin = 0x08da /* U+2282 SUBSET OF */,
+ includes = 0x08db /* U+2283 SUPERSET OF */,
+ intersection = 0x08dc /* U+2229 INTERSECTION */,
+ union = 0x08dd /* U+222A UNION */,
+ logicaland = 0x08de /* U+2227 LOGICAL AND */,
+ logicalor = 0x08df /* U+2228 LOGICAL OR */,
+ partialderivative = 0x08ef /* U+2202 PARTIAL DIFFERENTIAL */,
+ function = 0x08f6 /* U+0192 LATIN SMALL LETTER F WITH HOOK */,
+ leftarrow = 0x08fb /* U+2190 LEFTWARDS ARROW */,
+ uparrow = 0x08fc /* U+2191 UPWARDS ARROW */,
+ rightarrow = 0x08fd /* U+2192 RIGHTWARDS ARROW */,
+ downarrow = 0x08fe /* U+2193 DOWNWARDS ARROW */,
+ blank = 0x09df,
+ soliddiamond = 0x09e0 /* U+25C6 BLACK DIAMOND */,
+ checkerboard = 0x09e1 /* U+2592 MEDIUM SHADE */,
+ ht = 0x09e2 /* U+2409 SYMBOL FOR HORIZONTAL TABULATION */,
+ ff = 0x09e3 /* U+240C SYMBOL FOR FORM FEED */,
+ cr = 0x09e4 /* U+240D SYMBOL FOR CARRIAGE RETURN */,
+ lf = 0x09e5 /* U+240A SYMBOL FOR LINE FEED */,
+ nl = 0x09e8 /* U+2424 SYMBOL FOR NEWLINE */,
+ vt = 0x09e9 /* U+240B SYMBOL FOR VERTICAL TABULATION */,
+ lowrightcorner = 0x09ea /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT */,
+ uprightcorner = 0x09eb /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT */,
+ upleftcorner = 0x09ec /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT */,
+ lowleftcorner = 0x09ed /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT */,
+ crossinglines = 0x09ee /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */,
+ horizlinescan1 = 0x09ef /* U+23BA HORIZONTAL SCAN LINE-1 */,
+ horizlinescan3 = 0x09f0 /* U+23BB HORIZONTAL SCAN LINE-3 */,
+ horizlinescan5 = 0x09f1 /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL */,
+ horizlinescan7 = 0x09f2 /* U+23BC HORIZONTAL SCAN LINE-7 */,
+ horizlinescan9 = 0x09f3 /* U+23BD HORIZONTAL SCAN LINE-9 */,
+ leftt = 0x09f4 /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */,
+ rightt = 0x09f5 /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT */,
+ bott = 0x09f6 /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL */,
+ topt = 0x09f7 /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */,
+ vertbar = 0x09f8 /* U+2502 BOX DRAWINGS LIGHT VERTICAL */,
+ emspace = 0x0aa1 /* U+2003 EM SPACE */,
+ enspace = 0x0aa2 /* U+2002 EN SPACE */,
+ em3space = 0x0aa3 /* U+2004 THREE-PER-EM SPACE */,
+ em4space = 0x0aa4 /* U+2005 FOUR-PER-EM SPACE */,
+ digitspace = 0x0aa5 /* U+2007 FIGURE SPACE */,
+ punctspace = 0x0aa6 /* U+2008 PUNCTUATION SPACE */,
+ thinspace = 0x0aa7 /* U+2009 THIN SPACE */,
+ hairspace = 0x0aa8 /* U+200A HAIR SPACE */,
+ emdash = 0x0aa9 /* U+2014 EM DASH */,
+ endash = 0x0aaa /* U+2013 EN DASH */,
+ signifblank = 0x0aac /*(U+2423 OPEN BOX)*/,
+ ellipsis = 0x0aae /* U+2026 HORIZONTAL ELLIPSIS */,
+ doubbaselinedot = 0x0aaf /* U+2025 TWO DOT LEADER */,
+ onethird = 0x0ab0 /* U+2153 VULGAR FRACTION ONE THIRD */,
+ twothirds = 0x0ab1 /* U+2154 VULGAR FRACTION TWO THIRDS */,
+ onefifth = 0x0ab2 /* U+2155 VULGAR FRACTION ONE FIFTH */,
+ twofifths = 0x0ab3 /* U+2156 VULGAR FRACTION TWO FIFTHS */,
+ threefifths = 0x0ab4 /* U+2157 VULGAR FRACTION THREE FIFTHS */,
+ fourfifths = 0x0ab5 /* U+2158 VULGAR FRACTION FOUR FIFTHS */,
+ onesixth = 0x0ab6 /* U+2159 VULGAR FRACTION ONE SIXTH */,
+ fivesixths = 0x0ab7 /* U+215A VULGAR FRACTION FIVE SIXTHS */,
+ careof = 0x0ab8 /* U+2105 CARE OF */,
+ figdash = 0x0abb /* U+2012 FIGURE DASH */,
+ leftanglebracket = 0x0abc /*(U+27E8 MATHEMATICAL LEFT ANGLE BRACKET)*/,
+ decimalpoint = 0x0abd /*(U+002E FULL STOP)*/,
+ rightanglebracket = 0x0abe /*(U+27E9 MATHEMATICAL RIGHT ANGLE BRACKET)*/,
+ marker = 0x0abf,
+ oneeighth = 0x0ac3 /* U+215B VULGAR FRACTION ONE EIGHTH */,
+ threeeighths = 0x0ac4 /* U+215C VULGAR FRACTION THREE EIGHTHS */,
+ fiveeighths = 0x0ac5 /* U+215D VULGAR FRACTION FIVE EIGHTHS */,
+ seveneighths = 0x0ac6 /* U+215E VULGAR FRACTION SEVEN EIGHTHS */,
+ trademark = 0x0ac9 /* U+2122 TRADE MARK SIGN */,
+ signaturemark = 0x0aca /*(U+2613 SALTIRE)*/,
+ trademarkincircle = 0x0acb,
+ leftopentriangle = 0x0acc /*(U+25C1 WHITE LEFT-POINTING TRIANGLE)*/,
+ rightopentriangle = 0x0acd /*(U+25B7 WHITE RIGHT-POINTING TRIANGLE)*/,
+ emopencircle = 0x0ace /*(U+25CB WHITE CIRCLE)*/,
+ emopenrectangle = 0x0acf /*(U+25AF WHITE VERTICAL RECTANGLE)*/,
+ leftsinglequotemark = 0x0ad0 /* U+2018 LEFT SINGLE QUOTATION MARK */,
+ rightsinglequotemark = 0x0ad1 /* U+2019 RIGHT SINGLE QUOTATION MARK */,
+ leftdoublequotemark = 0x0ad2 /* U+201C LEFT DOUBLE QUOTATION MARK */,
+ rightdoublequotemark = 0x0ad3 /* U+201D RIGHT DOUBLE QUOTATION MARK */,
+ prescription = 0x0ad4 /* U+211E PRESCRIPTION TAKE */,
+ permille = 0x0ad5 /* U+2030 PER MILLE SIGN */,
+ minutes = 0x0ad6 /* U+2032 PRIME */,
+ seconds = 0x0ad7 /* U+2033 DOUBLE PRIME */,
+ latincross = 0x0ad9 /* U+271D LATIN CROSS */,
+ hexagram = 0x0ada,
+ filledrectbullet = 0x0adb /*(U+25AC BLACK RECTANGLE)*/,
+ filledlefttribullet = 0x0adc /*(U+25C0 BLACK LEFT-POINTING TRIANGLE)*/,
+ filledrighttribullet = 0x0add /*(U+25B6 BLACK RIGHT-POINTING TRIANGLE)*/,
+ emfilledcircle = 0x0ade /*(U+25CF BLACK CIRCLE)*/,
+ emfilledrect = 0x0adf /*(U+25AE BLACK VERTICAL RECTANGLE)*/,
+ enopencircbullet = 0x0ae0 /*(U+25E6 WHITE BULLET)*/,
+ enopensquarebullet = 0x0ae1 /*(U+25AB WHITE SMALL SQUARE)*/,
+ openrectbullet = 0x0ae2 /*(U+25AD WHITE RECTANGLE)*/,
+ opentribulletup = 0x0ae3 /*(U+25B3 WHITE UP-POINTING TRIANGLE)*/,
+ opentribulletdown = 0x0ae4 /*(U+25BD WHITE DOWN-POINTING TRIANGLE)*/,
+ openstar = 0x0ae5 /*(U+2606 WHITE STAR)*/,
+ enfilledcircbullet = 0x0ae6 /*(U+2022 BULLET)*/,
+ enfilledsqbullet = 0x0ae7 /*(U+25AA BLACK SMALL SQUARE)*/,
+ filledtribulletup = 0x0ae8 /*(U+25B2 BLACK UP-POINTING TRIANGLE)*/,
+ filledtribulletdown = 0x0ae9 /*(U+25BC BLACK DOWN-POINTING TRIANGLE)*/,
+ leftpointer = 0x0aea /*(U+261C WHITE LEFT POINTING INDEX)*/,
+ rightpointer = 0x0aeb /*(U+261E WHITE RIGHT POINTING INDEX)*/,
+ club = 0x0aec /* U+2663 BLACK CLUB SUIT */,
+ diamond = 0x0aed /* U+2666 BLACK DIAMOND SUIT */,
+ heart = 0x0aee /* U+2665 BLACK HEART SUIT */,
+ maltesecross = 0x0af0 /* U+2720 MALTESE CROSS */,
+ dagger = 0x0af1 /* U+2020 DAGGER */,
+ doubledagger = 0x0af2 /* U+2021 DOUBLE DAGGER */,
+ checkmark = 0x0af3 /* U+2713 CHECK MARK */,
+ ballotcross = 0x0af4 /* U+2717 BALLOT X */,
+ musicalsharp = 0x0af5 /* U+266F MUSIC SHARP SIGN */,
+ musicalflat = 0x0af6 /* U+266D MUSIC FLAT SIGN */,
+ malesymbol = 0x0af7 /* U+2642 MALE SIGN */,
+ femalesymbol = 0x0af8 /* U+2640 FEMALE SIGN */,
+ telephone = 0x0af9 /* U+260E BLACK TELEPHONE */,
+ telephonerecorder = 0x0afa /* U+2315 TELEPHONE RECORDER */,
+ phonographcopyright = 0x0afb /* U+2117 SOUND RECORDING COPYRIGHT */,
+ caret = 0x0afc /* U+2038 CARET */,
+ singlelowquotemark = 0x0afd /* U+201A SINGLE LOW-9 QUOTATION MARK */,
+ doublelowquotemark = 0x0afe /* U+201E DOUBLE LOW-9 QUOTATION MARK */,
+ cursor = 0x0aff,
+ leftcaret = 0x0ba3 /*(U+003C LESS-THAN SIGN)*/,
+ rightcaret = 0x0ba6 /*(U+003E GREATER-THAN SIGN)*/,
+ downcaret = 0x0ba8 /*(U+2228 LOGICAL OR)*/,
+ upcaret = 0x0ba9 /*(U+2227 LOGICAL AND)*/,
+ overbar = 0x0bc0 /*(U+00AF MACRON)*/,
+ downtack = 0x0bc2 /* U+22A4 DOWN TACK */,
+ upshoe = 0x0bc3 /*(U+2229 INTERSECTION)*/,
+ downstile = 0x0bc4 /* U+230A LEFT FLOOR */,
+ underbar = 0x0bc6 /*(U+005F LOW LINE)*/,
+ jot = 0x0bca /* U+2218 RING OPERATOR */,
+ quad = 0x0bcc /* U+2395 APL FUNCTIONAL SYMBOL QUAD */,
+ uptack = 0x0bce /* U+22A5 UP TACK */,
+ circle = 0x0bcf /* U+25CB WHITE CIRCLE */,
+ upstile = 0x0bd3 /* U+2308 LEFT CEILING */,
+ downshoe = 0x0bd6 /*(U+222A UNION)*/,
+ rightshoe = 0x0bd8 /*(U+2283 SUPERSET OF)*/,
+ leftshoe = 0x0bda /*(U+2282 SUBSET OF)*/,
+ lefttack = 0x0bdc /* U+22A3 LEFT TACK */,
+ righttack = 0x0bfc /* U+22A2 RIGHT TACK */,
+ hebrew_doublelowline = 0x0cdf /* U+2017 DOUBLE LOW LINE */,
+ hebrew_aleph = 0x0ce0 /* U+05D0 HEBREW LETTER ALEF */,
+ hebrew_bet = 0x0ce1 /* U+05D1 HEBREW LETTER BET */,
+ hebrew_beth = 0x0ce1 /* deprecated */,
+ hebrew_gimel = 0x0ce2 /* U+05D2 HEBREW LETTER GIMEL */,
+ hebrew_gimmel = 0x0ce2 /* deprecated */,
+ hebrew_dalet = 0x0ce3 /* U+05D3 HEBREW LETTER DALET */,
+ hebrew_daleth = 0x0ce3 /* deprecated */,
+ hebrew_he = 0x0ce4 /* U+05D4 HEBREW LETTER HE */,
+ hebrew_waw = 0x0ce5 /* U+05D5 HEBREW LETTER VAV */,
+ hebrew_zain = 0x0ce6 /* U+05D6 HEBREW LETTER ZAYIN */,
+ hebrew_zayin = 0x0ce6 /* deprecated */,
+ hebrew_chet = 0x0ce7 /* U+05D7 HEBREW LETTER HET */,
+ hebrew_het = 0x0ce7 /* deprecated */,
+ hebrew_tet = 0x0ce8 /* U+05D8 HEBREW LETTER TET */,
+ hebrew_teth = 0x0ce8 /* deprecated */,
+ hebrew_yod = 0x0ce9 /* U+05D9 HEBREW LETTER YOD */,
+ hebrew_finalkaph = 0x0cea /* U+05DA HEBREW LETTER FINAL KAF */,
+ hebrew_kaph = 0x0ceb /* U+05DB HEBREW LETTER KAF */,
+ hebrew_lamed = 0x0cec /* U+05DC HEBREW LETTER LAMED */,
+ hebrew_finalmem = 0x0ced /* U+05DD HEBREW LETTER FINAL MEM */,
+ hebrew_mem = 0x0cee /* U+05DE HEBREW LETTER MEM */,
+ hebrew_finalnun = 0x0cef /* U+05DF HEBREW LETTER FINAL NUN */,
+ hebrew_nun = 0x0cf0 /* U+05E0 HEBREW LETTER NUN */,
+ hebrew_samech = 0x0cf1 /* U+05E1 HEBREW LETTER SAMEKH */,
+ hebrew_samekh = 0x0cf1 /* deprecated */,
+ hebrew_ayin = 0x0cf2 /* U+05E2 HEBREW LETTER AYIN */,
+ hebrew_finalpe = 0x0cf3 /* U+05E3 HEBREW LETTER FINAL PE */,
+ hebrew_pe = 0x0cf4 /* U+05E4 HEBREW LETTER PE */,
+ hebrew_finalzade = 0x0cf5 /* U+05E5 HEBREW LETTER FINAL TSADI */,
+ hebrew_finalzadi = 0x0cf5 /* deprecated */,
+ hebrew_zade = 0x0cf6 /* U+05E6 HEBREW LETTER TSADI */,
+ hebrew_zadi = 0x0cf6 /* deprecated */,
+ hebrew_qoph = 0x0cf7 /* U+05E7 HEBREW LETTER QOF */,
+ hebrew_kuf = 0x0cf7 /* deprecated */,
+ hebrew_resh = 0x0cf8 /* U+05E8 HEBREW LETTER RESH */,
+ hebrew_shin = 0x0cf9 /* U+05E9 HEBREW LETTER SHIN */,
+ hebrew_taw = 0x0cfa /* U+05EA HEBREW LETTER TAV */,
+ hebrew_taf = 0x0cfa /* deprecated */,
+ Hebrew_switch = 0xff7e /* Alias for mode_switch */,
+ Thai_kokai = 0x0da1 /* U+0E01 THAI CHARACTER KO KAI */,
+ Thai_khokhai = 0x0da2 /* U+0E02 THAI CHARACTER KHO KHAI */,
+ Thai_khokhuat = 0x0da3 /* U+0E03 THAI CHARACTER KHO KHUAT */,
+ Thai_khokhwai = 0x0da4 /* U+0E04 THAI CHARACTER KHO KHWAI */,
+ Thai_khokhon = 0x0da5 /* U+0E05 THAI CHARACTER KHO KHON */,
+ Thai_khorakhang = 0x0da6 /* U+0E06 THAI CHARACTER KHO RAKHANG */,
+ Thai_ngongu = 0x0da7 /* U+0E07 THAI CHARACTER NGO NGU */,
+ Thai_chochan = 0x0da8 /* U+0E08 THAI CHARACTER CHO CHAN */,
+ Thai_choching = 0x0da9 /* U+0E09 THAI CHARACTER CHO CHING */,
+ Thai_chochang = 0x0daa /* U+0E0A THAI CHARACTER CHO CHANG */,
+ Thai_soso = 0x0dab /* U+0E0B THAI CHARACTER SO SO */,
+ Thai_chochoe = 0x0dac /* U+0E0C THAI CHARACTER CHO CHOE */,
+ Thai_yoying = 0x0dad /* U+0E0D THAI CHARACTER YO YING */,
+ Thai_dochada = 0x0dae /* U+0E0E THAI CHARACTER DO CHADA */,
+ Thai_topatak = 0x0daf /* U+0E0F THAI CHARACTER TO PATAK */,
+ Thai_thothan = 0x0db0 /* U+0E10 THAI CHARACTER THO THAN */,
+ Thai_thonangmontho = 0x0db1 /* U+0E11 THAI CHARACTER THO NANGMONTHO */,
+ Thai_thophuthao = 0x0db2 /* U+0E12 THAI CHARACTER THO PHUTHAO */,
+ Thai_nonen = 0x0db3 /* U+0E13 THAI CHARACTER NO NEN */,
+ Thai_dodek = 0x0db4 /* U+0E14 THAI CHARACTER DO DEK */,
+ Thai_totao = 0x0db5 /* U+0E15 THAI CHARACTER TO TAO */,
+ Thai_thothung = 0x0db6 /* U+0E16 THAI CHARACTER THO THUNG */,
+ Thai_thothahan = 0x0db7 /* U+0E17 THAI CHARACTER THO THAHAN */,
+ Thai_thothong = 0x0db8 /* U+0E18 THAI CHARACTER THO THONG */,
+ Thai_nonu = 0x0db9 /* U+0E19 THAI CHARACTER NO NU */,
+ Thai_bobaimai = 0x0dba /* U+0E1A THAI CHARACTER BO BAIMAI */,
+ Thai_popla = 0x0dbb /* U+0E1B THAI CHARACTER PO PLA */,
+ Thai_phophung = 0x0dbc /* U+0E1C THAI CHARACTER PHO PHUNG */,
+ Thai_fofa = 0x0dbd /* U+0E1D THAI CHARACTER FO FA */,
+ Thai_phophan = 0x0dbe /* U+0E1E THAI CHARACTER PHO PHAN */,
+ Thai_fofan = 0x0dbf /* U+0E1F THAI CHARACTER FO FAN */,
+ Thai_phosamphao = 0x0dc0 /* U+0E20 THAI CHARACTER PHO SAMPHAO */,
+ Thai_moma = 0x0dc1 /* U+0E21 THAI CHARACTER MO MA */,
+ Thai_yoyak = 0x0dc2 /* U+0E22 THAI CHARACTER YO YAK */,
+ Thai_rorua = 0x0dc3 /* U+0E23 THAI CHARACTER RO RUA */,
+ Thai_ru = 0x0dc4 /* U+0E24 THAI CHARACTER RU */,
+ Thai_loling = 0x0dc5 /* U+0E25 THAI CHARACTER LO LING */,
+ Thai_lu = 0x0dc6 /* U+0E26 THAI CHARACTER LU */,
+ Thai_wowaen = 0x0dc7 /* U+0E27 THAI CHARACTER WO WAEN */,
+ Thai_sosala = 0x0dc8 /* U+0E28 THAI CHARACTER SO SALA */,
+ Thai_sorusi = 0x0dc9 /* U+0E29 THAI CHARACTER SO RUSI */,
+ Thai_sosua = 0x0dca /* U+0E2A THAI CHARACTER SO SUA */,
+ Thai_hohip = 0x0dcb /* U+0E2B THAI CHARACTER HO HIP */,
+ Thai_lochula = 0x0dcc /* U+0E2C THAI CHARACTER LO CHULA */,
+ Thai_oang = 0x0dcd /* U+0E2D THAI CHARACTER O ANG */,
+ Thai_honokhuk = 0x0dce /* U+0E2E THAI CHARACTER HO NOKHUK */,
+ Thai_paiyannoi = 0x0dcf /* U+0E2F THAI CHARACTER PAIYANNOI */,
+ Thai_saraa = 0x0dd0 /* U+0E30 THAI CHARACTER SARA A */,
+ Thai_maihanakat = 0x0dd1 /* U+0E31 THAI CHARACTER MAI HAN-AKAT */,
+ Thai_saraaa = 0x0dd2 /* U+0E32 THAI CHARACTER SARA AA */,
+ Thai_saraam = 0x0dd3 /* U+0E33 THAI CHARACTER SARA AM */,
+ Thai_sarai = 0x0dd4 /* U+0E34 THAI CHARACTER SARA I */,
+ Thai_saraii = 0x0dd5 /* U+0E35 THAI CHARACTER SARA II */,
+ Thai_saraue = 0x0dd6 /* U+0E36 THAI CHARACTER SARA UE */,
+ Thai_sarauee = 0x0dd7 /* U+0E37 THAI CHARACTER SARA UEE */,
+ Thai_sarau = 0x0dd8 /* U+0E38 THAI CHARACTER SARA U */,
+ Thai_sarauu = 0x0dd9 /* U+0E39 THAI CHARACTER SARA UU */,
+ Thai_phinthu = 0x0dda /* U+0E3A THAI CHARACTER PHINTHU */,
+ Thai_maihanakat_maitho = 0x0dde,
+ Thai_baht = 0x0ddf /* U+0E3F THAI CURRENCY SYMBOL BAHT */,
+ Thai_sarae = 0x0de0 /* U+0E40 THAI CHARACTER SARA E */,
+ Thai_saraae = 0x0de1 /* U+0E41 THAI CHARACTER SARA AE */,
+ Thai_sarao = 0x0de2 /* U+0E42 THAI CHARACTER SARA O */,
+ Thai_saraaimaimuan = 0x0de3 /* U+0E43 THAI CHARACTER SARA AI MAIMUAN */,
+ Thai_saraaimaimalai = 0x0de4 /* U+0E44 THAI CHARACTER SARA AI MAIMALAI */,
+ Thai_lakkhangyao = 0x0de5 /* U+0E45 THAI CHARACTER LAKKHANGYAO */,
+ Thai_maiyamok = 0x0de6 /* U+0E46 THAI CHARACTER MAIYAMOK */,
+ Thai_maitaikhu = 0x0de7 /* U+0E47 THAI CHARACTER MAITAIKHU */,
+ Thai_maiek = 0x0de8 /* U+0E48 THAI CHARACTER MAI EK */,
+ Thai_maitho = 0x0de9 /* U+0E49 THAI CHARACTER MAI THO */,
+ Thai_maitri = 0x0dea /* U+0E4A THAI CHARACTER MAI TRI */,
+ Thai_maichattawa = 0x0deb /* U+0E4B THAI CHARACTER MAI CHATTAWA */,
+ Thai_thanthakhat = 0x0dec /* U+0E4C THAI CHARACTER THANTHAKHAT */,
+ Thai_nikhahit = 0x0ded /* U+0E4D THAI CHARACTER NIKHAHIT */,
+ Thai_leksun = 0x0df0 /* U+0E50 THAI DIGIT ZERO */,
+ Thai_leknung = 0x0df1 /* U+0E51 THAI DIGIT ONE */,
+ Thai_leksong = 0x0df2 /* U+0E52 THAI DIGIT TWO */,
+ Thai_leksam = 0x0df3 /* U+0E53 THAI DIGIT THREE */,
+ Thai_leksi = 0x0df4 /* U+0E54 THAI DIGIT FOUR */,
+ Thai_lekha = 0x0df5 /* U+0E55 THAI DIGIT FIVE */,
+ Thai_lekhok = 0x0df6 /* U+0E56 THAI DIGIT SIX */,
+ Thai_lekchet = 0x0df7 /* U+0E57 THAI DIGIT SEVEN */,
+ Thai_lekpaet = 0x0df8 /* U+0E58 THAI DIGIT EIGHT */,
+ Thai_lekkao = 0x0df9 /* U+0E59 THAI DIGIT NINE */,
+ Hangul = 0xff31 /* Hangul start/stop(toggle) */,
+ Hangul_Start = 0xff32 /* Hangul start */,
+ Hangul_End = 0xff33 /* Hangul end, English start */,
+ Hangul_Hanja = 0xff34 /* Start Hangul->Hanja Conversion */,
+ Hangul_Jamo = 0xff35 /* Hangul Jamo mode */,
+ Hangul_Romaja = 0xff36 /* Hangul Romaja mode */,
+ Hangul_Codeinput = 0xff37 /* Hangul code input mode */,
+ Hangul_Jeonja = 0xff38 /* Jeonja mode */,
+ Hangul_Banja = 0xff39 /* Banja mode */,
+ Hangul_PreHanja = 0xff3a /* Pre Hanja conversion */,
+ Hangul_PostHanja = 0xff3b /* Post Hanja conversion */,
+ Hangul_SingleCandidate = 0xff3c /* Single candidate */,
+ Hangul_MultipleCandidate = 0xff3d /* Multiple candidate */,
+ Hangul_PreviousCandidate = 0xff3e /* Previous candidate */,
+ Hangul_Special = 0xff3f /* Special symbols */,
+ Hangul_switch = 0xff7e /* Alias for mode_switch */,
+ Hangul_Kiyeog = 0x0ea1,
+ Hangul_SsangKiyeog = 0x0ea2,
+ Hangul_KiyeogSios = 0x0ea3,
+ Hangul_Nieun = 0x0ea4,
+ Hangul_NieunJieuj = 0x0ea5,
+ Hangul_NieunHieuh = 0x0ea6,
+ Hangul_Dikeud = 0x0ea7,
+ Hangul_SsangDikeud = 0x0ea8,
+ Hangul_Rieul = 0x0ea9,
+ Hangul_RieulKiyeog = 0x0eaa,
+ Hangul_RieulMieum = 0x0eab,
+ Hangul_RieulPieub = 0x0eac,
+ Hangul_RieulSios = 0x0ead,
+ Hangul_RieulTieut = 0x0eae,
+ Hangul_RieulPhieuf = 0x0eaf,
+ Hangul_RieulHieuh = 0x0eb0,
+ Hangul_Mieum = 0x0eb1,
+ Hangul_Pieub = 0x0eb2,
+ Hangul_SsangPieub = 0x0eb3,
+ Hangul_PieubSios = 0x0eb4,
+ Hangul_Sios = 0x0eb5,
+ Hangul_SsangSios = 0x0eb6,
+ Hangul_Ieung = 0x0eb7,
+ Hangul_Jieuj = 0x0eb8,
+ Hangul_SsangJieuj = 0x0eb9,
+ Hangul_Cieuc = 0x0eba,
+ Hangul_Khieuq = 0x0ebb,
+ Hangul_Tieut = 0x0ebc,
+ Hangul_Phieuf = 0x0ebd,
+ Hangul_Hieuh = 0x0ebe,
+ Hangul_A = 0x0ebf,
+ Hangul_AE = 0x0ec0,
+ Hangul_YA = 0x0ec1,
+ Hangul_YAE = 0x0ec2,
+ Hangul_EO = 0x0ec3,
+ Hangul_E = 0x0ec4,
+ Hangul_YEO = 0x0ec5,
+ Hangul_YE = 0x0ec6,
+ Hangul_O = 0x0ec7,
+ Hangul_WA = 0x0ec8,
+ Hangul_WAE = 0x0ec9,
+ Hangul_OE = 0x0eca,
+ Hangul_YO = 0x0ecb,
+ Hangul_U = 0x0ecc,
+ Hangul_WEO = 0x0ecd,
+ Hangul_WE = 0x0ece,
+ Hangul_WI = 0x0ecf,
+ Hangul_YU = 0x0ed0,
+ Hangul_EU = 0x0ed1,
+ Hangul_YI = 0x0ed2,
+ Hangul_I = 0x0ed3,
+ Hangul_J_Kiyeog = 0x0ed4,
+ Hangul_J_SsangKiyeog = 0x0ed5,
+ Hangul_J_KiyeogSios = 0x0ed6,
+ Hangul_J_Nieun = 0x0ed7,
+ Hangul_J_NieunJieuj = 0x0ed8,
+ Hangul_J_NieunHieuh = 0x0ed9,
+ Hangul_J_Dikeud = 0x0eda,
+ Hangul_J_Rieul = 0x0edb,
+ Hangul_J_RieulKiyeog = 0x0edc,
+ Hangul_J_RieulMieum = 0x0edd,
+ Hangul_J_RieulPieub = 0x0ede,
+ Hangul_J_RieulSios = 0x0edf,
+ Hangul_J_RieulTieut = 0x0ee0,
+ Hangul_J_RieulPhieuf = 0x0ee1,
+ Hangul_J_RieulHieuh = 0x0ee2,
+ Hangul_J_Mieum = 0x0ee3,
+ Hangul_J_Pieub = 0x0ee4,
+ Hangul_J_PieubSios = 0x0ee5,
+ Hangul_J_Sios = 0x0ee6,
+ Hangul_J_SsangSios = 0x0ee7,
+ Hangul_J_Ieung = 0x0ee8,
+ Hangul_J_Jieuj = 0x0ee9,
+ Hangul_J_Cieuc = 0x0eea,
+ Hangul_J_Khieuq = 0x0eeb,
+ Hangul_J_Tieut = 0x0eec,
+ Hangul_J_Phieuf = 0x0eed,
+ Hangul_J_Hieuh = 0x0eee,
+ Hangul_RieulYeorinHieuh = 0x0eef,
+ Hangul_SunkyeongeumMieum = 0x0ef0,
+ Hangul_SunkyeongeumPieub = 0x0ef1,
+ Hangul_PanSios = 0x0ef2,
+ Hangul_KkogjiDalrinIeung = 0x0ef3,
+ Hangul_SunkyeongeumPhieuf = 0x0ef4,
+ Hangul_YeorinHieuh = 0x0ef5,
+ Hangul_AraeA = 0x0ef6,
+ Hangul_AraeAE = 0x0ef7,
+ Hangul_J_PanSios = 0x0ef8,
+ Hangul_J_KkogjiDalrinIeung = 0x0ef9,
+ Hangul_J_YeorinHieuh = 0x0efa,
+ Korean_Won = 0x0eff /*(U+20A9 WON SIGN)*/,
+ Armenian_ligature_ew = 0x1000587 /* U+0587 ARMENIAN SMALL LIGATURE ECH YIWN */,
+ Armenian_full_stop = 0x1000589 /* U+0589 ARMENIAN FULL STOP */,
+ Armenian_verjaket = 0x1000589 /* U+0589 ARMENIAN FULL STOP */,
+ Armenian_separation_mark = 0x100055d /* U+055D ARMENIAN COMMA */,
+ Armenian_but = 0x100055d /* U+055D ARMENIAN COMMA */,
+ Armenian_hyphen = 0x100058a /* U+058A ARMENIAN HYPHEN */,
+ Armenian_yentamna = 0x100058a /* U+058A ARMENIAN HYPHEN */,
+ Armenian_exclam = 0x100055c /* U+055C ARMENIAN EXCLAMATION MARK */,
+ Armenian_amanak = 0x100055c /* U+055C ARMENIAN EXCLAMATION MARK */,
+ Armenian_accent = 0x100055b /* U+055B ARMENIAN EMPHASIS MARK */,
+ Armenian_shesht = 0x100055b /* U+055B ARMENIAN EMPHASIS MARK */,
+ Armenian_question = 0x100055e /* U+055E ARMENIAN QUESTION MARK */,
+ Armenian_paruyk = 0x100055e /* U+055E ARMENIAN QUESTION MARK */,
+ Armenian_AYB = 0x1000531 /* U+0531 ARMENIAN CAPITAL LETTER AYB */,
+ Armenian_ayb = 0x1000561 /* U+0561 ARMENIAN SMALL LETTER AYB */,
+ Armenian_BEN = 0x1000532 /* U+0532 ARMENIAN CAPITAL LETTER BEN */,
+ Armenian_ben = 0x1000562 /* U+0562 ARMENIAN SMALL LETTER BEN */,
+ Armenian_GIM = 0x1000533 /* U+0533 ARMENIAN CAPITAL LETTER GIM */,
+ Armenian_gim = 0x1000563 /* U+0563 ARMENIAN SMALL LETTER GIM */,
+ Armenian_DA = 0x1000534 /* U+0534 ARMENIAN CAPITAL LETTER DA */,
+ Armenian_da = 0x1000564 /* U+0564 ARMENIAN SMALL LETTER DA */,
+ Armenian_YECH = 0x1000535 /* U+0535 ARMENIAN CAPITAL LETTER ECH */,
+ Armenian_yech = 0x1000565 /* U+0565 ARMENIAN SMALL LETTER ECH */,
+ Armenian_ZA = 0x1000536 /* U+0536 ARMENIAN CAPITAL LETTER ZA */,
+ Armenian_za = 0x1000566 /* U+0566 ARMENIAN SMALL LETTER ZA */,
+ Armenian_E = 0x1000537 /* U+0537 ARMENIAN CAPITAL LETTER EH */,
+ Armenian_e = 0x1000567 /* U+0567 ARMENIAN SMALL LETTER EH */,
+ Armenian_AT = 0x1000538 /* U+0538 ARMENIAN CAPITAL LETTER ET */,
+ Armenian_at = 0x1000568 /* U+0568 ARMENIAN SMALL LETTER ET */,
+ Armenian_TO = 0x1000539 /* U+0539 ARMENIAN CAPITAL LETTER TO */,
+ Armenian_to = 0x1000569 /* U+0569 ARMENIAN SMALL LETTER TO */,
+ Armenian_ZHE = 0x100053a /* U+053A ARMENIAN CAPITAL LETTER ZHE */,
+ Armenian_zhe = 0x100056a /* U+056A ARMENIAN SMALL LETTER ZHE */,
+ Armenian_INI = 0x100053b /* U+053B ARMENIAN CAPITAL LETTER INI */,
+ Armenian_ini = 0x100056b /* U+056B ARMENIAN SMALL LETTER INI */,
+ Armenian_LYUN = 0x100053c /* U+053C ARMENIAN CAPITAL LETTER LIWN */,
+ Armenian_lyun = 0x100056c /* U+056C ARMENIAN SMALL LETTER LIWN */,
+ Armenian_KHE = 0x100053d /* U+053D ARMENIAN CAPITAL LETTER XEH */,
+ Armenian_khe = 0x100056d /* U+056D ARMENIAN SMALL LETTER XEH */,
+ Armenian_TSA = 0x100053e /* U+053E ARMENIAN CAPITAL LETTER CA */,
+ Armenian_tsa = 0x100056e /* U+056E ARMENIAN SMALL LETTER CA */,
+ Armenian_KEN = 0x100053f /* U+053F ARMENIAN CAPITAL LETTER KEN */,
+ Armenian_ken = 0x100056f /* U+056F ARMENIAN SMALL LETTER KEN */,
+ Armenian_HO = 0x1000540 /* U+0540 ARMENIAN CAPITAL LETTER HO */,
+ Armenian_ho = 0x1000570 /* U+0570 ARMENIAN SMALL LETTER HO */,
+ Armenian_DZA = 0x1000541 /* U+0541 ARMENIAN CAPITAL LETTER JA */,
+ Armenian_dza = 0x1000571 /* U+0571 ARMENIAN SMALL LETTER JA */,
+ Armenian_GHAT = 0x1000542 /* U+0542 ARMENIAN CAPITAL LETTER GHAD */,
+ Armenian_ghat = 0x1000572 /* U+0572 ARMENIAN SMALL LETTER GHAD */,
+ Armenian_TCHE = 0x1000543 /* U+0543 ARMENIAN CAPITAL LETTER CHEH */,
+ Armenian_tche = 0x1000573 /* U+0573 ARMENIAN SMALL LETTER CHEH */,
+ Armenian_MEN = 0x1000544 /* U+0544 ARMENIAN CAPITAL LETTER MEN */,
+ Armenian_men = 0x1000574 /* U+0574 ARMENIAN SMALL LETTER MEN */,
+ Armenian_HI = 0x1000545 /* U+0545 ARMENIAN CAPITAL LETTER YI */,
+ Armenian_hi = 0x1000575 /* U+0575 ARMENIAN SMALL LETTER YI */,
+ Armenian_NU = 0x1000546 /* U+0546 ARMENIAN CAPITAL LETTER NOW */,
+ Armenian_nu = 0x1000576 /* U+0576 ARMENIAN SMALL LETTER NOW */,
+ Armenian_SHA = 0x1000547 /* U+0547 ARMENIAN CAPITAL LETTER SHA */,
+ Armenian_sha = 0x1000577 /* U+0577 ARMENIAN SMALL LETTER SHA */,
+ Armenian_VO = 0x1000548 /* U+0548 ARMENIAN CAPITAL LETTER VO */,
+ Armenian_vo = 0x1000578 /* U+0578 ARMENIAN SMALL LETTER VO */,
+ Armenian_CHA = 0x1000549 /* U+0549 ARMENIAN CAPITAL LETTER CHA */,
+ Armenian_cha = 0x1000579 /* U+0579 ARMENIAN SMALL LETTER CHA */,
+ Armenian_PE = 0x100054a /* U+054A ARMENIAN CAPITAL LETTER PEH */,
+ Armenian_pe = 0x100057a /* U+057A ARMENIAN SMALL LETTER PEH */,
+ Armenian_JE = 0x100054b /* U+054B ARMENIAN CAPITAL LETTER JHEH */,
+ Armenian_je = 0x100057b /* U+057B ARMENIAN SMALL LETTER JHEH */,
+ Armenian_RA = 0x100054c /* U+054C ARMENIAN CAPITAL LETTER RA */,
+ Armenian_ra = 0x100057c /* U+057C ARMENIAN SMALL LETTER RA */,
+ Armenian_SE = 0x100054d /* U+054D ARMENIAN CAPITAL LETTER SEH */,
+ Armenian_se = 0x100057d /* U+057D ARMENIAN SMALL LETTER SEH */,
+ Armenian_VEV = 0x100054e /* U+054E ARMENIAN CAPITAL LETTER VEW */,
+ Armenian_vev = 0x100057e /* U+057E ARMENIAN SMALL LETTER VEW */,
+ Armenian_TYUN = 0x100054f /* U+054F ARMENIAN CAPITAL LETTER TIWN */,
+ Armenian_tyun = 0x100057f /* U+057F ARMENIAN SMALL LETTER TIWN */,
+ Armenian_RE = 0x1000550 /* U+0550 ARMENIAN CAPITAL LETTER REH */,
+ Armenian_re = 0x1000580 /* U+0580 ARMENIAN SMALL LETTER REH */,
+ Armenian_TSO = 0x1000551 /* U+0551 ARMENIAN CAPITAL LETTER CO */,
+ Armenian_tso = 0x1000581 /* U+0581 ARMENIAN SMALL LETTER CO */,
+ Armenian_VYUN = 0x1000552 /* U+0552 ARMENIAN CAPITAL LETTER YIWN */,
+ Armenian_vyun = 0x1000582 /* U+0582 ARMENIAN SMALL LETTER YIWN */,
+ Armenian_PYUR = 0x1000553 /* U+0553 ARMENIAN CAPITAL LETTER PIWR */,
+ Armenian_pyur = 0x1000583 /* U+0583 ARMENIAN SMALL LETTER PIWR */,
+ Armenian_KE = 0x1000554 /* U+0554 ARMENIAN CAPITAL LETTER KEH */,
+ Armenian_ke = 0x1000584 /* U+0584 ARMENIAN SMALL LETTER KEH */,
+ Armenian_O = 0x1000555 /* U+0555 ARMENIAN CAPITAL LETTER OH */,
+ Armenian_o = 0x1000585 /* U+0585 ARMENIAN SMALL LETTER OH */,
+ Armenian_FE = 0x1000556 /* U+0556 ARMENIAN CAPITAL LETTER FEH */,
+ Armenian_fe = 0x1000586 /* U+0586 ARMENIAN SMALL LETTER FEH */,
+ Armenian_apostrophe = 0x100055a /* U+055A ARMENIAN APOSTROPHE */,
+ Georgian_an = 0x10010d0 /* U+10D0 GEORGIAN LETTER AN */,
+ Georgian_ban = 0x10010d1 /* U+10D1 GEORGIAN LETTER BAN */,
+ Georgian_gan = 0x10010d2 /* U+10D2 GEORGIAN LETTER GAN */,
+ Georgian_don = 0x10010d3 /* U+10D3 GEORGIAN LETTER DON */,
+ Georgian_en = 0x10010d4 /* U+10D4 GEORGIAN LETTER EN */,
+ Georgian_vin = 0x10010d5 /* U+10D5 GEORGIAN LETTER VIN */,
+ Georgian_zen = 0x10010d6 /* U+10D6 GEORGIAN LETTER ZEN */,
+ Georgian_tan = 0x10010d7 /* U+10D7 GEORGIAN LETTER TAN */,
+ Georgian_in = 0x10010d8 /* U+10D8 GEORGIAN LETTER IN */,
+ Georgian_kan = 0x10010d9 /* U+10D9 GEORGIAN LETTER KAN */,
+ Georgian_las = 0x10010da /* U+10DA GEORGIAN LETTER LAS */,
+ Georgian_man = 0x10010db /* U+10DB GEORGIAN LETTER MAN */,
+ Georgian_nar = 0x10010dc /* U+10DC GEORGIAN LETTER NAR */,
+ Georgian_on = 0x10010dd /* U+10DD GEORGIAN LETTER ON */,
+ Georgian_par = 0x10010de /* U+10DE GEORGIAN LETTER PAR */,
+ Georgian_zhar = 0x10010df /* U+10DF GEORGIAN LETTER ZHAR */,
+ Georgian_rae = 0x10010e0 /* U+10E0 GEORGIAN LETTER RAE */,
+ Georgian_san = 0x10010e1 /* U+10E1 GEORGIAN LETTER SAN */,
+ Georgian_tar = 0x10010e2 /* U+10E2 GEORGIAN LETTER TAR */,
+ Georgian_un = 0x10010e3 /* U+10E3 GEORGIAN LETTER UN */,
+ Georgian_phar = 0x10010e4 /* U+10E4 GEORGIAN LETTER PHAR */,
+ Georgian_khar = 0x10010e5 /* U+10E5 GEORGIAN LETTER KHAR */,
+ Georgian_ghan = 0x10010e6 /* U+10E6 GEORGIAN LETTER GHAN */,
+ Georgian_qar = 0x10010e7 /* U+10E7 GEORGIAN LETTER QAR */,
+ Georgian_shin = 0x10010e8 /* U+10E8 GEORGIAN LETTER SHIN */,
+ Georgian_chin = 0x10010e9 /* U+10E9 GEORGIAN LETTER CHIN */,
+ Georgian_can = 0x10010ea /* U+10EA GEORGIAN LETTER CAN */,
+ Georgian_jil = 0x10010eb /* U+10EB GEORGIAN LETTER JIL */,
+ Georgian_cil = 0x10010ec /* U+10EC GEORGIAN LETTER CIL */,
+ Georgian_char = 0x10010ed /* U+10ED GEORGIAN LETTER CHAR */,
+ Georgian_xan = 0x10010ee /* U+10EE GEORGIAN LETTER XAN */,
+ Georgian_jhan = 0x10010ef /* U+10EF GEORGIAN LETTER JHAN */,
+ Georgian_hae = 0x10010f0 /* U+10F0 GEORGIAN LETTER HAE */,
+ Georgian_he = 0x10010f1 /* U+10F1 GEORGIAN LETTER HE */,
+ Georgian_hie = 0x10010f2 /* U+10F2 GEORGIAN LETTER HIE */,
+ Georgian_we = 0x10010f3 /* U+10F3 GEORGIAN LETTER WE */,
+ Georgian_har = 0x10010f4 /* U+10F4 GEORGIAN LETTER HAR */,
+ Georgian_hoe = 0x10010f5 /* U+10F5 GEORGIAN LETTER HOE */,
+ Georgian_fi = 0x10010f6 /* U+10F6 GEORGIAN LETTER FI */,
+ Xabovedot = 0x1001e8a /* U+1E8A LATIN CAPITAL LETTER X WITH DOT ABOVE */,
+ Ibreve = 0x100012c /* U+012C LATIN CAPITAL LETTER I WITH BREVE */,
+ Zstroke = 0x10001b5 /* U+01B5 LATIN CAPITAL LETTER Z WITH STROKE */,
+ Gcaron = 0x10001e6 /* U+01E6 LATIN CAPITAL LETTER G WITH CARON */,
+ Ocaron = 0x10001d1 /* U+01D2 LATIN CAPITAL LETTER O WITH CARON */,
+ Obarred = 0x100019f /* U+019F LATIN CAPITAL LETTER O WITH MIDDLE TILDE */,
+ xabovedot = 0x1001e8b /* U+1E8B LATIN SMALL LETTER X WITH DOT ABOVE */,
+ ibreve = 0x100012d /* U+012D LATIN SMALL LETTER I WITH BREVE */,
+ zstroke = 0x10001b6 /* U+01B6 LATIN SMALL LETTER Z WITH STROKE */,
+ gcaron = 0x10001e7 /* U+01E7 LATIN SMALL LETTER G WITH CARON */,
+ ocaron = 0x10001d2 /* U+01D2 LATIN SMALL LETTER O WITH CARON */,
+ obarred = 0x1000275 /* U+0275 LATIN SMALL LETTER BARRED O */,
+ SCHWA = 0x100018f /* U+018F LATIN CAPITAL LETTER SCHWA */,
+ schwa = 0x1000259 /* U+0259 LATIN SMALL LETTER SCHWA */,
+ EZH = 0x10001b7 /* U+01B7 LATIN CAPITAL LETTER EZH */,
+ ezh = 0x1000292 /* U+0292 LATIN SMALL LETTER EZH */,
+ Lbelowdot = 0x1001e36 /* U+1E36 LATIN CAPITAL LETTER L WITH DOT BELOW */,
+ lbelowdot = 0x1001e37 /* U+1E37 LATIN SMALL LETTER L WITH DOT BELOW */,
+ Abelowdot = 0x1001ea0 /* U+1EA0 LATIN CAPITAL LETTER A WITH DOT BELOW */,
+ abelowdot = 0x1001ea1 /* U+1EA1 LATIN SMALL LETTER A WITH DOT BELOW */,
+ Ahook = 0x1001ea2 /* U+1EA2 LATIN CAPITAL LETTER A WITH HOOK ABOVE */,
+ ahook = 0x1001ea3 /* U+1EA3 LATIN SMALL LETTER A WITH HOOK ABOVE */,
+ Acircumflexacute = 0x1001ea4 /* U+1EA4 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */,
+ acircumflexacute = 0x1001ea5 /* U+1EA5 LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE */,
+ Acircumflexgrave = 0x1001ea6 /* U+1EA6 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */,
+ acircumflexgrave = 0x1001ea7 /* U+1EA7 LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE */,
+ Acircumflexhook = 0x1001ea8 /* U+1EA8 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */,
+ acircumflexhook = 0x1001ea9 /* U+1EA9 LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */,
+ Acircumflextilde = 0x1001eaa /* U+1EAA LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */,
+ acircumflextilde = 0x1001eab /* U+1EAB LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE */,
+ Acircumflexbelowdot = 0x1001eac /* U+1EAC LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */,
+ acircumflexbelowdot = 0x1001ead /* U+1EAD LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW */,
+ Abreveacute = 0x1001eae /* U+1EAE LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */,
+ abreveacute = 0x1001eaf /* U+1EAF LATIN SMALL LETTER A WITH BREVE AND ACUTE */,
+ Abrevegrave = 0x1001eb0 /* U+1EB0 LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */,
+ abrevegrave = 0x1001eb1 /* U+1EB1 LATIN SMALL LETTER A WITH BREVE AND GRAVE */,
+ Abrevehook = 0x1001eb2 /* U+1EB2 LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */,
+ abrevehook = 0x1001eb3 /* U+1EB3 LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE */,
+ Abrevetilde = 0x1001eb4 /* U+1EB4 LATIN CAPITAL LETTER A WITH BREVE AND TILDE */,
+ abrevetilde = 0x1001eb5 /* U+1EB5 LATIN SMALL LETTER A WITH BREVE AND TILDE */,
+ Abrevebelowdot = 0x1001eb6 /* U+1EB6 LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */,
+ abrevebelowdot = 0x1001eb7 /* U+1EB7 LATIN SMALL LETTER A WITH BREVE AND DOT BELOW */,
+ Ebelowdot = 0x1001eb8 /* U+1EB8 LATIN CAPITAL LETTER E WITH DOT BELOW */,
+ ebelowdot = 0x1001eb9 /* U+1EB9 LATIN SMALL LETTER E WITH DOT BELOW */,
+ Ehook = 0x1001eba /* U+1EBA LATIN CAPITAL LETTER E WITH HOOK ABOVE */,
+ ehook = 0x1001ebb /* U+1EBB LATIN SMALL LETTER E WITH HOOK ABOVE */,
+ Etilde = 0x1001ebc /* U+1EBC LATIN CAPITAL LETTER E WITH TILDE */,
+ etilde = 0x1001ebd /* U+1EBD LATIN SMALL LETTER E WITH TILDE */,
+ Ecircumflexacute = 0x1001ebe /* U+1EBE LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */,
+ ecircumflexacute = 0x1001ebf /* U+1EBF LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE */,
+ Ecircumflexgrave = 0x1001ec0 /* U+1EC0 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */,
+ ecircumflexgrave = 0x1001ec1 /* U+1EC1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE */,
+ Ecircumflexhook = 0x1001ec2 /* U+1EC2 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */,
+ ecircumflexhook = 0x1001ec3 /* U+1EC3 LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */,
+ Ecircumflextilde = 0x1001ec4 /* U+1EC4 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */,
+ ecircumflextilde = 0x1001ec5 /* U+1EC5 LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE */,
+ Ecircumflexbelowdot = 0x1001ec6 /* U+1EC6 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */,
+ ecircumflexbelowdot = 0x1001ec7 /* U+1EC7 LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW */,
+ Ihook = 0x1001ec8 /* U+1EC8 LATIN CAPITAL LETTER I WITH HOOK ABOVE */,
+ ihook = 0x1001ec9 /* U+1EC9 LATIN SMALL LETTER I WITH HOOK ABOVE */,
+ Ibelowdot = 0x1001eca /* U+1ECA LATIN CAPITAL LETTER I WITH DOT BELOW */,
+ ibelowdot = 0x1001ecb /* U+1ECB LATIN SMALL LETTER I WITH DOT BELOW */,
+ Obelowdot = 0x1001ecc /* U+1ECC LATIN CAPITAL LETTER O WITH DOT BELOW */,
+ obelowdot = 0x1001ecd /* U+1ECD LATIN SMALL LETTER O WITH DOT BELOW */,
+ Ohook = 0x1001ece /* U+1ECE LATIN CAPITAL LETTER O WITH HOOK ABOVE */,
+ ohook = 0x1001ecf /* U+1ECF LATIN SMALL LETTER O WITH HOOK ABOVE */,
+ Ocircumflexacute = 0x1001ed0 /* U+1ED0 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */,
+ ocircumflexacute = 0x1001ed1 /* U+1ED1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE */,
+ Ocircumflexgrave = 0x1001ed2 /* U+1ED2 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */,
+ ocircumflexgrave = 0x1001ed3 /* U+1ED3 LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE */,
+ Ocircumflexhook = 0x1001ed4 /* U+1ED4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */,
+ ocircumflexhook = 0x1001ed5 /* U+1ED5 LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */,
+ Ocircumflextilde = 0x1001ed6 /* U+1ED6 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */,
+ ocircumflextilde = 0x1001ed7 /* U+1ED7 LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE */,
+ Ocircumflexbelowdot = 0x1001ed8 /* U+1ED8 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */,
+ ocircumflexbelowdot = 0x1001ed9 /* U+1ED9 LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW */,
+ Ohornacute = 0x1001eda /* U+1EDA LATIN CAPITAL LETTER O WITH HORN AND ACUTE */,
+ ohornacute = 0x1001edb /* U+1EDB LATIN SMALL LETTER O WITH HORN AND ACUTE */,
+ Ohorngrave = 0x1001edc /* U+1EDC LATIN CAPITAL LETTER O WITH HORN AND GRAVE */,
+ ohorngrave = 0x1001edd /* U+1EDD LATIN SMALL LETTER O WITH HORN AND GRAVE */,
+ Ohornhook = 0x1001ede /* U+1EDE LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */,
+ ohornhook = 0x1001edf /* U+1EDF LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE */,
+ Ohorntilde = 0x1001ee0 /* U+1EE0 LATIN CAPITAL LETTER O WITH HORN AND TILDE */,
+ ohorntilde = 0x1001ee1 /* U+1EE1 LATIN SMALL LETTER O WITH HORN AND TILDE */,
+ Ohornbelowdot = 0x1001ee2 /* U+1EE2 LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */,
+ ohornbelowdot = 0x1001ee3 /* U+1EE3 LATIN SMALL LETTER O WITH HORN AND DOT BELOW */,
+ Ubelowdot = 0x1001ee4 /* U+1EE4 LATIN CAPITAL LETTER U WITH DOT BELOW */,
+ ubelowdot = 0x1001ee5 /* U+1EE5 LATIN SMALL LETTER U WITH DOT BELOW */,
+ Uhook = 0x1001ee6 /* U+1EE6 LATIN CAPITAL LETTER U WITH HOOK ABOVE */,
+ uhook = 0x1001ee7 /* U+1EE7 LATIN SMALL LETTER U WITH HOOK ABOVE */,
+ Uhornacute = 0x1001ee8 /* U+1EE8 LATIN CAPITAL LETTER U WITH HORN AND ACUTE */,
+ uhornacute = 0x1001ee9 /* U+1EE9 LATIN SMALL LETTER U WITH HORN AND ACUTE */,
+ Uhorngrave = 0x1001eea /* U+1EEA LATIN CAPITAL LETTER U WITH HORN AND GRAVE */,
+ uhorngrave = 0x1001eeb /* U+1EEB LATIN SMALL LETTER U WITH HORN AND GRAVE */,
+ Uhornhook = 0x1001eec /* U+1EEC LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */,
+ uhornhook = 0x1001eed /* U+1EED LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE */,
+ Uhorntilde = 0x1001eee /* U+1EEE LATIN CAPITAL LETTER U WITH HORN AND TILDE */,
+ uhorntilde = 0x1001eef /* U+1EEF LATIN SMALL LETTER U WITH HORN AND TILDE */,
+ Uhornbelowdot = 0x1001ef0 /* U+1EF0 LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */,
+ uhornbelowdot = 0x1001ef1 /* U+1EF1 LATIN SMALL LETTER U WITH HORN AND DOT BELOW */,
+ Ybelowdot = 0x1001ef4 /* U+1EF4 LATIN CAPITAL LETTER Y WITH DOT BELOW */,
+ ybelowdot = 0x1001ef5 /* U+1EF5 LATIN SMALL LETTER Y WITH DOT BELOW */,
+ Yhook = 0x1001ef6 /* U+1EF6 LATIN CAPITAL LETTER Y WITH HOOK ABOVE */,
+ yhook = 0x1001ef7 /* U+1EF7 LATIN SMALL LETTER Y WITH HOOK ABOVE */,
+ Ytilde = 0x1001ef8 /* U+1EF8 LATIN CAPITAL LETTER Y WITH TILDE */,
+ ytilde = 0x1001ef9 /* U+1EF9 LATIN SMALL LETTER Y WITH TILDE */,
+ Ohorn = 0x10001a0 /* U+01A0 LATIN CAPITAL LETTER O WITH HORN */,
+ ohorn = 0x10001a1 /* U+01A1 LATIN SMALL LETTER O WITH HORN */,
+ Uhorn = 0x10001af /* U+01AF LATIN CAPITAL LETTER U WITH HORN */,
+ uhorn = 0x10001b0 /* U+01B0 LATIN SMALL LETTER U WITH HORN */,
+ EcuSign = 0x10020a0 /* U+20A0 EURO-CURRENCY SIGN */,
+ ColonSign = 0x10020a1 /* U+20A1 COLON SIGN */,
+ CruzeiroSign = 0x10020a2 /* U+20A2 CRUZEIRO SIGN */,
+ FFrancSign = 0x10020a3 /* U+20A3 FRENCH FRANC SIGN */,
+ LiraSign = 0x10020a4 /* U+20A4 LIRA SIGN */,
+ MillSign = 0x10020a5 /* U+20A5 MILL SIGN */,
+ NairaSign = 0x10020a6 /* U+20A6 NAIRA SIGN */,
+ PesetaSign = 0x10020a7 /* U+20A7 PESETA SIGN */,
+ RupeeSign = 0x10020a8 /* U+20A8 RUPEE SIGN */,
+ WonSign = 0x10020a9 /* U+20A9 WON SIGN */,
+ NewSheqelSign = 0x10020aa /* U+20AA NEW SHEQEL SIGN */,
+ DongSign = 0x10020ab /* U+20AB DONG SIGN */,
+ EuroSign = 0x20ac /* U+20AC EURO SIGN */,
+ zerosuperior = 0x1002070 /* U+2070 SUPERSCRIPT ZERO */,
+ foursuperior = 0x1002074 /* U+2074 SUPERSCRIPT FOUR */,
+ fivesuperior = 0x1002075 /* U+2075 SUPERSCRIPT FIVE */,
+ sixsuperior = 0x1002076 /* U+2076 SUPERSCRIPT SIX */,
+ sevensuperior = 0x1002077 /* U+2077 SUPERSCRIPT SEVEN */,
+ eightsuperior = 0x1002078 /* U+2078 SUPERSCRIPT EIGHT */,
+ ninesuperior = 0x1002079 /* U+2079 SUPERSCRIPT NINE */,
+ zerosubscript = 0x1002080 /* U+2080 SUBSCRIPT ZERO */,
+ onesubscript = 0x1002081 /* U+2081 SUBSCRIPT ONE */,
+ twosubscript = 0x1002082 /* U+2082 SUBSCRIPT TWO */,
+ threesubscript = 0x1002083 /* U+2083 SUBSCRIPT THREE */,
+ foursubscript = 0x1002084 /* U+2084 SUBSCRIPT FOUR */,
+ fivesubscript = 0x1002085 /* U+2085 SUBSCRIPT FIVE */,
+ sixsubscript = 0x1002086 /* U+2086 SUBSCRIPT SIX */,
+ sevensubscript = 0x1002087 /* U+2087 SUBSCRIPT SEVEN */,
+ eightsubscript = 0x1002088 /* U+2088 SUBSCRIPT EIGHT */,
+ ninesubscript = 0x1002089 /* U+2089 SUBSCRIPT NINE */,
+ partdifferential = 0x1002202 /* U+2202 PARTIAL DIFFERENTIAL */,
+ emptyset = 0x1002205 /* U+2205 NULL SET */,
+ elementof = 0x1002208 /* U+2208 ELEMENT OF */,
+ notelementof = 0x1002209 /* U+2209 NOT AN ELEMENT OF */,
+ containsas = 0x100220B /* U+220B CONTAINS AS MEMBER */,
+ squareroot = 0x100221A /* U+221A SQUARE ROOT */,
+ cuberoot = 0x100221B /* U+221B CUBE ROOT */,
+ fourthroot = 0x100221C /* U+221C FOURTH ROOT */,
+ dintegral = 0x100222C /* U+222C DOUBLE INTEGRAL */,
+ tintegral = 0x100222D /* U+222D TRIPLE INTEGRAL */,
+ because = 0x1002235 /* U+2235 BECAUSE */,
+ approxeq = 0x1002248 /* U+2245 ALMOST EQUAL TO */,
+ notapproxeq = 0x1002247 /* U+2247 NOT ALMOST EQUAL TO */,
+ notidentical = 0x1002262 /* U+2262 NOT IDENTICAL TO */,
+ stricteq = 0x1002263 /* U+2263 STRICTLY EQUIVALENT TO */,
+ braille_dot_1 = 0xfff1,
+ braille_dot_2 = 0xfff2,
+ braille_dot_3 = 0xfff3,
+ braille_dot_4 = 0xfff4,
+ braille_dot_5 = 0xfff5,
+ braille_dot_6 = 0xfff6,
+ braille_dot_7 = 0xfff7,
+ braille_dot_8 = 0xfff8,
+ braille_dot_9 = 0xfff9,
+ braille_dot_10 = 0xfffa,
+ braille_blank = 0x1002800 /* U+2800 BRAILLE PATTERN BLANK */,
+ braille_dots_1 = 0x1002801 /* U+2801 BRAILLE PATTERN DOTS-1 */,
+ braille_dots_2 = 0x1002802 /* U+2802 BRAILLE PATTERN DOTS-2 */,
+ braille_dots_12 = 0x1002803 /* U+2803 BRAILLE PATTERN DOTS-12 */,
+ braille_dots_3 = 0x1002804 /* U+2804 BRAILLE PATTERN DOTS-3 */,
+ braille_dots_13 = 0x1002805 /* U+2805 BRAILLE PATTERN DOTS-13 */,
+ braille_dots_23 = 0x1002806 /* U+2806 BRAILLE PATTERN DOTS-23 */,
+ braille_dots_123 = 0x1002807 /* U+2807 BRAILLE PATTERN DOTS-123 */,
+ braille_dots_4 = 0x1002808 /* U+2808 BRAILLE PATTERN DOTS-4 */,
+ braille_dots_14 = 0x1002809 /* U+2809 BRAILLE PATTERN DOTS-14 */,
+ braille_dots_24 = 0x100280a /* U+280a BRAILLE PATTERN DOTS-24 */,
+ braille_dots_124 = 0x100280b /* U+280b BRAILLE PATTERN DOTS-124 */,
+ braille_dots_34 = 0x100280c /* U+280c BRAILLE PATTERN DOTS-34 */,
+ braille_dots_134 = 0x100280d /* U+280d BRAILLE PATTERN DOTS-134 */,
+ braille_dots_234 = 0x100280e /* U+280e BRAILLE PATTERN DOTS-234 */,
+ braille_dots_1234 = 0x100280f /* U+280f BRAILLE PATTERN DOTS-1234 */,
+ braille_dots_5 = 0x1002810 /* U+2810 BRAILLE PATTERN DOTS-5 */,
+ braille_dots_15 = 0x1002811 /* U+2811 BRAILLE PATTERN DOTS-15 */,
+ braille_dots_25 = 0x1002812 /* U+2812 BRAILLE PATTERN DOTS-25 */,
+ braille_dots_125 = 0x1002813 /* U+2813 BRAILLE PATTERN DOTS-125 */,
+ braille_dots_35 = 0x1002814 /* U+2814 BRAILLE PATTERN DOTS-35 */,
+ braille_dots_135 = 0x1002815 /* U+2815 BRAILLE PATTERN DOTS-135 */,
+ braille_dots_235 = 0x1002816 /* U+2816 BRAILLE PATTERN DOTS-235 */,
+ braille_dots_1235 = 0x1002817 /* U+2817 BRAILLE PATTERN DOTS-1235 */,
+ braille_dots_45 = 0x1002818 /* U+2818 BRAILLE PATTERN DOTS-45 */,
+ braille_dots_145 = 0x1002819 /* U+2819 BRAILLE PATTERN DOTS-145 */,
+ braille_dots_245 = 0x100281a /* U+281a BRAILLE PATTERN DOTS-245 */,
+ braille_dots_1245 = 0x100281b /* U+281b BRAILLE PATTERN DOTS-1245 */,
+ braille_dots_345 = 0x100281c /* U+281c BRAILLE PATTERN DOTS-345 */,
+ braille_dots_1345 = 0x100281d /* U+281d BRAILLE PATTERN DOTS-1345 */,
+ braille_dots_2345 = 0x100281e /* U+281e BRAILLE PATTERN DOTS-2345 */,
+ braille_dots_12345 = 0x100281f /* U+281f BRAILLE PATTERN DOTS-12345 */,
+ braille_dots_6 = 0x1002820 /* U+2820 BRAILLE PATTERN DOTS-6 */,
+ braille_dots_16 = 0x1002821 /* U+2821 BRAILLE PATTERN DOTS-16 */,
+ braille_dots_26 = 0x1002822 /* U+2822 BRAILLE PATTERN DOTS-26 */,
+ braille_dots_126 = 0x1002823 /* U+2823 BRAILLE PATTERN DOTS-126 */,
+ braille_dots_36 = 0x1002824 /* U+2824 BRAILLE PATTERN DOTS-36 */,
+ braille_dots_136 = 0x1002825 /* U+2825 BRAILLE PATTERN DOTS-136 */,
+ braille_dots_236 = 0x1002826 /* U+2826 BRAILLE PATTERN DOTS-236 */,
+ braille_dots_1236 = 0x1002827 /* U+2827 BRAILLE PATTERN DOTS-1236 */,
+ braille_dots_46 = 0x1002828 /* U+2828 BRAILLE PATTERN DOTS-46 */,
+ braille_dots_146 = 0x1002829 /* U+2829 BRAILLE PATTERN DOTS-146 */,
+ braille_dots_246 = 0x100282a /* U+282a BRAILLE PATTERN DOTS-246 */,
+ braille_dots_1246 = 0x100282b /* U+282b BRAILLE PATTERN DOTS-1246 */,
+ braille_dots_346 = 0x100282c /* U+282c BRAILLE PATTERN DOTS-346 */,
+ braille_dots_1346 = 0x100282d /* U+282d BRAILLE PATTERN DOTS-1346 */,
+ braille_dots_2346 = 0x100282e /* U+282e BRAILLE PATTERN DOTS-2346 */,
+ braille_dots_12346 = 0x100282f /* U+282f BRAILLE PATTERN DOTS-12346 */,
+ braille_dots_56 = 0x1002830 /* U+2830 BRAILLE PATTERN DOTS-56 */,
+ braille_dots_156 = 0x1002831 /* U+2831 BRAILLE PATTERN DOTS-156 */,
+ braille_dots_256 = 0x1002832 /* U+2832 BRAILLE PATTERN DOTS-256 */,
+ braille_dots_1256 = 0x1002833 /* U+2833 BRAILLE PATTERN DOTS-1256 */,
+ braille_dots_356 = 0x1002834 /* U+2834 BRAILLE PATTERN DOTS-356 */,
+ braille_dots_1356 = 0x1002835 /* U+2835 BRAILLE PATTERN DOTS-1356 */,
+ braille_dots_2356 = 0x1002836 /* U+2836 BRAILLE PATTERN DOTS-2356 */,
+ braille_dots_12356 = 0x1002837 /* U+2837 BRAILLE PATTERN DOTS-12356 */,
+ braille_dots_456 = 0x1002838 /* U+2838 BRAILLE PATTERN DOTS-456 */,
+ braille_dots_1456 = 0x1002839 /* U+2839 BRAILLE PATTERN DOTS-1456 */,
+ braille_dots_2456 = 0x100283a /* U+283a BRAILLE PATTERN DOTS-2456 */,
+ braille_dots_12456 = 0x100283b /* U+283b BRAILLE PATTERN DOTS-12456 */,
+ braille_dots_3456 = 0x100283c /* U+283c BRAILLE PATTERN DOTS-3456 */,
+ braille_dots_13456 = 0x100283d /* U+283d BRAILLE PATTERN DOTS-13456 */,
+ braille_dots_23456 = 0x100283e /* U+283e BRAILLE PATTERN DOTS-23456 */,
+ braille_dots_123456 = 0x100283f /* U+283f BRAILLE PATTERN DOTS-123456 */,
+ braille_dots_7 = 0x1002840 /* U+2840 BRAILLE PATTERN DOTS-7 */,
+ braille_dots_17 = 0x1002841 /* U+2841 BRAILLE PATTERN DOTS-17 */,
+ braille_dots_27 = 0x1002842 /* U+2842 BRAILLE PATTERN DOTS-27 */,
+ braille_dots_127 = 0x1002843 /* U+2843 BRAILLE PATTERN DOTS-127 */,
+ braille_dots_37 = 0x1002844 /* U+2844 BRAILLE PATTERN DOTS-37 */,
+ braille_dots_137 = 0x1002845 /* U+2845 BRAILLE PATTERN DOTS-137 */,
+ braille_dots_237 = 0x1002846 /* U+2846 BRAILLE PATTERN DOTS-237 */,
+ braille_dots_1237 = 0x1002847 /* U+2847 BRAILLE PATTERN DOTS-1237 */,
+ braille_dots_47 = 0x1002848 /* U+2848 BRAILLE PATTERN DOTS-47 */,
+ braille_dots_147 = 0x1002849 /* U+2849 BRAILLE PATTERN DOTS-147 */,
+ braille_dots_247 = 0x100284a /* U+284a BRAILLE PATTERN DOTS-247 */,
+ braille_dots_1247 = 0x100284b /* U+284b BRAILLE PATTERN DOTS-1247 */,
+ braille_dots_347 = 0x100284c /* U+284c BRAILLE PATTERN DOTS-347 */,
+ braille_dots_1347 = 0x100284d /* U+284d BRAILLE PATTERN DOTS-1347 */,
+ braille_dots_2347 = 0x100284e /* U+284e BRAILLE PATTERN DOTS-2347 */,
+ braille_dots_12347 = 0x100284f /* U+284f BRAILLE PATTERN DOTS-12347 */,
+ braille_dots_57 = 0x1002850 /* U+2850 BRAILLE PATTERN DOTS-57 */,
+ braille_dots_157 = 0x1002851 /* U+2851 BRAILLE PATTERN DOTS-157 */,
+ braille_dots_257 = 0x1002852 /* U+2852 BRAILLE PATTERN DOTS-257 */,
+ braille_dots_1257 = 0x1002853 /* U+2853 BRAILLE PATTERN DOTS-1257 */,
+ braille_dots_357 = 0x1002854 /* U+2854 BRAILLE PATTERN DOTS-357 */,
+ braille_dots_1357 = 0x1002855 /* U+2855 BRAILLE PATTERN DOTS-1357 */,
+ braille_dots_2357 = 0x1002856 /* U+2856 BRAILLE PATTERN DOTS-2357 */,
+ braille_dots_12357 = 0x1002857 /* U+2857 BRAILLE PATTERN DOTS-12357 */,
+ braille_dots_457 = 0x1002858 /* U+2858 BRAILLE PATTERN DOTS-457 */,
+ braille_dots_1457 = 0x1002859 /* U+2859 BRAILLE PATTERN DOTS-1457 */,
+ braille_dots_2457 = 0x100285a /* U+285a BRAILLE PATTERN DOTS-2457 */,
+ braille_dots_12457 = 0x100285b /* U+285b BRAILLE PATTERN DOTS-12457 */,
+ braille_dots_3457 = 0x100285c /* U+285c BRAILLE PATTERN DOTS-3457 */,
+ braille_dots_13457 = 0x100285d /* U+285d BRAILLE PATTERN DOTS-13457 */,
+ braille_dots_23457 = 0x100285e /* U+285e BRAILLE PATTERN DOTS-23457 */,
+ braille_dots_123457 = 0x100285f /* U+285f BRAILLE PATTERN DOTS-123457 */,
+ braille_dots_67 = 0x1002860 /* U+2860 BRAILLE PATTERN DOTS-67 */,
+ braille_dots_167 = 0x1002861 /* U+2861 BRAILLE PATTERN DOTS-167 */,
+ braille_dots_267 = 0x1002862 /* U+2862 BRAILLE PATTERN DOTS-267 */,
+ braille_dots_1267 = 0x1002863 /* U+2863 BRAILLE PATTERN DOTS-1267 */,
+ braille_dots_367 = 0x1002864 /* U+2864 BRAILLE PATTERN DOTS-367 */,
+ braille_dots_1367 = 0x1002865 /* U+2865 BRAILLE PATTERN DOTS-1367 */,
+ braille_dots_2367 = 0x1002866 /* U+2866 BRAILLE PATTERN DOTS-2367 */,
+ braille_dots_12367 = 0x1002867 /* U+2867 BRAILLE PATTERN DOTS-12367 */,
+ braille_dots_467 = 0x1002868 /* U+2868 BRAILLE PATTERN DOTS-467 */,
+ braille_dots_1467 = 0x1002869 /* U+2869 BRAILLE PATTERN DOTS-1467 */,
+ braille_dots_2467 = 0x100286a /* U+286a BRAILLE PATTERN DOTS-2467 */,
+ braille_dots_12467 = 0x100286b /* U+286b BRAILLE PATTERN DOTS-12467 */,
+ braille_dots_3467 = 0x100286c /* U+286c BRAILLE PATTERN DOTS-3467 */,
+ braille_dots_13467 = 0x100286d /* U+286d BRAILLE PATTERN DOTS-13467 */,
+ braille_dots_23467 = 0x100286e /* U+286e BRAILLE PATTERN DOTS-23467 */,
+ braille_dots_123467 = 0x100286f /* U+286f BRAILLE PATTERN DOTS-123467 */,
+ braille_dots_567 = 0x1002870 /* U+2870 BRAILLE PATTERN DOTS-567 */,
+ braille_dots_1567 = 0x1002871 /* U+2871 BRAILLE PATTERN DOTS-1567 */,
+ braille_dots_2567 = 0x1002872 /* U+2872 BRAILLE PATTERN DOTS-2567 */,
+ braille_dots_12567 = 0x1002873 /* U+2873 BRAILLE PATTERN DOTS-12567 */,
+ braille_dots_3567 = 0x1002874 /* U+2874 BRAILLE PATTERN DOTS-3567 */,
+ braille_dots_13567 = 0x1002875 /* U+2875 BRAILLE PATTERN DOTS-13567 */,
+ braille_dots_23567 = 0x1002876 /* U+2876 BRAILLE PATTERN DOTS-23567 */,
+ braille_dots_123567 = 0x1002877 /* U+2877 BRAILLE PATTERN DOTS-123567 */,
+ braille_dots_4567 = 0x1002878 /* U+2878 BRAILLE PATTERN DOTS-4567 */,
+ braille_dots_14567 = 0x1002879 /* U+2879 BRAILLE PATTERN DOTS-14567 */,
+ braille_dots_24567 = 0x100287a /* U+287a BRAILLE PATTERN DOTS-24567 */,
+ braille_dots_124567 = 0x100287b /* U+287b BRAILLE PATTERN DOTS-124567 */,
+ braille_dots_34567 = 0x100287c /* U+287c BRAILLE PATTERN DOTS-34567 */,
+ braille_dots_134567 = 0x100287d /* U+287d BRAILLE PATTERN DOTS-134567 */,
+ braille_dots_234567 = 0x100287e /* U+287e BRAILLE PATTERN DOTS-234567 */,
+ braille_dots_1234567 = 0x100287f /* U+287f BRAILLE PATTERN DOTS-1234567 */,
+ braille_dots_8 = 0x1002880 /* U+2880 BRAILLE PATTERN DOTS-8 */,
+ braille_dots_18 = 0x1002881 /* U+2881 BRAILLE PATTERN DOTS-18 */,
+ braille_dots_28 = 0x1002882 /* U+2882 BRAILLE PATTERN DOTS-28 */,
+ braille_dots_128 = 0x1002883 /* U+2883 BRAILLE PATTERN DOTS-128 */,
+ braille_dots_38 = 0x1002884 /* U+2884 BRAILLE PATTERN DOTS-38 */,
+ braille_dots_138 = 0x1002885 /* U+2885 BRAILLE PATTERN DOTS-138 */,
+ braille_dots_238 = 0x1002886 /* U+2886 BRAILLE PATTERN DOTS-238 */,
+ braille_dots_1238 = 0x1002887 /* U+2887 BRAILLE PATTERN DOTS-1238 */,
+ braille_dots_48 = 0x1002888 /* U+2888 BRAILLE PATTERN DOTS-48 */,
+ braille_dots_148 = 0x1002889 /* U+2889 BRAILLE PATTERN DOTS-148 */,
+ braille_dots_248 = 0x100288a /* U+288a BRAILLE PATTERN DOTS-248 */,
+ braille_dots_1248 = 0x100288b /* U+288b BRAILLE PATTERN DOTS-1248 */,
+ braille_dots_348 = 0x100288c /* U+288c BRAILLE PATTERN DOTS-348 */,
+ braille_dots_1348 = 0x100288d /* U+288d BRAILLE PATTERN DOTS-1348 */,
+ braille_dots_2348 = 0x100288e /* U+288e BRAILLE PATTERN DOTS-2348 */,
+ braille_dots_12348 = 0x100288f /* U+288f BRAILLE PATTERN DOTS-12348 */,
+ braille_dots_58 = 0x1002890 /* U+2890 BRAILLE PATTERN DOTS-58 */,
+ braille_dots_158 = 0x1002891 /* U+2891 BRAILLE PATTERN DOTS-158 */,
+ braille_dots_258 = 0x1002892 /* U+2892 BRAILLE PATTERN DOTS-258 */,
+ braille_dots_1258 = 0x1002893 /* U+2893 BRAILLE PATTERN DOTS-1258 */,
+ braille_dots_358 = 0x1002894 /* U+2894 BRAILLE PATTERN DOTS-358 */,
+ braille_dots_1358 = 0x1002895 /* U+2895 BRAILLE PATTERN DOTS-1358 */,
+ braille_dots_2358 = 0x1002896 /* U+2896 BRAILLE PATTERN DOTS-2358 */,
+ braille_dots_12358 = 0x1002897 /* U+2897 BRAILLE PATTERN DOTS-12358 */,
+ braille_dots_458 = 0x1002898 /* U+2898 BRAILLE PATTERN DOTS-458 */,
+ braille_dots_1458 = 0x1002899 /* U+2899 BRAILLE PATTERN DOTS-1458 */,
+ braille_dots_2458 = 0x100289a /* U+289a BRAILLE PATTERN DOTS-2458 */,
+ braille_dots_12458 = 0x100289b /* U+289b BRAILLE PATTERN DOTS-12458 */,
+ braille_dots_3458 = 0x100289c /* U+289c BRAILLE PATTERN DOTS-3458 */,
+ braille_dots_13458 = 0x100289d /* U+289d BRAILLE PATTERN DOTS-13458 */,
+ braille_dots_23458 = 0x100289e /* U+289e BRAILLE PATTERN DOTS-23458 */,
+ braille_dots_123458 = 0x100289f /* U+289f BRAILLE PATTERN DOTS-123458 */,
+ braille_dots_68 = 0x10028a0 /* U+28a0 BRAILLE PATTERN DOTS-68 */,
+ braille_dots_168 = 0x10028a1 /* U+28a1 BRAILLE PATTERN DOTS-168 */,
+ braille_dots_268 = 0x10028a2 /* U+28a2 BRAILLE PATTERN DOTS-268 */,
+ braille_dots_1268 = 0x10028a3 /* U+28a3 BRAILLE PATTERN DOTS-1268 */,
+ braille_dots_368 = 0x10028a4 /* U+28a4 BRAILLE PATTERN DOTS-368 */,
+ braille_dots_1368 = 0x10028a5 /* U+28a5 BRAILLE PATTERN DOTS-1368 */,
+ braille_dots_2368 = 0x10028a6 /* U+28a6 BRAILLE PATTERN DOTS-2368 */,
+ braille_dots_12368 = 0x10028a7 /* U+28a7 BRAILLE PATTERN DOTS-12368 */,
+ braille_dots_468 = 0x10028a8 /* U+28a8 BRAILLE PATTERN DOTS-468 */,
+ braille_dots_1468 = 0x10028a9 /* U+28a9 BRAILLE PATTERN DOTS-1468 */,
+ braille_dots_2468 = 0x10028aa /* U+28aa BRAILLE PATTERN DOTS-2468 */,
+ braille_dots_12468 = 0x10028ab /* U+28ab BRAILLE PATTERN DOTS-12468 */,
+ braille_dots_3468 = 0x10028ac /* U+28ac BRAILLE PATTERN DOTS-3468 */,
+ braille_dots_13468 = 0x10028ad /* U+28ad BRAILLE PATTERN DOTS-13468 */,
+ braille_dots_23468 = 0x10028ae /* U+28ae BRAILLE PATTERN DOTS-23468 */,
+ braille_dots_123468 = 0x10028af /* U+28af BRAILLE PATTERN DOTS-123468 */,
+ braille_dots_568 = 0x10028b0 /* U+28b0 BRAILLE PATTERN DOTS-568 */,
+ braille_dots_1568 = 0x10028b1 /* U+28b1 BRAILLE PATTERN DOTS-1568 */,
+ braille_dots_2568 = 0x10028b2 /* U+28b2 BRAILLE PATTERN DOTS-2568 */,
+ braille_dots_12568 = 0x10028b3 /* U+28b3 BRAILLE PATTERN DOTS-12568 */,
+ braille_dots_3568 = 0x10028b4 /* U+28b4 BRAILLE PATTERN DOTS-3568 */,
+ braille_dots_13568 = 0x10028b5 /* U+28b5 BRAILLE PATTERN DOTS-13568 */,
+ braille_dots_23568 = 0x10028b6 /* U+28b6 BRAILLE PATTERN DOTS-23568 */,
+ braille_dots_123568 = 0x10028b7 /* U+28b7 BRAILLE PATTERN DOTS-123568 */,
+ braille_dots_4568 = 0x10028b8 /* U+28b8 BRAILLE PATTERN DOTS-4568 */,
+ braille_dots_14568 = 0x10028b9 /* U+28b9 BRAILLE PATTERN DOTS-14568 */,
+ braille_dots_24568 = 0x10028ba /* U+28ba BRAILLE PATTERN DOTS-24568 */,
+ braille_dots_124568 = 0x10028bb /* U+28bb BRAILLE PATTERN DOTS-124568 */,
+ braille_dots_34568 = 0x10028bc /* U+28bc BRAILLE PATTERN DOTS-34568 */,
+ braille_dots_134568 = 0x10028bd /* U+28bd BRAILLE PATTERN DOTS-134568 */,
+ braille_dots_234568 = 0x10028be /* U+28be BRAILLE PATTERN DOTS-234568 */,
+ braille_dots_1234568 = 0x10028bf /* U+28bf BRAILLE PATTERN DOTS-1234568 */,
+ braille_dots_78 = 0x10028c0 /* U+28c0 BRAILLE PATTERN DOTS-78 */,
+ braille_dots_178 = 0x10028c1 /* U+28c1 BRAILLE PATTERN DOTS-178 */,
+ braille_dots_278 = 0x10028c2 /* U+28c2 BRAILLE PATTERN DOTS-278 */,
+ braille_dots_1278 = 0x10028c3 /* U+28c3 BRAILLE PATTERN DOTS-1278 */,
+ braille_dots_378 = 0x10028c4 /* U+28c4 BRAILLE PATTERN DOTS-378 */,
+ braille_dots_1378 = 0x10028c5 /* U+28c5 BRAILLE PATTERN DOTS-1378 */,
+ braille_dots_2378 = 0x10028c6 /* U+28c6 BRAILLE PATTERN DOTS-2378 */,
+ braille_dots_12378 = 0x10028c7 /* U+28c7 BRAILLE PATTERN DOTS-12378 */,
+ braille_dots_478 = 0x10028c8 /* U+28c8 BRAILLE PATTERN DOTS-478 */,
+ braille_dots_1478 = 0x10028c9 /* U+28c9 BRAILLE PATTERN DOTS-1478 */,
+ braille_dots_2478 = 0x10028ca /* U+28ca BRAILLE PATTERN DOTS-2478 */,
+ braille_dots_12478 = 0x10028cb /* U+28cb BRAILLE PATTERN DOTS-12478 */,
+ braille_dots_3478 = 0x10028cc /* U+28cc BRAILLE PATTERN DOTS-3478 */,
+ braille_dots_13478 = 0x10028cd /* U+28cd BRAILLE PATTERN DOTS-13478 */,
+ braille_dots_23478 = 0x10028ce /* U+28ce BRAILLE PATTERN DOTS-23478 */,
+ braille_dots_123478 = 0x10028cf /* U+28cf BRAILLE PATTERN DOTS-123478 */,
+ braille_dots_578 = 0x10028d0 /* U+28d0 BRAILLE PATTERN DOTS-578 */,
+ braille_dots_1578 = 0x10028d1 /* U+28d1 BRAILLE PATTERN DOTS-1578 */,
+ braille_dots_2578 = 0x10028d2 /* U+28d2 BRAILLE PATTERN DOTS-2578 */,
+ braille_dots_12578 = 0x10028d3 /* U+28d3 BRAILLE PATTERN DOTS-12578 */,
+ braille_dots_3578 = 0x10028d4 /* U+28d4 BRAILLE PATTERN DOTS-3578 */,
+ braille_dots_13578 = 0x10028d5 /* U+28d5 BRAILLE PATTERN DOTS-13578 */,
+ braille_dots_23578 = 0x10028d6 /* U+28d6 BRAILLE PATTERN DOTS-23578 */,
+ braille_dots_123578 = 0x10028d7 /* U+28d7 BRAILLE PATTERN DOTS-123578 */,
+ braille_dots_4578 = 0x10028d8 /* U+28d8 BRAILLE PATTERN DOTS-4578 */,
+ braille_dots_14578 = 0x10028d9 /* U+28d9 BRAILLE PATTERN DOTS-14578 */,
+ braille_dots_24578 = 0x10028da /* U+28da BRAILLE PATTERN DOTS-24578 */,
+ braille_dots_124578 = 0x10028db /* U+28db BRAILLE PATTERN DOTS-124578 */,
+ braille_dots_34578 = 0x10028dc /* U+28dc BRAILLE PATTERN DOTS-34578 */,
+ braille_dots_134578 = 0x10028dd /* U+28dd BRAILLE PATTERN DOTS-134578 */,
+ braille_dots_234578 = 0x10028de /* U+28de BRAILLE PATTERN DOTS-234578 */,
+ braille_dots_1234578 = 0x10028df /* U+28df BRAILLE PATTERN DOTS-1234578 */,
+ braille_dots_678 = 0x10028e0 /* U+28e0 BRAILLE PATTERN DOTS-678 */,
+ braille_dots_1678 = 0x10028e1 /* U+28e1 BRAILLE PATTERN DOTS-1678 */,
+ braille_dots_2678 = 0x10028e2 /* U+28e2 BRAILLE PATTERN DOTS-2678 */,
+ braille_dots_12678 = 0x10028e3 /* U+28e3 BRAILLE PATTERN DOTS-12678 */,
+ braille_dots_3678 = 0x10028e4 /* U+28e4 BRAILLE PATTERN DOTS-3678 */,
+ braille_dots_13678 = 0x10028e5 /* U+28e5 BRAILLE PATTERN DOTS-13678 */,
+ braille_dots_23678 = 0x10028e6 /* U+28e6 BRAILLE PATTERN DOTS-23678 */,
+ braille_dots_123678 = 0x10028e7 /* U+28e7 BRAILLE PATTERN DOTS-123678 */,
+ braille_dots_4678 = 0x10028e8 /* U+28e8 BRAILLE PATTERN DOTS-4678 */,
+ braille_dots_14678 = 0x10028e9 /* U+28e9 BRAILLE PATTERN DOTS-14678 */,
+ braille_dots_24678 = 0x10028ea /* U+28ea BRAILLE PATTERN DOTS-24678 */,
+ braille_dots_124678 = 0x10028eb /* U+28eb BRAILLE PATTERN DOTS-124678 */,
+ braille_dots_34678 = 0x10028ec /* U+28ec BRAILLE PATTERN DOTS-34678 */,
+ braille_dots_134678 = 0x10028ed /* U+28ed BRAILLE PATTERN DOTS-134678 */,
+ braille_dots_234678 = 0x10028ee /* U+28ee BRAILLE PATTERN DOTS-234678 */,
+ braille_dots_1234678 = 0x10028ef /* U+28ef BRAILLE PATTERN DOTS-1234678 */,
+ braille_dots_5678 = 0x10028f0 /* U+28f0 BRAILLE PATTERN DOTS-5678 */,
+ braille_dots_15678 = 0x10028f1 /* U+28f1 BRAILLE PATTERN DOTS-15678 */,
+ braille_dots_25678 = 0x10028f2 /* U+28f2 BRAILLE PATTERN DOTS-25678 */,
+ braille_dots_125678 = 0x10028f3 /* U+28f3 BRAILLE PATTERN DOTS-125678 */,
+ braille_dots_35678 = 0x10028f4 /* U+28f4 BRAILLE PATTERN DOTS-35678 */,
+ braille_dots_135678 = 0x10028f5 /* U+28f5 BRAILLE PATTERN DOTS-135678 */,
+ braille_dots_235678 = 0x10028f6 /* U+28f6 BRAILLE PATTERN DOTS-235678 */,
+ braille_dots_1235678 = 0x10028f7 /* U+28f7 BRAILLE PATTERN DOTS-1235678 */,
+ braille_dots_45678 = 0x10028f8 /* U+28f8 BRAILLE PATTERN DOTS-45678 */,
+ braille_dots_145678 = 0x10028f9 /* U+28f9 BRAILLE PATTERN DOTS-145678 */,
+ braille_dots_245678 = 0x10028fa /* U+28fa BRAILLE PATTERN DOTS-245678 */,
+ braille_dots_1245678 = 0x10028fb /* U+28fb BRAILLE PATTERN DOTS-1245678 */,
+ braille_dots_345678 = 0x10028fc /* U+28fc BRAILLE PATTERN DOTS-345678 */,
+ braille_dots_1345678 = 0x10028fd /* U+28fd BRAILLE PATTERN DOTS-1345678 */,
+ braille_dots_2345678 = 0x10028fe /* U+28fe BRAILLE PATTERN DOTS-2345678 */,
+ braille_dots_12345678 = 0x10028ff /* U+28ff BRAILLE PATTERN DOTS-12345678 */,
+ Sinh_ng = 0x1000d82 /* U+0D82 SINHALA ANUSVARAYA */,
+ Sinh_h2 = 0x1000d83 /* U+0D83 SINHALA VISARGAYA */,
+ Sinh_a = 0x1000d85 /* U+0D85 SINHALA AYANNA */,
+ Sinh_aa = 0x1000d86 /* U+0D86 SINHALA AAYANNA */,
+ Sinh_ae = 0x1000d87 /* U+0D87 SINHALA AEYANNA */,
+ Sinh_aee = 0x1000d88 /* U+0D88 SINHALA AEEYANNA */,
+ Sinh_i = 0x1000d89 /* U+0D89 SINHALA IYANNA */,
+ Sinh_ii = 0x1000d8a /* U+0D8A SINHALA IIYANNA */,
+ Sinh_u = 0x1000d8b /* U+0D8B SINHALA UYANNA */,
+ Sinh_uu = 0x1000d8c /* U+0D8C SINHALA UUYANNA */,
+ Sinh_ri = 0x1000d8d /* U+0D8D SINHALA IRUYANNA */,
+ Sinh_rii = 0x1000d8e /* U+0D8E SINHALA IRUUYANNA */,
+ Sinh_lu = 0x1000d8f /* U+0D8F SINHALA ILUYANNA */,
+ Sinh_luu = 0x1000d90 /* U+0D90 SINHALA ILUUYANNA */,
+ Sinh_e = 0x1000d91 /* U+0D91 SINHALA EYANNA */,
+ Sinh_ee = 0x1000d92 /* U+0D92 SINHALA EEYANNA */,
+ Sinh_ai = 0x1000d93 /* U+0D93 SINHALA AIYANNA */,
+ Sinh_o = 0x1000d94 /* U+0D94 SINHALA OYANNA */,
+ Sinh_oo = 0x1000d95 /* U+0D95 SINHALA OOYANNA */,
+ Sinh_au = 0x1000d96 /* U+0D96 SINHALA AUYANNA */,
+ Sinh_ka = 0x1000d9a /* U+0D9A SINHALA KAYANNA */,
+ Sinh_kha = 0x1000d9b /* U+0D9B SINHALA MAHA. KAYANNA */,
+ Sinh_ga = 0x1000d9c /* U+0D9C SINHALA GAYANNA */,
+ Sinh_gha = 0x1000d9d /* U+0D9D SINHALA MAHA. GAYANNA */,
+ Sinh_ng2 = 0x1000d9e /* U+0D9E SINHALA KANTAJA NAASIKYAYA */,
+ Sinh_nga = 0x1000d9f /* U+0D9F SINHALA SANYAKA GAYANNA */,
+ Sinh_ca = 0x1000da0 /* U+0DA0 SINHALA CAYANNA */,
+ Sinh_cha = 0x1000da1 /* U+0DA1 SINHALA MAHA. CAYANNA */,
+ Sinh_ja = 0x1000da2 /* U+0DA2 SINHALA JAYANNA */,
+ Sinh_jha = 0x1000da3 /* U+0DA3 SINHALA MAHA. JAYANNA */,
+ Sinh_nya = 0x1000da4 /* U+0DA4 SINHALA TAALUJA NAASIKYAYA */,
+ Sinh_jnya = 0x1000da5 /* U+0DA5 SINHALA TAALUJA SANYOOGA NAASIKYAYA */,
+ Sinh_nja = 0x1000da6 /* U+0DA6 SINHALA SANYAKA JAYANNA */,
+ Sinh_tta = 0x1000da7 /* U+0DA7 SINHALA TTAYANNA */,
+ Sinh_ttha = 0x1000da8 /* U+0DA8 SINHALA MAHA. TTAYANNA */,
+ Sinh_dda = 0x1000da9 /* U+0DA9 SINHALA DDAYANNA */,
+ Sinh_ddha = 0x1000daa /* U+0DAA SINHALA MAHA. DDAYANNA */,
+ Sinh_nna = 0x1000dab /* U+0DAB SINHALA MUURDHAJA NAYANNA */,
+ Sinh_ndda = 0x1000dac /* U+0DAC SINHALA SANYAKA DDAYANNA */,
+ Sinh_tha = 0x1000dad /* U+0DAD SINHALA TAYANNA */,
+ Sinh_thha = 0x1000dae /* U+0DAE SINHALA MAHA. TAYANNA */,
+ Sinh_dha = 0x1000daf /* U+0DAF SINHALA DAYANNA */,
+ Sinh_dhha = 0x1000db0 /* U+0DB0 SINHALA MAHA. DAYANNA */,
+ Sinh_na = 0x1000db1 /* U+0DB1 SINHALA DANTAJA NAYANNA */,
+ Sinh_ndha = 0x1000db3 /* U+0DB3 SINHALA SANYAKA DAYANNA */,
+ Sinh_pa = 0x1000db4 /* U+0DB4 SINHALA PAYANNA */,
+ Sinh_pha = 0x1000db5 /* U+0DB5 SINHALA MAHA. PAYANNA */,
+ Sinh_ba = 0x1000db6 /* U+0DB6 SINHALA BAYANNA */,
+ Sinh_bha = 0x1000db7 /* U+0DB7 SINHALA MAHA. BAYANNA */,
+ Sinh_ma = 0x1000db8 /* U+0DB8 SINHALA MAYANNA */,
+ Sinh_mba = 0x1000db9 /* U+0DB9 SINHALA AMBA BAYANNA */,
+ Sinh_ya = 0x1000dba /* U+0DBA SINHALA YAYANNA */,
+ Sinh_ra = 0x1000dbb /* U+0DBB SINHALA RAYANNA */,
+ Sinh_la = 0x1000dbd /* U+0DBD SINHALA DANTAJA LAYANNA */,
+ Sinh_va = 0x1000dc0 /* U+0DC0 SINHALA VAYANNA */,
+ Sinh_sha = 0x1000dc1 /* U+0DC1 SINHALA TAALUJA SAYANNA */,
+ Sinh_ssha = 0x1000dc2 /* U+0DC2 SINHALA MUURDHAJA SAYANNA */,
+ Sinh_sa = 0x1000dc3 /* U+0DC3 SINHALA DANTAJA SAYANNA */,
+ Sinh_ha = 0x1000dc4 /* U+0DC4 SINHALA HAYANNA */,
+ Sinh_lla = 0x1000dc5 /* U+0DC5 SINHALA MUURDHAJA LAYANNA */,
+ Sinh_fa = 0x1000dc6 /* U+0DC6 SINHALA FAYANNA */,
+ Sinh_al = 0x1000dca /* U+0DCA SINHALA AL-LAKUNA */,
+ Sinh_aa2 = 0x1000dcf /* U+0DCF SINHALA AELA-PILLA */,
+ Sinh_ae2 = 0x1000dd0 /* U+0DD0 SINHALA AEDA-PILLA */,
+ Sinh_aee2 = 0x1000dd1 /* U+0DD1 SINHALA DIGA AEDA-PILLA */,
+ Sinh_i2 = 0x1000dd2 /* U+0DD2 SINHALA IS-PILLA */,
+ Sinh_ii2 = 0x1000dd3 /* U+0DD3 SINHALA DIGA IS-PILLA */,
+ Sinh_u2 = 0x1000dd4 /* U+0DD4 SINHALA PAA-PILLA */,
+ Sinh_uu2 = 0x1000dd6 /* U+0DD6 SINHALA DIGA PAA-PILLA */,
+ Sinh_ru2 = 0x1000dd8 /* U+0DD8 SINHALA GAETTA-PILLA */,
+ Sinh_e2 = 0x1000dd9 /* U+0DD9 SINHALA KOMBUVA */,
+ Sinh_ee2 = 0x1000dda /* U+0DDA SINHALA DIGA KOMBUVA */,
+ Sinh_ai2 = 0x1000ddb /* U+0DDB SINHALA KOMBU DEKA */,
+ Sinh_o2 = 0x1000ddc /* U+0DDC SINHALA KOMBUVA HAA AELA-PILLA*/,
+ Sinh_oo2 = 0x1000ddd /* U+0DDD SINHALA KOMBUVA HAA DIGA AELA-PILLA*/,
+ Sinh_au2 = 0x1000dde /* U+0DDE SINHALA KOMBUVA HAA GAYANUKITTA */,
+ Sinh_lu2 = 0x1000ddf /* U+0DDF SINHALA GAYANUKITTA */,
+ Sinh_ruu2 = 0x1000df2 /* U+0DF2 SINHALA DIGA GAETTA-PILLA */,
+ Sinh_luu2 = 0x1000df3 /* U+0DF3 SINHALA DIGA GAYANUKITTA */,
+ Sinh_kunddaliya = 0x1000df4 /* U+0DF4 SINHALA KUNDDALIYA */
+ }
+}
diff --git a/src/Avalonia.X11/Stubs.cs b/src/Avalonia.X11/Stubs.cs
new file mode 100644
index 0000000000..ec694ba9a8
--- /dev/null
+++ b/src/Avalonia.X11/Stubs.cs
@@ -0,0 +1,17 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Platform;
+
+namespace Avalonia.X11
+{
+ class PlatformSettingsStub : IPlatformSettings
+ {
+ public Size DoubleClickSize { get; } = new Size(2, 2);
+ public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500);
+ }
+}
diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs
new file mode 100644
index 0000000000..db74a32b99
--- /dev/null
+++ b/src/Avalonia.X11/X11Atoms.cs
@@ -0,0 +1,207 @@
+// 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.
+//
+// Copyright (c) 2006 Novell, Inc. (http://www.novell.com)
+//
+//
+
+using System;
+using System.Linq;
+using static Avalonia.X11.XLib;
+// ReSharper disable FieldCanBeMadeReadOnly.Global
+// ReSharper disable IdentifierTypo
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
+// ReSharper disable CommentTypo
+// ReSharper disable ArrangeThisQualifier
+// ReSharper disable NotAccessedField.Global
+// ReSharper disable InconsistentNaming
+// ReSharper disable StringLiteralTypo
+#pragma warning disable 649
+
+namespace Avalonia.X11
+{
+
+ internal class X11Atoms
+ {
+
+// Our atoms
+ public readonly IntPtr AnyPropertyType = (IntPtr)0;
+ public readonly IntPtr XA_PRIMARY = (IntPtr)1;
+ public readonly IntPtr XA_SECONDARY = (IntPtr)2;
+ public readonly IntPtr XA_ARC = (IntPtr)3;
+ public readonly IntPtr XA_ATOM = (IntPtr)4;
+ public readonly IntPtr XA_BITMAP = (IntPtr)5;
+ public readonly IntPtr XA_CARDINAL = (IntPtr)6;
+ public readonly IntPtr XA_COLORMAP = (IntPtr)7;
+ public readonly IntPtr XA_CURSOR = (IntPtr)8;
+ public readonly IntPtr XA_CUT_BUFFER0 = (IntPtr)9;
+ public readonly IntPtr XA_CUT_BUFFER1 = (IntPtr)10;
+ public readonly IntPtr XA_CUT_BUFFER2 = (IntPtr)11;
+ public readonly IntPtr XA_CUT_BUFFER3 = (IntPtr)12;
+ public readonly IntPtr XA_CUT_BUFFER4 = (IntPtr)13;
+ public readonly IntPtr XA_CUT_BUFFER5 = (IntPtr)14;
+ public readonly IntPtr XA_CUT_BUFFER6 = (IntPtr)15;
+ public readonly IntPtr XA_CUT_BUFFER7 = (IntPtr)16;
+ public readonly IntPtr XA_DRAWABLE = (IntPtr)17;
+ public readonly IntPtr XA_FONT = (IntPtr)18;
+ public readonly IntPtr XA_INTEGER = (IntPtr)19;
+ public readonly IntPtr XA_PIXMAP = (IntPtr)20;
+ public readonly IntPtr XA_POINT = (IntPtr)21;
+ public readonly IntPtr XA_RECTANGLE = (IntPtr)22;
+ public readonly IntPtr XA_RESOURCE_MANAGER = (IntPtr)23;
+ public readonly IntPtr XA_RGB_COLOR_MAP = (IntPtr)24;
+ public readonly IntPtr XA_RGB_BEST_MAP = (IntPtr)25;
+ public readonly IntPtr XA_RGB_BLUE_MAP = (IntPtr)26;
+ public readonly IntPtr XA_RGB_DEFAULT_MAP = (IntPtr)27;
+ public readonly IntPtr XA_RGB_GRAY_MAP = (IntPtr)28;
+ public readonly IntPtr XA_RGB_GREEN_MAP = (IntPtr)29;
+ public readonly IntPtr XA_RGB_RED_MAP = (IntPtr)30;
+ public readonly IntPtr XA_STRING = (IntPtr)31;
+ public readonly IntPtr XA_VISUALID = (IntPtr)32;
+ public readonly IntPtr XA_WINDOW = (IntPtr)33;
+ public readonly IntPtr XA_WM_COMMAND = (IntPtr)34;
+ public readonly IntPtr XA_WM_HINTS = (IntPtr)35;
+ public readonly IntPtr XA_WM_CLIENT_MACHINE = (IntPtr)36;
+ public readonly IntPtr XA_WM_ICON_NAME = (IntPtr)37;
+ public readonly IntPtr XA_WM_ICON_SIZE = (IntPtr)38;
+ public readonly IntPtr XA_WM_NAME = (IntPtr)39;
+ public readonly IntPtr XA_WM_NORMAL_HINTS = (IntPtr)40;
+ public readonly IntPtr XA_WM_SIZE_HINTS = (IntPtr)41;
+ public readonly IntPtr XA_WM_ZOOM_HINTS = (IntPtr)42;
+ public readonly IntPtr XA_MIN_SPACE = (IntPtr)43;
+ public readonly IntPtr XA_NORM_SPACE = (IntPtr)44;
+ public readonly IntPtr XA_MAX_SPACE = (IntPtr)45;
+ public readonly IntPtr XA_END_SPACE = (IntPtr)46;
+ public readonly IntPtr XA_SUPERSCRIPT_X = (IntPtr)47;
+ public readonly IntPtr XA_SUPERSCRIPT_Y = (IntPtr)48;
+ public readonly IntPtr XA_SUBSCRIPT_X = (IntPtr)49;
+ public readonly IntPtr XA_SUBSCRIPT_Y = (IntPtr)50;
+ public readonly IntPtr XA_UNDERLINE_POSITION = (IntPtr)51;
+ public readonly IntPtr XA_UNDERLINE_THICKNESS = (IntPtr)52;
+ public readonly IntPtr XA_STRIKEOUT_ASCENT = (IntPtr)53;
+ public readonly IntPtr XA_STRIKEOUT_DESCENT = (IntPtr)54;
+ public readonly IntPtr XA_ITALIC_ANGLE = (IntPtr)55;
+ public readonly IntPtr XA_X_HEIGHT = (IntPtr)56;
+ public readonly IntPtr XA_QUAD_WIDTH = (IntPtr)57;
+ public readonly IntPtr XA_WEIGHT = (IntPtr)58;
+ public readonly IntPtr XA_POINT_SIZE = (IntPtr)59;
+ public readonly IntPtr XA_RESOLUTION = (IntPtr)60;
+ public readonly IntPtr XA_COPYRIGHT = (IntPtr)61;
+ public readonly IntPtr XA_NOTICE = (IntPtr)62;
+ public readonly IntPtr XA_FONT_NAME = (IntPtr)63;
+ public readonly IntPtr XA_FAMILY_NAME = (IntPtr)64;
+ public readonly IntPtr XA_FULL_NAME = (IntPtr)65;
+ public readonly IntPtr XA_CAP_HEIGHT = (IntPtr)66;
+ public readonly IntPtr XA_WM_CLASS = (IntPtr)67;
+ public readonly IntPtr XA_WM_TRANSIENT_FOR = (IntPtr)68;
+
+ public readonly IntPtr WM_PROTOCOLS;
+ public readonly IntPtr WM_DELETE_WINDOW;
+ public readonly IntPtr WM_TAKE_FOCUS;
+ public readonly IntPtr _NET_SUPPORTED;
+ public readonly IntPtr _NET_CLIENT_LIST;
+ public readonly IntPtr _NET_NUMBER_OF_DESKTOPS;
+ public readonly IntPtr _NET_DESKTOP_GEOMETRY;
+ public readonly IntPtr _NET_DESKTOP_VIEWPORT;
+ public readonly IntPtr _NET_CURRENT_DESKTOP;
+ public readonly IntPtr _NET_DESKTOP_NAMES;
+ public readonly IntPtr _NET_ACTIVE_WINDOW;
+ public readonly IntPtr _NET_WORKAREA;
+ public readonly IntPtr _NET_SUPPORTING_WM_CHECK;
+ public readonly IntPtr _NET_VIRTUAL_ROOTS;
+ public readonly IntPtr _NET_DESKTOP_LAYOUT;
+ public readonly IntPtr _NET_SHOWING_DESKTOP;
+ public readonly IntPtr _NET_CLOSE_WINDOW;
+ public readonly IntPtr _NET_MOVERESIZE_WINDOW;
+ public readonly IntPtr _NET_WM_MOVERESIZE;
+ public readonly IntPtr _NET_RESTACK_WINDOW;
+ public readonly IntPtr _NET_REQUEST_FRAME_EXTENTS;
+ public readonly IntPtr _NET_WM_NAME;
+ public readonly IntPtr _NET_WM_VISIBLE_NAME;
+ public readonly IntPtr _NET_WM_ICON_NAME;
+ public readonly IntPtr _NET_WM_VISIBLE_ICON_NAME;
+ public readonly IntPtr _NET_WM_DESKTOP;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE;
+ public readonly IntPtr _NET_WM_STATE;
+ public readonly IntPtr _NET_WM_ALLOWED_ACTIONS;
+ public readonly IntPtr _NET_WM_STRUT;
+ public readonly IntPtr _NET_WM_STRUT_PARTIAL;
+ public readonly IntPtr _NET_WM_ICON_GEOMETRY;
+ public readonly IntPtr _NET_WM_ICON;
+ public readonly IntPtr _NET_WM_PID;
+ public readonly IntPtr _NET_WM_HANDLED_ICONS;
+ public readonly IntPtr _NET_WM_USER_TIME;
+ public readonly IntPtr _NET_FRAME_EXTENTS;
+ public readonly IntPtr _NET_WM_PING;
+ public readonly IntPtr _NET_WM_SYNC_REQUEST;
+ public readonly IntPtr _NET_SYSTEM_TRAY_S;
+ public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
+ public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE;
+ public readonly IntPtr _NET_WM_STATE_MAXIMIZED_HORZ;
+ public readonly IntPtr _NET_WM_STATE_MAXIMIZED_VERT;
+ public readonly IntPtr _XEMBED;
+ public readonly IntPtr _XEMBED_INFO;
+ public readonly IntPtr _MOTIF_WM_HINTS;
+ public readonly IntPtr _NET_WM_STATE_SKIP_TASKBAR;
+ public readonly IntPtr _NET_WM_STATE_ABOVE;
+ public readonly IntPtr _NET_WM_STATE_MODAL;
+ public readonly IntPtr _NET_WM_STATE_HIDDEN;
+ public readonly IntPtr _NET_WM_CONTEXT_HELP;
+ public readonly IntPtr _NET_WM_WINDOW_OPACITY;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_DESKTOP;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_DOCK;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_MENU;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
+ public readonly IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
+ public readonly IntPtr CLIPBOARD;
+ public readonly IntPtr CLIPBOARD_MANAGER;
+ public readonly IntPtr SAVE_TARGETS;
+ public readonly IntPtr MULTIPLE;
+ public readonly IntPtr PRIMARY;
+ public readonly IntPtr OEMTEXT;
+ public readonly IntPtr UNICODETEXT;
+ public readonly IntPtr TARGETS;
+ public readonly IntPtr UTF8_STRING;
+ public readonly IntPtr UTF16_STRING;
+ public readonly IntPtr ATOM_PAIR;
+
+
+ public X11Atoms(IntPtr display)
+ {
+
+ // make sure this array stays in sync with the statements below
+
+ var fields = typeof(X11Atoms).GetFields()
+ .Where(f => f.FieldType == typeof(IntPtr) && (IntPtr)f.GetValue(this) == IntPtr.Zero).ToArray();
+ var atomNames = fields.Select(f => f.Name).ToArray();
+
+ IntPtr[] atoms = new IntPtr [atomNames.Length];
+ ;
+
+ XInternAtoms(display, atomNames, atomNames.Length, true, atoms);
+
+ for (var c = 0; c < fields.Length; c++)
+ fields[c].SetValue(this, atoms[c]);
+ }
+ }
+}
diff --git a/src/Avalonia.X11/X11Clipboard.cs b/src/Avalonia.X11/X11Clipboard.cs
new file mode 100644
index 0000000000..cb9d3389e4
--- /dev/null
+++ b/src/Avalonia.X11/X11Clipboard.cs
@@ -0,0 +1,234 @@
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Input.Platform;
+using static Avalonia.X11.XLib;
+namespace Avalonia.X11
+{
+ class X11Clipboard : IClipboard
+ {
+ private readonly X11Info _x11;
+ private string _storedString;
+ private IntPtr _handle;
+ private TaskCompletionSource _requestedFormatsTcs;
+ private TaskCompletionSource _requestedTextTcs;
+ private readonly IntPtr[] _textAtoms;
+ private readonly IntPtr _avaloniaSaveTargetsAtom;
+
+ public X11Clipboard(AvaloniaX11Platform platform)
+ {
+ _x11 = platform.Info;
+ _handle = CreateEventWindow(platform, OnEvent);
+ _avaloniaSaveTargetsAtom = XInternAtom(_x11.Display, "AVALONIA_SAVE_TARGETS_PROPERTY_ATOM", false);
+ _textAtoms = new[]
+ {
+ _x11.Atoms.XA_STRING,
+ _x11.Atoms.OEMTEXT,
+ _x11.Atoms.UTF8_STRING,
+ _x11.Atoms.UTF16_STRING
+ }.Where(a => a != IntPtr.Zero).ToArray();
+ }
+
+ Encoding GetStringEncoding(IntPtr atom)
+ {
+ return (atom == _x11.Atoms.XA_STRING
+ || atom == _x11.Atoms.OEMTEXT)
+ ? Encoding.ASCII
+ : atom == _x11.Atoms.UTF8_STRING
+ ? Encoding.UTF8
+ : atom == _x11.Atoms.UTF16_STRING
+ ? Encoding.Unicode
+ : null;
+ }
+
+ private unsafe void OnEvent(XEvent ev)
+ {
+ if (ev.type == XEventName.SelectionRequest)
+ {
+ var sel = ev.SelectionRequestEvent;
+ var resp = new XEvent
+ {
+ SelectionEvent =
+ {
+ type = XEventName.SelectionNotify,
+ send_event = true,
+ display = _x11.Display,
+ selection = sel.selection,
+ target = sel.target,
+ requestor = sel.requestor,
+ time = sel.time,
+ property = IntPtr.Zero
+ }
+ };
+ if (sel.selection == _x11.Atoms.CLIPBOARD)
+ {
+ resp.SelectionEvent.property = WriteTargetToProperty(sel.target, sel.requestor, sel.property);
+ }
+
+ XSendEvent(_x11.Display, sel.requestor, false, new IntPtr((int)EventMask.NoEventMask), ref resp);
+ }
+
+ IntPtr WriteTargetToProperty(IntPtr target, IntPtr window, IntPtr property)
+ {
+ Encoding textEnc;
+ if (target == _x11.Atoms.TARGETS)
+ {
+ var atoms = _textAtoms;
+ atoms = atoms.Concat(new[] {_x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE})
+ .ToArray();
+ XChangeProperty(_x11.Display, window, property,
+ target, 32, PropertyMode.Replace, atoms, atoms.Length);
+ return property;
+ }
+ else if(target == _x11.Atoms.SAVE_TARGETS && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero)
+ {
+ return property;
+ }
+ else if ((textEnc = GetStringEncoding(target)) != null)
+ {
+
+ var data = textEnc.GetBytes(_storedString ?? "");
+ fixed (void* pdata = data)
+ XChangeProperty(_x11.Display, window, property, target, 8,
+ PropertyMode.Replace,
+ pdata, data.Length);
+ return property;
+ }
+ else if (target == _x11.Atoms.MULTIPLE && _x11.Atoms.MULTIPLE != IntPtr.Zero)
+ {
+ XGetWindowProperty(_x11.Display, window, property, IntPtr.Zero, new IntPtr(0x7fffffff), false,
+ _x11.Atoms.ATOM_PAIR, out _, out var actualFormat, out var nitems, out _, out var prop);
+ if (nitems == IntPtr.Zero)
+ return IntPtr.Zero;
+ if (actualFormat == 32)
+ {
+ var data = (IntPtr*)prop.ToPointer();
+ for (var c = 0; c < nitems.ToInt32(); c += 2)
+ {
+ var subTarget = data[c];
+ var subProp = data[c + 1];
+ var converted = WriteTargetToProperty(subTarget, window, subProp);
+ data[c + 1] = converted;
+ }
+
+ XChangeProperty(_x11.Display, window, property, _x11.Atoms.ATOM_PAIR, 32, PropertyMode.Replace,
+ prop.ToPointer(), nitems.ToInt32());
+ }
+
+ XFree(prop);
+
+ return property;
+ }
+ else
+ return IntPtr.Zero;
+ }
+
+ if (ev.type == XEventName.SelectionNotify && ev.SelectionEvent.selection == _x11.Atoms.CLIPBOARD)
+ {
+ var sel = ev.SelectionEvent;
+ if (sel.property == IntPtr.Zero)
+ {
+ _requestedFormatsTcs?.TrySetResult(null);
+ _requestedTextTcs?.TrySetResult(null);
+ }
+ XGetWindowProperty(_x11.Display, _handle, sel.property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType,
+ out var actualAtom, out var actualFormat, out var nitems, out var bytes_after, out var prop);
+ Encoding textEnc = null;
+ if (nitems == IntPtr.Zero)
+ {
+ _requestedFormatsTcs?.TrySetResult(null);
+ _requestedTextTcs?.TrySetResult(null);
+ }
+ else
+ {
+ if (sel.property == _x11.Atoms.TARGETS)
+ {
+ if (actualFormat != 32)
+ _requestedFormatsTcs?.TrySetResult(null);
+ else
+ {
+ var formats = new IntPtr[nitems.ToInt32()];
+ Marshal.Copy(prop, formats, 0, formats.Length);
+ _requestedFormatsTcs?.TrySetResult(formats);
+ }
+ }
+ else if ((textEnc = GetStringEncoding(sel.property)) != null)
+ {
+ var text = textEnc.GetString((byte*)prop.ToPointer(), nitems.ToInt32());
+ _requestedTextTcs?.TrySetResult(text);
+ }
+ }
+
+ XFree(prop);
+ }
+ }
+
+ Task SendFormatRequest()
+ {
+ if (_requestedFormatsTcs == null || _requestedFormatsTcs.Task.IsCompleted)
+ _requestedFormatsTcs = new TaskCompletionSource();
+ XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD, _x11.Atoms.TARGETS, _x11.Atoms.TARGETS, _handle,
+ IntPtr.Zero);
+ return _requestedFormatsTcs.Task;
+ }
+
+ Task SendTextRequest(IntPtr format)
+ {
+ if (_requestedTextTcs == null || _requestedFormatsTcs.Task.IsCompleted)
+ _requestedTextTcs = new TaskCompletionSource();
+ XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD, format, format, _handle, IntPtr.Zero);
+ return _requestedTextTcs.Task;
+ }
+
+ public async Task GetTextAsync()
+ {
+ if (XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) == IntPtr.Zero)
+ return null;
+ var res = await SendFormatRequest();
+ var target = _x11.Atoms.UTF8_STRING;
+ if (res != null)
+ {
+ var preferredFormats = new[] {_x11.Atoms.UTF16_STRING, _x11.Atoms.UTF8_STRING, _x11.Atoms.XA_STRING};
+ foreach (var pf in preferredFormats)
+ if (res.Contains(pf))
+ {
+ target = pf;
+ break;
+ }
+ }
+
+ return await SendTextRequest(target);
+ }
+
+ void StoreAtomsInClipboardManager(IntPtr[] atoms)
+ {
+ if (_x11.Atoms.CLIPBOARD_MANAGER != IntPtr.Zero && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero)
+ {
+ var clipboardManager = XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER);
+ if (clipboardManager != IntPtr.Zero)
+ {
+ XChangeProperty(_x11.Display, _handle, _avaloniaSaveTargetsAtom, _x11.Atoms.XA_ATOM, 32,
+ PropertyMode.Replace,
+ atoms, atoms.Length);
+ XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER, _x11.Atoms.SAVE_TARGETS,
+ _avaloniaSaveTargetsAtom, _handle, IntPtr.Zero);
+ }
+ }
+ }
+
+ public Task SetTextAsync(string text)
+ {
+ _storedString = text;
+ XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero);
+ StoreAtomsInClipboardManager(_textAtoms);
+ return Task.CompletedTask;
+ }
+
+ public Task ClearAsync()
+ {
+ return SetTextAsync(null);
+ }
+ }
+}
diff --git a/src/Avalonia.X11/X11CursorFactory.cs b/src/Avalonia.X11/X11CursorFactory.cs
new file mode 100644
index 0000000000..40b01117e3
--- /dev/null
+++ b/src/Avalonia.X11/X11CursorFactory.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Input;
+using Avalonia.Platform;
+
+namespace Avalonia.X11
+{
+ class X11CursorFactory : IStandardCursorFactory
+ {
+ private readonly IntPtr _display;
+ private Dictionary _cursors;
+
+ private static readonly Dictionary s_mapping =
+ new Dictionary
+ {
+ {StandardCursorType.Arrow, CursorFontShape.XC_top_left_arrow},
+ {StandardCursorType.Cross, CursorFontShape.XC_cross},
+ {StandardCursorType.Hand, CursorFontShape.XC_hand1},
+ {StandardCursorType.Help, CursorFontShape.XC_question_arrow},
+ {StandardCursorType.Ibeam, CursorFontShape.XC_xterm},
+ {StandardCursorType.No, CursorFontShape.XC_X_cursor},
+ {StandardCursorType.Wait, CursorFontShape.XC_watch},
+ {StandardCursorType.AppStarting, CursorFontShape.XC_watch},
+ {StandardCursorType.BottomSize, CursorFontShape.XC_bottom_side},
+ {StandardCursorType.DragCopy, CursorFontShape.XC_center_ptr},
+ {StandardCursorType.DragLink, CursorFontShape.XC_fleur},
+ {StandardCursorType.DragMove, CursorFontShape.XC_diamond_cross},
+ {StandardCursorType.LeftSide, CursorFontShape.XC_left_side},
+ {StandardCursorType.RightSide, CursorFontShape.XC_right_side},
+ {StandardCursorType.SizeAll, CursorFontShape.XC_sizing},
+ {StandardCursorType.TopSide, CursorFontShape.XC_top_side},
+ {StandardCursorType.UpArrow, CursorFontShape.XC_sb_up_arrow},
+ {StandardCursorType.BottomLeftCorner, CursorFontShape.XC_bottom_left_corner},
+ {StandardCursorType.BottomRightCorner, CursorFontShape.XC_bottom_right_corner},
+ {StandardCursorType.SizeNorthSouth, CursorFontShape.XC_sb_v_double_arrow},
+ {StandardCursorType.SizeWestEast, CursorFontShape.XC_sb_h_double_arrow},
+ {StandardCursorType.TopLeftCorner, CursorFontShape.XC_top_left_corner},
+ {StandardCursorType.TopRightCorner, CursorFontShape.XC_top_right_corner},
+ };
+
+ public X11CursorFactory(IntPtr display)
+ {
+ _display = display;
+ _cursors = Enum.GetValues(typeof(CursorFontShape)).Cast()
+ .ToDictionary(id => id, id => XLib.XCreateFontCursor(_display, id));
+ }
+
+ public IPlatformHandle GetCursor(StandardCursorType cursorType)
+ {
+ var handle = s_mapping.TryGetValue(cursorType, out var shape)
+ ? _cursors[shape]
+ : _cursors[CursorFontShape.XC_top_left_arrow];
+ return new PlatformHandle(handle, "XCURSOR");
+ }
+ }
+}
diff --git a/src/Avalonia.X11/X11Enums.cs b/src/Avalonia.X11/X11Enums.cs
new file mode 100644
index 0000000000..d97e1c42bb
--- /dev/null
+++ b/src/Avalonia.X11/X11Enums.cs
@@ -0,0 +1,110 @@
+using System;
+
+namespace Avalonia.X11
+{
+
+ public enum Status
+ {
+ Success = 0, /* everything's okay */
+ BadRequest = 1, /* bad request code */
+ BadValue = 2, /* int parameter out of range */
+ BadWindow = 3, /* parameter not a Window */
+ BadPixmap = 4, /* parameter not a Pixmap */
+ BadAtom = 5, /* parameter not an Atom */
+ BadCursor = 6, /* parameter not a Cursor */
+ BadFont = 7, /* parameter not a Font */
+ BadMatch = 8, /* parameter mismatch */
+ BadDrawable = 9, /* parameter not a Pixmap or Window */
+ BadAccess = 10, /* depending on context:
+ - key/button already grabbed
+ - attempt to free an illegal
+ cmap entry
+ - attempt to store into a read-only
+ color map entry.
+ - attempt to modify the access control
+ list from other than the local host.
+ */
+ BadAlloc = 11, /* insufficient resources */
+ BadColor = 12, /* no such colormap */
+ BadGC = 13, /* parameter not a GC */
+ BadIDChoice = 14, /* choice not in range or already used */
+ BadName = 15, /* font or color name doesn't exist */
+ BadLength = 16, /* Request length incorrect */
+ BadImplementation = 17, /* server is defective */
+
+ FirstExtensionError = 128,
+ LastExtensionError = 255,
+
+ }
+
+ [Flags]
+ public enum XEventMask : int
+ {
+ NoEventMask = 0,
+ KeyPressMask = (1 << 0),
+ KeyReleaseMask = (1 << 1),
+ ButtonPressMask = (1 << 2),
+ ButtonReleaseMask = (1 << 3),
+ EnterWindowMask = (1 << 4),
+ LeaveWindowMask = (1 << 5),
+ PointerMotionMask = (1 << 6),
+ PointerMotionHintMask = (1 << 7),
+ Button1MotionMask = (1 << 8),
+ Button2MotionMask = (1 << 9),
+ Button3MotionMask = (1 << 10),
+ Button4MotionMask = (1 << 11),
+ Button5MotionMask = (1 << 12),
+ ButtonMotionMask = (1 << 13),
+ KeymapStateMask = (1 << 14),
+ ExposureMask = (1 << 15),
+ VisibilityChangeMask = (1 << 16),
+ StructureNotifyMask = (1 << 17),
+ ResizeRedirectMask = (1 << 18),
+ SubstructureNotifyMask = (1 << 19),
+ SubstructureRedirectMask = (1 << 20),
+ FocusChangeMask = (1 << 21),
+ PropertyChangeMask = (1 << 22),
+ ColormapChangeMask = (1 << 23),
+ OwnerGrabButtonMask = (1 << 24)
+ }
+
+ [Flags]
+ public enum XModifierMask
+ {
+ ShiftMask = (1 << 0),
+ LockMask = (1 << 1),
+ ControlMask = (1 << 2),
+ Mod1Mask = (1 << 3),
+ Mod2Mask = (1 << 4),
+ Mod3Mask = (1 << 5),
+ Mod4Mask = (1 << 6),
+ Mod5Mask = (1 << 7),
+ Button1Mask = (1 << 8),
+ Button2Mask = (1 << 9),
+ Button3Mask = (1 << 10),
+ Button4Mask = (1 << 11),
+ Button5Mask = (1 << 12),
+ AnyModifier = (1 << 15)
+
+ }
+
+ [Flags]
+ public enum XCreateWindowFlags
+ {
+ CWBackPixmap = (1 << 0),
+ CWBackPixel = (1 << 1),
+ CWBorderPixmap = (1 << 2),
+ CWBorderPixel = (1 << 3),
+ CWBitGravity = (1 << 4),
+ CWWinGravity = (1 << 5),
+ CWBackingStore = (1 << 6),
+ CWBackingPlanes = (1 << 7),
+ CWBackingPixel = (1 << 8),
+ CWOverrideRedirect = (1 << 9),
+ CWSaveUnder = (1 << 10),
+ CWEventMask = (1 << 11),
+ CWDontPropagate = (1 << 12),
+ CWColormap = (1 << 13),
+ CWCursor = (1 << 14),
+ }
+}
diff --git a/src/Avalonia.X11/X11Exception.cs b/src/Avalonia.X11/X11Exception.cs
new file mode 100644
index 0000000000..2ac5a31d9b
--- /dev/null
+++ b/src/Avalonia.X11/X11Exception.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Avalonia.X11
+{
+ public class X11Exception : Exception
+ {
+ public X11Exception(string message) : base(message)
+ {
+
+ }
+ }
+}
diff --git a/src/Avalonia.X11/X11Framebuffer.cs b/src/Avalonia.X11/X11Framebuffer.cs
new file mode 100644
index 0000000000..00288f300d
--- /dev/null
+++ b/src/Avalonia.X11/X11Framebuffer.cs
@@ -0,0 +1,59 @@
+using System;
+using System.IO;
+using Avalonia.Platform;
+using SkiaSharp;
+using static Avalonia.X11.XLib;
+namespace Avalonia.X11
+{
+ class X11Framebuffer : ILockedFramebuffer
+ {
+ private readonly IntPtr _display;
+ private readonly IntPtr _xid;
+ private readonly int _depth;
+ private IUnmanagedBlob _blob;
+
+ public X11Framebuffer(IntPtr display, IntPtr xid, int depth, int width, int height, double factor)
+ {
+ _display = display;
+ _xid = xid;
+ _depth = depth;
+ Size = new PixelSize(width, height);
+ RowBytes = width * 4;
+ Dpi = new Vector(96, 96) * factor;
+ Format = PixelFormat.Bgra8888;
+ _blob = AvaloniaLocator.Current.GetService().AllocBlob(RowBytes * height);
+ Address = _blob.Address;
+ }
+
+ public void Dispose()
+ {
+ var image = new XImage();
+ int bitsPerPixel = 32;
+ image.width = Size.Width;
+ image.height = Size.Height;
+ image.format = 2; //ZPixmap;
+ image.data = Address;
+ image.byte_order = 0;// LSBFirst;
+ image.bitmap_unit = bitsPerPixel;
+ image.bitmap_bit_order = 0;// LSBFirst;
+ image.bitmap_pad = bitsPerPixel;
+ image.depth = _depth;
+ image.bytes_per_line = RowBytes;
+ image.bits_per_pixel = bitsPerPixel;
+ XLockDisplay(_display);
+ XInitImage(ref image);
+ var gc = XCreateGC(_display, _xid, 0, IntPtr.Zero);
+ XPutImage(_display, _xid, gc, ref image, 0, 0, 0, 0, (uint) Size.Width, (uint) Size.Height);
+ XFreeGC(_display, gc);
+ XSync(_display, true);
+ XUnlockDisplay(_display);
+ _blob.Dispose();
+ }
+
+ public IntPtr Address { get; }
+ public PixelSize Size { get; }
+ public int RowBytes { get; }
+ public Vector Dpi { get; }
+ public PixelFormat Format { get; }
+ }
+}
diff --git a/src/Avalonia.X11/X11FramebufferSurface.cs b/src/Avalonia.X11/X11FramebufferSurface.cs
new file mode 100644
index 0000000000..07c88b51a8
--- /dev/null
+++ b/src/Avalonia.X11/X11FramebufferSurface.cs
@@ -0,0 +1,31 @@
+using System;
+using Avalonia.Controls.Platform.Surfaces;
+using Avalonia.Platform;
+using static Avalonia.X11.XLib;
+namespace Avalonia.X11
+{
+ public class X11FramebufferSurface : IFramebufferPlatformSurface
+ {
+ private readonly IntPtr _display;
+ private readonly IntPtr _xid;
+ private readonly int _depth;
+ private readonly Func _scaling;
+
+ public X11FramebufferSurface(IntPtr display, IntPtr xid, int depth, Func scaling)
+ {
+ _display = display;
+ _xid = xid;
+ _depth = depth;
+ _scaling = scaling;
+ }
+
+ public ILockedFramebuffer Lock()
+ {
+ XLockDisplay(_display);
+ XGetGeometry(_display, _xid, out var root, out var x, out var y, out var width, out var height,
+ out var bw, out var d);
+ XUnlockDisplay(_display);
+ return new X11Framebuffer(_display, _xid, _depth, width, height, _scaling());
+ }
+ }
+}
diff --git a/src/Avalonia.X11/X11IconLoader.cs b/src/Avalonia.X11/X11IconLoader.cs
new file mode 100644
index 0000000000..f0e75536d0
--- /dev/null
+++ b/src/Avalonia.X11/X11IconLoader.cs
@@ -0,0 +1,105 @@
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using Avalonia.Controls.Platform.Surfaces;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+using Avalonia.Utilities;
+using Avalonia.Visuals.Media.Imaging;
+using static Avalonia.X11.XLib;
+namespace Avalonia.X11
+{
+ class X11IconLoader : IPlatformIconLoader
+ {
+ private readonly X11Info _x11;
+
+ public X11IconLoader(X11Info x11)
+ {
+ _x11 = x11;
+ }
+
+ IWindowIconImpl LoadIcon(Bitmap bitmap)
+ {
+ var rv = new X11IconData(bitmap);
+ bitmap.Dispose();
+ return rv;
+ }
+
+ public IWindowIconImpl LoadIcon(string fileName) => LoadIcon(new Bitmap(fileName));
+
+ public IWindowIconImpl LoadIcon(Stream stream) => LoadIcon(new Bitmap(stream));
+
+ public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
+ {
+ var ms = new MemoryStream();
+ bitmap.Save(ms);
+ ms.Position = 0;
+ return LoadIcon(ms);
+ }
+ }
+
+ unsafe class X11IconData : IWindowIconImpl, IFramebufferPlatformSurface
+ {
+ private int _width;
+ private int _height;
+ private uint[] _bdata;
+ public UIntPtr[] Data { get; }
+
+ public X11IconData(Bitmap bitmap)
+ {
+ _width = Math.Min(bitmap.PixelSize.Width, 128);
+ _height = Math.Min(bitmap.PixelSize.Height, 128);
+ _bdata = new uint[_width * _height];
+ fixed (void* ptr = _bdata)
+ {
+ var iptr = (int*)ptr;
+ iptr[0] = _width;
+ iptr[1] = _height;
+ }
+ using(var rt = AvaloniaLocator.Current.GetService().CreateRenderTarget(new[]{this}))
+ using (var ctx = rt.CreateDrawingContext(null))
+ ctx.DrawImage(bitmap.PlatformImpl, 1, new Rect(bitmap.Size),
+ new Rect(0, 0, _width, _height));
+ Data = new UIntPtr[_width * _height + 2];
+ Data[0] = new UIntPtr((uint)_width);
+ Data[1] = new UIntPtr((uint)_height);
+ for (var y = 0; y < _height; y++)
+ {
+ var r = y * _width;
+ for (var x = 0; x < _width; x++)
+ Data[r + x] = new UIntPtr(_bdata[r + x]);
+ }
+
+ _bdata = null;
+ }
+
+ public void Save(Stream outputStream)
+ {
+ using (var wr =
+ new WriteableBitmap(new PixelSize(_width, _height), new Vector(96, 96), PixelFormat.Bgra8888))
+ {
+ using (var fb = wr.Lock())
+ {
+ var fbp = (uint*)fb.Address;
+ for (var y = 0; y < _height; y++)
+ {
+ var r = y * _width;
+ var fbr = y * fb.RowBytes / 4;
+ for (var x = 0; x < _width; x++)
+ fbp[fbr + x] = Data[r + x].ToUInt32();
+ }
+ }
+ wr.Save(outputStream);
+ }
+ }
+
+ public ILockedFramebuffer Lock()
+ {
+ var h = GCHandle.Alloc(_bdata, GCHandleType.Pinned);
+ return new LockedFramebuffer(h.AddrOfPinnedObject(), new PixelSize(_width, _height), _width * 4,
+ new Vector(96, 96), PixelFormat.Bgra8888,
+ () => h.Free());
+ }
+ }
+}
diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs
new file mode 100644
index 0000000000..8cfcbb9836
--- /dev/null
+++ b/src/Avalonia.X11/X11Info.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using JetBrains.Annotations;
+using static Avalonia.X11.XLib;
+// ReSharper disable UnusedAutoPropertyAccessor.Local
+namespace Avalonia.X11
+{
+ unsafe class X11Info
+ {
+ public IntPtr Display { get; }
+ public IntPtr DeferredDisplay { get; }
+ public int DefaultScreen { get; }
+ public IntPtr BlackPixel { get; }
+ public IntPtr RootWindow { get; }
+ public IntPtr DefaultRootWindow { get; }
+ public IntPtr DefaultCursor { get; }
+ public X11Atoms Atoms { get; }
+ public IntPtr Xim { get; }
+
+ public int RandrEventBase { get; }
+ public int RandrErrorBase { get; }
+
+ public Version RandrVersion { get; }
+
+ public int XInputOpcode { get; }
+ public int XInputEventBase { get; }
+ public int XInputErrorBase { get; }
+
+ public Version XInputVersion { get; }
+
+ public IntPtr LastActivityTimestamp { get; set; }
+ public XVisualInfo? TransparentVisualInfo { get; set; }
+
+ public unsafe X11Info(IntPtr display, IntPtr deferredDisplay)
+ {
+ Display = display;
+ DeferredDisplay = deferredDisplay;
+ DefaultScreen = XDefaultScreen(display);
+ BlackPixel = XBlackPixel(display, DefaultScreen);
+ RootWindow = XRootWindow(display, DefaultScreen);
+ DefaultCursor = XCreateFontCursor(display, CursorFontShape.XC_top_left_arrow);
+ DefaultRootWindow = XDefaultRootWindow(display);
+ Atoms = new X11Atoms(display);
+ //TODO: Open an actual XIM once we get support for preedit in our textbox
+ XSetLocaleModifiers("@im=none");
+ Xim = XOpenIM(display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ XMatchVisualInfo(Display, DefaultScreen, 32, 4, out var visual);
+ if (visual.depth == 32)
+ TransparentVisualInfo = visual;
+
+ try
+ {
+ if (XRRQueryExtension(display, out int randrEventBase, out var randrErrorBase) != 0)
+ {
+ RandrEventBase = randrEventBase;
+ RandrErrorBase = randrErrorBase;
+ if (XRRQueryVersion(display, out var major, out var minor) != 0)
+ RandrVersion = new Version(major, minor);
+ }
+ }
+ catch
+ {
+ //Ignore, randr is not supported
+ }
+
+ try
+ {
+ if (XQueryExtension(display, "XInputExtension",
+ out var xiopcode, out var xievent, out var xierror))
+ {
+ int major = 2, minor = 2;
+ if (XIQueryVersion(display, ref major, ref minor) == Status.Success)
+ {
+ XInputVersion = new Version(major, minor);
+ XInputOpcode = xiopcode;
+ XInputEventBase = xievent;
+ XInputErrorBase = xierror;
+ }
+ }
+ }
+ catch
+ {
+ //Ignore, XI is not supported
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.X11/X11KeyTransform.cs b/src/Avalonia.X11/X11KeyTransform.cs
new file mode 100644
index 0000000000..26495111d1
--- /dev/null
+++ b/src/Avalonia.X11/X11KeyTransform.cs
@@ -0,0 +1,232 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Input;
+
+namespace Avalonia.X11
+{
+ static class X11KeyTransform
+ {
+ private static readonly Dictionary KeyDic = new Dictionary
+ {
+ {X11Key.Cancel, Key.Cancel},
+ {X11Key.BackSpace, Key.Back},
+ {X11Key.Tab, Key.Tab},
+ {X11Key.Linefeed, Key.LineFeed},
+ {X11Key.Clear, Key.Clear},
+ {X11Key.Return, Key.Return},
+ {X11Key.KP_Enter, Key.Return},
+ {X11Key.Pause, Key.Pause},
+ {X11Key.Caps_Lock, Key.CapsLock},
+ //{ X11Key.?, Key.HangulMode }
+ //{ X11Key.?, Key.JunjaMode }
+ //{ X11Key.?, Key.FinalMode }
+ //{ X11Key.?, Key.KanjiMode }
+ {X11Key.Escape, Key.Escape},
+ //{ X11Key.?, Key.ImeConvert }
+ //{ X11Key.?, Key.ImeNonConvert }
+ //{ X11Key.?, Key.ImeAccept }
+ //{ X11Key.?, Key.ImeModeChange }
+ {X11Key.space, Key.Space},
+ {X11Key.Prior, Key.Prior},
+ {X11Key.KP_Prior, Key.Prior},
+ {X11Key.Page_Down, Key.PageDown},
+ {X11Key.KP_Page_Down, Key.PageDown},
+ {X11Key.End, Key.End},
+ {X11Key.KP_End, Key.End},
+ {X11Key.Home, Key.Home},
+ {X11Key.KP_Home, Key.Home},
+ {X11Key.Left, Key.Left},
+ {X11Key.KP_Left, Key.Left},
+ {X11Key.Up, Key.Up},
+ {X11Key.KP_Up, Key.Up},
+ {X11Key.Right, Key.Right},
+ {X11Key.KP_Right, Key.Right},
+ {X11Key.Down, Key.Down},
+ {X11Key.KP_Down, Key.Down},
+ {X11Key.Select, Key.Select},
+ {X11Key.Print, Key.Print},
+ {X11Key.Execute, Key.Execute},
+ //{ X11Key.?, Key.Snapshot }
+ {X11Key.Insert, Key.Insert},
+ {X11Key.KP_Insert, Key.Insert},
+ {X11Key.Delete, Key.Delete},
+ {X11Key.KP_Delete, Key.Delete},
+ {X11Key.Help, Key.Help},
+ {X11Key.XK_0, Key.D0},
+ {X11Key.XK_1, Key.D1},
+ {X11Key.XK_2, Key.D2},
+ {X11Key.XK_3, Key.D3},
+ {X11Key.XK_4, Key.D4},
+ {X11Key.XK_5, Key.D5},
+ {X11Key.XK_6, Key.D6},
+ {X11Key.XK_7, Key.D7},
+ {X11Key.XK_8, Key.D8},
+ {X11Key.XK_9, Key.D9},
+ {X11Key.A, Key.A},
+ {X11Key.B, Key.B},
+ {X11Key.C, Key.C},
+ {X11Key.D, Key.D},
+ {X11Key.E, Key.E},
+ {X11Key.F, Key.F},
+ {X11Key.G, Key.G},
+ {X11Key.H, Key.H},
+ {X11Key.I, Key.I},
+ {X11Key.J, Key.J},
+ {X11Key.K, Key.K},
+ {X11Key.L, Key.L},
+ {X11Key.M, Key.M},
+ {X11Key.N, Key.N},
+ {X11Key.O, Key.O},
+ {X11Key.P, Key.P},
+ {X11Key.Q, Key.Q},
+ {X11Key.R, Key.R},
+ {X11Key.S, Key.S},
+ {X11Key.T, Key.T},
+ {X11Key.U, Key.U},
+ {X11Key.V, Key.V},
+ {X11Key.W, Key.W},
+ {X11Key.X, Key.X},
+ {X11Key.Y, Key.Y},
+ {X11Key.Z, Key.Z},
+ {X11Key.a, Key.A},
+ {X11Key.b, Key.B},
+ {X11Key.c, Key.C},
+ {X11Key.d, Key.D},
+ {X11Key.e, Key.E},
+ {X11Key.f, Key.F},
+ {X11Key.g, Key.G},
+ {X11Key.h, Key.H},
+ {X11Key.i, Key.I},
+ {X11Key.j, Key.J},
+ {X11Key.k, Key.K},
+ {X11Key.l, Key.L},
+ {X11Key.m, Key.M},
+ {X11Key.n, Key.N},
+ {X11Key.o, Key.O},
+ {X11Key.p, Key.P},
+ {X11Key.q, Key.Q},
+ {X11Key.r, Key.R},
+ {X11Key.s, Key.S},
+ {X11Key.t, Key.T},
+ {X11Key.u, Key.U},
+ {X11Key.v, Key.V},
+ {X11Key.w, Key.W},
+ {X11Key.x, Key.X},
+ {X11Key.y, Key.Y},
+ {X11Key.z, Key.Z},
+ //{ X11Key.?, Key.LWin }
+ //{ X11Key.?, Key.RWin }
+ {X11Key.Menu, Key.Apps},
+ //{ X11Key.?, Key.Sleep }
+ {X11Key.KP_0, Key.NumPad0},
+ {X11Key.KP_1, Key.NumPad1},
+ {X11Key.KP_2, Key.NumPad2},
+ {X11Key.KP_3, Key.NumPad3},
+ {X11Key.KP_4, Key.NumPad4},
+ {X11Key.KP_5, Key.NumPad5},
+ {X11Key.KP_6, Key.NumPad6},
+ {X11Key.KP_7, Key.NumPad7},
+ {X11Key.KP_8, Key.NumPad8},
+ {X11Key.KP_9, Key.NumPad9},
+ {X11Key.multiply, Key.Multiply},
+ {X11Key.KP_Multiply, Key.Multiply},
+ {X11Key.KP_Add, Key.Add},
+ //{ X11Key.?, Key.Separator }
+ {X11Key.KP_Subtract, Key.Subtract},
+ {X11Key.KP_Decimal, Key.Decimal},
+ {X11Key.KP_Divide, Key.Divide},
+ {X11Key.F1, Key.F1},
+ {X11Key.F2, Key.F2},
+ {X11Key.F3, Key.F3},
+ {X11Key.F4, Key.F4},
+ {X11Key.F5, Key.F5},
+ {X11Key.F6, Key.F6},
+ {X11Key.F7, Key.F7},
+ {X11Key.F8, Key.F8},
+ {X11Key.F9, Key.F9},
+ {X11Key.F10, Key.F10},
+ {X11Key.F11, Key.F11},
+ {X11Key.F12, Key.F12},
+ {X11Key.L3, Key.F13},
+ {X11Key.F14, Key.F14},
+ {X11Key.L5, Key.F15},
+ {X11Key.F16, Key.F16},
+ {X11Key.F17, Key.F17},
+ {X11Key.L8, Key.F18},
+ {X11Key.L9, Key.F19},
+ {X11Key.L10, Key.F20},
+ {X11Key.R1, Key.F21},
+ {X11Key.R2, Key.F22},
+ {X11Key.F23, Key.F23},
+ {X11Key.R4, Key.F24},
+ {X11Key.Num_Lock, Key.NumLock},
+ {X11Key.Scroll_Lock, Key.Scroll},
+ {X11Key.Shift_L, Key.LeftShift},
+ {X11Key.Shift_R, Key.RightShift},
+ {X11Key.Control_L, Key.LeftCtrl},
+ {X11Key.Control_R, Key.RightCtrl},
+ {X11Key.Alt_L, Key.LeftAlt},
+ {X11Key.Alt_R, Key.RightAlt},
+ //{ X11Key.?, Key.BrowserBack }
+ //{ X11Key.?, Key.BrowserForward }
+ //{ X11Key.?, Key.BrowserRefresh }
+ //{ X11Key.?, Key.BrowserStop }
+ //{ X11Key.?, Key.BrowserSearch }
+ //{ X11Key.?, Key.BrowserFavorites }
+ //{ X11Key.?, Key.BrowserHome }
+ //{ X11Key.?, Key.VolumeMute }
+ //{ X11Key.?, Key.VolumeDown }
+ //{ X11Key.?, Key.VolumeUp }
+ //{ X11Key.?, Key.MediaNextTrack }
+ //{ X11Key.?, Key.MediaPreviousTrack }
+ //{ X11Key.?, Key.MediaStop }
+ //{ X11Key.?, Key.MediaPlayPause }
+ //{ X11Key.?, Key.LaunchMail }
+ //{ X11Key.?, Key.SelectMedia }
+ //{ X11Key.?, Key.LaunchApplication1 }
+ //{ X11Key.?, Key.LaunchApplication2 }
+ {X11Key.semicolon, Key.OemSemicolon},
+ {X11Key.plus, Key.OemPlus},
+ {X11Key.equal, Key.OemPlus},
+ {X11Key.comma, Key.OemComma},
+ {X11Key.minus, Key.OemMinus},
+ {X11Key.period, Key.OemPeriod},
+ {X11Key.slash, Key.Oem2},
+ {X11Key.grave, Key.OemTilde},
+ //{ X11Key.?, Key.AbntC1 }
+ //{ X11Key.?, Key.AbntC2 }
+ {X11Key.bracketleft, Key.OemOpenBrackets},
+ {X11Key.backslash, Key.OemPipe},
+ {X11Key.bracketright, Key.OemCloseBrackets},
+ {X11Key.apostrophe, Key.OemQuotes},
+ //{ X11Key.?, Key.Oem8 }
+ //{ X11Key.?, Key.Oem102 }
+ //{ X11Key.?, Key.ImeProcessed }
+ //{ X11Key.?, Key.System }
+ //{ X11Key.?, Key.OemAttn }
+ //{ X11Key.?, Key.OemFinish }
+ //{ X11Key.?, Key.DbeHiragana }
+ //{ X11Key.?, Key.OemAuto }
+ //{ X11Key.?, Key.DbeDbcsChar }
+ //{ X11Key.?, Key.OemBackTab }
+ //{ X11Key.?, Key.Attn }
+ //{ X11Key.?, Key.DbeEnterWordRegisterMode }
+ //{ X11Key.?, Key.DbeEnterImeConfigureMode }
+ //{ X11Key.?, Key.EraseEof }
+ //{ X11Key.?, Key.Play }
+ //{ X11Key.?, Key.Zoom }
+ //{ X11Key.?, Key.NoName }
+ //{ X11Key.?, Key.DbeEnterDialogConversionMode }
+ //{ X11Key.?, Key.OemClear }
+ //{ X11Key.?, Key.DeadCharProcessed }
+ };
+
+ public static Key ConvertKey(IntPtr key)
+ {
+ var ikey = key.ToInt32();
+ Key result;
+ return KeyDic.TryGetValue((X11Key)ikey, out result) ? result : Key.None;
+ }
+}
+
+}
diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs
new file mode 100644
index 0000000000..323411e319
--- /dev/null
+++ b/src/Avalonia.X11/X11Platform.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Gtk3;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.OpenGL;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+using Avalonia.X11;
+using Avalonia.X11.Glx;
+using static Avalonia.X11.XLib;
+namespace Avalonia.X11
+{
+ class AvaloniaX11Platform : IWindowingPlatform
+ {
+ private Lazy _keyboardDevice = new Lazy(() => new KeyboardDevice());
+ private Lazy _mouseDevice = new Lazy(() => new MouseDevice());
+ public KeyboardDevice KeyboardDevice => _keyboardDevice.Value;
+ public MouseDevice MouseDevice => _mouseDevice.Value;
+ public Dictionary> Windows = new Dictionary>();
+ public XI2Manager XI2;
+ public X11Info Info { get; private set; }
+ public IX11Screens X11Screens { get; private set; }
+ public IScreenImpl Screens { get; private set; }
+ public void Initialize(X11PlatformOptions options)
+ {
+ XInitThreads();
+ Display = XOpenDisplay(IntPtr.Zero);
+ DeferredDisplay = XOpenDisplay(IntPtr.Zero);
+ if (Display == IntPtr.Zero)
+ throw new Exception("XOpenDisplay failed");
+ XError.Init();
+ Info = new X11Info(Display, DeferredDisplay);
+
+ AvaloniaLocator.CurrentMutable.BindToSelf(this)
+ .Bind().ToConstant(this)
+ .Bind().ToConstant(new X11PlatformThreading(this))
+ .Bind().ToConstant(new DefaultRenderTimer(60))
+ .Bind().ToConstant(new RenderLoop())
+ .Bind().ToConstant(new PlatformHotkeyConfiguration(InputModifiers.Control))
+ .Bind().ToFunc(() => KeyboardDevice)
+ .Bind().ToConstant(new X11CursorFactory(Display))
+ .Bind().ToConstant(new X11Clipboard(this))
+ .Bind().ToConstant(new PlatformSettingsStub())
+ .Bind().ToConstant(new X11IconLoader(Info))
+ .Bind().ToConstant(new Gtk3ForeignX11SystemDialog());
+
+ X11Screens = Avalonia.X11.X11Screens.Init(this);
+ Screens = new X11Screens(X11Screens);
+ if (Info.XInputVersion != null)
+ {
+ var xi2 = new XI2Manager();
+ if (xi2.Init(this))
+ XI2 = xi2;
+ }
+
+ if (options.UseGpu)
+ {
+ if (options.UseEGL)
+ EglGlPlatformFeature.TryInitialize();
+ else
+ GlxGlPlatformFeature.TryInitialize(Info);
+ }
+ }
+
+ public IntPtr DeferredDisplay { get; set; }
+ public IntPtr Display { get; set; }
+ public IWindowImpl CreateWindow()
+ {
+ return new X11Window(this, false);
+ }
+
+ public IEmbeddableWindowImpl CreateEmbeddableWindow()
+ {
+ throw new NotSupportedException();
+ }
+
+ public IPopupImpl CreatePopup()
+ {
+ return new X11Window(this, true);
+ }
+ }
+}
+
+namespace Avalonia
+{
+
+ public class X11PlatformOptions
+ {
+ public bool UseEGL { get; set; }
+ public bool UseGpu { get; set; } = true;
+ }
+ public static class AvaloniaX11PlatformExtensions
+ {
+ public static T UseX11(this T builder, X11PlatformOptions options = null) where T : AppBuilderBase, new()
+ {
+ builder.UseWindowingSubsystem(() => new AvaloniaX11Platform().Initialize(options ?? new X11PlatformOptions()));
+ return builder;
+ }
+
+ public static void InitializeX11Platform(X11PlatformOptions options = null) =>
+ new AvaloniaX11Platform().Initialize(options ?? new X11PlatformOptions());
+ }
+
+}
diff --git a/src/Avalonia.X11/X11PlatformThreading.cs b/src/Avalonia.X11/X11PlatformThreading.cs
new file mode 100644
index 0000000000..0215e43d98
--- /dev/null
+++ b/src/Avalonia.X11/X11PlatformThreading.cs
@@ -0,0 +1,279 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Avalonia.Platform;
+using Avalonia.Threading;
+using static Avalonia.X11.XLib;
+
+namespace Avalonia.X11
+{
+ unsafe class X11PlatformThreading : IPlatformThreadingInterface
+ {
+ private readonly AvaloniaX11Platform _platform;
+ private readonly IntPtr _display;
+ private readonly Dictionary> _eventHandlers;
+ private Thread _mainThread;
+
+ [StructLayout(LayoutKind.Explicit)]
+ struct epoll_data
+ {
+ [FieldOffset(0)]
+ public IntPtr ptr;
+ [FieldOffset(0)]
+ public int fd;
+ [FieldOffset(0)]
+ public uint u32;
+ [FieldOffset(0)]
+ public ulong u64;
+ }
+
+ private const int EPOLLIN = 1;
+ private const int EPOLL_CTL_ADD = 1;
+ private const int O_NONBLOCK = 2048;
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct epoll_event
+ {
+ public uint events;
+ public epoll_data data;
+ }
+
+ [DllImport("libc")]
+ extern static int epoll_create1(int size);
+
+ [DllImport("libc")]
+ extern static int epoll_ctl(int epfd, int op, int fd, ref epoll_event __event);
+
+ [DllImport("libc")]
+ extern static int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout);
+
+ [DllImport("libc")]
+ extern static int pipe2(int* fds, int flags);
+ [DllImport("libc")]
+ extern static IntPtr write(int fd, void* buf, IntPtr count);
+
+ [DllImport("libc")]
+ extern static IntPtr read(int fd, void* buf, IntPtr count);
+
+ enum EventCodes
+ {
+ X11 = 1,
+ Signal =2
+ }
+
+ private int _sigread, _sigwrite;
+ private object _lock = new object();
+ private bool _signaled;
+ private DispatcherPriority _signaledPriority;
+ private int _epoll;
+ private Stopwatch _clock = Stopwatch.StartNew();
+
+ class X11Timer : IDisposable
+ {
+ private readonly X11PlatformThreading _parent;
+
+ public X11Timer(X11PlatformThreading parent, DispatcherPriority prio, TimeSpan interval, Action tick)
+ {
+ _parent = parent;
+ Priority = prio;
+ Tick = tick;
+ Interval = interval;
+ Reschedule();
+ }
+
+ public DispatcherPriority Priority { get; }
+ public TimeSpan NextTick { get; private set; }
+ public TimeSpan Interval { get; }
+ public Action Tick { get; }
+ public bool Disposed { get; private set; }
+
+ public void Reschedule()
+ {
+ NextTick = _parent._clock.Elapsed + Interval;
+ }
+
+ public void Dispose()
+ {
+ Disposed = true;
+ lock (_parent._lock)
+ _parent._timers.Remove(this);
+ }
+ }
+
+ List _timers = new List();
+
+ public X11PlatformThreading(AvaloniaX11Platform platform)
+ {
+ _platform = platform;
+ _display = platform.Display;
+ _eventHandlers = platform.Windows;
+ _mainThread = Thread.CurrentThread;
+ var fd = XLib.XConnectionNumber(_display);
+ var ev = new epoll_event()
+ {
+ events = EPOLLIN,
+ data = {u32 = (int)EventCodes.X11}
+ };
+ _epoll = epoll_create1(0);
+ if (_epoll == -1)
+ throw new X11Exception("epoll_create1 failed");
+
+ if (epoll_ctl(_epoll, EPOLL_CTL_ADD, fd, ref ev) == -1)
+ throw new X11Exception("Unable to attach X11 connection handle to epoll");
+
+ var fds = stackalloc int[2];
+ pipe2(fds, O_NONBLOCK);
+ _sigread = fds[0];
+ _sigwrite = fds[1];
+
+ ev = new epoll_event
+ {
+ events = EPOLLIN,
+ data = {u32 = (int)EventCodes.Signal}
+ };
+ if (epoll_ctl(_epoll, EPOLL_CTL_ADD, _sigread, ref ev) == -1)
+ throw new X11Exception("Unable to attach signal pipe to epoll");
+ }
+
+ int TimerComparer(X11Timer t1, X11Timer t2)
+ {
+ return t2.Priority - t1.Priority;
+ }
+
+ void CheckSignaled()
+ {
+ int buf = 0;
+ while (read(_sigread, &buf, new IntPtr(4)).ToInt64() > 0)
+ {
+ }
+
+ DispatcherPriority prio;
+ lock (_lock)
+ {
+ if (!_signaled)
+ return;
+ _signaled = false;
+ prio = _signaledPriority;
+ _signaledPriority = DispatcherPriority.MinValue;
+ }
+
+ Signaled?.Invoke(prio);
+ }
+
+ void HandleX11(CancellationToken cancellationToken)
+ {
+ while (XPending(_display) != 0)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ return;
+ XNextEvent(_display, out var xev);
+ if (xev.type == XEventName.GenericEvent)
+ XGetEventData(_display, &xev.GenericEventCookie);
+ try
+ {
+ if (xev.type == XEventName.GenericEvent)
+ {
+ if (_platform.XI2 != null && _platform.Info.XInputOpcode ==
+ xev.GenericEventCookie.extension)
+ {
+ _platform.XI2.OnEvent((XIEvent*)xev.GenericEventCookie.data);
+ }
+ }
+ else if (_eventHandlers.TryGetValue(xev.AnyEvent.window, out var handler))
+ handler(xev);
+ }
+ finally
+ {
+ if (xev.type == XEventName.GenericEvent && xev.GenericEventCookie.data != null)
+ XFreeEventData(_display, &xev.GenericEventCookie);
+ }
+ }
+
+ Dispatcher.UIThread.RunJobs();
+ }
+
+ public void RunLoop(CancellationToken cancellationToken)
+ {
+ var readyTimers = new List();
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ var now = _clock.Elapsed;
+ TimeSpan? nextTick = null;
+ readyTimers.Clear();
+ lock(_timers)
+ foreach (var t in _timers)
+ {
+ if (nextTick == null || t.NextTick < nextTick.Value)
+ nextTick = t.NextTick;
+ if (t.NextTick < now)
+ readyTimers.Add(t);
+ }
+
+ readyTimers.Sort(TimerComparer);
+
+ foreach (var t in readyTimers)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ return;
+ t.Tick();
+ if(!t.Disposed)
+ {
+ t.Reschedule();
+ if (nextTick == null || t.NextTick < nextTick.Value)
+ nextTick = t.NextTick;
+ }
+ }
+
+ if (cancellationToken.IsCancellationRequested)
+ return;
+ //Flush whatever requests were made to XServer
+ XFlush(_display);
+ epoll_event ev;
+ if (XPending(_display) == 0)
+ epoll_wait(_epoll, &ev, 1,
+ nextTick == null ? -1 : Math.Max(1, (int)(nextTick.Value - _clock.Elapsed).TotalMilliseconds));
+ if (cancellationToken.IsCancellationRequested)
+ return;
+ CheckSignaled();
+ HandleX11(cancellationToken);
+ }
+ }
+
+
+
+ public void Signal(DispatcherPriority priority)
+ {
+ lock (_lock)
+ {
+ if (priority > _signaledPriority)
+ _signaledPriority = priority;
+
+ if(_signaled)
+ return;
+ _signaled = true;
+ int buf = 0;
+ write(_sigwrite, &buf, new IntPtr(1));
+ }
+ }
+
+ public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _mainThread;
+ public event Action Signaled;
+
+ public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
+ {
+ if (_mainThread != Thread.CurrentThread)
+ throw new InvalidOperationException("StartTimer can be only called from UI thread");
+ if (interval <= TimeSpan.Zero)
+ throw new ArgumentException("Interval must be positive", nameof(interval));
+
+ // We assume that we are on the main thread and outside of epoll_wait, so there is no need for wakeup signal
+
+ var timer = new X11Timer(this, priority, interval, tick);
+ lock(_timers)
+ _timers.Add(timer);
+ return timer;
+ }
+ }
+}
diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs
new file mode 100644
index 0000000000..f2a0520c10
--- /dev/null
+++ b/src/Avalonia.X11/X11Screens.cs
@@ -0,0 +1,252 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.InteropServices;
+using Avalonia.Platform;
+using static Avalonia.X11.XLib;
+using JetBrains.Annotations;
+
+namespace Avalonia.X11
+{
+ class X11Screens : IScreenImpl
+ {
+ private IX11Screens _impl;
+
+ public X11Screens(IX11Screens impl)
+ {
+ _impl = impl;
+ }
+
+ static unsafe X11Screen[] UpdateWorkArea(X11Info info, X11Screen[] screens)
+ {
+ var rect = default(PixelRect);
+ foreach (var s in screens)
+ {
+ rect = rect.Union(s.Bounds);
+ //Fallback value
+ s.WorkingArea = s.Bounds;
+ }
+
+ var res = XGetWindowProperty(info.Display,
+ info.RootWindow,
+ info.Atoms._NET_WORKAREA,
+ IntPtr.Zero,
+ new IntPtr(128),
+ false,
+ info.Atoms.AnyPropertyType,
+ out var type,
+ out var format,
+ out var count,
+ out var bytesAfter,
+ out var prop);
+
+ if (res != (int)Status.Success || type == IntPtr.Zero ||
+ format == 0 || bytesAfter.ToInt64() != 0 || count.ToInt64() % 4 != 0)
+ return screens;
+
+ var pwa = (IntPtr*)prop;
+ var wa = new PixelRect(pwa[0].ToInt32(), pwa[1].ToInt32(), pwa[2].ToInt32(), pwa[3].ToInt32());
+
+
+ foreach (var s in screens)
+ s.WorkingArea = s.Bounds.Intersect(wa);
+
+ XFree(prop);
+ return screens;
+ }
+
+ class Randr15ScreensImpl : IX11Screens
+ {
+ private readonly X11ScreensUserSettings _settings;
+ private X11Screen[] _cache;
+ private X11Info _x11;
+ private IntPtr _window;
+
+ public Randr15ScreensImpl(AvaloniaX11Platform platform, X11ScreensUserSettings settings)
+ {
+ _settings = settings;
+ _x11 = platform.Info;
+ _window = CreateEventWindow(platform, OnEvent);
+ XRRSelectInput(_x11.Display, _window, RandrEventMask.RRScreenChangeNotify);
+ }
+
+ private void OnEvent(XEvent ev)
+ {
+ // Invalidate cache on RRScreenChangeNotify
+ if ((int)ev.type == _x11.RandrEventBase + (int)RandrEvent.RRScreenChangeNotify)
+ _cache = null;
+ }
+
+ public unsafe X11Screen[] Screens
+ {
+ get
+ {
+ if (_cache != null)
+ return _cache;
+ var monitors = XRRGetMonitors(_x11.Display, _window, true, out var count);
+
+ var screens = new X11Screen[count];
+ for (var c = 0; c < count; c++)
+ {
+ var mon = monitors[c];
+ var namePtr = XGetAtomName(_x11.Display, mon.Name);
+ var name = Marshal.PtrToStringAnsi(namePtr);
+ XFree(namePtr);
+
+ var density = 1d;
+ if (_settings.NamedScaleFactors?.TryGetValue(name, out density) != true)
+ {
+ if (mon.MWidth == 0)
+ density = 1;
+ else
+ density = X11Screen.GuessPixelDensity(mon.Width, mon.MWidth);
+ }
+
+ density *= _settings.GlobalScaleFactor;
+
+ var bounds = new PixelRect(mon.X, mon.Y, mon.Width, mon.Height);
+ screens[c] = new X11Screen(bounds,
+ mon.Primary != 0,
+ name,
+ (mon.MWidth == 0 || mon.MHeight == 0) ? (Size?)null : new Size(mon.MWidth, mon.MHeight),
+ density);
+ }
+
+ XFree(new IntPtr(monitors));
+ _cache = UpdateWorkArea(_x11, screens);
+ return screens;
+ }
+ }
+ }
+
+ class FallbackScreensImpl : IX11Screens
+ {
+ public FallbackScreensImpl(X11Info info, X11ScreensUserSettings settings)
+ {
+ if (XGetGeometry(info.Display, info.RootWindow, out var geo))
+ {
+
+ Screens = UpdateWorkArea(info,
+ new[]
+ {
+ new X11Screen(new PixelRect(0, 0, geo.width, geo.height), true, "Default", null,
+ settings.GlobalScaleFactor)
+ });
+ }
+
+ Screens = new[] {new X11Screen(new PixelRect(0, 0, 1920, 1280), true, "Default", null, settings.GlobalScaleFactor)};
+ }
+
+ public X11Screen[] Screens { get; }
+ }
+
+ public static IX11Screens Init(AvaloniaX11Platform platform)
+ {
+ var info = platform.Info;
+ var settings = X11ScreensUserSettings.Detect();
+ var impl = (info.RandrVersion != null && info.RandrVersion >= new Version(1, 5))
+ ? new Randr15ScreensImpl(platform, settings)
+ : (IX11Screens)new FallbackScreensImpl(info, settings);
+
+ return impl;
+
+ }
+
+
+ public int ScreenCount => _impl.Screens.Length;
+
+ public Screen[] AllScreens =>
+ _impl.Screens.Select(s => new Screen(s.Bounds, s.WorkingArea, s.Primary)).ToArray();
+ }
+
+ interface IX11Screens
+ {
+ X11Screen[] Screens { get; }
+ }
+
+ class X11ScreensUserSettings
+ {
+ public double GlobalScaleFactor { get; set; } = 1;
+ public Dictionary NamedScaleFactors { get; set; }
+
+ static double? TryParse(string s)
+ {
+ if (s == null)
+ return null;
+ if (double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var rv))
+ return rv;
+ return null;
+ }
+
+
+ public static X11ScreensUserSettings DetectEnvironment()
+ {
+ var globalFactor = Environment.GetEnvironmentVariable("AVALONIA_GLOBAL_SCALE_FACTOR");
+ var screenFactors = Environment.GetEnvironmentVariable("AVALONIA_SCREEN_SCALE_FACTORS");
+ if (globalFactor == null && screenFactors == null)
+ return null;
+
+ var rv = new X11ScreensUserSettings
+ {
+ GlobalScaleFactor = TryParse(globalFactor) ?? 1
+ };
+
+ try
+ {
+ if (!string.IsNullOrWhiteSpace(screenFactors))
+ {
+ rv.NamedScaleFactors = screenFactors.Split(';').Where(x => !string.IsNullOrWhiteSpace(x))
+ .Select(x => x.Split('=')).ToDictionary(x => x[0],
+ x => double.Parse(x[1], CultureInfo.InvariantCulture));
+ }
+ }
+ catch
+ {
+ //Ignore
+ }
+
+ return rv;
+ }
+
+
+ public static X11ScreensUserSettings Detect()
+ {
+ return DetectEnvironment() ?? new X11ScreensUserSettings();
+ }
+ }
+
+ class X11Screen
+ {
+ public bool Primary { get; }
+ public string Name { get; set; }
+ public PixelRect Bounds { get; set; }
+ public Size? PhysicalSize { get; set; }
+ public double PixelDensity { get; set; }
+ public PixelRect WorkingArea { get; set; }
+
+ public X11Screen(PixelRect bounds, bool primary,
+ string name, Size? physicalSize, double? pixelDensity)
+ {
+ Primary = primary;
+ Name = name;
+ Bounds = bounds;
+ if (physicalSize == null && pixelDensity == null)
+ {
+ PixelDensity = 1;
+ }
+ else if (pixelDensity == null)
+ {
+ PixelDensity = GuessPixelDensity(bounds.Width, physicalSize.Value.Width);
+ }
+ else
+ {
+ PixelDensity = pixelDensity.Value;
+ PhysicalSize = physicalSize;
+ }
+ }
+
+ public static double GuessPixelDensity(double pixelWidth, double mmWidth)
+ => Math.Max(1, Math.Round(pixelWidth / mmWidth * 25.4 / 96));
+ }
+}
diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs
new file mode 100644
index 0000000000..0ae5c16aef
--- /dev/null
+++ b/src/Avalonia.X11/X11Structs.cs
@@ -0,0 +1,1886 @@
+// 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.
+//
+// Copyright (c) 2004 Novell, Inc.
+//
+// Authors:
+// Peter Bartok pbartok@novell.com
+//
+
+
+// NOT COMPLETE
+
+using System;
+using System.ComponentModel;
+using System.Collections;
+using System.Drawing;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+// ReSharper disable FieldCanBeMadeReadOnly.Global
+// ReSharper disable IdentifierTypo
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
+// ReSharper disable CommentTypo
+// ReSharper disable ArrangeThisQualifier
+// ReSharper disable NotAccessedField.Global
+#pragma warning disable 649
+
+namespace Avalonia.X11 {
+ //
+ // In the structures below, fields of type long are mapped to IntPtr.
+ // This will work on all platforms where sizeof(long)==sizeof(void*), which
+ // is almost all platforms except WIN64.
+ //
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XAnyEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XKeyEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr root;
+ internal IntPtr subwindow;
+ internal IntPtr time;
+ internal int x;
+ internal int y;
+ internal int x_root;
+ internal int y_root;
+ internal XModifierMask state;
+ internal int keycode;
+ internal bool same_screen;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XButtonEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr root;
+ internal IntPtr subwindow;
+ internal IntPtr time;
+ internal int x;
+ internal int y;
+ internal int x_root;
+ internal int y_root;
+ internal XModifierMask state;
+ internal int button;
+ internal bool same_screen;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XMotionEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr root;
+ internal IntPtr subwindow;
+ internal IntPtr time;
+ internal int x;
+ internal int y;
+ internal int x_root;
+ internal int y_root;
+ internal XModifierMask state;
+ internal byte is_hint;
+ internal bool same_screen;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XCrossingEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr root;
+ internal IntPtr subwindow;
+ internal IntPtr time;
+ internal int x;
+ internal int y;
+ internal int x_root;
+ internal int y_root;
+ internal NotifyMode mode;
+ internal NotifyDetail detail;
+ internal bool same_screen;
+ internal bool focus;
+ internal XModifierMask state;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XFocusChangeEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int mode;
+ internal NotifyDetail detail;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XKeymapEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal byte key_vector0;
+ internal byte key_vector1;
+ internal byte key_vector2;
+ internal byte key_vector3;
+ internal byte key_vector4;
+ internal byte key_vector5;
+ internal byte key_vector6;
+ internal byte key_vector7;
+ internal byte key_vector8;
+ internal byte key_vector9;
+ internal byte key_vector10;
+ internal byte key_vector11;
+ internal byte key_vector12;
+ internal byte key_vector13;
+ internal byte key_vector14;
+ internal byte key_vector15;
+ internal byte key_vector16;
+ internal byte key_vector17;
+ internal byte key_vector18;
+ internal byte key_vector19;
+ internal byte key_vector20;
+ internal byte key_vector21;
+ internal byte key_vector22;
+ internal byte key_vector23;
+ internal byte key_vector24;
+ internal byte key_vector25;
+ internal byte key_vector26;
+ internal byte key_vector27;
+ internal byte key_vector28;
+ internal byte key_vector29;
+ internal byte key_vector30;
+ internal byte key_vector31;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XExposeEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int count;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XGraphicsExposeEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr drawable;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int count;
+ internal int major_code;
+ internal int minor_code;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XNoExposeEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr drawable;
+ internal int major_code;
+ internal int minor_code;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XVisibilityEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int state;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XCreateWindowEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr parent;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal bool override_redirect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XDestroyWindowEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XUnmapEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal bool from_configure;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XMapEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal bool override_redirect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XMapRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr parent;
+ internal IntPtr window;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XReparentEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal IntPtr parent;
+ internal int x;
+ internal int y;
+ internal bool override_redirect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XConfigureEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal IntPtr above;
+ internal bool override_redirect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XGravityEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XResizeRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int width;
+ internal int height;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XConfigureRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr parent;
+ internal IntPtr window;
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal IntPtr above;
+ internal int detail;
+ internal IntPtr value_mask;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XCirculateEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr xevent;
+ internal IntPtr window;
+ internal int place;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XCirculateRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr parent;
+ internal IntPtr window;
+ internal int place;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XPropertyEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr atom;
+ internal IntPtr time;
+ internal int state;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSelectionClearEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr selection;
+ internal IntPtr time;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSelectionRequestEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr owner;
+ internal IntPtr requestor;
+ internal IntPtr selection;
+ internal IntPtr target;
+ internal IntPtr property;
+ internal IntPtr time;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSelectionEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr requestor;
+ internal IntPtr selection;
+ internal IntPtr target;
+ internal IntPtr property;
+ internal IntPtr time;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XColormapEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr colormap;
+ internal bool c_new;
+ internal int state;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XClientMessageEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal IntPtr message_type;
+ internal int format;
+ internal IntPtr ptr1;
+ internal IntPtr ptr2;
+ internal IntPtr ptr3;
+ internal IntPtr ptr4;
+ internal IntPtr ptr5;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XMappingEvent {
+ internal XEventName type;
+ internal IntPtr serial;
+ internal bool send_event;
+ internal IntPtr display;
+ internal IntPtr window;
+ internal int request;
+ internal int first_keycode;
+ internal int count;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XErrorEvent {
+ internal XEventName type;
+ internal IntPtr display;
+ internal IntPtr resourceid;
+ internal IntPtr serial;
+ internal byte error_code;
+ internal XRequest request_code;
+ internal byte minor_code;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XEventPad {
+ internal IntPtr pad0;
+ internal IntPtr pad1;
+ internal IntPtr pad2;
+ internal IntPtr pad3;
+ internal IntPtr pad4;
+ internal IntPtr pad5;
+ internal IntPtr pad6;
+ internal IntPtr pad7;
+ internal IntPtr pad8;
+ internal IntPtr pad9;
+ internal IntPtr pad10;
+ internal IntPtr pad11;
+ internal IntPtr pad12;
+ internal IntPtr pad13;
+ internal IntPtr pad14;
+ internal IntPtr pad15;
+ internal IntPtr pad16;
+ internal IntPtr pad17;
+ internal IntPtr pad18;
+ internal IntPtr pad19;
+ internal IntPtr pad20;
+ internal IntPtr pad21;
+ internal IntPtr pad22;
+ internal IntPtr pad23;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct XGenericEventCookie
+ {
+ internal int type; /* of event. Always GenericEvent */
+ internal IntPtr serial; /* # of last request processed */
+ internal bool send_event; /* true if from SendEvent request */
+ internal IntPtr display; /* Display the event was read from */
+ internal int extension; /* major opcode of extension that caused the event */
+ internal int evtype; /* actual event type. */
+ internal uint cookie;
+ internal void* data;
+
+ public T GetEvent() where T : unmanaged
+ {
+ if (data == null)
+ throw new InvalidOperationException();
+ return *(T*)data;
+ }
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct XEvent {
+ [ FieldOffset(0) ] internal XEventName type;
+ [ FieldOffset(0) ] internal XAnyEvent AnyEvent;
+ [ FieldOffset(0) ] internal XKeyEvent KeyEvent;
+ [ FieldOffset(0) ] internal XButtonEvent ButtonEvent;
+ [ FieldOffset(0) ] internal XMotionEvent MotionEvent;
+ [ FieldOffset(0) ] internal XCrossingEvent CrossingEvent;
+ [ FieldOffset(0) ] internal XFocusChangeEvent FocusChangeEvent;
+ [ FieldOffset(0) ] internal XExposeEvent ExposeEvent;
+ [ FieldOffset(0) ] internal XGraphicsExposeEvent GraphicsExposeEvent;
+ [ FieldOffset(0) ] internal XNoExposeEvent NoExposeEvent;
+ [ FieldOffset(0) ] internal XVisibilityEvent VisibilityEvent;
+ [ FieldOffset(0) ] internal XCreateWindowEvent CreateWindowEvent;
+ [ FieldOffset(0) ] internal XDestroyWindowEvent DestroyWindowEvent;
+ [ FieldOffset(0) ] internal XUnmapEvent UnmapEvent;
+ [ FieldOffset(0) ] internal XMapEvent MapEvent;
+ [ FieldOffset(0) ] internal XMapRequestEvent MapRequestEvent;
+ [ FieldOffset(0) ] internal XReparentEvent ReparentEvent;
+ [ FieldOffset(0) ] internal XConfigureEvent ConfigureEvent;
+ [ FieldOffset(0) ] internal XGravityEvent GravityEvent;
+ [ FieldOffset(0) ] internal XResizeRequestEvent ResizeRequestEvent;
+ [ FieldOffset(0) ] internal XConfigureRequestEvent ConfigureRequestEvent;
+ [ FieldOffset(0) ] internal XCirculateEvent CirculateEvent;
+ [ FieldOffset(0) ] internal XCirculateRequestEvent CirculateRequestEvent;
+ [ FieldOffset(0) ] internal XPropertyEvent PropertyEvent;
+ [ FieldOffset(0) ] internal XSelectionClearEvent SelectionClearEvent;
+ [ FieldOffset(0) ] internal XSelectionRequestEvent SelectionRequestEvent;
+ [ FieldOffset(0) ] internal XSelectionEvent SelectionEvent;
+ [ FieldOffset(0) ] internal XColormapEvent ColormapEvent;
+ [ FieldOffset(0) ] internal XClientMessageEvent ClientMessageEvent;
+ [ FieldOffset(0) ] internal XMappingEvent MappingEvent;
+ [ FieldOffset(0) ] internal XErrorEvent ErrorEvent;
+ [ FieldOffset(0) ] internal XKeymapEvent KeymapEvent;
+ [ FieldOffset(0) ] internal XGenericEventCookie GenericEventCookie;
+
+ //[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=24)]
+ //[ FieldOffset(0) ] internal int[] pad;
+ [ FieldOffset(0) ] internal XEventPad Pad;
+ public override string ToString() {
+ switch (type)
+ {
+ case XEventName.ButtonPress:
+ case XEventName.ButtonRelease:
+ return ToString (ButtonEvent);
+ case XEventName.CirculateNotify:
+ case XEventName.CirculateRequest:
+ return ToString (CirculateEvent);
+ case XEventName.ClientMessage:
+ return ToString (ClientMessageEvent);
+ case XEventName.ColormapNotify:
+ return ToString (ColormapEvent);
+ case XEventName.ConfigureNotify:
+ return ToString (ConfigureEvent);
+ case XEventName.ConfigureRequest:
+ return ToString (ConfigureRequestEvent);
+ case XEventName.CreateNotify:
+ return ToString (CreateWindowEvent);
+ case XEventName.DestroyNotify:
+ return ToString (DestroyWindowEvent);
+ case XEventName.Expose:
+ return ToString (ExposeEvent);
+ case XEventName.FocusIn:
+ case XEventName.FocusOut:
+ return ToString (FocusChangeEvent);
+ case XEventName.GraphicsExpose:
+ return ToString (GraphicsExposeEvent);
+ case XEventName.GravityNotify:
+ return ToString (GravityEvent);
+ case XEventName.KeymapNotify:
+ return ToString (KeymapEvent);
+ case XEventName.MapNotify:
+ return ToString (MapEvent);
+ case XEventName.MappingNotify:
+ return ToString (MappingEvent);
+ case XEventName.MapRequest:
+ return ToString (MapRequestEvent);
+ case XEventName.MotionNotify:
+ return ToString (MotionEvent);
+ case XEventName.NoExpose:
+ return ToString (NoExposeEvent);
+ case XEventName.PropertyNotify:
+ return ToString (PropertyEvent);
+ case XEventName.ReparentNotify:
+ return ToString (ReparentEvent);
+ case XEventName.ResizeRequest:
+ return ToString (ResizeRequestEvent);
+ case XEventName.SelectionClear:
+ return ToString (SelectionClearEvent);
+ case XEventName.SelectionNotify:
+ return ToString (SelectionEvent);
+ case XEventName.SelectionRequest:
+ return ToString (SelectionRequestEvent);
+ case XEventName.UnmapNotify:
+ return ToString (UnmapEvent);
+ case XEventName.VisibilityNotify:
+ return ToString (VisibilityEvent);
+ case XEventName.EnterNotify:
+ case XEventName.LeaveNotify:
+ return ToString (CrossingEvent);
+ default:
+ return type.ToString ();
+ }
+ }
+
+ public static string ToString (object ev)
+ {
+ string result = string.Empty;
+ Type type = ev.GetType ();
+ FieldInfo [] fields = type.GetFields (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance);
+ for (int i = 0; i < fields.Length; i++) {
+ if (result != string.Empty) {
+ result += ", ";
+ }
+ object value = fields [i].GetValue (ev);
+ result += fields [i].Name + "=" + (value == null ? "" : value.ToString ());
+ }
+ return type.Name + " (" + result + ")";
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XSetWindowAttributes {
+ internal IntPtr background_pixmap;
+ internal IntPtr background_pixel;
+ internal IntPtr border_pixmap;
+ internal IntPtr border_pixel;
+ internal Gravity bit_gravity;
+ internal Gravity win_gravity;
+ internal int backing_store;
+ internal IntPtr backing_planes;
+ internal IntPtr backing_pixel;
+ internal bool save_under;
+ internal IntPtr event_mask;
+ internal IntPtr do_not_propagate_mask;
+ internal bool override_redirect;
+ internal IntPtr colormap;
+ internal IntPtr cursor;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XWindowAttributes {
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal int depth;
+ internal IntPtr visual;
+ internal IntPtr root;
+ internal int c_class;
+ internal Gravity bit_gravity;
+ internal Gravity win_gravity;
+ internal int backing_store;
+ internal IntPtr backing_planes;
+ internal IntPtr backing_pixel;
+ internal bool save_under;
+ internal IntPtr colormap;
+ internal bool map_installed;
+ internal MapState map_state;
+ internal IntPtr all_event_masks;
+ internal IntPtr your_event_mask;
+ internal IntPtr do_not_propagate_mask;
+ internal bool override_direct;
+ internal IntPtr screen;
+
+ public override string ToString ()
+ {
+ return XEvent.ToString (this);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XTextProperty {
+ internal string value;
+ internal IntPtr encoding;
+ internal int format;
+ internal IntPtr nitems;
+ }
+
+ internal enum XWindowClass {
+ InputOutput = 1,
+ InputOnly = 2
+ }
+
+ internal enum XEventName {
+ KeyPress = 2,
+ KeyRelease = 3,
+ ButtonPress = 4,
+ ButtonRelease = 5,
+ MotionNotify = 6,
+ EnterNotify = 7,
+ LeaveNotify = 8,
+ FocusIn = 9,
+ FocusOut = 10,
+ KeymapNotify = 11,
+ Expose = 12,
+ GraphicsExpose = 13,
+ NoExpose = 14,
+ VisibilityNotify = 15,
+ CreateNotify = 16,
+ DestroyNotify = 17,
+ UnmapNotify = 18,
+ MapNotify = 19,
+ MapRequest = 20,
+ ReparentNotify = 21,
+ ConfigureNotify = 22,
+ ConfigureRequest = 23,
+ GravityNotify = 24,
+ ResizeRequest = 25,
+ CirculateNotify = 26,
+ CirculateRequest = 27,
+ PropertyNotify = 28,
+ SelectionClear = 29,
+ SelectionRequest = 30,
+ SelectionNotify = 31,
+ ColormapNotify = 32,
+ ClientMessage = 33,
+ MappingNotify = 34,
+ GenericEvent = 35,
+ LASTEvent
+ }
+
+ [Flags]
+ internal enum SetWindowValuemask {
+ Nothing = 0,
+ BackPixmap = 1,
+ BackPixel = 2,
+ BorderPixmap = 4,
+ BorderPixel = 8,
+ BitGravity = 16,
+ WinGravity = 32,
+ BackingStore = 64,
+ BackingPlanes = 128,
+ BackingPixel = 256,
+ OverrideRedirect = 512,
+ SaveUnder = 1024,
+ EventMask = 2048,
+ DontPropagate = 4096,
+ ColorMap = 8192,
+ Cursor = 16384
+ }
+
+ internal enum SendEventValues {
+ PointerWindow = 0,
+ InputFocus = 1
+ }
+
+ internal enum CreateWindowArgs {
+ CopyFromParent = 0,
+ ParentRelative = 1,
+ InputOutput = 1,
+ InputOnly = 2
+ }
+
+ internal enum Gravity {
+ ForgetGravity = 0,
+ NorthWestGravity= 1,
+ NorthGravity = 2,
+ NorthEastGravity= 3,
+ WestGravity = 4,
+ CenterGravity = 5,
+ EastGravity = 6,
+ SouthWestGravity= 7,
+ SouthGravity = 8,
+ SouthEastGravity= 9,
+ StaticGravity = 10
+ }
+
+ internal enum XKeySym : uint {
+ XK_BackSpace = 0xFF08,
+ XK_Tab = 0xFF09,
+ XK_Clear = 0xFF0B,
+ XK_Return = 0xFF0D,
+ XK_Home = 0xFF50,
+ XK_Left = 0xFF51,
+ XK_Up = 0xFF52,
+ XK_Right = 0xFF53,
+ XK_Down = 0xFF54,
+ XK_Page_Up = 0xFF55,
+ XK_Page_Down = 0xFF56,
+ XK_End = 0xFF57,
+ XK_Begin = 0xFF58,
+ XK_Menu = 0xFF67,
+ XK_Shift_L = 0xFFE1,
+ XK_Shift_R = 0xFFE2,
+ XK_Control_L = 0xFFE3,
+ XK_Control_R = 0xFFE4,
+ XK_Caps_Lock = 0xFFE5,
+ XK_Shift_Lock = 0xFFE6,
+ XK_Meta_L = 0xFFE7,
+ XK_Meta_R = 0xFFE8,
+ XK_Alt_L = 0xFFE9,
+ XK_Alt_R = 0xFFEA,
+ XK_Super_L = 0xFFEB,
+ XK_Super_R = 0xFFEC,
+ XK_Hyper_L = 0xFFED,
+ XK_Hyper_R = 0xFFEE,
+ }
+
+ [Flags]
+ internal enum EventMask {
+ NoEventMask = 0,
+ KeyPressMask = 1<<0,
+ KeyReleaseMask = 1<<1,
+ ButtonPressMask = 1<<2,
+ ButtonReleaseMask = 1<<3,
+ EnterWindowMask = 1<<4,
+ LeaveWindowMask = 1<<5,
+ PointerMotionMask = 1<<6,
+ PointerMotionHintMask = 1<<7,
+ Button1MotionMask = 1<<8,
+ Button2MotionMask = 1<<9,
+ Button3MotionMask = 1<<10,
+ Button4MotionMask = 1<<11,
+ Button5MotionMask = 1<<12,
+ ButtonMotionMask = 1<<13,
+ KeymapStateMask = 1<<14,
+ ExposureMask = 1<<15,
+ VisibilityChangeMask = 1<<16,
+ StructureNotifyMask = 1<<17,
+ ResizeRedirectMask = 1<<18,
+ SubstructureNotifyMask = 1<<19,
+ SubstructureRedirectMask= 1<<20,
+ FocusChangeMask = 1<<21,
+ PropertyChangeMask = 1<<22,
+ ColormapChangeMask = 1<<23,
+ OwnerGrabButtonMask = 1<<24
+ }
+
+ [Flags]
+ internal enum RandrEventMask
+ {
+ RRScreenChangeNotify = 1 << 0,
+
+/* V1.2 additions */
+ RRCrtcChangeNotifyMask = 1 << 1,
+ RROutputChangeNotifyMask = 1 << 2,
+ RROutputPropertyNotifyMask = 1 << 3,
+
+/* V1.4 additions */
+ RRProviderChangeNotifyMask = 1 << 4,
+ RRProviderPropertyNotifyMask = 1 << 5,
+ RRResourceChangeNotifyMask = 1 << 6,
+
+/* V1.6 additions */
+ RRLeaseNotifyMask = 1 << 7
+ }
+
+ internal enum RandrEvent
+ {
+ RRScreenChangeNotify = 0,
+
+ /* V1.2 additions */
+ RRNotify = 1
+ }
+
+ internal enum RandrRotate
+ {
+ /* used in the rotation field; rotation and reflection in 0.1 proto. */
+ RR_Rotate_0 = 1,
+ RR_Rotate_90 = 2,
+ RR_Rotate_180 = 4,
+ RR_Rotate_270 = 8
+ }
+
+ internal enum GrabMode {
+ GrabModeSync = 0,
+ GrabModeAsync = 1
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XStandardColormap {
+ internal IntPtr colormap;
+ internal IntPtr red_max;
+ internal IntPtr red_mult;
+ internal IntPtr green_max;
+ internal IntPtr green_mult;
+ internal IntPtr blue_max;
+ internal IntPtr blue_mult;
+ internal IntPtr base_pixel;
+ internal IntPtr visualid;
+ internal IntPtr killid;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack=2)]
+ internal struct XColor {
+ internal IntPtr pixel;
+ internal ushort red;
+ internal ushort green;
+ internal ushort blue;
+ internal byte flags;
+ internal byte pad;
+ }
+
+ internal enum Atom {
+ AnyPropertyType = 0,
+ XA_PRIMARY = 1,
+ XA_SECONDARY = 2,
+ XA_ARC = 3,
+ XA_ATOM = 4,
+ XA_BITMAP = 5,
+ XA_CARDINAL = 6,
+ XA_COLORMAP = 7,
+ XA_CURSOR = 8,
+ XA_CUT_BUFFER0 = 9,
+ XA_CUT_BUFFER1 = 10,
+ XA_CUT_BUFFER2 = 11,
+ XA_CUT_BUFFER3 = 12,
+ XA_CUT_BUFFER4 = 13,
+ XA_CUT_BUFFER5 = 14,
+ XA_CUT_BUFFER6 = 15,
+ XA_CUT_BUFFER7 = 16,
+ XA_DRAWABLE = 17,
+ XA_FONT = 18,
+ XA_INTEGER = 19,
+ XA_PIXMAP = 20,
+ XA_POINT = 21,
+ XA_RECTANGLE = 22,
+ XA_RESOURCE_MANAGER = 23,
+ XA_RGB_COLOR_MAP = 24,
+ XA_RGB_BEST_MAP = 25,
+ XA_RGB_BLUE_MAP = 26,
+ XA_RGB_DEFAULT_MAP = 27,
+ XA_RGB_GRAY_MAP = 28,
+ XA_RGB_GREEN_MAP = 29,
+ XA_RGB_RED_MAP = 30,
+ XA_STRING = 31,
+ XA_VISUALID = 32,
+ XA_WINDOW = 33,
+ XA_WM_COMMAND = 34,
+ XA_WM_HINTS = 35,
+ XA_WM_CLIENT_MACHINE = 36,
+ XA_WM_ICON_NAME = 37,
+ XA_WM_ICON_SIZE = 38,
+ XA_WM_NAME = 39,
+ XA_WM_NORMAL_HINTS = 40,
+ XA_WM_SIZE_HINTS = 41,
+ XA_WM_ZOOM_HINTS = 42,
+ XA_MIN_SPACE = 43,
+ XA_NORM_SPACE = 44,
+ XA_MAX_SPACE = 45,
+ XA_END_SPACE = 46,
+ XA_SUPERSCRIPT_X = 47,
+ XA_SUPERSCRIPT_Y = 48,
+ XA_SUBSCRIPT_X = 49,
+ XA_SUBSCRIPT_Y = 50,
+ XA_UNDERLINE_POSITION = 51,
+ XA_UNDERLINE_THICKNESS = 52,
+ XA_STRIKEOUT_ASCENT = 53,
+ XA_STRIKEOUT_DESCENT = 54,
+ XA_ITALIC_ANGLE = 55,
+ XA_X_HEIGHT = 56,
+ XA_QUAD_WIDTH = 57,
+ XA_WEIGHT = 58,
+ XA_POINT_SIZE = 59,
+ XA_RESOLUTION = 60,
+ XA_COPYRIGHT = 61,
+ XA_NOTICE = 62,
+ XA_FONT_NAME = 63,
+ XA_FAMILY_NAME = 64,
+ XA_FULL_NAME = 65,
+ XA_CAP_HEIGHT = 66,
+ XA_WM_CLASS = 67,
+ XA_WM_TRANSIENT_FOR = 68,
+
+ XA_LAST_PREDEFINED = 68
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XScreen {
+ internal IntPtr ext_data;
+ internal IntPtr display;
+ internal IntPtr root;
+ internal int width;
+ internal int height;
+ internal int mwidth;
+ internal int mheight;
+ internal int ndepths;
+ internal IntPtr depths;
+ internal int root_depth;
+ internal IntPtr root_visual;
+ internal IntPtr default_gc;
+ internal IntPtr cmap;
+ internal IntPtr white_pixel;
+ internal IntPtr black_pixel;
+ internal int max_maps;
+ internal int min_maps;
+ internal int backing_store;
+ internal bool save_unders;
+ internal IntPtr root_input_mask;
+ }
+
+ [Flags]
+ internal enum ChangeWindowFlags {
+ CWX = 1<<0,
+ CWY = 1<<1,
+ CWWidth = 1<<2,
+ CWHeight = 1<<3,
+ CWBorderWidth = 1<<4,
+ CWSibling = 1<<5,
+ CWStackMode = 1<<6
+ }
+
+ internal enum StackMode {
+ Above = 0,
+ Below = 1,
+ TopIf = 2,
+ BottomIf = 3,
+ Opposite = 4
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XWindowChanges {
+ internal int x;
+ internal int y;
+ internal int width;
+ internal int height;
+ internal int border_width;
+ internal IntPtr sibling;
+ internal StackMode stack_mode;
+ }
+
+ [Flags]
+ internal enum ColorFlags {
+ DoRed = 1<<0,
+ DoGreen = 1<<1,
+ DoBlue = 1<<2
+ }
+
+ internal enum NotifyMode {
+ NotifyNormal = 0,
+ NotifyGrab = 1,
+ NotifyUngrab = 2
+ }
+
+ internal enum NotifyDetail {
+ NotifyAncestor = 0,
+ NotifyVirtual = 1,
+ NotifyInferior = 2,
+ NotifyNonlinear = 3,
+ NotifyNonlinearVirtual = 4,
+ NotifyPointer = 5,
+ NotifyPointerRoot = 6,
+ NotifyDetailNone = 7
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MotifWmHints {
+ internal IntPtr flags;
+ internal IntPtr functions;
+ internal IntPtr decorations;
+ internal IntPtr input_mode;
+ internal IntPtr status;
+
+ public override string ToString ()
+ {
+ return string.Format("MotifWmHints _transientChildren = new HashSet();
+ private X11Window _transientParent;
+ public object SyncRoot { get; } = new object();
+
+ class InputEventContainer
+ {
+ public RawInputEventArgs Event;
+ }
+ private readonly Queue _inputQueue = new Queue();
+ private InputEventContainer _lastEvent;
+ private bool _useRenderWindow = false;
+ public X11Window(AvaloniaX11Platform platform, bool popup)
+ {
+ _platform = platform;
+ _popup = popup;
+ _x11 = platform.Info;
+ _mouse = platform.MouseDevice;
+ _keyboard = platform.KeyboardDevice;
+
+ var glfeature = AvaloniaLocator.Current.GetService();
+ XSetWindowAttributes attr = new XSetWindowAttributes();
+ var valueMask = default(SetWindowValuemask);
+
+ attr.backing_store = 1;
+ attr.bit_gravity = Gravity.NorthWestGravity;
+ attr.win_gravity = Gravity.NorthWestGravity;
+ valueMask |= SetWindowValuemask.BackPixel | SetWindowValuemask.BorderPixel
+ | SetWindowValuemask.BackPixmap | SetWindowValuemask.BackingStore
+ | SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
+
+ if (popup)
+ {
+ attr.override_redirect = true;
+ valueMask |= SetWindowValuemask.OverrideRedirect;
+ }
+
+ XVisualInfo? visualInfo = null;
+
+ // OpenGL seems to be do weird things to it's current window which breaks resize sometimes
+ _useRenderWindow = glfeature != null;
+
+ var glx = glfeature as GlxGlPlatformFeature;
+ if (glx != null)
+ visualInfo = *glx.Display.VisualInfo;
+ else if (glfeature == null)
+ visualInfo = _x11.TransparentVisualInfo;
+
+ var egl = glfeature as EglGlPlatformFeature;
+
+ var visual = IntPtr.Zero;
+ var depth = 24;
+ if (visualInfo != null)
+ {
+ visual = visualInfo.Value.visual;
+ depth = (int)visualInfo.Value.depth;
+ attr.colormap = XCreateColormap(_x11.Display, _x11.RootWindow, visualInfo.Value.visual, 0);
+ valueMask |= SetWindowValuemask.ColorMap;
+ }
+
+ _handle = XCreateWindow(_x11.Display, _x11.RootWindow, 10, 10, 300, 200, 0,
+ depth,
+ (int)CreateWindowArgs.InputOutput,
+ visual,
+ new UIntPtr((uint)valueMask), ref attr);
+
+ if (_useRenderWindow)
+ _renderHandle = XCreateWindow(_x11.Display, _handle, 0, 0, 300, 200, 0, depth,
+ (int)CreateWindowArgs.InputOutput,
+ visual,
+ new UIntPtr((uint)(SetWindowValuemask.BorderPixel | SetWindowValuemask.BitGravity |
+ SetWindowValuemask.WinGravity | SetWindowValuemask.BackingStore)), ref attr);
+ else
+ _renderHandle = _handle;
+
+ Handle = new PlatformHandle(_handle, "XID");
+ _realSize = new PixelSize(300, 200);
+ platform.Windows[_handle] = OnEvent;
+ XEventMask ignoredMask = XEventMask.SubstructureRedirectMask
+ | XEventMask.ResizeRedirectMask
+ | XEventMask.PointerMotionHintMask;
+ if (platform.XI2 != null)
+ ignoredMask |= platform.XI2.AddWindow(_handle, this);
+ var mask = new IntPtr(0xffffff ^ (int)ignoredMask);
+ XSelectInput(_x11.Display, _handle, mask);
+ var protocols = new[]
+ {
+ _x11.Atoms.WM_DELETE_WINDOW
+ };
+ XSetWMProtocols(_x11.Display, _handle, protocols, protocols.Length);
+ XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_WINDOW_TYPE, _x11.Atoms.XA_ATOM,
+ 32, PropertyMode.Replace, new[] {_x11.Atoms._NET_WM_WINDOW_TYPE_NORMAL}, 1);
+
+
+ var surfaces = new List
+ {
+ new X11FramebufferSurface(_x11.DeferredDisplay, _renderHandle,
+ depth, () => Scaling)
+ };
+
+ if (egl != null)
+ surfaces.Insert(0,
+ new EglGlPlatformSurface((EglDisplay)egl.Display, egl.DeferredContext,
+ new SurfaceInfo(this, _x11.DeferredDisplay, _handle, _renderHandle)));
+ if (glx != null)
+ surfaces.Insert(0, new GlxGlPlatformSurface(glx.Display, glx.DeferredContext,
+ new SurfaceInfo(this, _x11.Display, _handle, _renderHandle)));
+
+ Surfaces = surfaces.ToArray();
+ UpdateMotifHints();
+ _xic = XCreateIC(_x11.Xim, XNames.XNInputStyle, XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing,
+ XNames.XNClientWindow, _handle, IntPtr.Zero);
+ XFlush(_x11.Display);
+ }
+
+ class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
+ {
+ private readonly X11Window _window;
+ private readonly IntPtr _display;
+ private readonly IntPtr _parent;
+
+ public SurfaceInfo(X11Window window, IntPtr display, IntPtr parent, IntPtr xid)
+ {
+ _window = window;
+ _display = display;
+ _parent = parent;
+ Handle = xid;
+ }
+ public IntPtr Handle { get; }
+
+ public PixelSize Size
+ {
+ get
+ {
+ XLockDisplay(_display);
+ XGetGeometry(_display, _parent, out var geo);
+ XResizeWindow(_display, Handle, geo.width, geo.height);
+ XUnlockDisplay(_display);
+ return new PixelSize(geo.width, geo.height);
+ }
+ }
+
+ public double Scaling => _window.Scaling;
+ }
+
+ void UpdateMotifHints()
+ {
+ var functions = MotifFunctions.Move | MotifFunctions.Close | MotifFunctions.Resize |
+ MotifFunctions.Minimize | MotifFunctions.Maximize;
+ var decorations = MotifDecorations.Menu | MotifDecorations.Title | MotifDecorations.Border |
+ MotifDecorations.Maximize | MotifDecorations.Minimize | MotifDecorations.ResizeH;
+
+ if (_popup || !_systemDecorations)
+ {
+ decorations = 0;
+ }
+
+ if (!_canResize)
+ {
+ functions &= ~(MotifFunctions.Resize | MotifFunctions.Maximize);
+ decorations &= ~(MotifDecorations.Maximize | MotifDecorations.ResizeH);
+ }
+
+ var hints = new MotifWmHints
+ {
+ flags = new IntPtr((int)(MotifFlags.Decorations | MotifFlags.Functions)),
+ decorations = new IntPtr((int)decorations),
+ functions = new IntPtr((int)functions)
+ };
+
+ XChangeProperty(_x11.Display, _handle,
+ _x11.Atoms._MOTIF_WM_HINTS, _x11.Atoms._MOTIF_WM_HINTS, 32,
+ PropertyMode.Replace, ref hints, 5);
+ }
+
+ void UpdateSizeHints(PixelSize? preResize)
+ {
+ var min = _minMaxSize.minSize;
+ var max = _minMaxSize.maxSize;
+
+ if (!_canResize)
+ max = min = _realSize;
+
+ if (preResize.HasValue)
+ {
+ var desired = preResize.Value;
+ max = new PixelSize(Math.Max(desired.Width, max.Width), Math.Max(desired.Height, max.Height));
+ min = new PixelSize(Math.Min(desired.Width, min.Width), Math.Min(desired.Height, min.Height));
+ }
+
+ var hints = new XSizeHints
+ {
+ min_width = min.Width,
+ min_height = min.Height
+ };
+ hints.height_inc = hints.width_inc = 1;
+ var flags = XSizeHintsFlags.PMinSize | XSizeHintsFlags.PResizeInc;
+ // People might be passing double.MaxValue
+ if (max.Width < 100000 && max.Height < 100000)
+ {
+ hints.max_width = max.Width;
+ hints.max_height = max.Height;
+ flags |= XSizeHintsFlags.PMaxSize;
+ }
+
+ hints.flags = (IntPtr)flags;
+
+ XSetWMNormalHints(_x11.Display, _handle, ref hints);
+ }
+
+ public Size ClientSize => new Size(_realSize.Width / Scaling, _realSize.Height / Scaling);
+
+ public double Scaling
+ {
+ get
+ {
+ lock (SyncRoot)
+ return _scaling;
+
+ }
+ private set => _scaling = value;
+ }
+
+ public IEnumerable Surfaces { get; }
+ public Action Input { get; set; }
+ public Action Paint { get; set; }
+ public Action Resized { get; set; }
+ //TODO
+ public Action ScalingChanged { get; set; }
+ public Action Deactivated { get; set; }
+ public Action Activated { get; set; }
+ public Func Closing { get; set; }
+ public Action WindowStateChanged { get; set; }
+ public Action Closed { get; set; }
+ public Action PositionChanged { get; set; }
+
+ public IRenderer CreateRenderer(IRenderRoot root) =>
+ new DeferredRenderer(root, AvaloniaLocator.Current.GetService());
+
+ void OnEvent(XEvent ev)
+ {
+ lock (SyncRoot)
+ OnEventSync(ev);
+ }
+ void OnEventSync(XEvent ev)
+ {
+ if(XFilterEvent(ref ev, _handle))
+ return;
+ if (ev.type == XEventName.MapNotify)
+ {
+ _mapped = true;
+ if (_useRenderWindow)
+ XMapWindow(_x11.Display, _renderHandle);
+ }
+ else if (ev.type == XEventName.UnmapNotify)
+ _mapped = false;
+ else if (ev.type == XEventName.Expose)
+ {
+ if (!_triggeredExpose)
+ {
+ _triggeredExpose = true;
+ Dispatcher.UIThread.Post(() =>
+ {
+ _triggeredExpose = false;
+ DoPaint();
+ }, DispatcherPriority.Render);
+ }
+ }
+ else if (ev.type == XEventName.FocusIn)
+ {
+ if (ActivateTransientChildIfNeeded())
+ return;
+ Activated?.Invoke();
+ }
+ else if (ev.type == XEventName.FocusOut)
+ Deactivated?.Invoke();
+ else if (ev.type == XEventName.MotionNotify)
+ MouseEvent(RawMouseEventType.Move, ref ev, ev.MotionEvent.state);
+ else if (ev.type == XEventName.LeaveNotify)
+ MouseEvent(RawMouseEventType.LeaveWindow, ref ev, ev.CrossingEvent.state);
+ else if (ev.type == XEventName.PropertyNotify)
+ {
+ OnPropertyChange(ev.PropertyEvent.atom, ev.PropertyEvent.state == 0);
+ }
+ else if (ev.type == XEventName.ButtonPress)
+ {
+ if (ActivateTransientChildIfNeeded())
+ return;
+ if (ev.ButtonEvent.button < 4)
+ MouseEvent(ev.ButtonEvent.button == 1 ? RawMouseEventType.LeftButtonDown
+ : ev.ButtonEvent.button == 2 ? RawMouseEventType.MiddleButtonDown
+ : RawMouseEventType.RightButtonDown, ref ev, ev.ButtonEvent.state);
+ else
+ {
+ var delta = ev.ButtonEvent.button == 4
+ ? new Vector(0, 1)
+ : ev.ButtonEvent.button == 5
+ ? new Vector(0, -1)
+ : ev.ButtonEvent.button == 6
+ ? new Vector(1, 0)
+ : new Vector(-1, 0);
+ ScheduleInput(new RawMouseWheelEventArgs(_mouse, (ulong)ev.ButtonEvent.time.ToInt64(),
+ _inputRoot, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), delta,
+ TranslateModifiers(ev.ButtonEvent.state)), ref ev);
+ }
+
+ }
+ else if (ev.type == XEventName.ButtonRelease)
+ {
+ if (ev.ButtonEvent.button < 4)
+ MouseEvent(ev.ButtonEvent.button == 1 ? RawMouseEventType.LeftButtonUp
+ : ev.ButtonEvent.button == 2 ? RawMouseEventType.MiddleButtonUp
+ : RawMouseEventType.RightButtonUp, ref ev, ev.ButtonEvent.state);
+ }
+ else if (ev.type == XEventName.ConfigureNotify)
+ {
+ if (ev.ConfigureEvent.window != _handle)
+ return;
+ var needEnqueue = (_configure == null);
+ _configure = ev.ConfigureEvent;
+ if (ev.ConfigureEvent.override_redirect || ev.ConfigureEvent.send_event)
+ _configurePoint = new PixelPoint(ev.ConfigureEvent.x, ev.ConfigureEvent.y);
+ else
+ {
+ XTranslateCoordinates(_x11.Display, _handle, _x11.RootWindow,
+ 0, 0,
+ out var tx, out var ty, out _);
+ _configurePoint = new PixelPoint(tx, ty);
+ }
+ if (needEnqueue)
+ Dispatcher.UIThread.Post(() =>
+ {
+ if (_configure == null)
+ return;
+ var cev = _configure.Value;
+ var npos = _configurePoint.Value;
+ _configure = null;
+ _configurePoint = null;
+
+ var nsize = new PixelSize(cev.width, cev.height);
+ var changedSize = _realSize != nsize;
+ var changedPos = _position == null || npos != _position;
+ _realSize = nsize;
+ _position = npos;
+ bool updatedSizeViaScaling = false;
+ if (changedPos)
+ {
+ PositionChanged?.Invoke(npos);
+ updatedSizeViaScaling = UpdateScaling();
+ }
+
+ if (changedSize && !updatedSizeViaScaling)
+ Resized?.Invoke(ClientSize);
+
+ Dispatcher.UIThread.RunJobs(DispatcherPriority.Layout);
+ }, DispatcherPriority.Layout);
+ if (_useRenderWindow)
+ XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width,
+ ev.ConfigureEvent.height);
+ }
+ else if (ev.type == XEventName.DestroyNotify && ev.AnyEvent.window == _handle)
+ {
+ Cleanup();
+ }
+ else if (ev.type == XEventName.ClientMessage)
+ {
+ if (ev.ClientMessageEvent.message_type == _x11.Atoms.WM_PROTOCOLS)
+ {
+ if (ev.ClientMessageEvent.ptr1 == _x11.Atoms.WM_DELETE_WINDOW)
+ {
+ if (Closing?.Invoke() != true)
+ Dispose();
+ }
+
+ }
+ }
+ else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease)
+ {
+ if (ActivateTransientChildIfNeeded())
+ return;
+ var buffer = stackalloc byte[40];
+
+ var latinKeysym = XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, 0);
+ ScheduleInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(),
+ ev.type == XEventName.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
+ X11KeyTransform.ConvertKey(latinKeysym), TranslateModifiers(ev.KeyEvent.state)), ref ev);
+
+ if (ev.type == XEventName.KeyPress)
+ {
+ var len = Xutf8LookupString(_xic, ref ev, buffer, 40, out _, out _);
+ if (len != 0)
+ {
+ var text = Encoding.UTF8.GetString(buffer, len);
+ if (text.Length == 1)
+ {
+ if (text[0] < ' ' || text[0] == 0x7f) //Control codes or DEL
+ return;
+ }
+ ScheduleInput(new RawTextInputEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), text),
+ ref ev);
+ }
+ }
+ }
+ }
+
+ private bool UpdateScaling()
+ {
+ lock (SyncRoot)
+ {
+ var monitor = _platform.X11Screens.Screens.OrderBy(x => x.PixelDensity)
+ .FirstOrDefault(m => m.Bounds.Contains(Position));
+ var newScaling = monitor?.PixelDensity ?? Scaling;
+ if (Scaling != newScaling)
+ {
+ Console.WriteLine(
+ $"Updating scaling from {Scaling} to {newScaling} as a response to position change to {Position}");
+ var oldScaledSize = ClientSize;
+ Scaling = newScaling;
+ ScalingChanged?.Invoke(Scaling);
+ SetMinMaxSize(_scaledMinMaxSize.minSize, _scaledMinMaxSize.maxSize);
+ Resize(oldScaledSize, true);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private WindowState _lastWindowState;
+ public WindowState WindowState
+ {
+ get => _lastWindowState;
+ set
+ {
+ if(_lastWindowState == value)
+ return;
+ _lastWindowState = value;
+ if (value == WindowState.Minimized)
+ {
+ XIconifyWindow(_x11.Display, _handle, _x11.DefaultScreen);
+ }
+ else if (value == WindowState.Maximized)
+ {
+ SendNetWMMessage(_x11.Atoms._NET_WM_STATE, (IntPtr)0, _x11.Atoms._NET_WM_STATE_HIDDEN, IntPtr.Zero);
+ SendNetWMMessage(_x11.Atoms._NET_WM_STATE, (IntPtr)1, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT,
+ _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ);
+ }
+ else
+ {
+ SendNetWMMessage(_x11.Atoms._NET_WM_STATE, (IntPtr)0, _x11.Atoms._NET_WM_STATE_HIDDEN, IntPtr.Zero);
+ SendNetWMMessage(_x11.Atoms._NET_WM_STATE, (IntPtr)0, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT,
+ _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ);
+ }
+ }
+ }
+
+ private void OnPropertyChange(IntPtr atom, bool hasValue)
+ {
+ if (atom == _x11.Atoms._NET_WM_STATE)
+ {
+ WindowState state = WindowState.Normal;
+ if(hasValue)
+ {
+
+ XGetWindowProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_STATE, IntPtr.Zero, new IntPtr(256),
+ false, (IntPtr)Atom.XA_ATOM, out _, out _, out var nitems, out _,
+ out var prop);
+ int maximized = 0;
+ var pitems = (IntPtr*)prop.ToPointer();
+ for (var c = 0; c < nitems.ToInt32(); c++)
+ {
+ if (pitems[c] == _x11.Atoms._NET_WM_STATE_HIDDEN)
+ {
+ state = WindowState.Minimized;
+ break;
+ }
+
+ if (pitems[c] == _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ ||
+ pitems[c] == _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT)
+ {
+ maximized++;
+ if (maximized == 2)
+ {
+ state = WindowState.Maximized;
+ break;
+ }
+ }
+ }
+ XFree(prop);
+ }
+ if (_lastWindowState != state)
+ {
+ _lastWindowState = state;
+ WindowStateChanged?.Invoke(state);
+ }
+ }
+
+ }
+
+
+ InputModifiers TranslateModifiers(XModifierMask state)
+ {
+ var rv = default(InputModifiers);
+ if (state.HasFlag(XModifierMask.Button1Mask))
+ rv |= InputModifiers.LeftMouseButton;
+ if (state.HasFlag(XModifierMask.Button2Mask))
+ rv |= InputModifiers.RightMouseButton;
+ if (state.HasFlag(XModifierMask.Button2Mask))
+ rv |= InputModifiers.MiddleMouseButton;
+ if (state.HasFlag(XModifierMask.ShiftMask))
+ rv |= InputModifiers.Shift;
+ if (state.HasFlag(XModifierMask.ControlMask))
+ rv |= InputModifiers.Control;
+ if (state.HasFlag(XModifierMask.Mod1Mask))
+ rv |= InputModifiers.Alt;
+ if (state.HasFlag(XModifierMask.Mod4Mask))
+ rv |= InputModifiers.Windows;
+ return rv;
+ }
+
+ private bool _systemDecorations = true;
+ private bool _canResize = true;
+ private (Size minSize, Size maxSize) _scaledMinMaxSize;
+ private (PixelSize minSize, PixelSize maxSize) _minMaxSize;
+ private double _scaling = 1;
+
+ void ScheduleInput(RawInputEventArgs args, ref XEvent xev)
+ {
+ _x11.LastActivityTimestamp = xev.ButtonEvent.time;
+ ScheduleInput(args);
+ }
+
+ public void ScheduleInput(RawInputEventArgs args)
+ {
+ if (args is RawMouseEventArgs mouse)
+ mouse.Position = mouse.Position / Scaling;
+ if (args is RawDragEvent drag)
+ drag.Location = drag.Location / Scaling;
+
+ _lastEvent = new InputEventContainer() {Event = args};
+ _inputQueue.Enqueue(_lastEvent);
+ if (_inputQueue.Count == 1)
+ {
+ Dispatcher.UIThread.Post(() =>
+ {
+ while (_inputQueue.Count > 0)
+ {
+ Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
+ var ev = _inputQueue.Dequeue();
+ Input?.Invoke(ev.Event);
+ }
+ }, DispatcherPriority.Input);
+ }
+ }
+
+ void MouseEvent(RawMouseEventType type, ref XEvent ev, XModifierMask mods)
+ {
+ var mev = new RawMouseEventArgs(
+ _mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot,
+ type, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), TranslateModifiers(mods));
+ if(type == RawMouseEventType.Move && _inputQueue.Count>0 && _lastEvent.Event is RawMouseEventArgs ma)
+ if (ma.Type == RawMouseEventType.Move)
+ {
+ _lastEvent.Event = mev;
+ return;
+ }
+ ScheduleInput(mev, ref ev);
+ }
+
+ void DoPaint()
+ {
+ _invalidated = false;
+ Paint?.Invoke(new Rect());
+ }
+
+ public void Invalidate(Rect rect)
+ {
+ if(_invalidated)
+ return;
+ _invalidated = true;
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ if (_mapped)
+ DoPaint();
+ });
+ }
+
+ public IInputRoot InputRoot => _inputRoot;
+
+ public void SetInputRoot(IInputRoot inputRoot)
+ {
+ _inputRoot = inputRoot;
+ }
+
+ public void Dispose()
+ {
+ if (_handle != IntPtr.Zero)
+ {
+ XDestroyWindow(_x11.Display, _handle);
+ Cleanup();
+ }
+ }
+
+ void Cleanup()
+ {
+ SetTransientParent(null, false);
+ if (_xic != IntPtr.Zero)
+ {
+ XDestroyIC(_xic);
+ _xic = IntPtr.Zero;
+ }
+
+ if (_handle != IntPtr.Zero)
+ {
+ XDestroyWindow(_x11.Display, _handle);
+ _platform.Windows.Remove(_handle);
+ _platform.XI2?.OnWindowDestroyed(_handle);
+ _handle = IntPtr.Zero;
+ Closed?.Invoke();
+ }
+
+ if (_useRenderWindow && _renderHandle != IntPtr.Zero)
+ {
+ XDestroyWindow(_x11.Display, _renderHandle);
+ _renderHandle = IntPtr.Zero;
+ }
+ }
+
+ bool ActivateTransientChildIfNeeded()
+ {
+ if (_transientChildren.Count == 0)
+ return false;
+ var child = _transientChildren.First();
+ if (!child.ActivateTransientChildIfNeeded())
+ child.Activate();
+ return true;
+ }
+
+ void SetTransientParent(X11Window window, bool informServer = true)
+ {
+ _transientParent?._transientChildren.Remove(this);
+ _transientParent = window;
+ _transientParent?._transientChildren.Add(this);
+ if (informServer)
+ XSetTransientForHint(_x11.Display, _handle, _transientParent?._handle ?? IntPtr.Zero);
+ }
+
+ public void Show()
+ {
+ SetTransientParent(null);
+ ShowCore();
+ }
+
+ void ShowCore()
+ {
+ XMapWindow(_x11.Display, _handle);
+ XFlush(_x11.Display);
+ }
+
+ public void Hide() => XUnmapWindow(_x11.Display, _handle);
+
+
+ public Point PointToClient(PixelPoint point) => new Point((point.X - Position.X) / Scaling, (point.Y - Position.Y) / Scaling);
+
+ public PixelPoint PointToScreen(Point point) => new PixelPoint(
+ (int)(point.X * Scaling + Position.X),
+ (int)(point.Y * Scaling + Position.Y));
+
+ public void SetSystemDecorations(bool enabled)
+ {
+ _systemDecorations = enabled;
+ UpdateMotifHints();
+ }
+
+
+ public void Resize(Size clientSize) => Resize(clientSize, false);
+
+ PixelSize ToPixelSize(Size size) => new PixelSize((int)(size.Width * Scaling), (int)(size.Height * Scaling));
+
+ void Resize(Size clientSize, bool force)
+ {
+ if (!force && clientSize == ClientSize)
+ return;
+
+ var needImmediatePopupResize = clientSize != ClientSize;
+
+ var pixelSize = ToPixelSize(clientSize);
+ UpdateSizeHints(pixelSize);
+ XConfigureResizeWindow(_x11.Display, _handle, pixelSize);
+ if (_useRenderWindow)
+ XConfigureResizeWindow(_x11.Display, _renderHandle, pixelSize);
+ XFlush(_x11.Display);
+
+ if (force || (_popup && needImmediatePopupResize))
+ {
+ _realSize = pixelSize;
+ Resized?.Invoke(ClientSize);
+ }
+ }
+
+ public void CanResize(bool value)
+ {
+ _canResize = value;
+ UpdateMotifHints();
+ UpdateSizeHints(null);
+ }
+
+ public void SetCursor(IPlatformHandle cursor)
+ {
+ if (cursor == null)
+ XDefineCursor(_x11.Display, _handle, _x11.DefaultCursor);
+ else
+ {
+ if (cursor.HandleDescriptor != "XCURSOR")
+ throw new ArgumentException("Expected XCURSOR handle type");
+ XDefineCursor(_x11.Display, _handle, cursor.Handle);
+ }
+ }
+
+ public IPlatformHandle Handle { get; }
+
+ public PixelPoint Position
+ {
+ get => _position ?? default;
+ set
+ {
+ var changes = new XWindowChanges
+ {
+ x = (int)value.X,
+ y = (int)value.Y
+ };
+ XConfigureWindow(_x11.Display, _handle, ChangeWindowFlags.CWX | ChangeWindowFlags.CWY,
+ ref changes);
+ XFlush(_x11.Display);
+
+ }
+ }
+
+ public IMouseDevice MouseDevice => _mouse;
+
+ public void Activate()
+ {
+ if (_x11.Atoms._NET_ACTIVE_WINDOW != IntPtr.Zero)
+ {
+ SendNetWMMessage(_x11.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, _x11.LastActivityTimestamp,
+ IntPtr.Zero);
+ }
+ else
+ {
+ XRaiseWindow(_x11.Display, _handle);
+ XSetInputFocus(_x11.Display, _handle, 0, IntPtr.Zero);
+ }
+ }
+
+
+ public IScreenImpl Screen => _platform.Screens;
+
+ public Size MaxClientSize => _platform.X11Screens.Screens.Select(s => s.Bounds.Size.ToSize(s.PixelDensity))
+ .OrderByDescending(x => x.Width + x.Height).FirstOrDefault();
+
+
+ void SendNetWMMessage(IntPtr message_type, IntPtr l0,
+ IntPtr? l1 = null, IntPtr? l2 = null, IntPtr? l3 = null, IntPtr? l4 = null)
+ {
+ var xev = new XEvent
+ {
+ ClientMessageEvent =
+ {
+ type = XEventName.ClientMessage,
+ send_event = true,
+ window = _handle,
+ message_type = message_type,
+ format = 32,
+ ptr1 = l0,
+ ptr2 = l1 ?? IntPtr.Zero,
+ ptr3 = l2 ?? IntPtr.Zero,
+ ptr4 = l3 ?? IntPtr.Zero
+ }
+ };
+ xev.ClientMessageEvent.ptr4 = l4 ?? IntPtr.Zero;
+ XSendEvent(_x11.Display, _x11.RootWindow, false,
+ new IntPtr((int)(EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
+
+ }
+
+ void BeginMoveResize(NetWmMoveResize side)
+ {
+ var pos = GetCursorPos(_x11);
+ XUngrabPointer(_x11.Display, new IntPtr(0));
+ SendNetWMMessage (_x11.Atoms._NET_WM_MOVERESIZE, (IntPtr) pos.x, (IntPtr) pos.y,
+ (IntPtr) side,
+ (IntPtr) 1, (IntPtr)1); // left button
+ }
+
+ public void BeginMoveDrag()
+ {
+ BeginMoveResize(NetWmMoveResize._NET_WM_MOVERESIZE_MOVE);
+ }
+
+ public void BeginResizeDrag(WindowEdge edge)
+ {
+ var side = NetWmMoveResize._NET_WM_MOVERESIZE_CANCEL;
+ if (edge == WindowEdge.East)
+ side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_RIGHT;
+ if (edge == WindowEdge.North)
+ side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_TOP;
+ if (edge == WindowEdge.South)
+ side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_BOTTOM;
+ if (edge == WindowEdge.West)
+ side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_LEFT;
+ if (edge == WindowEdge.NorthEast)
+ side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
+ if (edge == WindowEdge.NorthWest)
+ side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_TOPLEFT;
+ if (edge == WindowEdge.SouthEast)
+ side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
+ if (edge == WindowEdge.SouthWest)
+ side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
+ BeginMoveResize(side);
+ }
+
+ public void SetTitle(string title)
+ {
+ var data = Encoding.UTF8.GetBytes(title);
+ fixed (void* pdata = data)
+ {
+ XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_NAME, _x11.Atoms.UTF8_STRING, 8,
+ PropertyMode.Replace, pdata, data.Length);
+ XStoreName(_x11.Display, _handle, title);
+ }
+ }
+
+ public void SetMinMaxSize(Size minSize, Size maxSize)
+ {
+ _scaledMinMaxSize = (minSize, maxSize);
+ var min = new PixelSize(
+ (int)(minSize.Width < 1 ? 1 : minSize.Width * Scaling),
+ (int)(minSize.Height < 1 ? 1 : minSize.Height * Scaling));
+
+ const int maxDim = 100000;
+ var max = new PixelSize(
+ (int)(maxSize.Width > maxDim ? maxDim : Math.Max(min.Width, minSize.Width * Scaling)),
+ (int)(maxSize.Height > maxDim ? maxDim : Math.Max(min.Height, minSize.Height * Scaling)));
+
+ _minMaxSize = (min, max);
+ UpdateSizeHints(null);
+ }
+
+ public void SetTopmost(bool value)
+ {
+ SendNetWMMessage(_x11.Atoms._NET_WM_STATE,
+ (IntPtr)(value ? 1 : 0), _x11.Atoms._NET_WM_STATE_ABOVE, IntPtr.Zero);
+ }
+
+ public void ShowDialog(IWindowImpl parent)
+ {
+ SetTransientParent((X11Window)parent);
+ ShowCore();
+ }
+
+ public void SetIcon(IWindowIconImpl icon)
+ {
+ var data = ((X11IconData)icon).Data;
+ fixed (void* pdata = data)
+ XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON,
+ new IntPtr((int)Atom.XA_CARDINAL), 32, PropertyMode.Replace,
+ pdata, data.Length);
+ }
+
+ public void ShowTaskbarIcon(bool value)
+ {
+ SendNetWMMessage(_x11.Atoms._NET_WM_STATE,
+ (IntPtr)(value ? 0 : 1), _x11.Atoms._NET_WM_STATE_SKIP_TASKBAR, IntPtr.Zero);
+ }
+ }
+}
diff --git a/src/Avalonia.X11/XError.cs b/src/Avalonia.X11/XError.cs
new file mode 100644
index 0000000000..2cc8f63c96
--- /dev/null
+++ b/src/Avalonia.X11/XError.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Avalonia.X11
+{
+ static class XError
+ {
+ private static readonly XErrorHandler s_errorHandlerDelegate = Handler;
+ public static XErrorEvent LastError;
+ static int Handler(IntPtr display, ref XErrorEvent error)
+ {
+ LastError = error;
+ return 0;
+ }
+
+ public static void ThrowLastError(string desc)
+ {
+ var err = LastError;
+ LastError = new XErrorEvent();
+ if (err.error_code == 0)
+ throw new X11Exception(desc);
+ throw new X11Exception(desc + ": " + err.error_code);
+
+ }
+
+ public static void Init()
+ {
+ XLib.XSetErrorHandler(s_errorHandlerDelegate);
+ }
+ }
+}
diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs
new file mode 100644
index 0000000000..ee73ccc907
--- /dev/null
+++ b/src/Avalonia.X11/XI2Manager.cs
@@ -0,0 +1,269 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using static Avalonia.X11.XLib;
+namespace Avalonia.X11
+{
+ unsafe class XI2Manager
+ {
+ private X11Info _x11;
+ private Dictionary _clients = new Dictionary();
+ class DeviceInfo
+ {
+ public int Id { get; }
+ public XIValuatorClassInfo[] Valuators { get; private set; }
+ public XIScrollClassInfo[] Scrollers { get; private set; }
+ public DeviceInfo(XIDeviceInfo info)
+ {
+ Id = info.Deviceid;
+ Update(info.Classes, info.NumClasses);
+ }
+
+ public virtual void Update(XIAnyClassInfo** classes, int num)
+ {
+ var valuators = new List();
+ var scrollers = new List();
+ for (var c = 0; c < num; c++)
+ {
+ if (classes[c]->Type == XiDeviceClass.XIValuatorClass)
+ valuators.Add(*((XIValuatorClassInfo**)classes)[c]);
+ if (classes[c]->Type == XiDeviceClass.XIScrollClass)
+ scrollers.Add(*((XIScrollClassInfo**)classes)[c]);
+ }
+
+ Valuators = valuators.ToArray();
+ Scrollers = scrollers.ToArray();
+ }
+
+ public void UpdateValuators(Dictionary valuators)
+ {
+ foreach (var v in valuators)
+ {
+ if (Valuators.Length > v.Key)
+ Valuators[v.Key].Value = v.Value;
+ }
+ }
+ }
+
+ class PointerDeviceInfo : DeviceInfo
+ {
+ public PointerDeviceInfo(XIDeviceInfo info) : base(info)
+ {
+ }
+
+ public bool HasScroll(ParsedDeviceEvent ev)
+ {
+ foreach (var val in ev.Valuators)
+ if (Scrollers.Any(s => s.Number == val.Key))
+ return true;
+
+ return false;
+ }
+
+ public bool HasMotion(ParsedDeviceEvent ev)
+ {
+ foreach (var val in ev.Valuators)
+ if (Scrollers.All(s => s.Number != val.Key))
+ return true;
+
+ return false;
+ }
+
+ }
+
+ private PointerDeviceInfo _pointerDevice;
+ private AvaloniaX11Platform _platform;
+
+ public bool Init(AvaloniaX11Platform platform)
+ {
+ _platform = platform;
+ _x11 = platform.Info;
+ var devices =(XIDeviceInfo*) XIQueryDevice(_x11.Display,
+ (int)XiPredefinedDeviceId.XIAllMasterDevices, out int num);
+ for (var c = 0; c < num; c++)
+ {
+ if (devices[c].Use == XiDeviceType.XIMasterPointer)
+ {
+ _pointerDevice = new PointerDeviceInfo(devices[c]);
+ break;
+ }
+ }
+ if(_pointerDevice == null)
+ return false;
+ /*
+ int mask = 0;
+
+ XISetMask(ref mask, XiEventType.XI_DeviceChanged);
+ var emask = new XIEventMask
+ {
+ Mask = &mask,
+ Deviceid = _pointerDevice.Id,
+ MaskLen = XiEventMaskLen
+ };
+
+ if (XISelectEvents(_x11.Display, _x11.RootWindow, &emask, 1) != Status.Success)
+ return false;
+ return true;
+ */
+ return XiSelectEvents(_x11.Display, _x11.RootWindow, new Dictionary>
+ {
+ [_pointerDevice.Id] = new List
+ {
+ XiEventType.XI_DeviceChanged
+ }
+ }) == Status.Success;
+ }
+
+ public XEventMask AddWindow(IntPtr xid, IXI2Client window)
+ {
+ _clients[xid] = window;
+
+ XiSelectEvents(_x11.Display, xid, new Dictionary>
+ {
+ [_pointerDevice.Id] = new List()
+ {
+ XiEventType.XI_Motion,
+ XiEventType.XI_ButtonPress,
+ XiEventType.XI_ButtonRelease,
+ }
+ });
+
+ // We are taking over mouse input handling from here
+ return XEventMask.PointerMotionMask
+ | XEventMask.ButtonMotionMask
+ | XEventMask.Button1MotionMask
+ | XEventMask.Button2MotionMask
+ | XEventMask.Button3MotionMask
+ | XEventMask.Button4MotionMask
+ | XEventMask.Button5MotionMask
+ | XEventMask.ButtonPressMask
+ | XEventMask.ButtonReleaseMask;
+ }
+
+ public void OnWindowDestroyed(IntPtr xid) => _clients.Remove(xid);
+
+ public void OnEvent(XIEvent* xev)
+ {
+ if (xev->evtype == XiEventType.XI_DeviceChanged)
+ {
+ var changed = (XIDeviceChangedEvent*)xev;
+ _pointerDevice.Update(changed->Classes, changed->NumClasses);
+ }
+
+ //TODO: this should only be used for non-touch devices
+ if (xev->evtype >= XiEventType.XI_ButtonPress && xev->evtype <= XiEventType.XI_Motion)
+ {
+ var dev = (XIDeviceEvent*)xev;
+ if (_clients.TryGetValue(dev->EventWindow, out var client))
+ OnDeviceEvent(client, new ParsedDeviceEvent(dev));
+ }
+ }
+
+ void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
+ {
+ if (ev.Type == XiEventType.XI_Motion)
+ {
+ Vector scrollDelta = default;
+ foreach (var v in ev.Valuators)
+ {
+ foreach (var scroller in _pointerDevice.Scrollers)
+ {
+ if (scroller.Number == v.Key)
+ {
+ var old = _pointerDevice.Valuators[scroller.Number].Value;
+ // Value was zero after reset, ignore the event and use it as a reference next time
+ if (old == 0)
+ continue;
+ var diff = (old - v.Value) / scroller.Increment;
+ if (scroller.ScrollType == XiScrollType.Horizontal)
+ scrollDelta = scrollDelta.WithX(scrollDelta.X + diff);
+ else
+ scrollDelta = scrollDelta.WithY(scrollDelta.Y + diff);
+
+ }
+ }
+
+
+ }
+
+ if (scrollDelta != default)
+ client.ScheduleInput(new RawMouseWheelEventArgs(_platform.MouseDevice, ev.Timestamp,
+ client.InputRoot, ev.Position, scrollDelta, ev.Modifiers));
+ if (_pointerDevice.HasMotion(ev))
+ client.ScheduleInput(new RawMouseEventArgs(_platform.MouseDevice, ev.Timestamp, client.InputRoot,
+ RawMouseEventType.Move, ev.Position, ev.Modifiers));
+ }
+
+ if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease)
+ {
+ var down = ev.Type == XiEventType.XI_ButtonPress;
+ var type =
+ ev.Button == 1 ? (down ? RawMouseEventType.LeftButtonDown : RawMouseEventType.LeftButtonUp)
+ : ev.Button == 2 ? (down ? RawMouseEventType.MiddleButtonDown : RawMouseEventType.MiddleButtonUp)
+ : ev.Button == 3 ? (down ? RawMouseEventType.RightButtonDown : RawMouseEventType.RightButtonUp)
+ : (RawMouseEventType?)null;
+ if (type.HasValue)
+ client.ScheduleInput(new RawMouseEventArgs(_platform.MouseDevice, ev.Timestamp, client.InputRoot,
+ type.Value, ev.Position, ev.Modifiers));
+ }
+
+ _pointerDevice.UpdateValuators(ev.Valuators);
+ }
+ }
+
+ unsafe class ParsedDeviceEvent
+ {
+ public XiEventType Type { get; }
+ public InputModifiers Modifiers { get; }
+ public ulong Timestamp { get; }
+ public Point Position { get; }
+ public int Button { get; set; }
+ public Dictionary Valuators { get; }
+ public ParsedDeviceEvent(XIDeviceEvent* ev)
+ {
+ Type = ev->evtype;
+ Timestamp = (ulong)ev->time.ToInt64();
+ var state = (XModifierMask)ev->mods.Effective;
+ if (state.HasFlag(XModifierMask.ShiftMask))
+ Modifiers |= InputModifiers.Shift;
+ if (state.HasFlag(XModifierMask.ControlMask))
+ Modifiers |= InputModifiers.Control;
+ if (state.HasFlag(XModifierMask.Mod1Mask))
+ Modifiers |= InputModifiers.Alt;
+ if (state.HasFlag(XModifierMask.Mod4Mask))
+ Modifiers |= InputModifiers.Windows;
+
+ if (ev->buttons.MaskLen > 0)
+ {
+ var buttons = ev->buttons.Mask;
+ if (XIMaskIsSet(buttons, 1))
+ Modifiers |= InputModifiers.LeftMouseButton;
+
+ if (XIMaskIsSet(buttons, 2))
+ Modifiers |= InputModifiers.MiddleMouseButton;
+
+ if (XIMaskIsSet(buttons, 3))
+ Modifiers |= InputModifiers.RightMouseButton;
+ }
+
+ Valuators = new Dictionary();
+ Position = new Point(ev->event_x, ev->event_y);
+ var values = ev->valuators.Values;
+ for (var c = 0; c < ev->valuators.MaskLen * 8; c++)
+ if (XIMaskIsSet(ev->valuators.Mask, c))
+ Valuators[c] = *values++;
+ if (Type == XiEventType.XI_ButtonPress || Type == XiEventType.XI_ButtonRelease)
+ Button = ev->detail;
+ }
+ }
+
+ interface IXI2Client
+ {
+ IInputRoot InputRoot { get; }
+ void ScheduleInput(RawInputEventArgs args);
+ }
+}
diff --git a/src/Avalonia.X11/XIStructs.cs b/src/Avalonia.X11/XIStructs.cs
new file mode 100644
index 0000000000..772bd1989c
--- /dev/null
+++ b/src/Avalonia.X11/XIStructs.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Runtime.InteropServices;
+using Bool = System.Boolean;
+using Atom = System.IntPtr;
+// ReSharper disable IdentifierTypo
+// ReSharper disable FieldCanBeMadeReadOnly.Global
+// ReSharper disable MemberCanBePrivate.Global
+#pragma warning disable 649
+
+namespace Avalonia.X11
+{
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIAddMasterInfo
+ {
+ public int Type;
+ public IntPtr Name;
+ public Bool SendCore;
+ public Bool Enable;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIRemoveMasterInfo
+ {
+ public int Type;
+ public int Deviceid;
+ public int ReturnMode; /* AttachToMaster, Floating */
+ public int ReturnPointer;
+ public int ReturnKeyboard;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIAttachSlaveInfo
+ {
+ public int Type;
+ public int Deviceid;
+ public int NewMaster;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIDetachSlaveInfo
+ {
+ public int Type;
+ public int Deviceid;
+ };
+
+ [StructLayout(LayoutKind.Explicit)]
+ struct XIAnyHierarchyChangeInfo
+ {
+ [FieldOffset(0)]
+ public int type; /* must be first element */
+ [FieldOffset(4)]
+ public XIAddMasterInfo add;
+ [FieldOffset(4)]
+ public XIRemoveMasterInfo remove;
+ [FieldOffset(4)]
+ public XIAttachSlaveInfo attach;
+ [FieldOffset(4)]
+ public XIDetachSlaveInfo detach;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIModifierState
+ {
+ public int Base;
+ public int Latched;
+ public int Locked;
+ public int Effective;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct XIButtonState
+ {
+ public int MaskLen;
+ public byte* Mask;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct XIValuatorState
+ {
+ public int MaskLen;
+ public byte* Mask;
+ public double* Values;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct XIEventMask
+ {
+ public int Deviceid;
+ public int MaskLen;
+ public int* Mask;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIAnyClassInfo
+ {
+ public XiDeviceClass Type;
+ public int Sourceid;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct XIButtonClassInfo
+ {
+ public int Type;
+ public int Sourceid;
+ public int NumButtons;
+ public IntPtr* Labels;
+ public XIButtonState State;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct XIKeyClassInfo
+ {
+ public int Type;
+ public int Sourceid;
+ public int NumKeycodes;
+ public int* Keycodes;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIValuatorClassInfo
+ {
+ public int Type;
+ public int Sourceid;
+ public int Number;
+ public IntPtr Label;
+ public double Min;
+ public double Max;
+ public double Value;
+ public int Resolution;
+ public int Mode;
+ };
+
+/* new in XI 2.1 */
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIScrollClassInfo
+ {
+ public int Type;
+ public int Sourceid;
+ public int Number;
+ public XiScrollType ScrollType;
+ public double Increment;
+ public int Flags;
+ };
+
+ enum XiScrollType
+ {
+ Vertical = 1,
+ Horizontal = 2
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct XITouchClassInfo
+ {
+ public int Type;
+ public int Sourceid;
+ public int Mode;
+ public int NumTouches;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct XIDeviceInfo
+ {
+ public int Deviceid;
+ public IntPtr Name;
+ public XiDeviceType Use;
+ public int Attachment;
+ public Bool Enabled;
+ public int NumClasses;
+ public XIAnyClassInfo** Classes;
+ }
+
+ enum XiDeviceType
+ {
+ XIMasterPointer = 1,
+ XIMasterKeyboard = 2,
+ XISlavePointer = 3,
+ XISlaveKeyboard = 4,
+ XIFloatingSlave = 5
+ }
+
+ enum XiPredefinedDeviceId : int
+ {
+ XIAllDevices = 0,
+ XIAllMasterDevices = 1
+ }
+
+ enum XiDeviceClass
+ {
+ XIKeyClass = 0,
+ XIButtonClass = 1,
+ XIValuatorClass = 2,
+ XIScrollClass = 3,
+ XITouchClass = 8,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct XIDeviceChangedEvent
+ {
+ public int Type; /* GenericEvent */
+ public ulong Serial; /* # of last request processed by server */
+ public Bool SendEvent; /* true if this came from a SendEvent request */
+ public IntPtr Display; /* Display the event was read from */
+ public int Extension; /* XI extension offset */
+ public int Evtype; /* XI_DeviceChanged */
+ public IntPtr Time;
+ public int Deviceid; /* id of the device that changed */
+ public int Sourceid; /* Source for the new classes. */
+ public int Reason; /* Reason for the change */
+ public int NumClasses;
+ public XIAnyClassInfo** Classes; /* same as in XIDeviceInfo */
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct XIDeviceEvent
+ {
+ public XEventName type; /* GenericEvent */
+ public ulong serial; /* # of last request processed by server */
+ public Bool send_event; /* true if this came from a SendEvent request */
+ public IntPtr display; /* Display the event was read from */
+ public int extension; /* XI extension offset */
+ public XiEventType evtype;
+ public IntPtr time;
+ public int deviceid;
+ public int sourceid;
+ public int detail;
+ public IntPtr RootWindow;
+ public IntPtr EventWindow;
+ public IntPtr ChildWindow;
+ public double root_x;
+ public double root_y;
+ public double event_x;
+ public double event_y;
+ public int flags;
+ public XIButtonState buttons;
+ public XIValuatorState valuators;
+ public XIModifierState mods;
+ public XIModifierState group;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct XIEvent
+ {
+ public int type; /* GenericEvent */
+ public ulong serial; /* # of last request processed by server */
+ public Bool send_event; /* true if this came from a SendEvent request */
+ public IntPtr display; /* Display the event was read from */
+ public int extension; /* XI extension offset */
+ public XiEventType evtype;
+ public IntPtr time;
+ }
+
+ enum XiEventType
+ {
+ XI_DeviceChanged = 1,
+ XI_KeyPress = 2,
+ XI_KeyRelease = 3,
+ XI_ButtonPress = 4,
+ XI_ButtonRelease = 5,
+ XI_Motion = 6,
+ XI_Enter = 7,
+ XI_Leave = 8,
+ XI_FocusIn = 9,
+ XI_FocusOut = 10,
+ XI_HierarchyChanged = 11,
+ XI_PropertyEvent = 12,
+ XI_RawKeyPress = 13,
+ XI_RawKeyRelease = 14,
+ XI_RawButtonPress = 15,
+ XI_RawButtonRelease = 16,
+ XI_RawMotion = 17,
+ XI_TouchBegin = 18 /* XI 2.2 */,
+ XI_TouchUpdate = 19,
+ XI_TouchEnd = 20,
+ XI_TouchOwnership = 21,
+ XI_RawTouchBegin = 22,
+ XI_RawTouchUpdate = 23,
+ XI_RawTouchEnd = 24,
+ XI_BarrierHit = 25 /* XI 2.3 */,
+ XI_BarrierLeave = 26,
+ XI_LASTEVENT = XI_BarrierLeave,
+ }
+
+}
diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs
new file mode 100644
index 0000000000..8a146f922d
--- /dev/null
+++ b/src/Avalonia.X11/XLib.cs
@@ -0,0 +1,632 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable FieldCanBeMadeReadOnly.Global
+// ReSharper disable CommentTypo
+// ReSharper disable UnusedMember.Global
+// ReSharper disable IdentifierTypo
+// ReSharper disable NotAccessedField.Global
+// ReSharper disable UnusedMethodReturnValue.Global
+
+namespace Avalonia.X11
+{
+ internal unsafe static class XLib
+ {
+ const string libX11 = "libX11.so.6";
+ const string libX11Randr = "libXrandr.so.2";
+ const string libX11Ext = "libXext.so.6";
+ const string libXInput = "libXi.so.6";
+
+ [DllImport(libX11)]
+ public static extern IntPtr XOpenDisplay(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern int XCloseDisplay(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XSynchronize(IntPtr display, bool onoff);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height,
+ int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask,
+ ref XSetWindowAttributes attributes);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width,
+ int height, int border_width, IntPtr border, IntPtr background);
+
+ [DllImport(libX11)]
+ public static extern int XMapWindow(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern int XUnmapWindow(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern int XMapSubindows(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern int XUnmapSubwindows(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XRootWindow(IntPtr display, int screen_number);
+ [DllImport(libX11)]
+ public static extern IntPtr XDefaultRootWindow(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XNextEvent(IntPtr display, out XEvent xevent);
+
+ [DllImport(libX11)]
+ public static extern int XConnectionNumber(IntPtr diplay);
+
+ [DllImport(libX11)]
+ public static extern int XPending(IntPtr diplay);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
+
+ [DllImport(libX11)]
+ public static extern int XDestroyWindow(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
+
+ [DllImport(libX11)]
+ public static extern int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+
+ [DllImport(libX11)]
+ public static extern int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
+
+ [DllImport(libX11)]
+ public static extern int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
+
+ [DllImport(libX11)]
+ public static extern int XFlush(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
+
+ [DllImport(libX11)]
+ public static extern int XStoreName(IntPtr display, IntPtr window, string window_name);
+
+ [DllImport(libX11)]
+ public static extern int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
+
+ [DllImport(libX11)]
+ public static extern int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask,
+ ref XEvent send_event);
+
+ [DllImport(libX11)]
+ public static extern int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return,
+ out IntPtr parent_return, out IntPtr children_return, out int nchildren_return);
+
+ [DllImport(libX11)]
+ public static extern int XFree(IntPtr data);
+
+ [DllImport(libX11)]
+ public static extern int XRaiseWindow(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern uint XLowerWindow(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask,
+ ref XWindowChanges values);
+
+ public static uint XConfigureResizeWindow(IntPtr display, IntPtr window, PixelSize size)
+ => XConfigureResizeWindow(display, window, size.Width, size.Height);
+
+ public static uint XConfigureResizeWindow(IntPtr display, IntPtr window, int width, int height)
+ {
+ var changes = new XWindowChanges
+ {
+ width = width,
+ height = height
+ };
+
+ return XConfigureWindow(display, window, ChangeWindowFlags.CWHeight | ChangeWindowFlags.CWWidth,
+ ref changes);
+ }
+
+ [DllImport(libX11)]
+ public static extern IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
+
+ [DllImport(libX11)]
+ public static extern int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists,
+ IntPtr[] atoms);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XGetAtomName(IntPtr display, IntPtr atom);
+
+ public static string GetAtomName(IntPtr display, IntPtr atom)
+ {
+ var ptr = XGetAtomName(display, atom);
+ if (ptr == IntPtr.Zero)
+ return null;
+ var s = Marshal.PtrToStringAnsi(ptr);
+ XFree(ptr);
+ return s;
+ }
+
+ [DllImport(libX11)]
+ public static extern int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
+
+ [DllImport(libX11)]
+ public static extern int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask,
+ GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp);
+
+ [DllImport(libX11)]
+ public static extern int XUngrabPointer(IntPtr display, IntPtr timestamp);
+
+ [DllImport(libX11)]
+ public static extern bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child,
+ out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons);
+
+ [DllImport(libX11)]
+ public static extern bool XTranslateCoordinates(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x,
+ int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return);
+
+ [DllImport(libX11)]
+ public static extern bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y,
+ out int width, out int height, out int border_width, out int depth);
+
+ [DllImport(libX11)]
+ public static extern bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y,
+ out int width, out int height, IntPtr border_width, IntPtr depth);
+
+ [DllImport(libX11)]
+ public static extern bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y,
+ IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth);
+
+ [DllImport(libX11)]
+ public static extern bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y,
+ out int width, out int height, IntPtr border_width, IntPtr depth);
+
+ [DllImport(libX11)]
+ public static extern uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y,
+ uint src_width, uint src_height, int dest_x, int dest_y);
+
+ [DllImport(libX11)]
+ public static extern int XClearWindow(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height,
+ bool exposures);
+
+ // Colormaps
+ [DllImport(libX11)]
+ public static extern IntPtr XDefaultScreenOfDisplay(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XDefaultVisual(IntPtr display, int screen_number);
+
+ [DllImport(libX11)]
+ public static extern uint XDefaultDepth(IntPtr display, int screen_number);
+
+ [DllImport(libX11)]
+ public static extern int XDefaultScreen(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XDefaultColormap(IntPtr display, int screen_number);
+
+ [DllImport(libX11)]
+ public static extern int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem,
+ ref XColor exact_def_color, ref XColor screen_def_color);
+
+ [DllImport(libX11)]
+ public static extern int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
+
+ [DllImport(libX11)]
+ public static extern int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr parent);
+
+ [DllImport(libX11)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, ref MotifWmHints data, int nelements);
+
+ [DllImport(libX11)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, ref uint value, int nelements);
+
+ [DllImport(libX11)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, ref IntPtr value, int nelements);
+
+ [DllImport(libX11)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, uint[] data, int nelements);
+
+ [DllImport(libX11)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, int[] data, int nelements);
+
+ [DllImport(libX11)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, IntPtr[] data, int nelements);
+ [DllImport(libX11)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, void* data, int nelements);
+
+ [DllImport(libX11)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, IntPtr atoms, int nelements);
+
+ [DllImport(libX11, CharSet = CharSet.Ansi)]
+ public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
+ int format, PropertyMode mode, string text, int text_length);
+
+ [DllImport(libX11)]
+ public static extern int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
+
+ // Drawing
+ [DllImport(libX11)]
+ public static extern IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
+
+ [DllImport(libX11)]
+ public static extern int XFreeGC(IntPtr display, IntPtr gc);
+
+ [DllImport(libX11)]
+ public static extern int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
+
+ [DllImport(libX11)]
+ internal static extern int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style,
+ GCCapStyle cap_style, GCJoinStyle join_style);
+
+ [DllImport(libX11)]
+ public static extern int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
+
+ [DllImport(libX11)]
+ public static extern int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width,
+ int height);
+
+ [DllImport(libX11)]
+ public static extern int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width,
+ int height);
+
+ [DllImport(libX11)]
+ public static extern int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
+
+ [DllImport(libX11)]
+ public static extern int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y,
+ int width, int height, int dest_x, int dest_y);
+
+ [DllImport(libX11)]
+ public static extern int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset,
+ IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format,
+ out IntPtr nitems, out IntPtr bytes_after, out IntPtr prop);
+
+ [DllImport(libX11)]
+ public static extern int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
+
+ [DllImport(libX11)]
+ public static extern int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
+
+ [DllImport(libX11)]
+ public static extern int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
+
+ [DllImport(libX11)]
+ public static extern int XUndefineCursor(IntPtr display, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern int XFreeCursor(IntPtr display, IntPtr cursor);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask,
+ ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width,
+ int height, IntPtr fg, IntPtr bg, int depth);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
+
+ [DllImport(libX11)]
+ public static extern int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height,
+ out int best_width, out int best_height);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XWhitePixel(IntPtr display, int screen_no);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XBlackPixel(IntPtr display, int screen_no);
+
+ [DllImport(libX11)]
+ public static extern void XGrabServer(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern void XUngrabServer(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints,
+ out IntPtr supplied_return);
+
+ [DllImport(libX11)]
+ public static extern void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
+
+ [DllImport(libX11)]
+ public static extern void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
+
+ [DllImport(libX11)]
+ public static extern void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
+
+ [DllImport(libX11)]
+ public static extern int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XSetErrorHandler(XErrorHandler error_handler);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
+
+ [DllImport(libX11)]
+ public static extern int XInitThreads();
+
+ [DllImport(libX11)]
+ public static extern int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property,
+ IntPtr requestor, IntPtr time);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
+
+ [DllImport(libX11)]
+ public static extern int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
+
+ [DllImport(libX11)]
+ public static extern int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
+
+ [DllImport(libX11)]
+ public static extern int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
+
+ [DllImport(libX11)]
+ public static extern int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
+
+ [DllImport(libX11)]
+ public static extern int XBell(IntPtr display, int percent);
+
+ [DllImport(libX11)]
+ public static extern int XChangeActivePointerGrab(IntPtr display, EventMask event_mask, IntPtr cursor,
+ IntPtr time);
+
+ [DllImport(libX11)]
+ public static extern bool XFilterEvent(ref XEvent xevent, IntPtr window);
+
+ [DllImport(libX11)]
+ public static extern void XkbSetDetectableAutoRepeat(IntPtr display, bool detectable, IntPtr supported);
+
+ [DllImport(libX11)]
+ public static extern void XPeekEvent(IntPtr display, out XEvent xevent);
+
+ [DllImport(libX11)]
+ public static extern void XMatchVisualInfo(IntPtr display, int screen, int depth, int klass, out XVisualInfo info);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XLockDisplay(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XUnlockDisplay(IntPtr display);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XCreateGC(IntPtr display, IntPtr drawable, ulong valuemask, IntPtr values);
+
+ [DllImport(libX11)]
+ public static extern int XInitImage(ref XImage image);
+
+ [DllImport(libX11)]
+ public static extern int XDestroyImage(ref XImage image);
+
+ [DllImport(libX11)]
+ public static extern int XPutImage(IntPtr display, IntPtr drawable, IntPtr gc, ref XImage image,
+ int srcx, int srcy, int destx, int desty, uint width, uint height);
+ [DllImport(libX11)]
+ public static extern int XSync(IntPtr display, bool discard);
+
+ [DllImport(libX11)]
+ public static extern IntPtr XCreateColormap(IntPtr display, IntPtr window, IntPtr visual, int create);
+
+ public enum XLookupStatus
+ {
+ XBufferOverflow = -1,
+ XLookupNone = 1,
+ XLookupChars = 2,
+ XLookupKeySym = 3,
+ XLookupBoth = 4
+ }
+
+ [DllImport (libX11)]
+ public static extern unsafe int XLookupString(ref XEvent xevent, void* buffer, int num_bytes, out IntPtr keysym, out IntPtr status);
+
+ [DllImport (libX11)]
+ public static extern unsafe int Xutf8LookupString(IntPtr xic, ref XEvent xevent, void* buffer, int num_bytes, out IntPtr keysym, out IntPtr status);
+
+ [DllImport (libX11)]
+ public static extern unsafe IntPtr XKeycodeToKeysym(IntPtr display, int keycode, int index);
+
+ [DllImport (libX11)]
+ public static extern unsafe IntPtr XSetLocaleModifiers(string modifiers);
+
+ [DllImport (libX11)]
+ public static extern IntPtr XOpenIM (IntPtr display, IntPtr rdb, IntPtr res_name, IntPtr res_class);
+
+ [DllImport (libX11)]
+ public static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, IntPtr terminator);
+
+ [DllImport (libX11)]
+ public static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, string name3, IntPtr value3, IntPtr terminator);
+
+ [DllImport (libX11)]
+ public static extern void XCloseIM (IntPtr xim);
+
+ [DllImport (libX11)]
+ public static extern void XDestroyIC (IntPtr xic);
+
+ [DllImport(libX11)]
+ public static extern bool XQueryExtension(IntPtr display, [MarshalAs(UnmanagedType.LPStr)] string name,
+ out int majorOpcode, out int firstEvent, out int firstError);
+
+ [DllImport(libX11)]
+ public static extern bool XGetEventData(IntPtr display, void* cookie);
+
+ [DllImport(libX11)]
+ public static extern void XFreeEventData(IntPtr display, void* cookie);
+
+ [DllImport(libX11Randr)]
+ public static extern int XRRQueryExtension (IntPtr dpy,
+ out int event_base_return,
+ out int error_base_return);
+
+ [DllImport(libX11Randr)]
+ public static extern int XRRQueryVersion(IntPtr dpy,
+ out int major_version_return,
+ out int minor_version_return);
+
+ [DllImport(libX11Randr)]
+ public static extern XRRMonitorInfo*
+ XRRGetMonitors(IntPtr dpy, IntPtr window, bool get_active, out int nmonitors);
+ [DllImport(libX11Randr)]
+ public static extern void XRRSelectInput(IntPtr dpy, IntPtr window, RandrEventMask mask);
+
+ [DllImport(libXInput)]
+ public static extern Status XIQueryVersion(IntPtr dpy, ref int major, ref int minor);
+
+ [DllImport(libXInput)]
+ public static extern IntPtr XIQueryDevice(IntPtr dpy, int deviceid, out int ndevices_return);
+
+ [DllImport(libXInput)]
+ public static extern void XIFreeDeviceInfo(XIDeviceInfo* info);
+
+ public static void XISetMask(ref int mask, XiEventType ev)
+ {
+ mask |= (1 << (int)ev);
+ }
+
+ public static int XiEventMaskLen { get; } = 4;
+
+ public static bool XIMaskIsSet(void* ptr, int shift) =>
+ (((byte*)(ptr))[(shift) >> 3] & (1 << (shift & 7))) != 0;
+
+ [DllImport(libXInput)]
+ public static extern Status XISelectEvents(
+ IntPtr dpy,
+ IntPtr win,
+ XIEventMask* masks,
+ int num_masks
+ );
+
+ public static Status XiSelectEvents(IntPtr display, IntPtr window, Dictionary> devices)
+ {
+ var masks = stackalloc int[devices.Count];
+ var emasks = stackalloc XIEventMask[devices.Count];
+ int c = 0;
+ foreach (var d in devices)
+ {
+ foreach (var ev in d.Value)
+ XISetMask(ref masks[c], ev);
+ emasks[c] = new XIEventMask
+ {
+ Mask = &masks[c],
+ Deviceid = d.Key,
+ MaskLen = XiEventMaskLen
+ };
+ c++;
+ }
+
+
+ return XISelectEvents(display, window, emasks, devices.Count);
+
+ }
+
+ public struct XGeometry
+ {
+ public IntPtr root;
+ public int x;
+ public int y;
+ public int width;
+ public int height;
+ public int bw;
+ public int d;
+ }
+
+ public static bool XGetGeometry(IntPtr display, IntPtr window, out XGeometry geo)
+ {
+ geo = new XGeometry();
+ return XGetGeometry(display, window, out geo.root, out geo.x, out geo.y, out geo.width, out geo.height,
+ out geo.bw, out geo.d);
+ }
+
+ public static void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child,
+ out int root_x, out int root_y, out int child_x, out int child_y,
+ out int mask)
+ {
+
+ IntPtr c;
+
+ XGrabServer (display);
+
+ XQueryPointer(display, w, out root, out c,
+ out root_x, out root_y, out child_x, out child_y,
+ out mask);
+
+ if (root != w)
+ c = root;
+
+ IntPtr child_last = IntPtr.Zero;
+ while (c != IntPtr.Zero) {
+ child_last = c;
+ XQueryPointer(display, c, out root, out c,
+ out root_x, out root_y, out child_x, out child_y,
+ out mask);
+ }
+ XUngrabServer (display);
+ XFlush (display);
+
+ child = child_last;
+ }
+
+ public static (int x, int y) GetCursorPos(X11Info x11, IntPtr? handle = null)
+ {
+ IntPtr root;
+ IntPtr child;
+ int root_x;
+ int root_y;
+ int win_x;
+ int win_y;
+ int keys_buttons;
+
+
+
+ QueryPointer(x11.Display, handle ?? x11.RootWindow, out root, out child, out root_x, out root_y, out win_x, out win_y,
+ out keys_buttons);
+
+
+ if (handle != null)
+ {
+ return (win_x, win_y);
+ }
+ else
+ {
+ return (root_x, root_y);
+ }
+ }
+
+ public static IntPtr CreateEventWindow(AvaloniaX11Platform plat, Action handler)
+ {
+ var win = XCreateSimpleWindow(plat.Display, plat.Info.DefaultRootWindow,
+ 0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero);
+ plat.Windows[win] = handler;
+ return win;
+ }
+
+
+ }
+}
diff --git a/src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs b/src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs
new file mode 100644
index 0000000000..b80914572b
--- /dev/null
+++ b/src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Gtk3.Interop;
+using Avalonia.Platform;
+using Avalonia.Platform.Interop;
+
+namespace Avalonia.Gtk3
+{
+ public class Gtk3ForeignX11SystemDialog : ISystemDialogImpl
+ {
+ private Task _initialized;
+ private SystemDialogBase _inner = new SystemDialogBase();
+
+
+ public async Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
+ {
+ await EnsureInitialized();
+ var xid = parent.Handle.Handle;
+ return await await RunOnGtkThread(
+ () => _inner.ShowFileDialogAsync(dialog, GtkWindow.Null, chooser => UpdateParent(chooser, xid)));
+ }
+
+ public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
+ {
+ await EnsureInitialized();
+ var xid = parent.Handle.Handle;
+ return await await RunOnGtkThread(
+ () => _inner.ShowFolderDialogAsync(dialog, GtkWindow.Null, chooser => UpdateParent(chooser, xid)));
+ }
+
+ void UpdateParent(GtkFileChooser chooser, IntPtr xid)
+ {
+ Native.GtkWidgetRealize(chooser);
+ var window = Native.GtkWidgetGetWindow(chooser);
+ var parent = Native.GdkWindowForeignNewForDisplay(GdkDisplay, xid);
+ if (window != IntPtr.Zero && parent != IntPtr.Zero)
+ Native.GdkWindowSetTransientFor(window, parent);
+ }
+
+ async Task EnsureInitialized()
+ {
+ if (_initialized == null)
+ {
+ var tcs = new TaskCompletionSource();
+ _initialized = tcs.Task;
+ new Thread(() => GtkThread(tcs))
+ {
+ IsBackground = true
+ }.Start();
+ }
+
+ if (!(await _initialized))
+ throw new Exception("Unable to initialize GTK on separate thread");
+
+ }
+
+ Task RunOnGtkThread(Func action)
+ {
+ var tcs = new TaskCompletionSource();
+ GlibTimeout.Add(0, 0, () =>
+ {
+
+ try
+ {
+ tcs.SetResult(action());
+ }
+ catch (Exception e)
+ {
+ tcs.TrySetException(e);
+ }
+
+ return false;
+ });
+ return tcs.Task;
+ }
+
+
+ void GtkThread(TaskCompletionSource tcs)
+ {
+ try
+ {
+ X11.XInitThreads();
+ }catch{}
+ Resolver.Resolve();
+ if (Native.GdkWindowForeignNewForDisplay == null)
+ throw new Exception("gdk_x11_window_foreign_new_for_display is not found in your libgdk-3.so");
+ using (var backends = new Utf8Buffer("x11"))
+ Native.GdkSetAllowedBackends?.Invoke(backends);
+ if (!Native.GtkInitCheck(0, IntPtr.Zero))
+ {
+ tcs.SetResult(false);
+ return;
+ }
+
+ using (var utf = new Utf8Buffer($"avalonia.app.a{Guid.NewGuid().ToString("N")}"))
+ App = Native.GtkApplicationNew(utf, 0);
+ if (App == IntPtr.Zero)
+ {
+ tcs.SetResult(false);
+ return;
+ }
+ GdkDisplay = Native.GdkGetDefaultDisplay();
+ tcs.SetResult(true);
+ while (true)
+ Native.GtkMainIteration();
+ }
+
+ private IntPtr GdkDisplay { get; set; }
+ private IntPtr App { get; set; }
+ }
+}
diff --git a/src/Gtk/Avalonia.Gtk3/GtkScreen.cs b/src/Gtk/Avalonia.Gtk3/GtkScreen.cs
index 7c28dd47b9..a2b4604130 100644
--- a/src/Gtk/Avalonia.Gtk3/GtkScreen.cs
+++ b/src/Gtk/Avalonia.Gtk3/GtkScreen.cs
@@ -6,7 +6,7 @@ namespace Avalonia.Gtk3
{
private readonly int _screenId;
- public GtkScreen(Rect bounds, Rect workingArea, bool primary, int screenId) : base(bounds, workingArea, primary)
+ public GtkScreen(PixelRect bounds, PixelRect workingArea, bool primary, int screenId) : base(bounds, workingArea, primary)
{
this._screenId = screenId;
}
@@ -21,4 +21,4 @@ namespace Avalonia.Gtk3
return (obj is GtkScreen screen) ? this._screenId == screen._screenId : base.Equals(obj);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
index bf973119a9..765c19a796 100644
--- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
+++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
@@ -50,6 +50,9 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_init(int argc, IntPtr argv);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
+ public delegate bool gtk_init_check(int argc, IntPtr argv);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk, optional: true)]
public delegate IntPtr gdk_set_allowed_backends (Utf8Buffer backends);
@@ -288,6 +291,12 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gdk_window_end_paint(IntPtr window);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk, optional: true)]
+ public delegate IntPtr gdk_x11_window_foreign_new_for_display(IntPtr display, IntPtr xid);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
+ public delegate void gdk_window_set_transient_for(IntPtr window, IntPtr parent);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gdk_event_request_motions(IntPtr ev);
@@ -414,6 +423,7 @@ namespace Avalonia.Gtk3.Interop
public static D.gtk_window_set_transient_for GtkWindowSetTransientFor;
public static D.gdk_set_allowed_backends GdkSetAllowedBackends;
public static D.gtk_init GtkInit;
+ public static D.gtk_init_check GtkInitCheck;
public static D.gtk_window_present GtkWindowPresent;
public static D.gtk_widget_hide GtkWidgetHide;
public static D.gtk_widget_show GtkWidgetShow;
@@ -483,8 +493,9 @@ namespace Avalonia.Gtk3.Interop
public static D.gdk_window_process_updates GdkWindowProcessUpdates;
public static D.gdk_window_begin_paint_rect GdkWindowBeginPaintRect;
public static D.gdk_window_end_paint GdkWindowEndPaint;
+ public static D.gdk_x11_window_foreign_new_for_display GdkWindowForeignNewForDisplay;
+ public static D.gdk_window_set_transient_for GdkWindowSetTransientFor;
-
public static D.gdk_pixbuf_new_from_file GdkPixbufNewFromFile;
public static D.gtk_icon_theme_get_default GtkIconThemeGetDefault;
public static D.gtk_icon_theme_load_icon GtkIconThemeLoadIcon;
diff --git a/src/Gtk/Avalonia.Gtk3/ScreenImpl.cs b/src/Gtk/Avalonia.Gtk3/ScreenImpl.cs
index 97b5029219..9a19ed00e0 100644
--- a/src/Gtk/Avalonia.Gtk3/ScreenImpl.cs
+++ b/src/Gtk/Avalonia.Gtk3/ScreenImpl.cs
@@ -27,8 +27,8 @@ namespace Avalonia.Gtk3
GdkRectangle workArea = new GdkRectangle(), geometry = new GdkRectangle();
Native.GdkScreenGetMonitorGeometry(screen, i, ref geometry);
Native.GdkScreenGetMonitorWorkarea(screen, i, ref workArea);
- Rect workAreaRect = new Rect(workArea.X, workArea.Y, workArea.Width, workArea.Height);
- Rect geometryRect = new Rect(geometry.X, geometry.Y, geometry.Width, geometry.Height);
+ PixelRect workAreaRect = new PixelRect(workArea.X, workArea.Y, workArea.Width, workArea.Height);
+ PixelRect geometryRect = new PixelRect(geometry.X, geometry.Y, geometry.Width, geometry.Height);
GtkScreen s = new GtkScreen(geometryRect, workAreaRect, i == primary, i);
screens[i] = s;
}
diff --git a/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs b/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs
index 5e6615f92d..1e85eaa156 100644
--- a/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs
+++ b/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs
@@ -11,16 +11,17 @@ using Avalonia.Platform.Interop;
namespace Avalonia.Gtk3
{
- class SystemDialog : ISystemDialogImpl
+ class SystemDialogBase
{
- unsafe static Task ShowDialog(string title, GtkWindow parent, GtkFileChooserAction action,
- bool multiselect, string initialFileName)
+ public unsafe static Task ShowDialog(string title, GtkWindow parent, GtkFileChooserAction action,
+ bool multiselect, string initialFileName, Action modify)
{
GtkFileChooser dlg;
parent = parent ?? GtkWindow.Null;
using (var name = new Utf8Buffer(title))
dlg = Native.GtkFileChooserDialogNew(name, parent, action, IntPtr.Zero);
+ modify?.Invoke(dlg);
if (multiselect)
Native.GtkFileChooserSetSelectMultiple(dlg, true);
@@ -42,7 +43,7 @@ namespace Avalonia.Gtk3
dispose();
return false;
}),
- Signal.Connect(dlg, "response", (_, resp, __)=>
+ Signal.Connect(dlg, "response", (_, resp, __) =>
{
string[] result = null;
if (resp == GtkResponseType.Accept)
@@ -56,9 +57,11 @@ namespace Avalonia.Gtk3
rlst.Add(Utf8Buffer.StringFromPtr(cgs->Data));
cgs = cgs->Next;
}
+
Native.GSlistFree(gs);
result = rlst.ToArray();
}
+
Native.GtkWidgetHide(dlg);
dispose();
tcs.TrySetResult(result);
@@ -70,27 +73,38 @@ namespace Avalonia.Gtk3
Native.GtkDialogAddButton(dlg, open, GtkResponseType.Accept);
using (var open = new Utf8Buffer("Cancel"))
Native.GtkDialogAddButton(dlg, open, GtkResponseType.Cancel);
- if(initialFileName!=null)
+ if (initialFileName != null)
using (var fn = new Utf8Buffer(initialFileName))
Native.GtkFileChooserSetFilename(dlg, fn);
Native.GtkWindowPresent(dlg);
return tcs.Task;
}
- public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
+ public Task ShowFileDialogAsync(FileDialog dialog, GtkWindow parent,
+ Action modify = null)
{
- return ShowDialog(dialog.Title, ((WindowBaseImpl)parent)?.GtkWidget,
+ return ShowDialog(dialog.Title, parent,
dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save,
(dialog as OpenFileDialog)?.AllowMultiple ?? false,
Path.Combine(string.IsNullOrEmpty(dialog.InitialDirectory) ? "" : dialog.InitialDirectory,
- string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName));
+ string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName), modify);
}
- public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
+ public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, GtkWindow parent,
+ Action modify = null)
{
- var res = await ShowDialog(dialog.Title, ((WindowBaseImpl) parent)?.GtkWidget,
- GtkFileChooserAction.SelectFolder, false, dialog.InitialDirectory);
+ var res = await ShowDialog(dialog.Title, parent,
+ GtkFileChooserAction.SelectFolder, false, dialog.InitialDirectory, modify);
return res?.FirstOrDefault();
}
}
+
+ class SystemDialog : SystemDialogBase, ISystemDialogImpl
+ {
+ public Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
+ => ShowFolderDialogAsync(dialog, ((WindowBaseImpl)parent)?.GtkWidget);
+
+ public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
+ => ShowFileDialogAsync(dialog, ((WindowBaseImpl)parent)?.GtkWidget);
+ }
}
diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
index 6d4544bfbd..c4697462d2 100644
--- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
+++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
@@ -24,7 +24,7 @@ namespace Avalonia.Gtk3
private readonly EglGlPlatformSurface _egl;
protected readonly List Disposables = new List();
private Size _lastSize;
- private Point _lastPosition;
+ private PixelPoint _lastPosition;
private double _lastScaling;
private uint _lastKbdEvent;
private uint _lastSmoothScrollEvent;
@@ -383,7 +383,7 @@ namespace Avalonia.Gtk3
public Action Paint { get; set; }
public Action Resized { get; set; }
public Action ScalingChanged { get; set; } //TODO
- public Action PositionChanged { get; set; }
+ public Action PositionChanged { get; set; }
public void Activate() => Native.GtkWidgetActivate(GtkWidget);
@@ -402,7 +402,7 @@ namespace Avalonia.Gtk3
Dispatcher.UIThread.Post(() => Input?.Invoke(args), DispatcherPriority.Input);
}
- public Point PointToClient(Point point)
+ public Point PointToClient(PixelPoint point)
{
int x, y;
Native.GdkWindowGetOrigin(Native.GtkWidgetGetWindow(GtkWidget), out x, out y);
@@ -410,11 +410,11 @@ namespace Avalonia.Gtk3
return new Point(point.X - x, point.Y - y);
}
- public Point PointToScreen(Point point)
+ public PixelPoint PointToScreen(Point point)
{
int x, y;
Native.GdkWindowGetOrigin(Native.GtkWidgetGetWindow(GtkWidget), out x, out y);
- return new Point(point.X + x, point.Y + y);
+ return new PixelPoint((int)(point.X + x), (int)(point.Y + y));
}
public void SetCursor(IPlatformHandle cursor)
@@ -490,13 +490,13 @@ namespace Avalonia.Gtk3
get;
} = new ScreenImpl();
- public Point Position
+ public PixelPoint Position
{
get
{
int x, y;
Native.GtkWindowGetPosition(GtkWidget, out x, out y);
- return new Point(x, y);
+ return new PixelPoint(x, y);
}
set { Native.GtkWindowMove(GtkWidget, (int)value.X, (int)value.Y); }
}
diff --git a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
index 968873abc0..6a63014e1a 100644
--- a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
+++ b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
@@ -51,9 +51,9 @@ namespace Avalonia.LinuxFramebuffer
InputRoot = inputRoot;
}
- public Point PointToClient(Point point) => point;
+ public Point PointToClient(PixelPoint p) => p.ToPoint(1);
- public Point PointToScreen(Point point) => point;
+ public PixelPoint PointToScreen(Point p) => PixelPoint.FromPoint(p, 1);
public void SetCursor(IPlatformHandle cursor)
{
diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs
index e09d9bfd17..c30822aacb 100644
--- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs
@@ -44,6 +44,12 @@ namespace Avalonia.Markup.Xaml
{ typeof(FontFamily), typeof(FontFamilyTypeConverter) }
};
+ internal static Type GetBuiltinTypeConverter(Type type)
+ {
+ _converters.TryGetValue(type, out var result);
+ return result;
+ }
+
///
/// Tries to lookup a for a type.
///
diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
index 83f4919d4b..7558a5df0b 100644
--- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
@@ -42,7 +42,10 @@ namespace Avalonia.Markup.Xaml.PortableXaml
}
else if (attributeType == typeof(TypeConverterAttribute))
{
- result = ti.GetCustomAttribute(attributeType, inherit);
+ var builtin = AvaloniaTypeConverters.GetBuiltinTypeConverter(_type);
+ if (builtin != null)
+ result = new TypeConverterAttribute(builtin);
+ result = result ?? ti.GetCustomAttribute(attributeType, inherit);
if (result == null)
{
@@ -111,4 +114,4 @@ namespace Avalonia.Markup.Xaml.PortableXaml
return null;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
index f66d3e51fc..55c3aab81f 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Avalonia.Data.Core;
using Avalonia.Utilities;
@@ -32,6 +33,11 @@ namespace Avalonia.Markup.Parsers
public static IEnumerable Parse(string s)
{
var r = new CharacterReader(s.AsSpan());
+ return Parse(ref r, null);
+ }
+
+ private static IEnumerable Parse(ref CharacterReader r, char? end)
+ {
var state = State.Start;
var selector = new List();
while (!r.End && state != State.End)
@@ -43,7 +49,7 @@ namespace Avalonia.Markup.Parsers
state = ParseStart(ref r);
break;
case State.Middle:
- state = ParseMiddle(ref r);
+ state = ParseMiddle(ref r, end);
break;
case State.CanHaveType:
state = ParseCanHaveType(ref r);
@@ -107,7 +113,7 @@ namespace Avalonia.Markup.Parsers
return State.TypeName;
}
- private static State ParseMiddle(ref CharacterReader r)
+ private static State ParseMiddle(ref CharacterReader r, char? end)
{
if (r.TakeIf(':'))
{
@@ -129,6 +135,10 @@ namespace Avalonia.Markup.Parsers
{
return State.Name;
}
+ else if (end.HasValue && !r.End && r.Peek == end.Value)
+ {
+ return State.End;
+ }
return State.TypeName;
}
@@ -151,16 +161,23 @@ namespace Avalonia.Markup.Parsers
}
const string IsKeyword = "is";
+ const string NotKeyword = "not";
+
if (identifier.SequenceEqual(IsKeyword.AsSpan()) && r.TakeIf('('))
{
var syntax = ParseType(ref r, new IsSyntax());
- if (r.End || !r.TakeIf(')'))
- {
- throw new ExpressionParseException(r.Position, $"Expected ')', got {r.Peek}");
- }
+ Expect(ref r, ')');
return (State.CanHaveType, syntax);
}
+ if (identifier.SequenceEqual(NotKeyword.AsSpan()) && r.TakeIf('('))
+ {
+ var argument = Parse(ref r, ')');
+ Expect(ref r, ')');
+
+ var syntax = new NotSyntax { Argument = argument };
+ return (State.Middle, syntax);
+ }
else
{
return (
@@ -282,6 +299,18 @@ namespace Avalonia.Markup.Parsers
return syntax;
}
+ private static void Expect(ref CharacterReader r, char c)
+ {
+ if (r.End)
+ {
+ throw new ExpressionParseException(r.Position, $"Expected '{c}', got end of selector.");
+ }
+ else if (!r.TakeIf(')'))
+ {
+ throw new ExpressionParseException(r.Position, $"Expected '{c}', got '{r.Peek}'.");
+ }
+ }
+
public interface ISyntax
{
}
@@ -376,5 +405,15 @@ namespace Avalonia.Markup.Parsers
return obj is TemplateSyntax;
}
}
+
+ public class NotSyntax : ISyntax
+ {
+ public IEnumerable Argument { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ return (obj is NotSyntax not) && Argument.SequenceEqual(not.Argument);
+ }
+ }
}
}
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorParser.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorParser.cs
index bf5b396bec..8d1216e1dc 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorParser.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorParser.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.Collections.Generic;
using System.Globalization;
using Avalonia.Styling;
using Avalonia.Utilities;
@@ -25,7 +26,7 @@ namespace Avalonia.Markup.Parsers
///
public SelectorParser(Func typeResolver)
{
- this._typeResolver = typeResolver;
+ _typeResolver = typeResolver;
}
///
@@ -36,6 +37,11 @@ namespace Avalonia.Markup.Parsers
public Selector Parse(string s)
{
var syntax = SelectorGrammar.Parse(s);
+ return Create(syntax);
+ }
+
+ private Selector Create(IEnumerable syntax)
+ {
var result = default(Selector);
foreach (var i in syntax)
@@ -97,6 +103,11 @@ namespace Avalonia.Markup.Parsers
case SelectorGrammar.TemplateSyntax template:
result = result.Template();
break;
+ case SelectorGrammar.NotSyntax not:
+ result = result.Not(x => Create(not.Argument));
+ break;
+ default:
+ throw new NotSupportedException($"Unsupported selector grammar '{i.GetType()}'.");
}
}
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index 076d69ae4a..353354da5e 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Threading;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering;
@@ -20,7 +21,7 @@ namespace Avalonia.Skia
///
public class DrawingContextImpl : IDrawingContextImpl
{
- private readonly IDisposable[] _disposables;
+ private IDisposable[] _disposables;
private readonly Vector _dpi;
private readonly Stack _maskStack = new Stack();
private readonly Stack _opacityStack = new Stack();
@@ -30,7 +31,7 @@ namespace Avalonia.Skia
private readonly bool _canTextUseLcdRendering;
private Matrix _currentTransform;
private GRContext _grContext;
-
+ private bool _disposed;
///
/// Context create info.
///
@@ -74,6 +75,8 @@ namespace Avalonia.Skia
_disposables = disposables;
_canTextUseLcdRendering = !createInfo.DisableTextLcdRendering;
_grContext = createInfo.GrContext;
+ if (_grContext != null)
+ Monitor.Enter(_grContext);
Canvas = createInfo.Canvas;
@@ -257,14 +260,26 @@ namespace Avalonia.Skia
///
public virtual void Dispose()
{
- if (_disposables == null)
- {
+ if(_disposed)
return;
- }
+ try
+ {
+ if (_grContext != null)
+ {
+ Monitor.Exit(_grContext);
+ _grContext = null;
+ }
- foreach (var disposable in _disposables)
+ if (_disposables != null)
+ {
+ foreach (var disposable in _disposables)
+ disposable?.Dispose();
+ _disposables = null;
+ }
+ }
+ finally
{
- disposable?.Dispose();
+ _disposed = true;
}
}
@@ -386,15 +401,15 @@ namespace Avalonia.Skia
/// Tile brush image.
private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage)
{
- var calc = new TileBrushCalculator(tileBrush, tileBrushImage.PixelSize.ToSize(_dpi), targetSize);
+ var calc = new TileBrushCalculator(tileBrush, tileBrushImage.PixelSize.ToSizeWithDpi(_dpi), targetSize);
var intermediate = CreateRenderTarget(calc.IntermediateSize);
paintWrapper.AddDisposable(intermediate);
using (var context = intermediate.CreateDrawingContext(null))
{
- var sourceRect = new Rect(tileBrushImage.PixelSize.ToSize(96));
- var targetRect = new Rect(tileBrushImage.PixelSize.ToSize(_dpi));
+ var sourceRect = new Rect(tileBrushImage.PixelSize.ToSizeWithDpi(96));
+ var targetRect = new Rect(tileBrushImage.PixelSize.ToSizeWithDpi(_dpi));
context.Clear(Colors.Transparent);
context.PushClip(calc.IntermediateClip);
@@ -619,7 +634,7 @@ namespace Avalonia.Skia
///
private SurfaceRenderTarget CreateRenderTarget(Size size, PixelFormat? format = null)
{
- var pixelSize = PixelSize.FromSize(size, _dpi);
+ var pixelSize = PixelSize.FromSizeWithDpi(size, _dpi);
var createInfo = new SurfaceRenderTarget.CreateInfo
{
Width = pixelSize.Width,
diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs
index 56c5c57f7b..7e3f4aa40a 100644
--- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs
+++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs
@@ -272,7 +272,7 @@ namespace Avalonia.Skia
}
var textLine = Text.Substring(line.Start, line.Length);
- currX -= paint.MeasureText(textLine) * factor;
+ currX -= textLine.Length == 0 ? 0 : paint.MeasureText(textLine) * factor;
for (int i = line.Start; i < line.Start + line.Length;)
{
diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
index 02b6188fb6..0cb4c3db67 100644
--- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
@@ -61,7 +61,7 @@ namespace Avalonia.Skia
DisableTextLcdRendering = true
};
- return new DrawingContextImpl(createInfo, _preFramebufferCopyHandler, framebuffer);
+ return new DrawingContextImpl(createInfo, _preFramebufferCopyHandler, canvas, framebuffer);
}
///
@@ -119,11 +119,7 @@ namespace Avalonia.Skia
_conversionShim = null;
_preFramebufferCopyHandler = null;
- if (_conversionShim != null)
- {
- _framebufferSurface?.Dispose();
- }
-
+ _framebufferSurface?.Dispose();
_framebufferSurface = null;
_currentFramebufferAddress = IntPtr.Zero;
}
diff --git a/src/Skia/Avalonia.Skia/GlRenderTarget.cs b/src/Skia/Avalonia.Skia/GlRenderTarget.cs
index 81c70e2be7..cd8c334b53 100644
--- a/src/Skia/Avalonia.Skia/GlRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/GlRenderTarget.cs
@@ -30,36 +30,46 @@ namespace Avalonia.Skia
var size = session.Size;
var scaling = session.Scaling;
+ if (size.Width <= 0 || size.Height <= 0 || scaling < 0)
+ {
+ throw new InvalidOperationException(
+ $"Can't create drawing context for surface with {size} size and {scaling} scaling");
+ }
gl.Viewport(0, 0, size.Width, size.Height);
gl.ClearStencil(0);
gl.ClearColor(0, 0, 0, 0);
gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- _grContext.ResetContext();
-
- GRBackendRenderTarget renderTarget =
- new GRBackendRenderTarget(size.Width, size.Height, disp.SampleCount, disp.StencilSize,
- new GRGlFramebufferInfo((uint)fb, GRPixelConfig.Rgba8888.ToGlSizedFormat()));
- var surface = SKSurface.Create(_grContext, renderTarget,
- GRSurfaceOrigin.BottomLeft,
- GRPixelConfig.Rgba8888.ToColorType());
-
- var nfo = new DrawingContextImpl.CreateInfo
+ lock (_grContext)
{
- GrContext = _grContext,
- Canvas = surface.Canvas,
- Dpi = SkiaPlatform.DefaultDpi * scaling,
- VisualBrushRenderer = visualBrushRenderer,
- DisableTextLcdRendering = true
- };
+ _grContext.ResetContext();
- return new DrawingContextImpl(nfo, Disposable.Create(() =>
- {
- surface.Canvas.Flush();
- surface.Dispose();
- renderTarget.Dispose();
- session.Dispose();
- }));
+ GRBackendRenderTarget renderTarget =
+ new GRBackendRenderTarget(size.Width, size.Height, disp.SampleCount, disp.StencilSize,
+ new GRGlFramebufferInfo((uint)fb, GRPixelConfig.Rgba8888.ToGlSizedFormat()));
+ var surface = SKSurface.Create(_grContext, renderTarget,
+ GRSurfaceOrigin.BottomLeft,
+ GRPixelConfig.Rgba8888.ToColorType());
+
+ var nfo = new DrawingContextImpl.CreateInfo
+ {
+ GrContext = _grContext,
+ Canvas = surface.Canvas,
+ Dpi = SkiaPlatform.DefaultDpi * scaling,
+ VisualBrushRenderer = visualBrushRenderer,
+ DisableTextLcdRendering = true
+ };
+
+ return new DrawingContextImpl(nfo, Disposable.Create(() =>
+ {
+
+ surface.Canvas.Flush();
+ surface.Dispose();
+ renderTarget.Dispose();
+ _grContext.Flush();
+ session.Dispose();
+ }));
+ }
}
}
}
diff --git a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs
index f94a226bbc..49992df395 100644
--- a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs
+++ b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs
@@ -24,7 +24,8 @@ namespace Avalonia.Skia
{
using (var skiaStream = new SKManagedStream(stream))
{
- _image = SKImage.FromEncodedData(SKData.Create(skiaStream));
+ using (var data = SKData.Create(skiaStream))
+ _image = SKImage.FromEncodedData(data);
if (_image == null)
{
diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
index 9b10d74c64..c6e68b1c8b 100644
--- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
+++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
@@ -19,17 +19,22 @@ namespace Avalonia.Skia
{
private GRContext GrContext { get; }
+ public IEnumerable InstalledFontNames => SKFontManager.Default.FontFamilies;
+
public PlatformRenderInterface()
{
var gl = AvaloniaLocator.Current.GetService();
if (gl != null)
{
var display = gl.ImmediateContext.Display;
- var iface = display.Type == GlDisplayType.OpenGL2
- ? GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc))
- : GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc));
gl.ImmediateContext.MakeCurrent();
- GrContext = GRContext.Create(GRBackend.OpenGL, iface);
+ using (var iface = display.Type == GlDisplayType.OpenGL2
+ ? GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc))
+ : GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc)))
+ {
+
+ GrContext = GRContext.Create(GRBackend.OpenGL, iface);
+ }
}
}
diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
index 3ec18dac5e..8412a65e23 100644
--- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
+++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
@@ -41,6 +41,19 @@ namespace Avalonia.Direct2D1
public static SharpDX.DXGI.Device1 DxgiDevice { get; private set; }
+ public IEnumerable InstalledFontNames
+ {
+ get
+ {
+ var cache = Direct2D1FontCollectionCache.s_installedFontCollection;
+ var length = cache.FontFamilyCount;
+ for (int i = 0; i < length; i++)
+ {
+ var names = cache.GetFontFamily(i).FamilyNames;
+ yield return names.GetString(0);
+ }
+ }
+ }
private static readonly object s_initLock = new object();
private static bool s_initialized = false;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/Direct2D1FontCollectionCache.cs b/src/Windows/Avalonia.Direct2D1/Media/Direct2D1FontCollectionCache.cs
index d60aa15a5e..d93a59d384 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/Direct2D1FontCollectionCache.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/Direct2D1FontCollectionCache.cs
@@ -7,7 +7,7 @@ namespace Avalonia.Direct2D1.Media
internal static class Direct2D1FontCollectionCache
{
private static readonly ConcurrentDictionary s_cachedCollections;
- private static readonly SharpDX.DirectWrite.FontCollection s_installedFontCollection;
+ internal static readonly SharpDX.DirectWrite.FontCollection s_installedFontCollection;
static Direct2D1FontCollectionCache()
{
diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
index aaca1a3b00..5e150ff647 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
@@ -330,7 +330,7 @@ namespace Avalonia.Direct2D1.Media
{
var platform = AvaloniaLocator.Current.GetService();
var dpi = new Vector(_deviceContext.DotsPerInch.Width, _deviceContext.DotsPerInch.Height);
- var pixelSize = PixelSize.FromSize(size, dpi);
+ var pixelSize = PixelSize.FromSizeWithDpi(size, dpi);
return platform.CreateRenderTargetBitmap(pixelSize, dpi);
}
}
@@ -438,12 +438,12 @@ namespace Avalonia.Direct2D1.Media
// D2D alters the DPI of the render target, which messes stuff up. PixelSize.FromSize
// will do the rounding for us.
var dpi = new Vector(_deviceContext.DotsPerInch.Width, _deviceContext.DotsPerInch.Height);
- var pixelSize = PixelSize.FromSize(intermediateSize, dpi);
+ var pixelSize = PixelSize.FromSizeWithDpi(intermediateSize, dpi);
using (var intermediate = new BitmapRenderTarget(
_deviceContext,
CompatibleRenderTargetOptions.None,
- pixelSize.ToSize(dpi).ToSharpDX()))
+ pixelSize.ToSizeWithDpi(dpi).ToSharpDX()))
{
using (var ctx = new RenderTarget(intermediate).CreateDrawingContext(_visualBrushRenderer))
{
diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
index 19d320b783..fbc6d21cb7 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
@@ -21,7 +21,7 @@ namespace Avalonia.Direct2D1.Media
Size targetSize)
{
var dpi = new Vector(target.DotsPerInch.Width, target.DotsPerInch.Height);
- var calc = new TileBrushCalculator(brush, bitmap.PixelSize.ToSize(dpi), targetSize);
+ var calc = new TileBrushCalculator(brush, bitmap.PixelSize.ToSizeWithDpi(dpi), targetSize);
if (!calc.NeedsIntermediate)
{
@@ -101,7 +101,7 @@ namespace Avalonia.Direct2D1.Media
using (var context = new RenderTarget(result).CreateDrawingContext(null))
{
var dpi = new Vector(target.DotsPerInch.Width, target.DotsPerInch.Height);
- var rect = new Rect(bitmap.PixelSize.ToSize(dpi));
+ var rect = new Rect(bitmap.PixelSize.ToSizeWithDpi(dpi));
context.Clear(Colors.Transparent);
context.PushClip(calc.IntermediateClip);
diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
index fbe7f840d7..8ec368c999 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
@@ -61,8 +61,8 @@ namespace Avalonia.Direct2D1.Media.Imaging
dc.DrawImage(
RefCountable.CreateUnownedNotClonable(this),
1,
- new Rect(PixelSize.ToSize(Dpi.X)),
- new Rect(PixelSize.ToSize(Dpi.X)));
+ new Rect(PixelSize.ToSizeWithDpi(Dpi.X)),
+ new Rect(PixelSize.ToSizeWithDpi(Dpi.X)));
}
wic.Save(stream);
diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs
index 44c4c84cd6..cbfc259eda 100644
--- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs
+++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs
@@ -3,7 +3,9 @@
static class WpfInteropExtensions
{
public static System.Windows.Point ToWpfPoint(this Point pt) => new System.Windows.Point(pt.X, pt.Y);
+ public static System.Windows.Point ToWpfPoint(this PixelPoint pt) => new System.Windows.Point(pt.X, pt.Y);
public static Point ToAvaloniaPoint(this System.Windows.Point pt) => new Point(pt.X, pt.Y);
+ public static PixelPoint ToAvaloniaPixelPoint(this System.Windows.Point pt) => new PixelPoint((int)pt.X, (int)pt.Y);
public static System.Windows.Size ToWpfSize(this Size pt) => new System.Windows.Size(pt.Width, pt.Height);
public static Size ToAvaloniaSize(this System.Windows.Size pt) => new Size(pt.Width, pt.Height);
}
diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
index b5fb158168..7005459487 100644
--- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
+++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
@@ -135,9 +135,9 @@ namespace Avalonia.Win32.Interop.Wpf
void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
- Point ITopLevelImpl.PointToClient(Point point) => PointFromScreen(point.ToWpfPoint()).ToAvaloniaPoint();
+ Point ITopLevelImpl.PointToClient(PixelPoint point) => PointFromScreen(point.ToWpfPoint()).ToAvaloniaPoint();
- Point ITopLevelImpl.PointToScreen(Point point) => PointToScreen(point.ToWpfPoint()).ToAvaloniaPoint();
+ PixelPoint ITopLevelImpl.PointToScreen(Point point) => PointToScreen(point.ToWpfPoint()).ToAvaloniaPixelPoint();
protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke();
diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs
index 7013931be9..28065566d0 100644
--- a/src/Windows/Avalonia.Win32/OleDropTarget.cs
+++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs
@@ -177,7 +177,7 @@ namespace Avalonia.Win32
int x = (int)dragPoint;
int y = (int)(dragPoint >> 32);
- Point screenPt = new Point(x, y);
+ var screenPt = new PixelPoint(x, y);
return _target.PointToClient(screenPt);
}
}
diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs
index 5cfceb68b7..aa3b23eb50 100644
--- a/src/Windows/Avalonia.Win32/ScreenImpl.cs
+++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs
@@ -31,10 +31,10 @@ namespace Avalonia.Win32
{
RECT bounds = monitorInfo.rcMonitor;
RECT workingArea = monitorInfo.rcWork;
- Rect avaloniaBounds = new Rect(bounds.left, bounds.top, bounds.right - bounds.left,
+ PixelRect avaloniaBounds = new PixelRect(bounds.left, bounds.top, bounds.right - bounds.left,
bounds.bottom - bounds.top);
- Rect avaloniaWorkArea =
- new Rect(workingArea.left, workingArea.top, workingArea.right - workingArea.left,
+ PixelRect avaloniaWorkArea =
+ new PixelRect(workingArea.left, workingArea.top, workingArea.right - workingArea.left,
workingArea.bottom - workingArea.top);
screens[index] =
new WinScreen(avaloniaBounds, avaloniaWorkArea, monitorInfo.dwFlags == 1,
diff --git a/src/Windows/Avalonia.Win32/WinScreen.cs b/src/Windows/Avalonia.Win32/WinScreen.cs
index 2f8dcb0f3e..e849800e62 100644
--- a/src/Windows/Avalonia.Win32/WinScreen.cs
+++ b/src/Windows/Avalonia.Win32/WinScreen.cs
@@ -7,7 +7,7 @@ namespace Avalonia.Win32
{
private readonly IntPtr _hMonitor;
- public WinScreen(Rect bounds, Rect workingArea, bool primary, IntPtr hMonitor) : base(bounds, workingArea, primary)
+ public WinScreen(PixelRect bounds, PixelRect workingArea, bool primary, IntPtr hMonitor) : base(bounds, workingArea, primary)
{
this._hMonitor = hMonitor;
}
@@ -22,4 +22,4 @@ namespace Avalonia.Win32
return (obj is WinScreen screen) ? this._hMonitor == screen._hMonitor : base.Equals(obj);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index f4eb0e2ea8..081a713e95 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -87,7 +87,7 @@ namespace Avalonia.Win32
public Action ScalingChanged { get; set; }
- public Action PositionChanged { get; set; }
+ public Action PositionChanged { get; set; }
public Action WindowStateChanged { get; set; }
@@ -297,19 +297,19 @@ namespace Avalonia.Win32
UnmanagedMethods.InvalidateRect(_hwnd, ref r, false);
}
- public Point PointToClient(Point point)
+ public Point PointToClient(PixelPoint point)
{
var p = new UnmanagedMethods.POINT { X = (int)point.X, Y = (int)point.Y };
UnmanagedMethods.ScreenToClient(_hwnd, ref p);
return new Point(p.X, p.Y) / Scaling;
}
- public Point PointToScreen(Point point)
+ public PixelPoint PointToScreen(Point point)
{
point *= Scaling;
var p = new UnmanagedMethods.POINT { X = (int)point.X, Y = (int)point.Y };
UnmanagedMethods.ClientToScreen(_hwnd, ref p);
- return new Point(p.X, p.Y);
+ return new PixelPoint(p.X, p.Y);
}
public void SetInputRoot(IInputRoot inputRoot)
@@ -357,21 +357,21 @@ namespace Avalonia.Win32
#endif
}
- public Point Position
+ public PixelPoint Position
{
get
{
UnmanagedMethods.RECT rc;
UnmanagedMethods.GetWindowRect(_hwnd, out rc);
- return new Point(rc.left, rc.top);
+ return new PixelPoint(rc.left, rc.top);
}
set
{
UnmanagedMethods.SetWindowPos(
Handle.Handle,
IntPtr.Zero,
- (int)value.X,
- (int)value.Y,
+ value.X,
+ value.Y,
0,
0,
UnmanagedMethods.SetWindowPosFlags.SWP_NOSIZE | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE);
@@ -661,7 +661,7 @@ namespace Avalonia.Win32
return IntPtr.Zero;
case UnmanagedMethods.WindowsMessage.WM_MOVE:
- PositionChanged?.Invoke(new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)));
+ PositionChanged?.Invoke(new PixelPoint((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)));
return IntPtr.Zero;
case UnmanagedMethods.WindowsMessage.WM_GETMINMAXINFO:
@@ -785,9 +785,9 @@ namespace Avalonia.Win32
return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / Scaling;
}
- private Point PointFromLParam(IntPtr lParam)
+ private PixelPoint PointFromLParam(IntPtr lParam)
{
- return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16));
+ return new PixelPoint((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16));
}
private Point ScreenToClient(Point point)
diff --git a/src/iOS/Avalonia.iOS/TopLevelImpl.cs b/src/iOS/Avalonia.iOS/TopLevelImpl.cs
index 1101f53222..83d10b8b44 100644
--- a/src/iOS/Avalonia.iOS/TopLevelImpl.cs
+++ b/src/iOS/Avalonia.iOS/TopLevelImpl.cs
@@ -68,9 +68,9 @@ namespace Avalonia.iOS
public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
- public Point PointToClient(Point point) => point;
+ public Point PointToClient(PixelPoint point) => point.ToPoint(1);
- public Point PointToScreen(Point point) => point;
+ public PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, 1);
public void SetCursor(IPlatformHandle cursor)
{
diff --git a/tests/Avalonia.Animation.UnitTests/AnimationIterationTests.cs b/tests/Avalonia.Animation.UnitTests/AnimationIterationTests.cs
index d89b8469df..f7a8774689 100644
--- a/tests/Avalonia.Animation.UnitTests/AnimationIterationTests.cs
+++ b/tests/Avalonia.Animation.UnitTests/AnimationIterationTests.cs
@@ -8,6 +8,7 @@ using Avalonia.Styling;
using Avalonia.UnitTests;
using Avalonia.Data;
using Xunit;
+using Avalonia.Animation.Easings;
namespace Avalonia.Animation.UnitTests
{
@@ -73,5 +74,58 @@ namespace Avalonia.Animation.UnitTests
Assert.True(animationRun.Status == TaskStatus.RanToCompletion);
Assert.Equal(border.Width, 100d);
}
+
+ [Fact]
+ public void Check_FillModes_Start_and_End_Values_if_Retained()
+ {
+ var keyframe1 = new KeyFrame()
+ {
+ Setters =
+ {
+ new Setter(Border.WidthProperty, 0d),
+ },
+ Cue = new Cue(0.0d)
+ };
+
+ var keyframe2 = new KeyFrame()
+ {
+ Setters =
+ {
+ new Setter(Border.WidthProperty, 300d),
+ },
+ Cue = new Cue(1.0d)
+ };
+
+ var animation = new Animation()
+ {
+ Duration = TimeSpan.FromSeconds(0.05d),
+ Delay = TimeSpan.FromSeconds(0.05d),
+ Easing = new SineEaseInOut(),
+ FillMode = FillMode.Both,
+ Children =
+ {
+ keyframe1,
+ keyframe2
+ }
+ };
+
+ var border = new Border()
+ {
+ Height = 100d,
+ Width = 100d,
+ };
+
+ var clock = new TestClock();
+ var animationRun = animation.RunAsync(border, clock);
+
+ clock.Step(TimeSpan.FromSeconds(0d));
+ Assert.Equal(border.Width, 0d);
+
+ clock.Step(TimeSpan.FromSeconds(0.050d));
+ Assert.Equal(border.Width, 0d);
+
+ clock.Step(TimeSpan.FromSeconds(0.100d));
+ Assert.Equal(border.Width, 300d);
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs
index 76f2898700..91b37596b7 100644
--- a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs
@@ -238,9 +238,9 @@ namespace Avalonia.Controls.UnitTests
public void Invalidate(Rect rect) => throw new NotImplementedException();
- public Point PointToClient(Point point) => throw new NotImplementedException();
+ public Point PointToClient(PixelPoint p) => throw new NotImplementedException();
- public Point PointToScreen(Point point) => throw new NotImplementedException();
+ public PixelPoint PointToScreen(Point p) => throw new NotImplementedException();
}
private void RaisePointerPressed(Button button, IMouseDevice device, int clickCount, MouseButton mouseButton)
diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
index 66f0cc3a40..834c49ba6b 100644
--- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
@@ -160,7 +160,7 @@ namespace Avalonia.Controls.UnitTests
private IDisposable Application()
{
- var screen = new Rect(new Point(), new Size(100, 100));
+ var screen = new PixelRect(new PixelPoint(), new PixelSize(100, 100));
var screenImpl = new Mock();
screenImpl.Setup(x => x.ScreenCount).Returns(1);
screenImpl.Setup(X => X.AllScreens).Returns( new[] { new Screen(screen, screen, true) });
diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs
index ba4ccb0527..3ea32ed719 100644
--- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs
+++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs
@@ -336,25 +336,11 @@ namespace Avalonia.Controls.UnitTests.Presenters
public double LayoutScaling => 1;
public ILayoutManager LayoutManager { get; } = new LayoutManager();
- public IRenderTarget CreateRenderTarget()
- {
- throw new NotImplementedException();
- }
-
- public void Invalidate(Rect rect)
- {
- throw new NotImplementedException();
- }
- public Point PointToClient(Point point)
- {
- throw new NotImplementedException();
- }
-
- public Point PointToScreen(Point point)
- {
- throw new NotImplementedException();
- }
+ public IRenderTarget CreateRenderTarget() => throw new NotImplementedException();
+ public void Invalidate(Rect rect) => throw new NotImplementedException();
+ public Point PointToClient(PixelPoint p) => throw new NotImplementedException();
+ public PixelPoint PointToScreen(Point p) => throw new NotImplementedException();
}
private class TestItemsPresenter : ItemsPresenter
diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
index 7187ea16da..9921a8de6c 100644
--- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
+++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
@@ -1077,30 +1077,10 @@ namespace Avalonia.Controls.UnitTests.Presenters
public ILayoutManager LayoutManager { get; } = new LayoutManager();
- public IRenderTarget CreateRenderTarget()
- {
- throw new NotImplementedException();
- }
-
- public void Invalidate(Rect rect)
- {
- throw new NotImplementedException();
- }
-
- public Point PointToClient(Point point)
- {
- throw new NotImplementedException();
- }
-
- public Point PointToScreen(Point point)
- {
- throw new NotImplementedException();
- }
-
- protected override Size MeasureOverride(Size availableSize)
- {
- return base.MeasureOverride(availableSize);
- }
+ public IRenderTarget CreateRenderTarget() => throw new NotImplementedException();
+ public void Invalidate(Rect rect) => throw new NotImplementedException();
+ public Point PointToClient(PixelPoint p) => throw new NotImplementedException();
+ public PixelPoint PointToScreen(Point p) => throw new NotImplementedException();
}
private class TestItemsPresenter : ItemsPresenter
diff --git a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs
index a5c3881d37..e00084eba4 100644
--- a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs
@@ -267,26 +267,46 @@ namespace Avalonia.Controls.UnitTests
Assert.Null(page.Content);
}
+ [Fact]
+ public void DataTemplate_Created_Content_Should_Be_Logical_Child_After_ApplyTemplate()
+ {
+ TabControl target = new TabControl
+ {
+ Template = TabControlTemplate(),
+ ContentTemplate = new FuncDataTemplate(x =>
+ new TextBlock { Tag = "bar", Text = x }),
+ Items = new[] { "Foo" },
+ };
+
+ ApplyTemplate(target);
+ target.ContentPart.UpdateChild();
+
+ var content = Assert.IsType(target.ContentPart.Child);
+ Assert.Equal("bar", content.Tag);
+ Assert.Same(target, content.GetLogicalParent());
+ Assert.Single(target.GetLogicalChildren(), content);
+ }
+
private IControlTemplate TabControlTemplate()
{
return new FuncControlTemplate(parent =>
-
new StackPanel
{
- Children = {
- new ItemsPresenter
- {
- Name = "PART_ItemsPresenter",
- [!TabStrip.ItemsProperty] = parent[!TabControl.ItemsProperty],
- [!TabStrip.ItemTemplateProperty] = parent[!TabControl.ItemTemplateProperty],
- },
- new ContentPresenter
- {
- Name = "PART_Content",
- [!ContentPresenter.ContentProperty] = parent[!TabControl.SelectedContentProperty],
- [!ContentPresenter.ContentTemplateProperty] = parent[!TabControl.SelectedContentTemplateProperty],
- }
- }
+ Children =
+ {
+ new ItemsPresenter
+ {
+ Name = "PART_ItemsPresenter",
+ [!TabStrip.ItemsProperty] = parent[!TabControl.ItemsProperty],
+ [!TabStrip.ItemTemplateProperty] = parent[!TabControl.ItemTemplateProperty],
+ },
+ new ContentPresenter
+ {
+ Name = "PART_SelectedContentHost",
+ [!ContentPresenter.ContentProperty] = parent[!TabControl.SelectedContentProperty],
+ [!ContentPresenter.ContentTemplateProperty] = parent[!TabControl.SelectedContentTemplateProperty],
+ }
+ }
});
}
diff --git a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
index 51a4d21392..6d00409ae0 100644
--- a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
@@ -199,6 +199,22 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void Showing_Should_Raise_Opened()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var target = new TestWindowBase();
+ var raised = false;
+
+ target.Opened += (s, e) => raised = true;
+
+ target.Show();
+
+ Assert.True(raised);
+ }
+ }
+
[Fact]
public void Hiding_Should_Stop_Renderer()
{
diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs
index adf9bd9cec..8221dadc86 100644
--- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs
@@ -228,18 +228,35 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void ShowDialog_Should_Start_Renderer()
{
-
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
+ var parent = Mock.Of();
var renderer = new Mock();
var target = new Window(CreateImpl(renderer));
- target.Show();
+ target.ShowDialog(parent);
renderer.Verify(x => x.Start(), Times.Once);
}
}
+ [Fact]
+ public void ShowDialog_Should_Raise_Opened()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var parent = Mock.Of();
+ var target = new Window();
+ var raised = false;
+
+ target.Opened += (s, e) => raised = true;
+
+ target.ShowDialog(parent);
+
+ Assert.True(raised);
+ }
+ }
+
[Fact]
public void Hiding_Should_Stop_Renderer()
{
@@ -278,8 +295,8 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Window_Should_Be_Centered_When_WindowStartupLocation_Is_CenterScreen()
{
- var screen1 = new Mock(new Rect(new Size(1920, 1080)), new Rect(new Size(1920, 1040)), true);
- var screen2 = new Mock(new Rect(new Size(1366, 768)), new Rect(new Size(1366, 728)), false);
+ var screen1 = new Mock(new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true);
+ var screen2 = new Mock(new PixelRect(new PixelSize(1366, 768)), new PixelRect(new PixelSize(1366, 728)), false);
var screens = new Mock();
screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object, screen2.Object });
@@ -294,13 +311,13 @@ namespace Avalonia.Controls.UnitTests
{
var window = new Window(windowImpl.Object);
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
- window.Position = new Point(60, 40);
+ window.Position = new PixelPoint(60, 40);
window.Show();
- var expectedPosition = new Point(
- screen1.Object.WorkingArea.Size.Width / 2 - window.ClientSize.Width / 2,
- screen1.Object.WorkingArea.Size.Height / 2 - window.ClientSize.Height / 2);
+ var expectedPosition = new PixelPoint(
+ (int)(screen1.Object.WorkingArea.Size.Width / 2 - window.ClientSize.Width / 2),
+ (int)(screen1.Object.WorkingArea.Size.Height / 2 - window.ClientSize.Height / 2));
Assert.Equal(window.Position, expectedPosition);
}
@@ -330,7 +347,7 @@ namespace Avalonia.Controls.UnitTests
using (UnitTestApplication.Start(parentWindowServices))
{
var parentWindow = new Window();
- parentWindow.Position = new Point(60, 40);
+ parentWindow.Position = new PixelPoint(60, 40);
parentWindow.Show();
@@ -338,14 +355,14 @@ namespace Avalonia.Controls.UnitTests
{
var window = new Window();
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
- window.Position = new Point(60, 40);
+ window.Position = new PixelPoint(60, 40);
window.Owner = parentWindow;
window.Show();
- var expectedPosition = new Point(
- parentWindow.Position.X + parentWindow.ClientSize.Width / 2 - window.ClientSize.Width / 2,
- parentWindow.Position.Y + parentWindow.ClientSize.Height / 2 - window.ClientSize.Height / 2);
+ var expectedPosition = new PixelPoint(
+ (int)(parentWindow.Position.X + parentWindow.ClientSize.Width / 2 - window.ClientSize.Width / 2),
+ (int)(parentWindow.Position.Y + parentWindow.ClientSize.Height / 2 - window.ClientSize.Height / 2));
Assert.Equal(window.Position, expectedPosition);
}
diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs
index 4dcd98cb93..b7aa452a18 100644
--- a/tests/Avalonia.LeakTests/ControlTests.cs
+++ b/tests/Avalonia.LeakTests/ControlTests.cs
@@ -348,6 +348,7 @@ namespace Avalonia.LeakTests
{
public bool DrawFps { get; set; }
public bool DrawDirtyRects { get; set; }
+ public event EventHandler SceneInvalidated;
public void AddDirty(IVisual visual)
{
diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Converters.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Converters.cs
index 123aadfda5..1ede4ee0b0 100644
--- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Converters.cs
+++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Converters.cs
@@ -22,14 +22,14 @@ namespace Avalonia.Markup.UnitTests.Data
var target = new Binding(nameof(Class1.Foo))
{
- Converter = StringConverters.NullOrEmpty,
+ Converter = StringConverters.IsNullOrEmpty,
};
var expressionObserver = (BindingExpression)target.Initiate(
textBlock,
TextBlock.TextProperty).Observable;
- Assert.Same(StringConverters.NullOrEmpty, expressionObserver.Converter);
+ Assert.Same(StringConverters.IsNullOrEmpty, expressionObserver.Converter);
}
public class When_Binding_To_String
@@ -129,7 +129,7 @@ namespace Avalonia.Markup.UnitTests.Data
var target = new Binding(nameof(Class1.Foo))
{
- Converter = StringConverters.NotNullOrEmpty,
+ Converter = StringConverters.IsNotNullOrEmpty,
StringFormat = "Hello {0}",
};
diff --git a/tests/Avalonia.Markup.UnitTests/Parsers/SelectorGrammarTests.cs b/tests/Avalonia.Markup.UnitTests/Parsers/SelectorGrammarTests.cs
index 88fe5a2a12..e3ce4b0968 100644
--- a/tests/Avalonia.Markup.UnitTests/Parsers/SelectorGrammarTests.cs
+++ b/tests/Avalonia.Markup.UnitTests/Parsers/SelectorGrammarTests.cs
@@ -200,6 +200,67 @@ namespace Avalonia.Markup.UnitTests.Parsers
result);
}
+ [Fact]
+ public void Not_OfType()
+ {
+ var result = SelectorGrammar.Parse(":not(Button)");
+
+ Assert.Equal(
+ new SelectorGrammar.ISyntax[]
+ {
+ new SelectorGrammar.NotSyntax
+ {
+ Argument = new SelectorGrammar.ISyntax[]
+ {
+ new SelectorGrammar.OfTypeSyntax { TypeName = "Button" },
+ },
+ }
+ },
+ result);
+ }
+
+ [Fact]
+ public void OfType_Not_Class()
+ {
+ var result = SelectorGrammar.Parse("Button:not(.foo)");
+
+ Assert.Equal(
+ new SelectorGrammar.ISyntax[]
+ {
+ new SelectorGrammar.OfTypeSyntax { TypeName = "Button" },
+ new SelectorGrammar.NotSyntax
+ {
+ Argument = new SelectorGrammar.ISyntax[]
+ {
+ new SelectorGrammar.ClassSyntax { Class = "foo" },
+ },
+ }
+ },
+ result);
+ }
+
+ [Fact]
+ public void Is_Descendent_Not_OfType_Class()
+ {
+ var result = SelectorGrammar.Parse(":is(Control) :not(Button.foo)");
+
+ Assert.Equal(
+ new SelectorGrammar.ISyntax[]
+ {
+ new SelectorGrammar.IsSyntax { TypeName = "Control" },
+ new SelectorGrammar.DescendantSyntax { },
+ new SelectorGrammar.NotSyntax
+ {
+ Argument = new SelectorGrammar.ISyntax[]
+ {
+ new SelectorGrammar.OfTypeSyntax { TypeName = "Button" },
+ new SelectorGrammar.ClassSyntax { Class = "foo" },
+ },
+ }
+ },
+ result);
+ }
+
[Fact]
public void Namespace_Alone_Fails()
{
@@ -223,5 +284,17 @@ namespace Avalonia.Markup.UnitTests.Parsers
{
Assert.Throws(() => SelectorGrammar.Parse(".%foo"));
}
+
+ [Fact]
+ public void Not_Without_Argument_Fails()
+ {
+ Assert.Throws(() => SelectorGrammar.Parse(":not()"));
+ }
+
+ [Fact]
+ public void Not_Without_Closing_Parenthesis_Fails()
+ {
+ Assert.Throws(() => SelectorGrammar.Parse(":not(Button"));
+ }
}
}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Converters/ConverterTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Converters/ConverterTests.cs
new file mode 100644
index 0000000000..6ffaaaee5c
--- /dev/null
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Converters/ConverterTests.cs
@@ -0,0 +1,23 @@
+using System;
+using Xunit;
+
+namespace Avalonia.Markup.Xaml.UnitTests.Converters
+{
+ public class ConverterTests
+ {
+ [Fact]
+ public void Bug_2228_Relative_Uris_Should_Be_Correctly_Parsed()
+ {
+ var testClass = typeof(TestClassWithUri);
+ var parsed = AvaloniaXamlLoader.Parse(
+ $"<{testClass.Name} xmlns='clr-namespace:{testClass.Namespace}' Uri='/test'/>", testClass.Assembly);
+
+ Assert.False(parsed.Uri.IsAbsoluteUri);
+ }
+ }
+
+ public class TestClassWithUri
+ {
+ public Uri Uri { get; set; }
+ }
+}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs
index beaf7477d0..a84ce74a88 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs
@@ -198,5 +198,33 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
ex.InnerException.Message);
}
}
+
+ [Fact]
+ public void Style_Can_Use_Not_Selector()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+
+
+
+
+
+
+ ";
+ var loader = new AvaloniaXamlLoader();
+ var window = (Window)loader.Load(xaml);
+ var foo = window.FindControl("foo");
+ var notFoo = window.FindControl("notFoo");
+
+ Assert.Null(foo.Background);
+ Assert.Equal(Colors.Red, ((ISolidColorBrush)notFoo.Background).Color);
+ }
+ }
}
}
diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs
index b782311729..70a5504a7d 100644
--- a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs
+++ b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs
@@ -10,6 +10,7 @@ using ReactiveUI;
using DynamicData;
using Xunit;
using Splat;
+using Avalonia.Markup.Xaml;
namespace Avalonia
{
@@ -70,12 +71,40 @@ namespace Avalonia
public class ActivatableWindow : ReactiveWindow
{
- public ActivatableWindow() => this.WhenActivated(disposables => { });
+ public ActivatableWindow()
+ {
+ InitializeComponent();
+ Assert.IsType(Content);
+ this.WhenActivated(disposables => { });
+ }
+
+ private void InitializeComponent()
+ {
+ var loader = new AvaloniaXamlLoader();
+ loader.Load(@"
+
+
+ ", null, this);
+ }
}
public class ActivatableUserControl : ReactiveUserControl
{
- public ActivatableUserControl() => this.WhenActivated(disposables => { });
+ public ActivatableUserControl()
+ {
+ InitializeComponent();
+ Assert.IsType(Content);
+ this.WhenActivated(disposables => { });
+ }
+
+ private void InitializeComponent()
+ {
+ var loader = new AvaloniaXamlLoader();
+ loader.Load(@"
+
+
+ ", null, this);
+ }
}
public AvaloniaActivationForViewFetcherTest()
@@ -183,4 +212,4 @@ namespace Avalonia
Assert.False(viewModel.IsActivated);
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs b/tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs
index 04b29376b0..ba9b443d92 100644
--- a/tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs
+++ b/tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs
@@ -85,6 +85,44 @@ namespace Avalonia.Styling.UnitTests
Assert.Equal(SelectorMatchResult.NeverThisType, match.Result);
}
+ [Fact]
+ public void Named_Class_Template_Child_Of_Control()
+ {
+ var template = new FuncControlTemplate(parent =>
+ {
+ return new Border
+ {
+ Name = "border",
+ };
+ });
+
+ var control = new Button
+ {
+ Template = template,
+ };
+
+ control.ApplyTemplate();
+
+ var selector = default(Selector)
+ .OfType()
+ .Template()
+ .Name("border")
+ .Class("foo");
+
+ var border = (Border)((IVisual)control).VisualChildren.Single();
+ var values = new List();
+ var match = selector.Match(border);
+
+ Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
+ match.Activator.Subscribe(x => values.Add(x));
+
+ Assert.Equal(new[] { false }, values);
+ border.Classes.AddRange(new[] { "foo" });
+ Assert.Equal(new[] { false, true }, values);
+ border.Classes.Remove("foo");
+ Assert.Equal(new[] { false, true, false }, values);
+ }
+
[Fact]
public void TargetType_OfType()
{
diff --git a/tests/Avalonia.Styling.UnitTests/SelectorTests_Not.cs b/tests/Avalonia.Styling.UnitTests/SelectorTests_Not.cs
new file mode 100644
index 0000000000..2f3e2b8f34
--- /dev/null
+++ b/tests/Avalonia.Styling.UnitTests/SelectorTests_Not.cs
@@ -0,0 +1,114 @@
+// 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.Reactive.Linq;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Xunit;
+
+namespace Avalonia.Styling.UnitTests
+{
+ public class SelectorTests_Not
+ {
+ [Fact]
+ public void Not_Selector_Should_Have_Correct_String_Representation()
+ {
+ var target = default(Selector).Not(x => x.Class("foo"));
+
+ Assert.Equal(":not(.foo)", target.ToString());
+ }
+
+ [Fact]
+ public void Not_OfType_Matches_Control_Of_Incorrect_Type()
+ {
+ var control = new Control1();
+ var target = default(Selector).Not(x => x.OfType());
+
+ Assert.Equal(SelectorMatchResult.NeverThisType, target.Match(control).Result);
+ }
+
+ [Fact]
+ public void Not_OfType_Doesnt_Match_Control_Of_Correct_Type()
+ {
+ var control = new Control2();
+ var target = default(Selector).Not(x => x.OfType());
+
+ Assert.Equal(SelectorMatchResult.AlwaysThisType, target.Match(control).Result);
+ }
+
+ [Fact]
+ public async Task Not_Class_Doesnt_Match_Control_With_Class()
+ {
+ var control = new Control1
+ {
+ Classes = new Classes { "foo" },
+ };
+
+ var target = default(Selector).Not(x => x.Class("foo"));
+ var match = target.Match(control);
+
+ Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
+ Assert.False(await match.Activator.Take(1));
+ }
+
+ [Fact]
+ public async Task Not_Class_Matches_Control_Without_Class()
+ {
+ var control = new Control1
+ {
+ Classes = new Classes { "bar" },
+ };
+
+ var target = default(Selector).Not(x => x.Class("foo"));
+ var match = target.Match(control);
+
+ Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
+ Assert.True(await match.Activator.Take(1));
+ }
+
+ [Fact]
+ public async Task OfType_Not_Class_Matches_Control_Without_Class()
+ {
+ var control = new Control1
+ {
+ Classes = new Classes { "bar" },
+ };
+
+ var target = default(Selector).OfType().Not(x => x.Class("foo"));
+ var match = target.Match(control);
+
+ Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
+ Assert.True(await match.Activator.Take(1));
+ }
+
+ [Fact]
+ public void OfType_Not_Class_Doesnt_Match_Control_Of_Wrong_Type()
+ {
+ var control = new Control2
+ {
+ Classes = new Classes { "foo" },
+ };
+
+ var target = default(Selector).OfType().Not(x => x.Class("foo"));
+ var match = target.Match(control);
+
+ Assert.Equal(SelectorMatchResult.NeverThisType, match.Result);
+ }
+
+ [Fact]
+ public void Returns_Correct_TargetType()
+ {
+ var target = default(Selector).OfType().Not(x => x.Class("foo"));
+
+ Assert.Equal(typeof(Control1), target.TargetType);
+ }
+
+ public class Control1 : TestControlBase
+ {
+ }
+
+ public class Control2 : TestControlBase
+ {
+ }
+ }
+}
diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs
index f8ad7e63f2..0e2abb314d 100644
--- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs
+++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs
@@ -9,6 +9,8 @@ namespace Avalonia.UnitTests
{
public class MockPlatformRenderInterface : IPlatformRenderInterface
{
+ public IEnumerable InstalledFontNames => new string[0];
+
public IFormattedTextImpl CreateFormattedText(
string text,
Typeface typeface,
diff --git a/tests/Avalonia.UnitTests/TestRoot.cs b/tests/Avalonia.UnitTests/TestRoot.cs
index 972b1d78c0..370ddba410 100644
--- a/tests/Avalonia.UnitTests/TestRoot.cs
+++ b/tests/Avalonia.UnitTests/TestRoot.cs
@@ -90,9 +90,9 @@ namespace Avalonia.UnitTests
{
}
- public Point PointToClient(Point p) => p;
+ public Point PointToClient(PixelPoint p) => p.ToPoint(1);
- public Point PointToScreen(Point p) => p;
+ public PixelPoint PointToScreen(Point p) => PixelPoint.FromPoint(p, 1);
void INameScope.Register(string name, object element)
{
diff --git a/tests/Avalonia.UnitTests/TestTemplatedRoot.cs b/tests/Avalonia.UnitTests/TestTemplatedRoot.cs
index 2d896435a3..5d42699d3f 100644
--- a/tests/Avalonia.UnitTests/TestTemplatedRoot.cs
+++ b/tests/Avalonia.UnitTests/TestTemplatedRoot.cs
@@ -57,9 +57,9 @@ namespace Avalonia.UnitTests
throw new NotImplementedException();
}
- public Point PointToClient(Point p) => p;
+ public Point PointToClient(PixelPoint p) => p.ToPoint(1);
- public Point PointToScreen(Point p) => p;
+ public PixelPoint PointToScreen(Point p) => PixelPoint.FromPoint(p, 1);
void INameScope.Register(string name, object element)
{
diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs
index 92c12c6b9e..fec0f0831a 100644
--- a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs
+++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs
@@ -8,6 +8,8 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
{
class MockRenderInterface : IPlatformRenderInterface
{
+ public IEnumerable InstalledFontNames => new string[0];
+
public IFormattedTextImpl CreateFormattedText(
string text,
Typeface typeface,