diff --git a/Avalonia.sln b/Avalonia.sln
index 74a2dbb94b..75f1dd8407 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -230,6 +230,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicroComGenerator", "src\to
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniMvvm", "samples\MiniMvvm\MiniMvvm.csproj", "{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@@ -2116,6 +2118,30 @@ Global
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhone.Build.0 = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.Build.0 = Release|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2176,6 +2202,7 @@ Global
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
+ {BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
diff --git a/Documentation/build.md b/Documentation/build.md
index 2f59146a48..5f75290424 100644
--- a/Documentation/build.md
+++ b/Documentation/build.md
@@ -60,15 +60,10 @@ git submodule update --init --recursive
### Build native libraries (macOS only)
-On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). The steps to get this working correctly are:
-- (for revisions after 2 Nov 2020) Run `./build.sh GenerateCppHeaders` to generate `avalonia-native.h` from `avn.idl`
-- Navigate to the Avalonia/native/Avalonia.Native/src/OSX folder and open the `Avalonia.Native.OSX.xcodeproj` project
-- Build the library via the Product->Build menu. This will generate binaries in your local path under ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-*guid* where "guid" is uniquely generated every time you build.
-- Manually install the native library by copying it from the build artifacts folder into the shared dynamic library path:
+On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). Execute the build script in the root project with the `CompileNative` task. It will build the headers, build the libraries, and place them in the appropriate place to allow .NET to find them at compilation and run time.
-```
-cd ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-[guid]/Build/Products/Debug
-cp libAvalonia.Native.OSX.dylib /usr/local/lib/libAvaloniaNative.dylib
+```bash
+./build.sh CompileNative
```
### Build and Run Avalonia
diff --git a/NuGet.Config b/NuGet.Config
index 3abd236d42..7a1f28bea7 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -4,6 +4,6 @@
-
+
diff --git a/build/ApiDiff.props b/build/ApiDiff.props
index 3d322f56d5..fb65ef6e87 100644
--- a/build/ApiDiff.props
+++ b/build/ApiDiff.props
@@ -1,6 +1,6 @@
- 0.10.0-preview3
+ 0.10.0-preview6
$(PackageId)
Avalonia
diff --git a/build/EmbedXaml.props b/build/EmbedXaml.props
index 7ce0366dea..0bb8da4f47 100644
--- a/build/EmbedXaml.props
+++ b/build/EmbedXaml.props
@@ -4,8 +4,9 @@
%(Filename)
+
Designer
-
\ No newline at end of file
+
diff --git a/build/MicroCom.targets b/build/MicroCom.targets
index 3a07950616..b48e377fd4 100644
--- a/build/MicroCom.targets
+++ b/build/MicroCom.targets
@@ -2,7 +2,7 @@
-
+
false
all
true
@@ -12,10 +12,10 @@
-
+
@@ -24,7 +24,7 @@
-
+
<_AvaloniaPatchComInterop>true
diff --git a/build/Rx.props b/build/Rx.props
index 8a15ccd6a9..fde1f80ea1 100644
--- a/build/Rx.props
+++ b/build/Rx.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/SharedVersion.props b/build/SharedVersion.props
index a5c0aa1bea..43ec995ed9 100644
--- a/build/SharedVersion.props
+++ b/build/SharedVersion.props
@@ -16,7 +16,7 @@
https://github.com/AvaloniaUI/Avalonia/releases
git
$(MSBuildThisFileDirectory)\avalonia.snk
- false
+ true
$(DefineConstants);SIGNED_BUILD
diff --git a/native/Avalonia.Native/inc/key.h b/native/Avalonia.Native/inc/key.h
deleted file mode 100644
index 12d283cc17..0000000000
--- a/native/Avalonia.Native/inc/key.h
+++ /dev/null
@@ -1,1020 +0,0 @@
-#ifndef _KEY_H_
-#define _KEY_H_
-
-///
-/// Defines the keys available on a keyboard.
-///
-enum AvnKey
-{
- ///
- /// No key pressed.
- ///
- AvnKeyNone = 0,
-
- ///
- /// The Cancel key.
- ///
- AvnKeyCancel = 1,
-
- ///
- /// The Back key.
- ///
- AvnKeyBack = 2,
-
- ///
- /// The Tab key.
- ///
- AvnKeyTab = 3,
-
- ///
- /// The Linefeed key.
- ///
- AvnKeyLineFeed = 4,
-
- ///
- /// The Clear key.
- ///
- AvnKeyClear = 5,
-
- ///
- /// The Return key.
- ///
- AvnKeyReturn = 6,
-
- ///
- /// The Enter key.
- ///
- AvnKeyEnter = 6,
-
- ///
- /// The Pause key.
- ///
- AvnKeyPause = 7,
-
- ///
- /// The Caps Lock key.
- ///
- AvnKeyCapsLock = 8,
-
- ///
- /// The Caps Lock key.
- ///
- AvnKeyCapital = 8,
-
- ///
- /// The IME Hangul mode key.
- ///
- AvnKeyHangulMode = 9,
-
- ///
- /// The IME Kana mode key.
- ///
- AvnKeyKanaMode = 9,
-
- ///
- /// The IME Junja mode key.
- ///
- AvnKeyJunjaMode = 10,
-
- ///
- /// The IME Final mode key.
- ///
- AvnKeyFinalMode = 11,
-
- ///
- /// The IME Kanji mode key.
- ///
- AvnKeyKanjiMode = 12,
-
- ///
- /// The IME Hanja mode key.
- ///
- HanjaMode = 12,
-
- ///
- /// The Escape key.
- ///
- Escape = 13,
-
- ///
- /// The IME Convert key.
- ///
- ImeConvert = 14,
-
- ///
- /// The IME NonConvert key.
- ///
- ImeNonConvert = 15,
-
- ///
- /// The IME Accept key.
- ///
- ImeAccept = 16,
-
- ///
- /// The IME Mode change key.
- ///
- ImeModeChange = 17,
-
- ///
- /// The space bar.
- ///
- Space = 18,
-
- ///
- /// The Page Up key.
- ///
- PageUp = 19,
-
- ///
- /// The Page Up key.
- ///
- Prior = 19,
-
- ///
- /// The Page Down key.
- ///
- PageDown = 20,
-
- ///
- /// The Page Down key.
- ///
- Next = 20,
-
- ///
- /// The End key.
- ///
- End = 21,
-
- ///
- /// The Home key.
- ///
- Home = 22,
-
- ///
- /// The Left arrow key.
- ///
- Left = 23,
-
- ///
- /// The Up arrow key.
- ///
- Up = 24,
-
- ///
- /// The Right arrow key.
- ///
- Right = 25,
-
- ///
- /// The Down arrow key.
- ///
- Down = 26,
-
- ///
- /// The Select key.
- ///
- Select = 27,
-
- ///
- /// The Print key.
- ///
- Print = 28,
-
- ///
- /// The Execute key.
- ///
- Execute = 29,
-
- ///
- /// The Print Screen key.
- ///
- Snapshot = 30,
-
- ///
- /// The Print Screen key.
- ///
- PrintScreen = 30,
-
- ///
- /// The Insert key.
- ///
- Insert = 31,
-
- ///
- /// The Delete key.
- ///
- Delete = 32,
-
- ///
- /// The Help key.
- ///
- Help = 33,
-
- ///
- /// The 0 key.
- ///
- D0 = 34,
-
- ///
- /// The 1 key.
- ///
- D1 = 35,
-
- ///
- /// The 2 key.
- ///
- D2 = 36,
-
- ///
- /// The 3 key.
- ///
- D3 = 37,
-
- ///
- /// The 4 key.
- ///
- D4 = 38,
-
- ///
- /// The 5 key.
- ///
- D5 = 39,
-
- ///
- /// The 6 key.
- ///
- D6 = 40,
-
- ///
- /// The 7 key.
- ///
- D7 = 41,
-
- ///
- /// The 8 key.
- ///
- D8 = 42,
-
- ///
- /// The 9 key.
- ///
- D9 = 43,
-
- ///
- /// The A key.
- ///
- A = 44,
-
- ///
- /// The B key.
- ///
- B = 45,
-
- ///
- /// The C key.
- ///
- C = 46,
-
- ///
- /// The D key.
- ///
- D = 47,
-
- ///
- /// The E key.
- ///
- E = 48,
-
- ///
- /// The F key.
- ///
- F = 49,
-
- ///
- /// The G key.
- ///
- G = 50,
-
- ///
- /// The H key.
- ///
- H = 51,
-
- ///
- /// The I key.
- ///
- I = 52,
-
- ///
- /// The J key.
- ///
- J = 53,
-
- ///
- /// The K key.
- ///
- AvnKeyK = 54,
-
- ///
- /// The L key.
- ///
- L = 55,
-
- ///
- /// The M key.
- ///
- M = 56,
-
- ///
- /// The N key.
- ///
- N = 57,
-
- ///
- /// The O key.
- ///
- O = 58,
-
- ///
- /// The P key.
- ///
- P = 59,
-
- ///
- /// The Q key.
- ///
- Q = 60,
-
- ///
- /// The R key.
- ///
- R = 61,
-
- ///
- /// The S key.
- ///
- S = 62,
-
- ///
- /// The T key.
- ///
- T = 63,
-
- ///
- /// The U key.
- ///
- U = 64,
-
- ///
- /// The V key.
- ///
- V = 65,
-
- ///
- /// The W key.
- ///
- W = 66,
-
- ///
- /// The X key.
- ///
- X = 67,
-
- ///
- /// The Y key.
- ///
- Y = 68,
-
- ///
- /// The Z key.
- ///
- Z = 69,
-
- ///
- /// The left Windows key.
- ///
- LWin = 70,
-
- ///
- /// The right Windows key.
- ///
- RWin = 71,
-
- ///
- /// The Application key.
- ///
- Apps = 72,
-
- ///
- /// The Sleep key.
- ///
- Sleep = 73,
-
- ///
- /// The 0 key on the numeric keypad.
- ///
- NumPad0 = 74,
-
- ///
- /// The 1 key on the numeric keypad.
- ///
- NumPad1 = 75,
-
- ///
- /// The 2 key on the numeric keypad.
- ///
- NumPad2 = 76,
-
- ///
- /// The 3 key on the numeric keypad.
- ///
- NumPad3 = 77,
-
- ///
- /// The 4 key on the numeric keypad.
- ///
- NumPad4 = 78,
-
- ///
- /// The 5 key on the numeric keypad.
- ///
- NumPad5 = 79,
-
- ///
- /// The 6 key on the numeric keypad.
- ///
- NumPad6 = 80,
-
- ///
- /// The 7 key on the numeric keypad.
- ///
- NumPad7 = 81,
-
- ///
- /// The 8 key on the numeric keypad.
- ///
- NumPad8 = 82,
-
- ///
- /// The 9 key on the numeric keypad.
- ///
- NumPad9 = 83,
-
- ///
- /// The Multiply key.
- ///
- Multiply = 84,
-
- ///
- /// The Add key.
- ///
- Add = 85,
-
- ///
- /// The Separator key.
- ///
- Separator = 86,
-
- ///
- /// The Subtract key.
- ///
- Subtract = 87,
-
- ///
- /// The Decimal key.
- ///
- Decimal = 88,
-
- ///
- /// The Divide key.
- ///
- Divide = 89,
-
- ///
- /// The F1 key.
- ///
- F1 = 90,
-
- ///
- /// The F2 key.
- ///
- F2 = 91,
-
- ///
- /// The F3 key.
- ///
- F3 = 92,
-
- ///
- /// The F4 key.
- ///
- F4 = 93,
-
- ///
- /// The F5 key.
- ///
- F5 = 94,
-
- ///
- /// The F6 key.
- ///
- F6 = 95,
-
- ///
- /// The F7 key.
- ///
- F7 = 96,
-
- ///
- /// The F8 key.
- ///
- F8 = 97,
-
- ///
- /// The F9 key.
- ///
- F9 = 98,
-
- ///
- /// The F10 key.
- ///
- F10 = 99,
-
- ///
- /// The F11 key.
- ///
- F11 = 100,
-
- ///
- /// The F12 key.
- ///
- F12 = 101,
-
- ///
- /// The F13 key.
- ///
- F13 = 102,
-
- ///
- /// The F14 key.
- ///
- F14 = 103,
-
- ///
- /// The F15 key.
- ///
- F15 = 104,
-
- ///
- /// The F16 key.
- ///
- F16 = 105,
-
- ///
- /// The F17 key.
- ///
- F17 = 106,
-
- ///
- /// The F18 key.
- ///
- F18 = 107,
-
- ///
- /// The F19 key.
- ///
- F19 = 108,
-
- ///
- /// The F20 key.
- ///
- F20 = 109,
-
- ///
- /// The F21 key.
- ///
- F21 = 110,
-
- ///
- /// The F22 key.
- ///
- F22 = 111,
-
- ///
- /// The F23 key.
- ///
- F23 = 112,
-
- ///
- /// The F24 key.
- ///
- F24 = 113,
-
- ///
- /// The Numlock key.
- ///
- NumLock = 114,
-
- ///
- /// The Scroll key.
- ///
- Scroll = 115,
-
- ///
- /// The left Shift key.
- ///
- LeftShift = 116,
-
- ///
- /// The right Shift key.
- ///
- RightShift = 117,
-
- ///
- /// The left Ctrl key.
- ///
- LeftCtrl = 118,
-
- ///
- /// The right Ctrl key.
- ///
- RightCtrl = 119,
-
- ///
- /// The left Alt key.
- ///
- LeftAlt = 120,
-
- ///
- /// The right Alt key.
- ///
- RightAlt = 121,
-
- ///
- /// The browser Back key.
- ///
- BrowserBack = 122,
-
- ///
- /// The browser Forward key.
- ///
- BrowserForward = 123,
-
- ///
- /// The browser Refresh key.
- ///
- BrowserRefresh = 124,
-
- ///
- /// The browser Stop key.
- ///
- BrowserStop = 125,
-
- ///
- /// The browser Search key.
- ///
- BrowserSearch = 126,
-
- ///
- /// The browser Favorites key.
- ///
- BrowserFavorites = 127,
-
- ///
- /// The browser Home key.
- ///
- BrowserHome = 128,
-
- ///
- /// The Volume Mute key.
- ///
- VolumeMute = 129,
-
- ///
- /// The Volume Down key.
- ///
- VolumeDown = 130,
-
- ///
- /// The Volume Up key.
- ///
- VolumeUp = 131,
-
- ///
- /// The media Next Track key.
- ///
- MediaNextTrack = 132,
-
- ///
- /// The media Previous Track key.
- ///
- MediaPreviousTrack = 133,
-
- ///
- /// The media Stop key.
- ///
- MediaStop = 134,
-
- ///
- /// The media Play/Pause key.
- ///
- MediaPlayPause = 135,
-
- ///
- /// The Launch Mail key.
- ///
- LaunchMail = 136,
-
- ///
- /// The Select Media key.
- ///
- SelectMedia = 137,
-
- ///
- /// The Launch Application 1 key.
- ///
- LaunchApplication1 = 138,
-
- ///
- /// The Launch Application 2 key.
- ///
- LaunchApplication2 = 139,
-
- ///
- /// The OEM Semicolon key.
- ///
- OemSemicolon = 140,
-
- ///
- /// The OEM 1 key.
- ///
- Oem1 = 140,
-
- ///
- /// The OEM Plus key.
- ///
- OemPlus = 141,
-
- ///
- /// The OEM Comma key.
- ///
- OemComma = 142,
-
- ///
- /// The OEM Minus key.
- ///
- OemMinus = 143,
-
- ///
- /// The OEM Period key.
- ///
- OemPeriod = 144,
-
- ///
- /// The OEM Question Mark key.
- ///
- OemQuestion = 145,
-
- ///
- /// The OEM 2 key.
- ///
- Oem2 = 145,
-
- ///
- /// The OEM Tilde key.
- ///
- OemTilde = 146,
-
- ///
- /// The OEM 3 key.
- ///
- Oem3 = 146,
-
- ///
- /// The ABNT_C1 (Brazilian) key.
- ///
- AbntC1 = 147,
-
- ///
- /// The ABNT_C2 (Brazilian) key.
- ///
- AbntC2 = 148,
-
- ///
- /// The OEM Open Brackets key.
- ///
- OemOpenBrackets = 149,
-
- ///
- /// The OEM 4 key.
- ///
- Oem4 = 149,
-
- ///
- /// The OEM Pipe key.
- ///
- OemPipe = 150,
-
- ///
- /// The OEM 5 key.
- ///
- Oem5 = 150,
-
- ///
- /// The OEM Close Brackets key.
- ///
- OemCloseBrackets = 151,
-
- ///
- /// The OEM 6 key.
- ///
- Oem6 = 151,
-
- ///
- /// The OEM Quotes key.
- ///
- OemQuotes = 152,
-
- ///
- /// The OEM 7 key.
- ///
- Oem7 = 152,
-
- ///
- /// The OEM 8 key.
- ///
- Oem8 = 153,
-
- ///
- /// The OEM Backslash key.
- ///
- OemBackslash = 154,
-
- ///
- /// The OEM 3 key.
- ///
- Oem102 = 154,
-
- ///
- /// A special key masking the real key being processed by an IME.
- ///
- ImeProcessed = 155,
-
- ///
- /// A special key masking the real key being processed as a system key.
- ///
- System = 156,
-
- ///
- /// The OEM ATTN key.
- ///
- OemAttn = 157,
-
- ///
- /// The DBE_ALPHANUMERIC key.
- ///
- DbeAlphanumeric = 157,
-
- ///
- /// The OEM Finish key.
- ///
- OemFinish = 158,
-
- ///
- /// The DBE_KATAKANA key.
- ///
- DbeKatakana = 158,
-
- ///
- /// The DBE_HIRAGANA key.
- ///
- DbeHiragana = 159,
-
- ///
- /// The OEM Copy key.
- ///
- OemCopy = 159,
-
- ///
- /// The DBE_SBCSCHAR key.
- ///
- DbeSbcsChar = 160,
-
- ///
- /// The OEM Auto key.
- ///
- OemAuto = 160,
-
- ///
- /// The DBE_DBCSCHAR key.
- ///
- DbeDbcsChar = 161,
-
- ///
- /// The OEM ENLW key.
- ///
- OemEnlw = 161,
-
- ///
- /// The OEM BackTab key.
- ///
- OemBackTab = 162,
-
- ///
- /// The DBE_ROMAN key.
- ///
- DbeRoman = 162,
-
- ///
- /// The DBE_NOROMAN key.
- ///
- DbeNoRoman = 163,
-
- ///
- /// The ATTN key.
- ///
- Attn = 163,
-
- ///
- /// The CRSEL key.
- ///
- CrSel = 164,
-
- ///
- /// The DBE_ENTERWORDREGISTERMODE key.
- ///
- DbeEnterWordRegisterMode = 164,
-
- ///
- /// The EXSEL key.
- ///
- ExSel = 165,
-
- ///
- /// The DBE_ENTERIMECONFIGMODE key.
- ///
- DbeEnterImeConfigureMode = 165,
-
- ///
- /// The ERASE EOF Key.
- ///
- EraseEof = 166,
-
- ///
- /// The DBE_FLUSHSTRING key.
- ///
- DbeFlushString = 166,
-
- ///
- /// The Play key.
- ///
- Play = 167,
-
- ///
- /// The DBE_CODEINPUT key.
- ///
- DbeCodeInput = 167,
-
- ///
- /// The DBE_NOCODEINPUT key.
- ///
- DbeNoCodeInput = 168,
-
- ///
- /// The Zoom key.
- ///
- Zoom = 168,
-
- ///
- /// Reserved for future use.
- ///
- NoName = 169,
-
- ///
- /// The DBE_DETERMINESTRING key.
- ///
- DbeDetermineString = 169,
-
- ///
- /// The DBE_ENTERDLGCONVERSIONMODE key.
- ///
- DbeEnterDialogConversionMode = 170,
-
- ///
- /// The PA1 key.
- ///
- Pa1 = 170,
-
- ///
- /// The OEM Clear key.
- ///
- OemClear = 171,
-
- ///
- /// The key is used with another key to create a single combined character.
- ///
- DeadCharProcessed = 172,
-};
-
-#endif
diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
index d5cad4d1ca..dba3ee6d31 100644
--- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
+++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
@@ -8,19 +8,20 @@
/* Begin PBXBuildFile section */
1A002B9E232135EE00021753 /* app.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A002B9D232135EE00021753 /* app.mm */; };
+ 1A1852DC23E05814008F0DED /* deadlock.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A1852DB23E05814008F0DED /* deadlock.mm */; };
1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */; };
1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */; };
- 1A1852DC23E05814008F0DED /* deadlock.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A1852DB23E05814008F0DED /* deadlock.mm */; };
- 1AFD334123E03C4F0042899B /* controlhost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AFD334023E03C4F0042899B /* controlhost.mm */; };
1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EAD23E9FB1300EDE661 /* cgl.mm */; };
1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */; };
1A465D10246AB61600C5858B /* dnd.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A465D0F246AB61600C5858B /* dnd.mm */; };
+ 1AFD334123E03C4F0042899B /* controlhost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AFD334023E03C4F0042899B /* controlhost.mm */; };
37155CE4233C00EB0034DCE9 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 37155CE3233C00EB0034DCE9 /* menu.h */; };
37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; };
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; };
37DDA9B0219330F8002E132B /* AvnString.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37DDA9AF219330F8002E132B /* AvnString.mm */; };
37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; };
520624B322973F4100C4DCEF /* menu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 520624B222973F4100C4DCEF /* menu.mm */; };
+ 522D5959258159C1006F7F7A /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 522D5958258159C1006F7F7A /* Carbon.framework */; };
5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; };
5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
@@ -32,13 +33,13 @@
/* Begin PBXFileReference section */
1A002B9D232135EE00021753 /* app.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = app.mm; sourceTree = ""; };
+ 1A1852DB23E05814008F0DED /* deadlock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = deadlock.mm; sourceTree = ""; };
1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = rendertarget.mm; sourceTree = ""; };
1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = System/Library/Frameworks/IOSurface.framework; sourceTree = SDKROOT; };
- 1A1852DB23E05814008F0DED /* deadlock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = deadlock.mm; sourceTree = ""; };
- 1AFD334023E03C4F0042899B /* controlhost.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = controlhost.mm; sourceTree = ""; };
1A3E5EAD23E9FB1300EDE661 /* cgl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cgl.mm; sourceTree = ""; };
1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
1A465D0F246AB61600C5858B /* dnd.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = dnd.mm; sourceTree = ""; };
+ 1AFD334023E03C4F0042899B /* controlhost.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = controlhost.mm; sourceTree = ""; };
37155CE3233C00EB0034DCE9 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = ""; };
379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = ""; };
37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = ""; };
@@ -49,6 +50,7 @@
37DDA9B121933371002E132B /* AvnString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnString.h; sourceTree = ""; };
37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = ""; };
520624B222973F4100C4DCEF /* menu.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = menu.mm; sourceTree = ""; };
+ 522D5958258159C1006F7F7A /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = ""; };
5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = ""; };
5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = ""; };
@@ -69,6 +71,7 @@
1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */,
1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */,
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */,
+ 522D5959258159C1006F7F7A /* Carbon.framework in Frameworks */,
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -79,6 +82,7 @@
AB661C1C2148230E00291242 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 522D5958258159C1006F7F7A /* Carbon.framework */,
1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */,
1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */,
AB1E522B217613570091CD71 /* OpenGL.framework */,
diff --git a/native/Avalonia.Native/src/OSX/KeyTransform.h b/native/Avalonia.Native/src/OSX/KeyTransform.h
index ea4fbecd5c..2f434570c9 100644
--- a/native/Avalonia.Native/src/OSX/KeyTransform.h
+++ b/native/Avalonia.Native/src/OSX/KeyTransform.h
@@ -1,9 +1,14 @@
#ifndef keytransform_h
#define keytransform_h
#include "common.h"
-#include "key.h"
#include
-
+
diff --git a/samples/interop/Direct3DInteropSample/MainWindowViewModel.cs b/samples/interop/Direct3DInteropSample/MainWindowViewModel.cs
index d39a21cd07..21679a99c5 100644
--- a/samples/interop/Direct3DInteropSample/MainWindowViewModel.cs
+++ b/samples/interop/Direct3DInteropSample/MainWindowViewModel.cs
@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using ReactiveUI;
+using MiniMvvm;
namespace Direct3DInteropSample
{
- public class MainWindowViewModel : ReactiveObject
+ public class MainWindowViewModel : ViewModelBase
{
private double _rotationX;
diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
index c067d38595..8394d7cb13 100644
--- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
+++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
@@ -136,10 +136,6 @@
{42472427-4774-4c81-8aff-9f27b8e31721}
Avalonia.Layout
-
- {6417b24e-49c2-4985-8db2-3ab9d898ec91}
- Avalonia.ReactiveUI
-
{eb582467-6abb-43a1-b052-e981ba910e3a}
Avalonia.Visuals
@@ -190,4 +186,4 @@
-
\ No newline at end of file
+
diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
index b8697e0ca2..f880e48282 100644
--- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
+++ b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
@@ -127,10 +127,6 @@
{42472427-4774-4c81-8aff-9f27b8e31721}
Avalonia.Layout
-
- {6417b24e-49c2-4985-8db2-3ab9d898ec91}
- Avalonia.ReactiveUI
-
{eb582467-6abb-43a1-b052-e981ba910e3a}
Avalonia.Visuals
diff --git a/src/Avalonia.Base/ApiCompatBaseline.txt b/src/Avalonia.Base/ApiCompatBaseline.txt
index 5d19373a92..d17f25ec49 100644
--- a/src/Avalonia.Base/ApiCompatBaseline.txt
+++ b/src/Avalonia.Base/ApiCompatBaseline.txt
@@ -1,4 +1,4 @@
Compat issues with assembly Avalonia.Base:
-CannotAddAbstractMembers : Member 'protected System.IObservable Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract.
-TypesMustExist : Type 'Avalonia.Logging.DebugLogSink' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Threading.AvaloniaSynchronizationContext..ctor(Avalonia.Threading.AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider)' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'Avalonia.Threading.AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider' does not exist in the implementation but it does exist in the contract.
Total Issues: 2
diff --git a/src/Avalonia.Base/Collections/AvaloniaList.cs b/src/Avalonia.Base/Collections/AvaloniaList.cs
index d43b4e04bb..5681214222 100644
--- a/src/Avalonia.Base/Collections/AvaloniaList.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaList.cs
@@ -63,6 +63,15 @@ namespace Avalonia.Collections
_inner = new List();
}
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// Initial list capacity.
+ public AvaloniaList(int capacity)
+ {
+ _inner = new List(capacity);
+ }
+
///
/// Initializes a new instance of the class.
///
@@ -175,6 +184,15 @@ namespace Avalonia.Collections
set { this[index] = (T)value; }
}
+ ///
+ /// Gets or sets the total number of elements the internal data structure can hold without resizing.
+ ///
+ public int Capacity
+ {
+ get => _inner.Capacity;
+ set => _inner.Capacity = value;
+ }
+
///
/// Adds an item to the collection.
///
diff --git a/src/Avalonia.Base/Data/Core/TypeCastNode.cs b/src/Avalonia.Base/Data/Core/TypeCastNode.cs
new file mode 100644
index 0000000000..476fd5527f
--- /dev/null
+++ b/src/Avalonia.Base/Data/Core/TypeCastNode.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Avalonia.Data.Core
+{
+ public class TypeCastNode : ExpressionNode
+ {
+ public override string Description => $"as {TargetType.FullName}";
+
+ public Type TargetType { get; }
+
+ public TypeCastNode(Type type)
+ {
+ TargetType = type;
+ }
+
+ protected virtual object Cast(object value)
+ {
+ return TargetType.IsInstanceOfType(value) ? value : null;
+ }
+
+ protected override void StartListeningCore(WeakReference reference)
+ {
+ if (reference.TryGetTarget(out object target))
+ {
+ target = Cast(target);
+ reference = target == null ? NullReference : new WeakReference(target);
+ }
+
+ base.StartListeningCore(reference);
+ }
+ }
+}
diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs
index e06cb75a4d..b054c186ae 100644
--- a/src/Avalonia.Base/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs
@@ -11,10 +11,12 @@ using Avalonia.Metadata;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
+[assembly: InternalsVisibleTo("Avalonia.Visuals, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
#else
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")]
+[assembly: InternalsVisibleTo("Avalonia.Visuals")]
#endif
diff --git a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
index 40cf81358f..1a78792173 100644
--- a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
+++ b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
@@ -9,20 +9,6 @@ namespace Avalonia.Threading
///
public class AvaloniaSynchronizationContext : SynchronizationContext
{
- public interface INonPumpingPlatformWaitProvider
- {
- int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
- }
-
- private readonly INonPumpingPlatformWaitProvider _waitProvider;
-
- public AvaloniaSynchronizationContext(INonPumpingPlatformWaitProvider waitProvider)
- {
- _waitProvider = waitProvider;
- if (_waitProvider != null)
- SetWaitNotificationRequired();
- }
-
///
/// Controls if SynchronizationContext should be installed in InstallIfNeeded. Used by Designer.
///
@@ -38,8 +24,7 @@ namespace Avalonia.Threading
return;
}
- SetSynchronizationContext(new AvaloniaSynchronizationContext(AvaloniaLocator.Current
- .GetService()));
+ SetSynchronizationContext(new AvaloniaSynchronizationContext());
}
///
@@ -57,12 +42,6 @@ namespace Avalonia.Threading
Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send).Wait();
}
- [PrePrepareMethod]
- public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
- {
- if (_waitProvider != null)
- return _waitProvider.Wait(waitHandles, waitAll, millisecondsTimeout);
- return base.Wait(waitHandles, waitAll, millisecondsTimeout);
- }
+
}
}
diff --git a/src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs b/src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs
index 0238446892..6e52b6770a 100644
--- a/src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs
+++ b/src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs
@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+
+#nullable enable
namespace Avalonia.Utilities
{
@@ -9,12 +12,14 @@ namespace Avalonia.Utilities
/// Stored value type.
internal sealed class AvaloniaPropertyValueStore
{
+ // The last item in the list is always int.MaxValue.
+ private static readonly Entry[] s_emptyEntries = { new Entry { PropertyId = int.MaxValue, Value = default! } };
+
private Entry[] _entries;
public AvaloniaPropertyValueStore()
{
- // The last item in the list is always int.MaxValue
- _entries = new[] { new Entry { PropertyId = int.MaxValue, Value = default } };
+ _entries = s_emptyEntries;
}
private (int, bool) TryFindEntry(int propertyId)
@@ -86,7 +91,7 @@ namespace Avalonia.Utilities
return (0, false);
}
- public bool TryGetValue(AvaloniaProperty property, out TValue value)
+ public bool TryGetValue(AvaloniaProperty property, [MaybeNull] out TValue value)
{
(int index, bool found) = TryFindEntry(property.Id);
if (!found)
@@ -132,7 +137,18 @@ namespace Avalonia.Utilities
if (found)
{
- Entry[] entries = new Entry[_entries.Length - 1];
+ var newLength = _entries.Length - 1;
+
+ // Special case - one element left means that value store is empty so we can just reuse our "empty" array.
+ if (newLength == 1)
+ {
+ _entries = s_emptyEntries;
+
+ return;
+ }
+
+ var entries = new Entry[newLength];
+
int ix = 0;
for (int i = 0; i < _entries.Length; ++i)
diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs
index 2a92e75f58..446b366dc8 100644
--- a/src/Avalonia.Base/Utilities/MathUtilities.cs
+++ b/src/Avalonia.Base/Utilities/MathUtilities.cs
@@ -5,7 +5,10 @@ namespace Avalonia.Utilities
///
/// Provides math utilities not provided in System.Math.
///
- public static class MathUtilities
+#if !BUILDTASK
+ public
+#endif
+ static class MathUtilities
{
// smallest such that 1.0+DoubleEpsilon != 1.0
internal static readonly double DoubleEpsilon = 2.2204460492503131e-016;
diff --git a/src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs b/src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs
new file mode 100644
index 0000000000..fd4e5d2ace
--- /dev/null
+++ b/src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Avalonia.Utilities
+{
+ public class NonPumpingLockHelper
+ {
+ public interface IHelperImpl
+ {
+ IDisposable Use();
+ }
+
+ public static IDisposable Use() => AvaloniaLocator.Current.GetService()?.Use();
+ }
+}
diff --git a/src/Avalonia.Base/Utilities/StringTokenizer.cs b/src/Avalonia.Base/Utilities/StringTokenizer.cs
index a159bfb72e..24e99febb9 100644
--- a/src/Avalonia.Base/Utilities/StringTokenizer.cs
+++ b/src/Avalonia.Base/Utilities/StringTokenizer.cs
@@ -4,7 +4,10 @@ using static System.Char;
namespace Avalonia.Utilities
{
- public struct StringTokenizer : IDisposable
+#if !BUILDTASK
+ public
+#endif
+ struct StringTokenizer : IDisposable
{
private const char DefaultSeparatorChar = ',';
diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
index 94ad4adb7d..90f6abc873 100644
--- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
+++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
@@ -1,7 +1,7 @@
netstandard2.0
- netstandard2.0;netcoreapp2.0
+ netstandard2.0;netcoreapp3.1
exe
false
tools
@@ -45,6 +45,12 @@
Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
Markup/%(RecursiveDir)%(FileName)%(Extension)
@@ -57,6 +63,33 @@
Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Markup/%(RecursiveDir)%(FileName)%(Extension)
+
diff --git a/src/Avalonia.Build.Tasks/SpanCompat.cs b/src/Avalonia.Build.Tasks/SpanCompat.cs
index d5c406293e..f8960f56ec 100644
--- a/src/Avalonia.Build.Tasks/SpanCompat.cs
+++ b/src/Avalonia.Build.Tasks/SpanCompat.cs
@@ -1,3 +1,4 @@
+#if !NETCOREAPP3_1
namespace System
{
// This is a hack to enable our span code to work inside MSBuild task without referencing System.Memory
@@ -63,6 +64,8 @@ namespace System
}
public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length);
+
+ public static implicit operator ReadOnlySpan(char[] arr) => new ReadOnlySpan(new string(arr));
}
static class SpanCompatExtensions
@@ -71,3 +74,4 @@ namespace System
}
}
+#endif
diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
index 0b9b50e771..6ef8a98fae 100644
--- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
+++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
@@ -46,7 +46,9 @@ namespace Avalonia.Build.Tasks
string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool patchCom,
bool skipXamlCompilation)
{
- var typeSystem = new CecilTypeSystem(references.Concat(new[] { input }), input);
+ var typeSystem = new CecilTypeSystem(references
+ .Where(r => !r.ToLowerInvariant().EndsWith("avalonia.build.tasks.dll"))
+ .Concat(new[] { input }), input);
var asm = typeSystem.TargetAssemblyDefinition;
diff --git a/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
index 82472c505a..fcc74cf864 100644
--- a/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
+++ b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
@@ -1,5 +1 @@
-Compat issues with assembly Avalonia.Controls.DataGrid:
-MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.DataGridTextColumn.FontFamilyProperty' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public System.String Avalonia.Controls.DataGridTextColumn.FontFamily.get()' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public void Avalonia.Controls.DataGridTextColumn.FontFamily.set(System.String)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 3
+Total Issues: 0
diff --git a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml
index cf062e0920..09d19c8e43 100644
--- a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml
+++ b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml
@@ -137,12 +137,37 @@
+
diff --git a/src/Avalonia.Themes.Default/ToggleSwitch.xaml b/src/Avalonia.Themes.Default/ToggleSwitch.xaml
index 9d1c024eb9..f11f77df5a 100644
--- a/src/Avalonia.Themes.Default/ToggleSwitch.xaml
+++ b/src/Avalonia.Themes.Default/ToggleSwitch.xaml
@@ -5,7 +5,7 @@
0,0,0,6
6
6
- 154
+ 0
0
1
diff --git a/src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt b/src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt
new file mode 100644
index 0000000000..44e250b889
--- /dev/null
+++ b/src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt
@@ -0,0 +1,4 @@
+Compat issues with assembly Avalonia.Themes.Fluent:
+CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Themes.Fluent.FluentTheme' does not inherit from base type 'Avalonia.Styling.Styles' in the implementation but it does in the contract.
+MembersMustExist : Member 'public void Avalonia.Themes.Fluent.FluentTheme..ctor()' does not exist in the implementation but it does exist in the contract.
+Total Issues: 2
diff --git a/src/Avalonia.Themes.Fluent/AutoCompleteBox.xaml b/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/AutoCompleteBox.xaml
rename to src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
diff --git a/src/Avalonia.Themes.Fluent/Button.xaml b/src/Avalonia.Themes.Fluent/Controls/Button.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/Button.xaml
rename to src/Avalonia.Themes.Fluent/Controls/Button.xaml
diff --git a/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/ButtonSpinner.xaml
rename to src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml
diff --git a/src/Avalonia.Themes.Fluent/Calendar.xaml b/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/Calendar.xaml
rename to src/Avalonia.Themes.Fluent/Controls/Calendar.xaml
diff --git a/src/Avalonia.Themes.Fluent/CalendarButton.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/CalendarButton.xaml
rename to src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
diff --git a/src/Avalonia.Themes.Fluent/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/CalendarDatePicker.xaml
rename to src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
diff --git a/src/Avalonia.Themes.Fluent/CalendarDayButton.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDayButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/CalendarDayButton.xaml
rename to src/Avalonia.Themes.Fluent/Controls/CalendarDayButton.xaml
diff --git a/src/Avalonia.Themes.Fluent/CalendarItem.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/CalendarItem.xaml
rename to src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml
diff --git a/src/Avalonia.Themes.Fluent/CaptionButtons.xaml b/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
similarity index 91%
rename from src/Avalonia.Themes.Fluent/CaptionButtons.xaml
rename to src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
index f288372b77..1f8887c283 100644
--- a/src/Avalonia.Themes.Fluent/CaptionButtons.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
@@ -3,7 +3,7 @@
-
+
+
diff --git a/src/Avalonia.Themes.Fluent/PopupRoot.xaml b/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/PopupRoot.xaml
rename to src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml
diff --git a/src/Avalonia.Themes.Fluent/ProgressBar.xaml b/src/Avalonia.Themes.Fluent/Controls/ProgressBar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/ProgressBar.xaml
rename to src/Avalonia.Themes.Fluent/Controls/ProgressBar.xaml
diff --git a/src/Avalonia.Themes.Fluent/RadioButton.xaml b/src/Avalonia.Themes.Fluent/Controls/RadioButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/RadioButton.xaml
rename to src/Avalonia.Themes.Fluent/Controls/RadioButton.xaml
diff --git a/src/Avalonia.Themes.Fluent/RepeatButton.xaml b/src/Avalonia.Themes.Fluent/Controls/RepeatButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/RepeatButton.xaml
rename to src/Avalonia.Themes.Fluent/Controls/RepeatButton.xaml
diff --git a/src/Avalonia.Themes.Fluent/ScrollBar.xaml b/src/Avalonia.Themes.Fluent/Controls/ScrollBar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/ScrollBar.xaml
rename to src/Avalonia.Themes.Fluent/Controls/ScrollBar.xaml
diff --git a/src/Avalonia.Themes.Fluent/ScrollViewer.xaml b/src/Avalonia.Themes.Fluent/Controls/ScrollViewer.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/ScrollViewer.xaml
rename to src/Avalonia.Themes.Fluent/Controls/ScrollViewer.xaml
diff --git a/src/Avalonia.Themes.Fluent/Separator.xaml b/src/Avalonia.Themes.Fluent/Controls/Separator.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/Separator.xaml
rename to src/Avalonia.Themes.Fluent/Controls/Separator.xaml
diff --git a/src/Avalonia.Themes.Fluent/Slider.xaml b/src/Avalonia.Themes.Fluent/Controls/Slider.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/Slider.xaml
rename to src/Avalonia.Themes.Fluent/Controls/Slider.xaml
diff --git a/src/Avalonia.Themes.Fluent/SplitView.xaml b/src/Avalonia.Themes.Fluent/Controls/SplitView.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/SplitView.xaml
rename to src/Avalonia.Themes.Fluent/Controls/SplitView.xaml
diff --git a/src/Avalonia.Themes.Fluent/TabControl.xaml b/src/Avalonia.Themes.Fluent/Controls/TabControl.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TabControl.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TabControl.xaml
diff --git a/src/Avalonia.Themes.Fluent/TabItem.xaml b/src/Avalonia.Themes.Fluent/Controls/TabItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TabItem.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TabItem.xaml
diff --git a/src/Avalonia.Themes.Fluent/TabStrip.xaml b/src/Avalonia.Themes.Fluent/Controls/TabStrip.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TabStrip.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TabStrip.xaml
diff --git a/src/Avalonia.Themes.Fluent/TabStripItem.xaml b/src/Avalonia.Themes.Fluent/Controls/TabStripItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TabStripItem.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TabStripItem.xaml
diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/Controls/TextBox.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TextBox.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TextBox.xaml
diff --git a/src/Avalonia.Themes.Fluent/TimePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TimePicker.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/Controls/TitleBar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TitleBar.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TitleBar.xaml
diff --git a/src/Avalonia.Themes.Fluent/ToggleButton.xaml b/src/Avalonia.Themes.Fluent/Controls/ToggleButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/ToggleButton.xaml
rename to src/Avalonia.Themes.Fluent/Controls/ToggleButton.xaml
diff --git a/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml b/src/Avalonia.Themes.Fluent/Controls/ToggleSwitch.xaml
similarity index 99%
rename from src/Avalonia.Themes.Fluent/ToggleSwitch.xaml
rename to src/Avalonia.Themes.Fluent/Controls/ToggleSwitch.xaml
index 2491225a44..45537e41ad 100644
--- a/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ToggleSwitch.xaml
@@ -5,7 +5,7 @@
0,0,0,6
6
6
- 154
+ 0
diff --git a/src/Avalonia.Themes.Fluent/ToolTip.xaml b/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/ToolTip.xaml
rename to src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml
diff --git a/src/Avalonia.Themes.Fluent/TreeView.xaml b/src/Avalonia.Themes.Fluent/Controls/TreeView.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TreeView.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TreeView.xaml
diff --git a/src/Avalonia.Themes.Fluent/TreeViewItem.xaml b/src/Avalonia.Themes.Fluent/Controls/TreeViewItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/TreeViewItem.xaml
rename to src/Avalonia.Themes.Fluent/Controls/TreeViewItem.xaml
diff --git a/src/Avalonia.Themes.Fluent/UserControl.xaml b/src/Avalonia.Themes.Fluent/Controls/UserControl.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/UserControl.xaml
rename to src/Avalonia.Themes.Fluent/Controls/UserControl.xaml
diff --git a/src/Avalonia.Themes.Fluent/Window.xaml b/src/Avalonia.Themes.Fluent/Controls/Window.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/Window.xaml
rename to src/Avalonia.Themes.Fluent/Controls/Window.xaml
diff --git a/src/Avalonia.Themes.Fluent/WindowNotificationManager.xaml b/src/Avalonia.Themes.Fluent/Controls/WindowNotificationManager.xaml
similarity index 100%
rename from src/Avalonia.Themes.Fluent/WindowNotificationManager.xaml
rename to src/Avalonia.Themes.Fluent/Controls/WindowNotificationManager.xaml
diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentDark.xaml b/src/Avalonia.Themes.Fluent/FluentDark.xaml
similarity index 85%
rename from src/Avalonia.Themes.Fluent/Accents/FluentDark.xaml
rename to src/Avalonia.Themes.Fluent/FluentDark.xaml
index 9ef92a44d5..74b583a240 100644
--- a/src/Avalonia.Themes.Fluent/Accents/FluentDark.xaml
+++ b/src/Avalonia.Themes.Fluent/FluentDark.xaml
@@ -5,5 +5,5 @@
-
+
diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentLight.xaml b/src/Avalonia.Themes.Fluent/FluentLight.xaml
similarity index 85%
rename from src/Avalonia.Themes.Fluent/Accents/FluentLight.xaml
rename to src/Avalonia.Themes.Fluent/FluentLight.xaml
index 8c92040122..1bc51f655e 100644
--- a/src/Avalonia.Themes.Fluent/Accents/FluentLight.xaml
+++ b/src/Avalonia.Themes.Fluent/FluentLight.xaml
@@ -5,5 +5,5 @@
-
+
diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.cs b/src/Avalonia.Themes.Fluent/FluentTheme.cs
new file mode 100644
index 0000000000..43b71567fa
--- /dev/null
+++ b/src/Avalonia.Themes.Fluent/FluentTheme.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Styling;
+
+#nullable enable
+
+namespace Avalonia.Themes.Fluent
+{
+ public enum FluentThemeMode
+ {
+ Light,
+ Dark,
+ }
+
+ ///
+ /// Includes the fluent theme in an application.
+ ///
+ public class FluentTheme : IStyle, IResourceProvider
+ {
+ private readonly Uri _baseUri;
+ private IStyle[]? _loaded;
+ private bool _isLoading;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The base URL for the XAML context.
+ public FluentTheme(Uri baseUri)
+ {
+ _baseUri = baseUri;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The XAML service provider.
+ public FluentTheme(IServiceProvider serviceProvider)
+ {
+ _baseUri = ((IUriContext)serviceProvider.GetService(typeof(IUriContext))).BaseUri;
+ }
+
+ ///
+ /// Gets or sets the mode of the fluent theme (light, dark).
+ ///
+ public FluentThemeMode Mode { get; set; }
+
+ public IResourceHost? Owner => (Loaded as IResourceProvider)?.Owner;
+
+ ///
+ /// Gets the loaded style.
+ ///
+ public IStyle Loaded
+ {
+ get
+ {
+ if (_loaded == null)
+ {
+ _isLoading = true;
+ var loaded = (IStyle)AvaloniaXamlLoader.Load(GetUri(), _baseUri);
+ _loaded = new[] { loaded };
+ _isLoading = false;
+ }
+
+ return _loaded?[0]!;
+ }
+ }
+
+ bool IResourceNode.HasResources => (Loaded as IResourceProvider)?.HasResources ?? false;
+
+ IReadOnlyList IStyle.Children => _loaded ?? Array.Empty();
+
+ public event EventHandler OwnerChanged
+ {
+ add
+ {
+ if (Loaded is IResourceProvider rp)
+ {
+ rp.OwnerChanged += value;
+ }
+ }
+ remove
+ {
+ if (Loaded is IResourceProvider rp)
+ {
+ rp.OwnerChanged -= value;
+ }
+ }
+ }
+
+ public SelectorMatchResult TryAttach(IStyleable target, IStyleHost? host) => Loaded.TryAttach(target, host);
+
+ public bool TryGetResource(object key, out object? value)
+ {
+ if (!_isLoading && Loaded is IResourceProvider p)
+ {
+ return p.TryGetResource(key, out value);
+ }
+
+ value = null;
+ return false;
+ }
+
+ void IResourceProvider.AddOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.AddOwner(owner);
+ void IResourceProvider.RemoveOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.RemoveOwner(owner);
+
+ private Uri GetUri() => Mode switch
+ {
+ FluentThemeMode.Dark => new Uri("avares://Avalonia.Themes.Fluent/FluentDark.xaml", UriKind.Absolute),
+ _ => new Uri("avares://Avalonia.Themes.Fluent/FluentLight.xaml", UriKind.Absolute),
+ };
+ }
+}
diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.xaml b/src/Avalonia.Themes.Fluent/FluentTheme.xaml
deleted file mode 100644
index 4e0e4fe862..0000000000
--- a/src/Avalonia.Themes.Fluent/FluentTheme.xaml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Avalonia.Themes.Fluent/Properties/AssemblyInfo.cs b/src/Avalonia.Themes.Fluent/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..0bad226ba7
--- /dev/null
+++ b/src/Avalonia.Themes.Fluent/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using Avalonia.Metadata;
+
+[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Themes.Fluent")]
diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt
index 2d00d82a46..62f4def701 100644
--- a/src/Avalonia.Visuals/ApiCompatBaseline.txt
+++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt
@@ -1,39 +1,5 @@
Compat issues with assembly Avalonia.Visuals:
-MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.Geometry.GetRenderBounds(Avalonia.Media.Pen)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public System.Boolean Avalonia.Media.Geometry.StrokeContains(Avalonia.Media.Pen, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public void Avalonia.Media.GlyphRunDrawing.BaselineOrigin.set(Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
-CannotSealType : Type 'Avalonia.Media.Typeface' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract.
-TypeCannotChangeClassification : Type 'Avalonia.Media.Typeface' is a 'struct' in the implementation but is a 'class' in the contract.
-CannotMakeMemberNonVirtual : Member 'public System.Boolean Avalonia.Media.Typeface.Equals(System.Object)' is non-virtual in the implementation but is virtual in the contract.
-CannotMakeMemberNonVirtual : Member 'public System.Int32 Avalonia.Media.Typeface.GetHashCode()' is non-virtual in the implementation but is virtual in the contract.
-TypesMustExist : Type 'Avalonia.Media.Fonts.FontKey' does not exist in the implementation but it does exist in the contract.
-CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size' is abstract in the implementation but is missing in the contract.
-MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.DrawableTextRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
-CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
-MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
-CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size.get()' is abstract in the implementation but is missing in the contract.
-MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.ShapedTextCharacters.Bounds.get()' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.ShapedTextCharacters.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLayout.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
-CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak' is abstract in the implementation but is missing in the contract.
-CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
-MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.LineBreak.get()' does not exist in the implementation but it does exist in the contract.
-CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak.get()' is abstract in the implementation but is missing in the contract.
-InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IDrawingContextLayerImpl Avalonia.Platform.IDrawingContextImpl.CreateLayer(Avalonia.Size)' is present in the implementation but not in the contract.
-InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IRenderTargetBitmapImpl Avalonia.Platform.IDrawingContextImpl.CreateLayer(Avalonia.Size)' is present in the contract but not in the implementation.
-MembersMustExist : Member 'public Avalonia.Platform.IRenderTargetBitmapImpl Avalonia.Platform.IDrawingContextImpl.CreateLayer(Avalonia.Size)' does not exist in the implementation but it does exist in the contract.
-InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun)' is present in the implementation but not in the contract.
-InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' is present in the contract but not in the implementation.
-MembersMustExist : Member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
-InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' is present in the contract but not in the implementation.
-MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract.
-InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract.
-MembersMustExist : Member 'public Avalonia.Utilities.IRef Avalonia.Rendering.RenderLayer.Bitmap.get()' does not exist in the implementation but it does exist in the contract.
-Total Issues: 37
+MembersMustExist : Member 'public Avalonia.StyledProperty> Avalonia.StyledProperty> Avalonia.Media.DashStyle.DashesProperty' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyList Avalonia.Media.DashStyle.Dashes.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Media.DashStyle.Dashes.set(System.Collections.Generic.IReadOnlyList)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 3
diff --git a/src/Avalonia.Visuals/CornerRadius.cs b/src/Avalonia.Visuals/CornerRadius.cs
index c02aacfb4d..037bb16e31 100644
--- a/src/Avalonia.Visuals/CornerRadius.cs
+++ b/src/Avalonia.Visuals/CornerRadius.cs
@@ -1,6 +1,8 @@
using System;
using System.Globalization;
+#if !BUILDTASK
using Avalonia.Animation.Animators;
+#endif
using Avalonia.Utilities;
namespace Avalonia
@@ -8,11 +10,16 @@ namespace Avalonia
///
/// Represents the radii of a rectangle's corners.
///
- public readonly struct CornerRadius : IEquatable
+#if !BUILDTASK
+ public
+#endif
+ readonly struct CornerRadius : IEquatable
{
static CornerRadius()
{
+#if !BUILDTASK
Animation.Animation.RegisterAnimator(prop => typeof(CornerRadius).IsAssignableFrom(prop.PropertyType));
+#endif
}
public CornerRadius(double uniformRadius)
diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs
index 206b842220..8136f843df 100644
--- a/src/Avalonia.Visuals/Matrix.cs
+++ b/src/Avalonia.Visuals/Matrix.cs
@@ -7,7 +7,10 @@ namespace Avalonia
///
/// A 2x3 matrix.
///
- public readonly struct Matrix : IEquatable
+#if !BUILDTASK
+ public
+#endif
+ readonly struct Matrix : IEquatable
{
private readonly double _m11;
private readonly double _m12;
@@ -279,25 +282,44 @@ namespace Avalonia
}
///
- /// Inverts the Matrix.
+ /// Attempts to invert the Matrix.
///
- /// The inverted matrix.
- public Matrix Invert()
+ /// The inverted matrix or when matrix is not invertible.
+ public bool TryInvert(out Matrix inverted)
{
double d = GetDeterminant();
if (MathUtilities.IsZero(d))
{
- throw new InvalidOperationException("Transform is not invertible.");
+ inverted = default;
+
+ return false;
}
- return new Matrix(
+ inverted = new Matrix(
_m22 / d,
-_m12 / d,
-_m21 / d,
_m11 / d,
((_m21 * _m32) - (_m22 * _m31)) / d,
((_m12 * _m31) - (_m11 * _m32)) / d);
+
+ return true;
+ }
+
+ ///
+ /// Inverts the Matrix.
+ ///
+ /// Matrix is not invertible.
+ /// The inverted matrix.
+ public Matrix Invert()
+ {
+ if (!TryInvert(out Matrix inverted))
+ {
+ throw new InvalidOperationException("Transform is not invertible.");
+ }
+
+ return inverted;
}
///
diff --git a/src/Avalonia.Visuals/Media/Color.cs b/src/Avalonia.Visuals/Media/Color.cs
index 16b4f90d57..a57a962db4 100644
--- a/src/Avalonia.Visuals/Media/Color.cs
+++ b/src/Avalonia.Visuals/Media/Color.cs
@@ -1,17 +1,24 @@
using System;
using System.Globalization;
+#if !BUILDTASK
using Avalonia.Animation.Animators;
+#endif
namespace Avalonia.Media
{
///
/// An ARGB color.
///
- public readonly struct Color : IEquatable
+#if !BUILDTASK
+ public
+#endif
+ readonly struct Color : IEquatable
{
static Color()
{
+#if !BUILDTASK
Animation.Animation.RegisterAnimator(prop => typeof(Color).IsAssignableFrom(prop.PropertyType));
+#endif
}
///
@@ -223,7 +230,12 @@ namespace Avalonia.Media
if (input.Length == 3 || input.Length == 4)
{
var extendedLength = 2 * input.Length;
+
+#if !BUILDTASK
Span extended = stackalloc char[extendedLength];
+#else
+ char[] extended = new char[extendedLength];
+#endif
for (int i = 0; i < input.Length; i++)
{
diff --git a/src/Avalonia.Visuals/Media/DashStyle.cs b/src/Avalonia.Visuals/Media/DashStyle.cs
index 1e813edc13..acba2d3615 100644
--- a/src/Avalonia.Visuals/Media/DashStyle.cs
+++ b/src/Avalonia.Visuals/Media/DashStyle.cs
@@ -1,11 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using Avalonia.Animation;
+using Avalonia.Collections;
+using Avalonia.Media.Immutable;
+
+#nullable enable
+
namespace Avalonia.Media
{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Avalonia.Animation;
- using Avalonia.Media.Immutable;
-
///
/// Represents the sequence of dashes and gaps that will be applied by a .
///
@@ -14,8 +17,8 @@ namespace Avalonia.Media
///
/// Defines the property.
///
- public static readonly StyledProperty> DashesProperty =
- AvaloniaProperty.Register>(nameof(Dashes));
+ public static readonly StyledProperty> DashesProperty =
+ AvaloniaProperty.Register>(nameof(Dashes));
///
/// Defines the property.
@@ -23,10 +26,10 @@ namespace Avalonia.Media
public static readonly StyledProperty OffsetProperty =
AvaloniaProperty.Register(nameof(Offset));
- private static ImmutableDashStyle s_dash;
- private static ImmutableDashStyle s_dot;
- private static ImmutableDashStyle s_dashDot;
- private static ImmutableDashStyle s_dashDotDot;
+ private static ImmutableDashStyle? s_dash;
+ private static ImmutableDashStyle? s_dot;
+ private static ImmutableDashStyle? s_dashDot;
+ private static ImmutableDashStyle? s_dashDotDot;
///
/// Initializes a new instance of the class.
@@ -41,9 +44,9 @@ namespace Avalonia.Media
///
/// The dashes collection.
/// The dash sequence offset.
- public DashStyle(IEnumerable dashes, double offset)
+ public DashStyle(IEnumerable? dashes, double offset)
{
- Dashes = (IReadOnlyList)dashes?.ToList() ?? Array.Empty();
+ Dashes = (dashes as AvaloniaList) ?? new AvaloniaList(dashes ?? Array.Empty());
Offset = offset;
}
@@ -61,31 +64,27 @@ namespace Avalonia.Media
///
/// Represents a dashed .
///
- public static IDashStyle Dash =>
- s_dash ?? (s_dash = new ImmutableDashStyle(new double[] { 2, 2 }, 1));
+ public static IDashStyle Dash => s_dash ??= new ImmutableDashStyle(new double[] { 2, 2 }, 1);
///
/// Represents a dotted .
///
- public static IDashStyle Dot =>
- s_dot ?? (s_dot = new ImmutableDashStyle(new double[] { 0, 2 }, 0));
+ public static IDashStyle Dot => s_dot ??= new ImmutableDashStyle(new double[] { 0, 2 }, 0);
///
/// Represents a dashed dotted .
///
- public static IDashStyle DashDot =>
- s_dashDot ?? (s_dashDot = new ImmutableDashStyle(new double[] { 2, 2, 0, 2 }, 1));
+ public static IDashStyle DashDot => s_dashDot ??= new ImmutableDashStyle(new double[] { 2, 2, 0, 2 }, 1);
///
/// Represents a dashed double dotted .
///
- public static IDashStyle DashDotDot =>
- s_dashDotDot ?? (s_dashDotDot = new ImmutableDashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1));
+ public static IDashStyle DashDotDot => s_dashDotDot ??= new ImmutableDashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1);
///
/// Gets or sets the length of alternating dashes and gaps.
///
- public IReadOnlyList Dashes
+ public AvaloniaList Dashes
{
get => GetValue(DashesProperty);
set => SetValue(DashesProperty, value);
@@ -100,15 +99,43 @@ namespace Avalonia.Media
set => SetValue(OffsetProperty, value);
}
+ IReadOnlyList IDashStyle.Dashes => Dashes;
+
///
/// Raised when the dash style changes.
///
- public event EventHandler Invalidated;
+ public event EventHandler? Invalidated;
///
/// Returns an immutable clone of the .
///
///
public ImmutableDashStyle ToImmutable() => new ImmutableDashStyle(Dashes, Offset);
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == DashesProperty)
+ {
+ var oldValue = change.OldValue.GetValueOrDefault>();
+ var newValue = change.NewValue.GetValueOrDefault>();
+
+ if (oldValue is object)
+ {
+ oldValue.CollectionChanged -= DashesChanged;
+ }
+
+ if (newValue is object)
+ {
+ newValue.CollectionChanged += DashesChanged;
+ }
+ }
+ }
+
+ private void DashesChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ Invalidated?.Invoke(this, e);
+ }
}
}
diff --git a/src/Avalonia.Visuals/Media/EllipseGeometry.cs b/src/Avalonia.Visuals/Media/EllipseGeometry.cs
index fd73eee69a..bae6dc3d8c 100644
--- a/src/Avalonia.Visuals/Media/EllipseGeometry.cs
+++ b/src/Avalonia.Visuals/Media/EllipseGeometry.cs
@@ -12,10 +12,28 @@ namespace Avalonia.Media
///
public static readonly StyledProperty RectProperty =
AvaloniaProperty.Register(nameof(Rect));
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty RadiusXProperty =
+ AvaloniaProperty.Register(nameof(RadiusX));
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty RadiusYProperty =
+ AvaloniaProperty.Register(nameof(RadiusY));
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty CenterProperty =
+ AvaloniaProperty.Register(nameof(Center));
static EllipseGeometry()
{
- AffectsGeometry(RectProperty);
+ AffectsGeometry(RectProperty, RadiusXProperty, RadiusYProperty, CenterProperty);
}
///
@@ -43,6 +61,33 @@ namespace Avalonia.Media
set => SetValue(RectProperty, value);
}
+ ///
+ /// Gets or sets a double that defines the radius in the X-axis of the ellipse.
+ ///
+ public double RadiusX
+ {
+ get => GetValue(RadiusXProperty);
+ set => SetValue(RadiusXProperty, value);
+ }
+
+ ///
+ /// Gets or sets a double that defines the radius in the Y-axis of the ellipse.
+ ///
+ public double RadiusY
+ {
+ get => GetValue(RadiusYProperty);
+ set => SetValue(RadiusYProperty, value);
+ }
+
+ ///
+ /// Gets or sets a point that defines the center of the ellipse.
+ ///
+ public Point Center
+ {
+ get => GetValue(CenterProperty);
+ set => SetValue(CenterProperty, value);
+ }
+
///
public override Geometry Clone()
{
@@ -54,7 +99,14 @@ namespace Avalonia.Media
{
var factory = AvaloniaLocator.Current.GetService();
- return factory.CreateEllipseGeometry(Rect);
+ if (Rect != default) return factory.CreateEllipseGeometry(Rect);
+
+ var originX = Center.X - RadiusX;
+ var originY = Center.Y - RadiusY;
+ var width = RadiusX * 2;
+ var height = RadiusY * 2;
+
+ return factory.CreateEllipseGeometry(new Rect(originX, originY, width, height));
}
}
}
diff --git a/src/Avalonia.Visuals/Media/KnownColors.cs b/src/Avalonia.Visuals/Media/KnownColors.cs
index 0887d2c913..fe09f5f538 100644
--- a/src/Avalonia.Visuals/Media/KnownColors.cs
+++ b/src/Avalonia.Visuals/Media/KnownColors.cs
@@ -8,7 +8,9 @@ namespace Avalonia.Media
{
private static readonly IReadOnlyDictionary _knownColorNames;
private static readonly IReadOnlyDictionary _knownColors;
+#if !BUILDTASK
private static readonly Dictionary _knownBrushes;
+#endif
static KnownColors()
{
@@ -32,14 +34,19 @@ namespace Avalonia.Media
_knownColorNames = knownColorNames;
_knownColors = knownColors;
+
+#if !BUILDTASK
_knownBrushes = new Dictionary();
+#endif
}
+#if !BUILDTASK
public static ISolidColorBrush GetKnownBrush(string s)
{
var color = GetKnownColor(s);
return color != KnownColor.None ? color.ToBrush() : null;
}
+#endif
public static KnownColor GetKnownColor(string s)
{
@@ -61,6 +68,7 @@ namespace Avalonia.Media
return Color.FromUInt32((uint)color);
}
+#if !BUILDTASK
public static ISolidColorBrush ToBrush(this KnownColor color)
{
lock (_knownBrushes)
@@ -74,6 +82,7 @@ namespace Avalonia.Media
return brush;
}
}
+#endif
}
internal enum KnownColor : uint
diff --git a/src/Avalonia.Visuals/Media/PathFigure.cs b/src/Avalonia.Visuals/Media/PathFigure.cs
index d0eb67ba39..caf86cb234 100644
--- a/src/Avalonia.Visuals/Media/PathFigure.cs
+++ b/src/Avalonia.Visuals/Media/PathFigure.cs
@@ -1,3 +1,7 @@
+#nullable enable
+using System;
+using System.Linq;
+using Avalonia.Collections;
using Avalonia.Metadata;
namespace Avalonia.Media
@@ -8,22 +12,36 @@ namespace Avalonia.Media
/// Defines the property.
///
public static readonly StyledProperty IsClosedProperty
- = AvaloniaProperty.Register(nameof(IsClosed), true);
+ = AvaloniaProperty.Register(nameof(IsClosed), true);
+
///
/// Defines the property.
///
public static readonly StyledProperty IsFilledProperty
- = AvaloniaProperty.Register(nameof(IsFilled), true);
+ = AvaloniaProperty.Register(nameof(IsFilled), true);
+
///
/// Defines the property.
///
- public static readonly DirectProperty SegmentsProperty
- = AvaloniaProperty.RegisterDirect(nameof(Segments), f => f.Segments, (f, s) => f.Segments = s);
+ public static readonly DirectProperty SegmentsProperty
+ = AvaloniaProperty.RegisterDirect(
+ nameof(Segments),
+ f => f.Segments,
+ (f, s) => f.Segments = s);
+
///
/// Defines the property.
///
public static readonly StyledProperty StartPointProperty
- = AvaloniaProperty.Register(nameof(StartPoint));
+ = AvaloniaProperty.Register(nameof(StartPoint));
+
+ internal event EventHandler? SegmentsInvalidated;
+
+ private PathSegments? _segments;
+
+ private IDisposable? _segmentsDisposable;
+
+ private IDisposable? _segmentsPropertiesDisposable;
///
/// Initializes a new instance of the class.
@@ -33,6 +51,31 @@ namespace Avalonia.Media
Segments = new PathSegments();
}
+ static PathFigure()
+ {
+ SegmentsProperty.Changed.AddClassHandler(
+ (s, e) =>
+ s.OnSegmentsChanged());
+ }
+
+ private void OnSegmentsChanged()
+ {
+ _segmentsDisposable?.Dispose();
+ _segmentsPropertiesDisposable?.Dispose();
+
+ _segmentsDisposable = _segments?.ForEachItem(
+ _ => InvalidateSegments(),
+ _ => InvalidateSegments(),
+ InvalidateSegments);
+
+ _segmentsPropertiesDisposable = _segments?.TrackItemPropertyChanged(_ => InvalidateSegments());
+ }
+
+ private void InvalidateSegments()
+ {
+ SegmentsInvalidated?.Invoke(this, EventArgs.Empty);
+ }
+
///
/// Gets or sets a value indicating whether this instance is closed.
///
@@ -64,7 +107,7 @@ namespace Avalonia.Media
/// The segments.
///
[Content]
- public PathSegments Segments
+ public PathSegments? Segments
{
get { return _segments; }
set { SetAndRaise(SegmentsProperty, ref _segments, value); }
@@ -81,22 +124,23 @@ namespace Avalonia.Media
get { return GetValue(StartPointProperty); }
set { SetValue(StartPointProperty, value); }
}
+
+ public override string ToString()
+ => $"M {StartPoint} {string.Join(" ", _segments ?? Enumerable.Empty())}{(IsClosed ? "Z" : "")}";
internal void ApplyTo(StreamGeometryContext ctx)
{
ctx.BeginFigure(StartPoint, IsFilled);
- foreach (var segment in Segments)
+ if (Segments != null)
{
- segment.ApplyTo(ctx);
+ foreach (var segment in Segments)
+ {
+ segment.ApplyTo(ctx);
+ }
}
ctx.EndFigure(IsClosed);
}
-
- private PathSegments _segments;
-
- public override string ToString()
- => $"M {StartPoint} {string.Join(" ", _segments)}{(IsClosed ? "Z" : "")}";
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Visuals/Media/PathGeometry.cs b/src/Avalonia.Visuals/Media/PathGeometry.cs
index fbc29aedc8..3d11c19b7d 100644
--- a/src/Avalonia.Visuals/Media/PathGeometry.cs
+++ b/src/Avalonia.Visuals/Media/PathGeometry.cs
@@ -104,12 +104,26 @@ namespace Avalonia.Media
_figuresPropertiesObserver?.Dispose();
_figuresObserver = figures?.ForEachItem(
- _ => InvalidateGeometry(),
- _ => InvalidateGeometry(),
- () => InvalidateGeometry());
+ s =>
+ {
+ s.SegmentsInvalidated += InvalidateGeometryFromSegments;
+ InvalidateGeometry();
+ },
+ s =>
+ {
+ s.SegmentsInvalidated -= InvalidateGeometryFromSegments;
+ InvalidateGeometry();
+ },
+ InvalidateGeometry);
+
_figuresPropertiesObserver = figures?.TrackItemPropertyChanged(_ => InvalidateGeometry());
+
}
+ private void InvalidateGeometryFromSegments(object _, EventArgs __)
+ {
+ InvalidateGeometry();
+ }
public override string ToString()
=> $"{(FillRule != FillRule.EvenOdd ? "F1 " : "")}{(string.Join(" ", Figures))}";
diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs
index 7324f5fbd0..6febe9c802 100644
--- a/src/Avalonia.Visuals/Point.cs
+++ b/src/Avalonia.Visuals/Point.cs
@@ -1,6 +1,8 @@
using System;
using System.Globalization;
+#if !BUILDTASK
using Avalonia.Animation.Animators;
+#endif
using Avalonia.Utilities;
namespace Avalonia
@@ -8,11 +10,16 @@ namespace Avalonia
///
/// Defines a point.
///
- public readonly struct Point : IEquatable
+#if !BUILDTASK
+ public
+#endif
+ readonly struct Point : IEquatable
{
static Point()
{
+#if !BUILDTASK
Animation.Animation.RegisterAnimator(prop => typeof(Point).IsAssignableFrom(prop.PropertyType));
+#endif
}
///
diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
index 15e14935ca..3bd8e05ee2 100644
--- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
@@ -99,6 +99,11 @@ namespace Avalonia.Rendering
///
public string DebugFramesPath { get; set; }
+ ///
+ /// Forces the renderer to only draw frames on the render thread. Makes Paint to wait until frame is rendered
+ ///
+ public bool RenderOnlyOnRenderThread { get; set; }
+
///
public event EventHandler SceneInvalidated;
@@ -180,11 +185,44 @@ namespace Avalonia.Rendering
///
public void Paint(Rect rect)
{
- var t = (IRenderLoopTask)this;
- if(t.NeedsUpdate)
- UpdateScene();
- if(_scene?.Item != null)
- Render(true);
+ if (RenderOnlyOnRenderThread)
+ {
+ // Renderer is stopped and doesn't tick on the render thread
+ // This indicates a bug somewhere in our code
+ // (currently happens when a window gets minimized with Show desktop on Windows 10)
+ if(!_running)
+ return;
+
+ while (true)
+ {
+ Scene scene;
+ bool? updated;
+ lock (_sceneLock)
+ {
+ updated = UpdateScene();
+ scene = _scene?.Item;
+ }
+
+ // Renderer is in invalid state, skip drawing
+ if(updated == null)
+ return;
+
+ // Wait for the scene to be rendered or disposed
+ scene?.Rendered.Wait();
+
+ // That was an up-to-date scene, we can return immediately
+ if (updated == true)
+ return;
+ }
+ }
+ else
+ {
+ var t = (IRenderLoopTask)this;
+ if (t.NeedsUpdate)
+ UpdateScene();
+ if (_scene?.Item != null)
+ Render(true);
+ }
}
///
@@ -270,13 +308,20 @@ namespace Avalonia.Rendering
{
if (scene?.Item != null)
{
- var overlay = DrawDirtyRects || DrawFps;
- if (DrawDirtyRects)
- _dirtyRectsDisplay.Tick();
- if (overlay)
- RenderOverlay(scene.Item, ref context);
- if (updated || forceComposite || overlay)
- RenderComposite(scene.Item, ref context);
+ try
+ {
+ var overlay = DrawDirtyRects || DrawFps;
+ if (DrawDirtyRects)
+ _dirtyRectsDisplay.Tick();
+ if (overlay)
+ RenderOverlay(scene.Item, ref context);
+ if (updated || forceComposite || overlay)
+ RenderComposite(scene.Item, ref context);
+ }
+ finally
+ {
+ scene.Item.MarkAsRendered();
+ }
}
}
}
@@ -559,15 +604,16 @@ namespace Avalonia.Rendering
UpdateScene();
}
- private void UpdateScene()
+ private bool? UpdateScene()
{
Dispatcher.UIThread.VerifyAccess();
+ using var noPump = NonPumpingLockHelper.Use();
lock (_sceneLock)
{
if (_disposed)
- return;
+ return null;
if (_scene?.Item.Generation > _lastSceneId)
- return;
+ return false;
}
if (_root.IsVisible)
{
@@ -619,6 +665,8 @@ namespace Avalonia.Rendering
SceneInvalidated(this, new SceneInvalidatedEventArgs((IRenderRoot)_root, rect));
}
+
+ return true;
}
else
{
@@ -628,6 +676,8 @@ namespace Avalonia.Rendering
_scene = null;
oldScene?.Dispose();
}
+
+ return null;
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
index 4f5c97cdff..6a4c532d4a 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using Avalonia.Collections.Pooled;
using Avalonia.VisualTree;
@@ -13,6 +14,7 @@ namespace Avalonia.Rendering.SceneGraph
public class Scene : IDisposable
{
private readonly Dictionary _index;
+ private readonly TaskCompletionSource _rendered = new TaskCompletionSource();
///
/// Initializes a new instance of the class.
@@ -41,6 +43,8 @@ namespace Avalonia.Rendering.SceneGraph
root.LayerRoot = root.Visual;
}
+ public Task Rendered => _rendered.Task;
+
///
/// Gets a value identifying the scene's generation. This is incremented each time the scene is cloned.
///
@@ -97,6 +101,7 @@ namespace Avalonia.Rendering.SceneGraph
public void Dispose()
{
+ _rendered.TrySetResult(false);
foreach (var node in _index.Values)
{
node.Dispose();
@@ -340,5 +345,7 @@ namespace Avalonia.Rendering.SceneGraph
}
}
}
+
+ public void MarkAsRendered() => _rendered.TrySetResult(true);
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
index 872f69c884..7d5d62a091 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
@@ -24,7 +24,8 @@ namespace Avalonia.Rendering.SceneGraph
using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
using (var context = new DrawingContext(impl))
{
- Update(context, scene, (VisualNode)scene.Root, scene.Root.Visual.Bounds, true);
+ var clip = new Rect(scene.Root.Visual.Bounds.Size);
+ Update(context, scene, (VisualNode)scene.Root, clip, true);
}
}
@@ -77,7 +78,7 @@ namespace Avalonia.Rendering.SceneGraph
using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
using (var context = new DrawingContext(impl))
{
- var clip = scene.Root.Visual.Bounds;
+ var clip = new Rect(scene.Root.Visual.Bounds.Size);
if (node.Parent != null)
{
@@ -174,7 +175,9 @@ namespace Avalonia.Rendering.SceneGraph
if (visual.IsVisible)
{
- var m = Matrix.CreateTranslation(visual.Bounds.Position);
+ var m = node != scene.Root ?
+ Matrix.CreateTranslation(visual.Bounds.Position) :
+ Matrix.Identity;
var renderTransform = Matrix.Identity;
diff --git a/src/Avalonia.Visuals/Size.cs b/src/Avalonia.Visuals/Size.cs
index d87d2c5fc2..8a805dc6c5 100644
--- a/src/Avalonia.Visuals/Size.cs
+++ b/src/Avalonia.Visuals/Size.cs
@@ -1,6 +1,8 @@
using System;
using System.Globalization;
+#if !BUILDTASK
using Avalonia.Animation.Animators;
+#endif
using Avalonia.Utilities;
namespace Avalonia
@@ -8,11 +10,16 @@ namespace Avalonia
///
/// Defines a size.
///
- public readonly struct Size : IEquatable
+#if !BUILDTASK
+ public
+#endif
+ readonly struct Size : IEquatable
{
static Size()
{
+#if !BUILDTASK
Animation.Animation.RegisterAnimator(prop => typeof(Size).IsAssignableFrom(prop.PropertyType));
+#endif
}
///
diff --git a/src/Avalonia.Visuals/Thickness.cs b/src/Avalonia.Visuals/Thickness.cs
index 6d69c4d9a9..06ebc9bfe7 100644
--- a/src/Avalonia.Visuals/Thickness.cs
+++ b/src/Avalonia.Visuals/Thickness.cs
@@ -1,6 +1,8 @@
using System;
using System.Globalization;
+#if !BUILDTASK
using Avalonia.Animation.Animators;
+#endif
using Avalonia.Utilities;
namespace Avalonia
@@ -8,11 +10,16 @@ namespace Avalonia
///
/// Describes the thickness of a frame around a rectangle.
///
- public readonly struct Thickness : IEquatable
+#if !BUILDTASK
+ public
+#endif
+ readonly struct Thickness : IEquatable
{
static Thickness()
{
+#if !BUILDTASK
Animation.Animation.RegisterAnimator(prop => typeof(Thickness).IsAssignableFrom(prop.PropertyType));
+#endif
}
///
diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs
index 2fcf804f14..1b9f5c67d5 100644
--- a/src/Avalonia.Visuals/Vector.cs
+++ b/src/Avalonia.Visuals/Vector.cs
@@ -1,6 +1,8 @@
using System;
using System.Globalization;
+#if !BUILDTASK
using Avalonia.Animation.Animators;
+#endif
using Avalonia.Utilities;
#nullable enable
@@ -10,11 +12,16 @@ namespace Avalonia
///
/// Defines a vector.
///
- public readonly struct Vector : IEquatable
+#if !BUILDTASK
+ public
+#endif
+ readonly struct Vector : IEquatable
{
static Vector()
{
+#if !BUILDTASK
Animation.Animation.RegisterAnimator(prop => typeof(Vector).IsAssignableFrom(prop.PropertyType));
+#endif
}
///
diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs
index 283d9deb52..9327531b46 100644
--- a/src/Avalonia.Visuals/Visual.cs
+++ b/src/Avalonia.Visuals/Visual.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Specialized;
using Avalonia.Collections;
using Avalonia.Data;
@@ -484,7 +485,7 @@ namespace Avalonia
BindingPriority.LocalValue);
}
- protected override sealed void LogBindingError(AvaloniaProperty property, Exception e)
+ protected internal sealed override void LogBindingError(AvaloniaProperty property, Exception e)
{
// Don't log a binding error unless the control is attached to a logical or visual tree.
// In theory this should only need to check for logical tree attachment, but in practise
@@ -619,34 +620,30 @@ namespace Avalonia
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
- foreach (Visual v in e.NewItems)
- {
- v.SetVisualParent(this);
- }
-
+ SetVisualParent(e.NewItems, this);
break;
case NotifyCollectionChangedAction.Remove:
- foreach (Visual v in e.OldItems)
- {
- v.SetVisualParent(null);
- }
-
+ SetVisualParent(e.OldItems, null);
break;
case NotifyCollectionChangedAction.Replace:
- foreach (Visual v in e.OldItems)
- {
- v.SetVisualParent(null);
- }
-
- foreach (Visual v in e.NewItems)
- {
- v.SetVisualParent(this);
- }
-
+ SetVisualParent(e.OldItems, null);
+ SetVisualParent(e.NewItems, this);
break;
}
}
+
+ private static void SetVisualParent(IList children, Visual parent)
+ {
+ var count = children.Count;
+
+ for (var i = 0; i < count; i++)
+ {
+ var visual = (Visual) children[i];
+
+ visual.SetVisualParent(parent);
+ }
+ }
}
}
diff --git a/src/Avalonia.Visuals/VisualExtensions.cs b/src/Avalonia.Visuals/VisualExtensions.cs
index 6079e5941f..e6523a1469 100644
--- a/src/Avalonia.Visuals/VisualExtensions.cs
+++ b/src/Avalonia.Visuals/VisualExtensions.cs
@@ -50,7 +50,13 @@ namespace Avalonia
{
var thisOffset = GetOffsetFrom(common, from);
var thatOffset = GetOffsetFrom(common, to);
- return -thatOffset * thisOffset;
+
+ if (!thatOffset.TryInvert(out var thatOffsetInverted))
+ {
+ return null;
+ }
+
+ return thatOffsetInverted * thisOffset;
}
return null;
diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs
index 2cd3b973d8..b061920d6a 100644
--- a/src/Avalonia.X11/X11Window.cs
+++ b/src/Avalonia.X11/X11Window.cs
@@ -189,6 +189,11 @@ namespace Avalonia.X11
if (platform.Options.UseDBusMenu)
NativeMenuExporter = DBusMenuExporter.TryCreate(_handle);
NativeControlHost = new X11NativeControlHost(_platform, this);
+ DispatcherTimer.Run(() =>
+ {
+ Paint?.Invoke(default);
+ return _handle != IntPtr.Zero;
+ }, TimeSpan.FromMilliseconds(100));
}
class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
@@ -338,7 +343,10 @@ namespace Avalonia.X11
return customRendererFactory.Create(root, loop);
return _platform.Options.UseDeferredRendering ?
- new DeferredRenderer(root, loop) :
+ new DeferredRenderer(root, loop)
+ {
+ RenderOnlyOnRenderThread = true
+ } :
(IRenderer)new X11ImmediateRendererProxy(root, loop);
}
@@ -815,7 +823,7 @@ namespace Avalonia.X11
XSetTransientForHint(_x11.Display, _handle, parent.Handle.Handle);
}
- public void Show()
+ public void Show(bool activate)
{
_wasMappedAtLeastOnce = true;
XMapWindow(_x11.Display, _handle);
diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs
index b3a24e6c37..8cdf24cc7b 100644
--- a/src/Avalonia.X11/XI2Manager.cs
+++ b/src/Avalonia.X11/XI2Manager.cs
@@ -351,7 +351,7 @@ namespace Avalonia.X11
if (state.HasFlag(XModifierMask.Mod4Mask))
Modifiers |= RawInputModifiers.Meta;
- Modifiers = ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
+ Modifiers |= ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
Valuators = new Dictionary();
Position = new Point(ev->event_x, ev->event_y);
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj b/src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
index 514556d0b9..db9c414840 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
@@ -4,6 +4,7 @@
netstandard2.0
true
Avalonia.Markup.Xaml.Loader
+ $(DefineConstants);XAMLX_INTERNAL
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlAvaloniaListConstantAstNode.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlAvaloniaListConstantAstNode.cs
new file mode 100644
index 0000000000..0f4efc9f65
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlAvaloniaListConstantAstNode.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes
+{
+ class AvaloniaXamlIlAvaloniaListConstantAstNode : XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
+ {
+ private readonly IXamlType _elementType;
+ private readonly IReadOnlyList _values;
+ private readonly IXamlConstructor _constructor;
+ private readonly IXamlMethod _listAddMethod;
+ private readonly IXamlMethod _listSetCapacityMethod;
+
+ public AvaloniaXamlIlAvaloniaListConstantAstNode(IXamlLineInfo lineInfo, AvaloniaXamlIlWellKnownTypes types, IXamlType listType, IXamlType elementType, IReadOnlyList values) : base(lineInfo)
+ {
+ _constructor = listType.GetConstructor();
+ _listAddMethod = listType.GetMethod(new FindMethodMethodSignature("Add", types.XamlIlTypes.Void, elementType));
+ _listSetCapacityMethod = listType.GetMethod(new FindMethodMethodSignature("set_Capacity", types.XamlIlTypes.Void, types.Int));
+
+ _elementType = elementType;
+ _values = values;
+
+ Type = new XamlAstClrTypeReference(lineInfo, listType, false);
+ }
+
+ public IXamlAstTypeReference Type { get; }
+
+ public XamlILNodeEmitResult Emit(XamlEmitContext context, IXamlILEmitter codeGen)
+ {
+ codeGen.Newobj(_constructor);
+
+ codeGen
+ .Dup()
+ .Ldc_I4(_values.Count)
+ .EmitCall(_listSetCapacityMethod);
+
+ foreach (var value in _values)
+ {
+ codeGen.Dup();
+
+ context.Emit(value, codeGen, _elementType);
+
+ codeGen.EmitCall(_listAddMethod);
+ }
+
+ return XamlILNodeEmitResult.Type(0, Type.GetClrType());
+ }
+ }
+}
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlGridLengthAstNode.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlGridLengthAstNode.cs
new file mode 100644
index 0000000000..218c49512c
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlGridLengthAstNode.cs
@@ -0,0 +1,34 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes
+{
+ class AvaloniaXamlIlGridLengthAstNode : XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
+ {
+ private readonly AvaloniaXamlIlWellKnownTypes _types;
+ private readonly GridLength _gridLength;
+
+ public AvaloniaXamlIlGridLengthAstNode(IXamlLineInfo lineInfo, AvaloniaXamlIlWellKnownTypes types, GridLength gridLength) : base(lineInfo)
+ {
+ _types = types;
+ _gridLength = gridLength;
+
+ Type = new XamlAstClrTypeReference(lineInfo, types.GridLength, false);
+ }
+
+ public IXamlAstTypeReference Type { get; }
+
+ public XamlILNodeEmitResult Emit(XamlEmitContext context, IXamlILEmitter codeGen)
+ {
+ codeGen
+ .Ldc_R8(_gridLength.Value)
+ .Ldc_I4((int)_gridLength.GridUnitType)
+ .Newobj(_types.GridLengthConstructorValueType);
+
+ return XamlILNodeEmitResult.Type(0, Type.GetClrType());
+ }
+ }
+}
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlVectorLikeConstantAstNode.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlVectorLikeConstantAstNode.cs
new file mode 100644
index 0000000000..35cc9b3cf2
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlVectorLikeConstantAstNode.cs
@@ -0,0 +1,54 @@
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes
+{
+ class AvaloniaXamlIlVectorLikeConstantAstNode : XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
+ {
+ private readonly IXamlConstructor _constructor;
+ private readonly double[] _values;
+
+ public AvaloniaXamlIlVectorLikeConstantAstNode(IXamlLineInfo lineInfo, AvaloniaXamlIlWellKnownTypes types, IXamlType type, IXamlConstructor constructor, double[] values) : base(lineInfo)
+ {
+ var parameters = constructor.Parameters;
+
+ if (parameters.Count != values.Length)
+ {
+ throw new XamlTypeSystemException($"Constructor that takes {values.Length} parameters is expected, got {parameters.Count} instead.");
+ }
+
+ var elementType = types.XamlIlTypes.Double;
+
+ foreach (var parameter in parameters)
+ {
+ if (parameter != elementType)
+ {
+ throw new XamlTypeSystemException($"Expected parameter of type {elementType}, got {parameter} instead.");
+ }
+ }
+
+ _constructor = constructor;
+ _values = values;
+
+ Type = new XamlAstClrTypeReference(lineInfo, type, false);
+ }
+
+ public IXamlAstTypeReference Type { get; }
+
+ public XamlILNodeEmitResult Emit(XamlEmitContext context, IXamlILEmitter codeGen)
+ {
+ foreach (var value in _values)
+ {
+ codeGen.Ldc_R8(value);
+ }
+
+ codeGen.Newobj(_constructor);
+
+ return XamlILNodeEmitResult.Type(0, Type.GetClrType());
+ }
+ }
+}
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs
index 15413689f8..a82f5b9e60 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs
@@ -2,8 +2,10 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using Avalonia.Controls;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+using Avalonia.Media;
using XamlX;
using XamlX.Ast;
using XamlX.Emit;
@@ -175,37 +177,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
var text = textNode.Text;
-
var types = context.GetAvaloniaTypes();
- if (type.FullName == "System.TimeSpan")
- {
- var tsText = text.Trim();
-
- if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan))
- {
- // // shorthand seconds format (ie. "0.25")
- if (!tsText.Contains(":") && double.TryParse(tsText,
- NumberStyles.Float | NumberStyles.AllowThousands,
- CultureInfo.InvariantCulture, out var seconds))
- timeSpan = TimeSpan.FromSeconds(seconds);
- else
- throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node);
- }
-
-
- result = new XamlStaticOrTargetedReturnMethodCallNode(node,
- type.FindMethod("FromTicks", type, false, types.Long),
- new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) });
- return true;
- }
-
- if (type.Equals(types.FontFamily))
+ if (AvaloniaXamlIlLanguageParseIntrinsics.TryConvert(context, node, text, type, types, out result))
{
- result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node);
return true;
}
-
+
if (type.FullName == "Avalonia.AvaloniaProperty")
{
var scope = context.ParentNodes().OfType().FirstOrDefault();
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
new file mode 100644
index 0000000000..7c4cc8d28b
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
@@ -0,0 +1,243 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+using Avalonia.Media;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
+{
+ class AvaloniaXamlIlLanguageParseIntrinsics
+ {
+ public static bool TryConvert(AstTransformationContext context, IXamlAstValueNode node, string text, IXamlType type, AvaloniaXamlIlWellKnownTypes types, out IXamlAstValueNode result)
+ {
+ if (type.FullName == "System.TimeSpan")
+ {
+ var tsText = text.Trim();
+
+ if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan))
+ {
+ // // shorthand seconds format (ie. "0.25")
+ if (!tsText.Contains(":") && double.TryParse(tsText,
+ NumberStyles.Float | NumberStyles.AllowThousands,
+ CultureInfo.InvariantCulture, out var seconds))
+ timeSpan = TimeSpan.FromSeconds(seconds);
+ else
+ throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node);
+ }
+
+ result = new XamlStaticOrTargetedReturnMethodCallNode(node,
+ type.FindMethod("FromTicks", type, false, types.Long),
+ new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) });
+ return true;
+ }
+
+ if (type.Equals(types.FontFamily))
+ {
+ result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node);
+ return true;
+ }
+
+ if (type.Equals(types.Thickness))
+ {
+ try
+ {
+ var thickness = Thickness.Parse(text);
+
+ result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Thickness, types.ThicknessFullConstructor,
+ new[] { thickness.Left, thickness.Top, thickness.Right, thickness.Bottom });
+
+ return true;
+ }
+ catch
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a thickness", node);
+ }
+ }
+
+ if (type.Equals(types.Point))
+ {
+ try
+ {
+ var point = Point.Parse(text);
+
+ result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Point, types.PointFullConstructor,
+ new[] { point.X, point.Y });
+
+ return true;
+ }
+ catch
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a point", node);
+ }
+ }
+
+ if (type.Equals(types.Vector))
+ {
+ try
+ {
+ var vector = Vector.Parse(text);
+
+ result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Vector, types.VectorFullConstructor,
+ new[] { vector.X, vector.Y });
+
+ return true;
+ }
+ catch
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a vector", node);
+ }
+ }
+
+ if (type.Equals(types.Size))
+ {
+ try
+ {
+ var size = Size.Parse(text);
+
+ result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Size, types.SizeFullConstructor,
+ new[] { size.Width, size.Height });
+
+ return true;
+ }
+ catch
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a size", node);
+ }
+ }
+
+ if (type.Equals(types.Matrix))
+ {
+ try
+ {
+ var matrix = Matrix.Parse(text);
+
+ result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Matrix, types.MatrixFullConstructor,
+ new[] { matrix.M11, matrix.M12, matrix.M21, matrix.M22, matrix.M31, matrix.M32 });
+
+ return true;
+ }
+ catch
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a matrix", node);
+ }
+ }
+
+ if (type.Equals(types.CornerRadius))
+ {
+ try
+ {
+ var cornerRadius = CornerRadius.Parse(text);
+
+ result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.CornerRadius, types.CornerRadiusFullConstructor,
+ new[] { cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.BottomRight, cornerRadius.BottomLeft });
+
+ return true;
+ }
+ catch
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a corner radius", node);
+ }
+ }
+
+ if (type.Equals(types.Color))
+ {
+ if (!Color.TryParse(text, out Color color))
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a color", node);
+ }
+
+ result = new XamlStaticOrTargetedReturnMethodCallNode(node,
+ type.GetMethod(
+ new FindMethodMethodSignature("FromUInt32", type, types.UInt) { IsStatic = true }),
+ new[] { new XamlConstantNode(node, types.UInt, color.ToUint32()) });
+
+ return true;
+ }
+
+ if (type.Equals(types.GridLength))
+ {
+ try
+ {
+ var gridLength = GridLength.Parse(text);
+
+ result = new AvaloniaXamlIlGridLengthAstNode(node, types, gridLength);
+
+ return true;
+ }
+ catch
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a grid length", node);
+ }
+ }
+
+ if (type.Equals(types.Cursor))
+ {
+ if (TypeSystemHelpers.TryGetEnumValueNode(types.StandardCursorType, text, node, out var enumConstantNode))
+ {
+ var cursorTypeRef = new XamlAstClrTypeReference(node, types.Cursor, false);
+
+ result = new XamlAstNewClrObjectNode(node, cursorTypeRef, types.CursorTypeConstructor, new List { enumConstantNode });
+
+ return true;
+ }
+ }
+
+ if (type.Equals(types.ColumnDefinitions))
+ {
+ return ConvertDefinitionList(node, text, types, types.ColumnDefinitions, types.ColumnDefinition, "column definitions", out result);
+ }
+
+ if (type.Equals(types.RowDefinitions))
+ {
+ return ConvertDefinitionList(node, text, types, types.RowDefinitions, types.RowDefinition, "row definitions", out result);
+ }
+
+ result = null;
+ return false;
+ }
+
+ private static bool ConvertDefinitionList(
+ IXamlAstValueNode node,
+ string text,
+ AvaloniaXamlIlWellKnownTypes types,
+ IXamlType listType,
+ IXamlType elementType,
+ string errorDisplayName,
+ out IXamlAstValueNode result)
+ {
+ try
+ {
+ var lengths = GridLength.ParseLengths(text);
+
+ var definitionTypeRef = new XamlAstClrTypeReference(node, elementType, false);
+
+ var definitionConstructorGridLength = elementType.GetConstructor(new List {types.GridLength});
+
+ IXamlAstValueNode CreateDefinitionNode(GridLength length)
+ {
+ var lengthNode = new AvaloniaXamlIlGridLengthAstNode(node, types, length);
+
+ return new XamlAstNewClrObjectNode(node, definitionTypeRef,
+ definitionConstructorGridLength, new List {lengthNode});
+ }
+
+ var definitionNodes =
+ new List(lengths.Select(CreateDefinitionNode));
+
+ result = new AvaloniaXamlIlAvaloniaListConstantAstNode(node, types, listType, elementType, definitionNodes);
+
+ return true;
+ }
+ catch
+ {
+ throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a {errorDisplayName}", node);
+ }
+ }
+ }
+}
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
index d78ceeb918..f87e73a783 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
@@ -22,7 +22,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
var avaloniaObject = context.Configuration.TypeSystem.FindType("Avalonia.AvaloniaObject");
if (avaloniaObject.IsAssignableFrom(targetRef.Type)
&& avaloniaObject.IsAssignableFrom(declaringRef.Type)
- && !targetRef.Type.IsAssignableFrom(declaringRef.Type))
+ && !declaringRef.Type.IsAssignableFrom(targetRef.Type))
{
// Instance property
var clrProp = declaringRef.Type.GetAllProperties().FirstOrDefault(p => p.Name == prop.Name);
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
index 58f4ddfe31..125701ca9e 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using XamlX.Emit;
using XamlX.IL;
using XamlX.Transform;
@@ -48,11 +49,34 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType ReflectionBindingExtension { get; }
public IXamlType RelativeSource { get; }
+ public IXamlType UInt { get; }
+ public IXamlType Int { get; }
public IXamlType Long { get; }
public IXamlType Uri { get; }
public IXamlType FontFamily { get; }
public IXamlConstructor FontFamilyConstructorUriName { get; }
-
+ public IXamlType Thickness { get; }
+ public IXamlConstructor ThicknessFullConstructor { get; }
+ public IXamlType Point { get; }
+ public IXamlConstructor PointFullConstructor { get; }
+ public IXamlType Vector { get; }
+ public IXamlConstructor VectorFullConstructor { get; }
+ public IXamlType Size { get; }
+ public IXamlConstructor SizeFullConstructor { get; }
+ public IXamlType Matrix { get; }
+ public IXamlConstructor MatrixFullConstructor { get; }
+ public IXamlType CornerRadius { get; }
+ public IXamlConstructor CornerRadiusFullConstructor { get; }
+ public IXamlType GridLength { get; }
+ public IXamlConstructor GridLengthConstructorValueType { get; }
+ public IXamlType Color { get; }
+ public IXamlType StandardCursorType { get; }
+ public IXamlType Cursor { get; }
+ public IXamlConstructor CursorTypeConstructor { get; }
+ public IXamlType RowDefinition { get; }
+ public IXamlType RowDefinitions { get; }
+ public IXamlType ColumnDefinition { get; }
+ public IXamlType ColumnDefinitions { get; }
public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg)
{
@@ -110,10 +134,38 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
ItemsRepeater = cfg.TypeSystem.GetType("Avalonia.Controls.ItemsRepeater");
ReflectionBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension");
RelativeSource = cfg.TypeSystem.GetType("Avalonia.Data.RelativeSource");
+ UInt = cfg.TypeSystem.GetType("System.UInt32");
+ Int = cfg.TypeSystem.GetType("System.Int32");
Long = cfg.TypeSystem.GetType("System.Int64");
Uri = cfg.TypeSystem.GetType("System.Uri");
FontFamily = cfg.TypeSystem.GetType("Avalonia.Media.FontFamily");
- FontFamilyConstructorUriName = FontFamily.FindConstructor(new List { Uri, XamlIlTypes.String });
+ FontFamilyConstructorUriName = FontFamily.GetConstructor(new List { Uri, XamlIlTypes.String });
+
+ (IXamlType, IXamlConstructor) GetNumericTypeInfo(string name, IXamlType componentType, int componentCount)
+ {
+ var type = cfg.TypeSystem.GetType(name);
+ var ctor = type.GetConstructor(Enumerable.Range(0, componentCount).Select(_ => componentType).ToList());
+
+ return (type, ctor);
+ }
+
+ (Thickness, ThicknessFullConstructor) = GetNumericTypeInfo("Avalonia.Thickness", XamlIlTypes.Double, 4);
+ (Point, PointFullConstructor) = GetNumericTypeInfo("Avalonia.Point", XamlIlTypes.Double, 2);
+ (Vector, VectorFullConstructor) = GetNumericTypeInfo("Avalonia.Vector", XamlIlTypes.Double, 2);
+ (Size, SizeFullConstructor) = GetNumericTypeInfo("Avalonia.Size", XamlIlTypes.Double, 2);
+ (Matrix, MatrixFullConstructor) = GetNumericTypeInfo("Avalonia.Matrix", XamlIlTypes.Double, 6);
+ (CornerRadius, CornerRadiusFullConstructor) = GetNumericTypeInfo("Avalonia.CornerRadius", XamlIlTypes.Double, 4);
+
+ GridLength = cfg.TypeSystem.GetType("Avalonia.Controls.GridLength");
+ GridLengthConstructorValueType = GridLength.GetConstructor(new List { XamlIlTypes.Double, cfg.TypeSystem.GetType("Avalonia.Controls.GridUnitType") });
+ Color = cfg.TypeSystem.GetType("Avalonia.Media.Color");
+ StandardCursorType = cfg.TypeSystem.GetType("Avalonia.Input.StandardCursorType");
+ Cursor = cfg.TypeSystem.GetType("Avalonia.Input.Cursor");
+ CursorTypeConstructor = Cursor.GetConstructor(new List { StandardCursorType });
+ ColumnDefinition = cfg.TypeSystem.GetType("Avalonia.Controls.ColumnDefinition");
+ ColumnDefinitions = cfg.TypeSystem.GetType("Avalonia.Controls.ColumnDefinitions");
+ RowDefinition = cfg.TypeSystem.GetType("Avalonia.Controls.RowDefinition");
+ RowDefinitions = cfg.TypeSystem.GetType("Avalonia.Controls.RowDefinitions");
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
index 03ec32b9cf..1974dfe3bc 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
@@ -203,6 +203,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.ParentNodes()
.OfType()
.Where(x => styledElementType.IsAssignableFrom(x.Type.GetClrType()))
+ .Skip(1)
.ElementAtOrDefault(ancestor.Level)
?.Type.GetClrType();
@@ -242,6 +243,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
case RawSourceBindingExpressionNode rawSource:
nodes.Add(new RawSourcePathElementNode(rawSource.RawSource));
break;
+ case BindingExpressionGrammar.TypeCastNode typeCastNode:
+ var castType = GetType(typeCastNode.Namespace, typeCastNode.TypeName);
+
+ if (castType is null)
+ {
+ throw new XamlX.XamlParseException($"Unable to resolve cast to type {typeCastNode.Namespace}:{typeCastNode.TypeName} based on XAML tree.", lineInfo);
+ }
+
+ nodes.Add(new TypeCastPathElementNode(castType));
+ break;
}
}
@@ -422,7 +433,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{
codeGen.Ldtype(Type)
.Ldc_I4(_level)
- .EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "FindAncestor"));
+ .EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "Ancestor"));
}
}
@@ -608,10 +619,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
private readonly IXamlAstValueNode _rawSource;
public RawSourcePathElementNode(IXamlAstValueNode rawSource)
- :base(rawSource)
+ : base(rawSource)
{
_rawSource = rawSource;
-
+
}
public IXamlType Type => _rawSource.Type.GetClrType();
@@ -625,6 +636,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
}
+ class TypeCastPathElementNode : IXamlIlBindingPathElementNode
+ {
+ public TypeCastPathElementNode(IXamlType ancestorType)
+ {
+ Type = ancestorType;
+ }
+
+ public IXamlType Type { get; }
+
+ public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
+ {
+ codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "TypeCast").MakeGenericMethod(new[] { Type }));
+ }
+ }
+
class XamlIlBindingPathNode : XamlAstNode, IXamlIlBindingPathNode, IXamlAstEmitableNode
{
private readonly List _transformElements;
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github b/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
index 5420df861c..ea80a607c5 160000
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
@@ -1 +1 @@
-Subproject commit 5420df861ce6f2be5ead9efa078fe7242ce88f18
+Subproject commit ea80a607c5e9d8f000160dbbb48c27ed4cfafbc9
diff --git a/src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt b/src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt
index c87dcacda4..fcc74cf864 100644
--- a/src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt
+++ b/src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt
@@ -1,4 +1 @@
-Compat issues with assembly Avalonia.Markup.Xaml:
-MembersMustExist : Member 'public Avalonia.Data.Binding Avalonia.Markup.Xaml.Templates.TreeDataTemplate.ItemsSource.get()' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'public void Avalonia.Markup.Xaml.Templates.TreeDataTemplate.ItemsSource.set(Avalonia.Data.Binding)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 2
+Total Issues: 0
diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
index 3e15d2f700..217da2d50d 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
@@ -23,6 +23,7 @@
+
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
index aab733cb43..da39920eb3 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
@@ -26,6 +26,8 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
{
Path = Path,
Converter = Converter,
+ ConverterParameter = ConverterParameter,
+ TargetNullValue = TargetNullValue,
FallbackValue = FallbackValue,
Mode = Mode,
Priority = Priority,
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
index d627fe3cd3..f6636664c1 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Avalonia.Controls;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
@@ -53,6 +54,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
case IStronglyTypedStreamElement stream:
node = new StreamNode(stream.CreatePlugin());
break;
+ case ITypeCastElement typeCast:
+ node = new StrongTypeCastNode(typeCast.Type, typeCast.Cast);
+ break;
default:
throw new InvalidOperationException($"Unknown binding path element type {element.GetType().FullName}");
}
@@ -66,6 +70,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal SourceMode SourceMode => _elements.Count > 0 && _elements[0] is IControlSourceBindingPathElement ? SourceMode.Control : SourceMode.Data;
internal object RawSource { get; }
+
+ public override string ToString()
+ => string.Concat(_elements.Select(e => e.ToString()));
}
public class CompiledBindingPathBuilder
@@ -126,6 +133,12 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return this;
}
+ public CompiledBindingPathBuilder TypeCast()
+ {
+ _elements.Add(new TypeCastPathElement());
+ return this;
+ }
+
public CompiledBindingPathBuilder SetRawSource(object rawSource)
{
_rawSource = rawSource;
@@ -157,6 +170,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public IPropertyInfo Property { get; }
public Func, IPropertyInfo, IPropertyAccessor> AccessorFactory { get; }
+
+ public override string ToString()
+ => $".{Property.Name}";
}
internal interface IStronglyTypedStreamElement : ICompiledBindingPathElement
@@ -164,6 +180,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
IStreamPlugin CreatePlugin();
}
+ internal interface ITypeCastElement : ICompiledBindingPathElement
+ {
+ Type Type { get; }
+
+ Func Cast { get; }
+ }
+
internal class TaskStreamPathElement : IStronglyTypedStreamElement
{
public static readonly TaskStreamPathElement Instance = new TaskStreamPathElement();
@@ -181,6 +204,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class SelfPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
{
public static readonly SelfPathElement Instance = new SelfPathElement();
+
+ public override string ToString()
+ => "$self";
}
internal class AncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
@@ -193,6 +219,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public Type AncestorType { get; }
public int Level { get; }
+
+ public override string ToString()
+ => $"$parent[{AncestorType?.Name},{Level}]";
}
internal class VisualAncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
@@ -217,6 +246,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public INameScope NameScope { get; }
public string Name { get; }
+
+ public override string ToString()
+ => $"#{Name}";
}
internal class ArrayElementPathElement : ICompiledBindingPathElement
@@ -229,5 +261,24 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public int[] Indices { get; }
public Type ElementType { get; }
+ public override string ToString()
+ => $"[{string.Join(",", Indices)}]";
+ }
+
+ internal class TypeCastPathElement : ITypeCastElement
+ {
+ private static object TryCast(object obj)
+ {
+ if (obj is T result)
+ return result;
+ return null;
+ }
+
+ public Type Type => typeof(T);
+
+ public Func Cast => TryCast;
+
+ public override string ToString()
+ => $"({Type.FullName})";
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs
new file mode 100644
index 0000000000..1252ec7eca
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs
@@ -0,0 +1,18 @@
+using System;
+using Avalonia.Data.Core;
+
+namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
+{
+ public class StrongTypeCastNode : TypeCastNode
+ {
+ private Func _cast;
+
+ public StrongTypeCastNode(Type type, Func cast) : base(type)
+ {
+ _cast = cast;
+ }
+
+ protected override object Cast(object value)
+ => _cast(value);
+ }
+}
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
index 03fd2e60dd..95380be65f 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
@@ -10,8 +10,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
{
public class DynamicResourceExtension : IBinding
{
- private IStyledElement? _anchor;
- private IResourceProvider? _resourceProvider;
+ private object? _anchor;
public DynamicResourceExtension()
{
@@ -30,12 +29,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
if (!(provideTarget.TargetObject is IStyledElement))
{
- _anchor = serviceProvider.GetFirstParent();
-
- if (_anchor is null)
- {
- _resourceProvider = serviceProvider.GetFirstParent();
- }
+ _anchor = serviceProvider.GetFirstParent() ??
+ serviceProvider.GetFirstParent() ??
+ (object?)serviceProvider.GetFirstParent();
}
return this;
@@ -52,16 +48,16 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
return null;
}
- var control = target as IStyledElement ?? _anchor as IStyledElement;
+ var control = target as IResourceHost ?? _anchor as IResourceHost;
if (control != null)
{
var source = control.GetResourceObservable(ResourceKey, GetConverter(targetProperty));
return InstancedBinding.OneWay(source);
}
- else if (_resourceProvider is object)
+ else if (_anchor is IResourceProvider resourceProvider)
{
- var source = _resourceProvider.GetResourceObservable(ResourceKey, GetConverter(targetProperty));
+ var source = resourceProvider.GetResourceObservable(ResourceKey, GetConverter(targetProperty));
return InstancedBinding.OneWay(source);
}
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs
index 8e5631e198..7c362e24cc 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs
@@ -46,6 +46,10 @@ namespace Avalonia.Markup.Parsers
state = ParseIndexer(ref r, nodes);
break;
+ case State.TypeCast:
+ state = ParseTypeCast(ref r, nodes);
+ break;
+
case State.ElementName:
state = ParseElementName(ref r, nodes);
mode = SourceMode.Control;
@@ -84,6 +88,11 @@ namespace Avalonia.Markup.Parsers
}
else if (ParseOpenBrace(ref r))
{
+ if (PeekOpenBrace(ref r))
+ {
+ return State.TypeCast;
+ }
+
return State.AttachedProperty;
}
else if (PeekOpenBracket(ref r))
@@ -124,6 +133,10 @@ namespace Avalonia.Markup.Parsers
{
return State.Indexer;
}
+ else if (ParseOpenBrace(ref r))
+ {
+ return State.TypeCast;
+ }
return State.End;
}
@@ -132,6 +145,11 @@ namespace Avalonia.Markup.Parsers
{
if (ParseOpenBrace(ref r))
{
+ if (PeekOpenBrace(ref r))
+ {
+ return State.TypeCast;
+ }
+
return State.AttachedProperty;
}
else
@@ -152,6 +170,12 @@ namespace Avalonia.Markup.Parsers
{
var (ns, owner) = ParseTypeName(ref r);
+ if(!r.End && r.TakeIf(')'))
+ {
+ nodes.Add(new TypeCastNode() { Namespace = ns, TypeName = owner });
+ return State.AfterMember;
+ }
+
if (r.End || !r.TakeIf('.'))
{
throw new ExpressionParseException(r.Position, "Invalid attached property name.");
@@ -159,6 +183,11 @@ namespace Avalonia.Markup.Parsers
var name = r.ParseIdentifier();
+ if (name.Length == 0)
+ {
+ throw new ExpressionParseException(r.Position, "Attached Property name expected after '.'.");
+ }
+
if (r.End || !r.TakeIf(')'))
{
throw new ExpressionParseException(r.Position, "Expected ')'.");
@@ -186,6 +215,39 @@ namespace Avalonia.Markup.Parsers
return State.AfterMember;
}
+ private static State ParseTypeCast(ref CharacterReader r, List nodes)
+ {
+ bool parseMemberBeforeAddCast = ParseOpenBrace(ref r);
+
+ var (ns, typeName) = ParseTypeName(ref r);
+
+ var result = State.AfterMember;
+
+ if (parseMemberBeforeAddCast)
+ {
+ if (!ParseCloseBrace(ref r))
+ {
+ throw new ExpressionParseException(r.Position, "Expected ')'.");
+ }
+
+ result = ParseBeforeMember(ref r, nodes);
+
+ if(r.Peek == '[')
+ {
+ result = ParseIndexer(ref r, nodes);
+ }
+ }
+
+ nodes.Add(new TypeCastNode { Namespace = ns, TypeName = typeName });
+
+ if (r.End || !r.TakeIf(')'))
+ {
+ throw new ExpressionParseException(r.Position, "Expected ')'.");
+ }
+
+ return result;
+ }
+
private static State ParseElementName(ref CharacterReader r, List nodes)
{
var name = r.ParseIdentifier();
@@ -288,11 +350,21 @@ namespace Avalonia.Markup.Parsers
return !r.End && r.TakeIf('(');
}
+ private static bool ParseCloseBrace(ref CharacterReader r)
+ {
+ return !r.End && r.TakeIf(')');
+ }
+
private static bool PeekOpenBracket(ref CharacterReader r)
{
return !r.End && r.Peek == '[';
}
+ private static bool PeekOpenBrace(ref CharacterReader r)
+ {
+ return !r.End && r.Peek == '(';
+ }
+
private static bool ParseStreamOperator(ref CharacterReader r)
{
return !r.End && r.TakeIf('^');
@@ -322,6 +394,7 @@ namespace Avalonia.Markup.Parsers
BeforeMember,
AttachedProperty,
Indexer,
+ TypeCast,
End,
}
@@ -343,9 +416,9 @@ namespace Avalonia.Markup.Parsers
}
}
- public interface INode {}
+ public interface INode { }
- public interface ITransformNode {}
+ public interface ITransformNode { }
public class EmptyExpressionNode : INode { }
@@ -366,11 +439,11 @@ namespace Avalonia.Markup.Parsers
public IList Arguments { get; set; }
}
- public class NotNode : INode, ITransformNode {}
+ public class NotNode : INode, ITransformNode { }
- public class StreamNode : INode {}
+ public class StreamNode : INode { }
- public class SelfNode : INode {}
+ public class SelfNode : INode { }
public class NameNode : INode
{
@@ -383,5 +456,11 @@ namespace Avalonia.Markup.Parsers
public string TypeName { get; set; }
public int Level { get; set; }
}
+
+ public class TypeCastNode : INode
+ {
+ public string Namespace { get; set; }
+ public string TypeName { get; set; }
+ }
}
}
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
index 1048148c1f..558130e23f 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
@@ -59,6 +59,9 @@ namespace Avalonia.Markup.Parsers
case BindingExpressionGrammar.NameNode elementName:
nextNode = new ElementNameNode(_nameScope, elementName.Name);
break;
+ case BindingExpressionGrammar.TypeCastNode typeCast:
+ nextNode = ParseTypeCastNode(typeCast);
+ break;
}
if (rootNode is null)
{
@@ -92,6 +95,22 @@ namespace Avalonia.Markup.Parsers
return new FindAncestorNode(ancestorType, ancestorLevel);
}
+ private TypeCastNode ParseTypeCastNode(BindingExpressionGrammar.TypeCastNode node)
+ {
+ Type castType = null;
+ if (!(node.Namespace is null) && !(node.TypeName is null))
+ {
+ if (_typeResolver == null)
+ {
+ throw new InvalidOperationException("Cannot parse a binding path with a typed Cast without a type resolver. Maybe you can use a LINQ Expression binding path instead?");
+ }
+
+ castType = _typeResolver(node.Namespace, node.TypeName);
+ }
+
+ return new TypeCastNode(castType);
+ }
+
private AvaloniaPropertyAccessorNode ParseAttachedProperty(BindingExpressionGrammar.AttachedPropertyNameNode node)
{
if (_typeResolver == null)
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index 44e0c82110..2a79a4bb50 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -434,7 +434,7 @@ namespace Avalonia.Skia
///
public IDrawingContextLayerImpl CreateLayer(Size size)
{
- return CreateRenderTarget( size);
+ return CreateRenderTarget(size, true);
}
///
@@ -673,7 +673,7 @@ namespace Avalonia.Skia
private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage)
{
var calc = new TileBrushCalculator(tileBrush, tileBrushImage.PixelSize.ToSizeWithDpi(_dpi), targetSize);
- var intermediate = CreateRenderTarget(calc.IntermediateSize);
+ var intermediate = CreateRenderTarget(calc.IntermediateSize, false);
paintWrapper.AddDisposable(intermediate);
@@ -748,7 +748,7 @@ namespace Avalonia.Skia
if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1)
{
- var intermediate = CreateRenderTarget(intermediateSize);
+ var intermediate = CreateRenderTarget(intermediateSize, false);
using (var ctx = intermediate.CreateDrawingContext(visualBrushRenderer))
{
@@ -978,9 +978,10 @@ namespace Avalonia.Skia
/// Create new render target compatible with this drawing context.
///
/// The size of the render target in DIPs.
+ /// Whether the render target is being created for a layer.
/// Pixel format.
///
- private SurfaceRenderTarget CreateRenderTarget(Size size, PixelFormat? format = null)
+ private SurfaceRenderTarget CreateRenderTarget(Size size, bool isLayer, PixelFormat? format = null)
{
var pixelSize = PixelSize.FromSizeWithDpi(size, _dpi);
var createInfo = new SurfaceRenderTarget.CreateInfo
@@ -992,7 +993,8 @@ namespace Avalonia.Skia
DisableTextLcdRendering = !_canTextUseLcdRendering,
GrContext = _grContext,
Gpu = _gpu,
- Session = _session
+ Session = _session,
+ DisableManualFbo = !isLayer,
};
return new SurfaceRenderTarget(createInfo);
diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
index d6f76a2c20..6d0be9f64d 100644
--- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
+++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
@@ -3,6 +3,8 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Threading;
+
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Media;
using Avalonia.OpenGL;
@@ -124,7 +126,8 @@ namespace Avalonia.Skia
Width = size.Width,
Height = size.Height,
Dpi = dpi,
- DisableTextLcdRendering = false
+ DisableTextLcdRendering = false,
+ DisableManualFbo = true,
};
return new SurfaceRenderTarget(createInfo);
@@ -165,12 +168,13 @@ namespace Avalonia.Skia
LinearMetrics = true
};
- private static readonly SKTextBlobBuilder s_textBlobBuilder = new SKTextBlobBuilder();
+ private static readonly ThreadLocal s_textBlobBuilderThreadLocal = new ThreadLocal(() => new SKTextBlobBuilder());
///
public IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun, out double width)
{
var count = glyphRun.GlyphIndices.Length;
+ var textBlobBuilder = s_textBlobBuilderThreadLocal.Value;
var glyphTypeface = (GlyphTypefaceImpl)glyphRun.GlyphTypeface.PlatformImpl;
@@ -190,15 +194,15 @@ namespace Avalonia.Skia
{
if (glyphTypeface.IsFixedPitch)
{
- s_textBlobBuilder.AddRun(glyphRun.GlyphIndices.Buffer.Span, s_font);
+ textBlobBuilder.AddRun(glyphRun.GlyphIndices.Buffer.Span, s_font);
- textBlob = s_textBlobBuilder.Build();
+ textBlob = textBlobBuilder.Build();
width = glyphTypeface.GetGlyphAdvance(glyphRun.GlyphIndices[0]) * scale * glyphRun.GlyphIndices.Length;
}
else
{
- var buffer = s_textBlobBuilder.AllocateHorizontalRun(s_font, count, 0);
+ var buffer = textBlobBuilder.AllocateHorizontalRun(s_font, count, 0);
var positions = buffer.GetPositionSpan();
@@ -218,12 +222,12 @@ namespace Avalonia.Skia
buffer.SetGlyphs(glyphRun.GlyphIndices.Buffer.Span);
- textBlob = s_textBlobBuilder.Build();
+ textBlob = textBlobBuilder.Build();
}
}
else
{
- var buffer = s_textBlobBuilder.AllocatePositionedRun(s_font, count);
+ var buffer = textBlobBuilder.AllocatePositionedRun(s_font, count);
var glyphPositions = buffer.GetPositionSpan();
@@ -249,7 +253,7 @@ namespace Avalonia.Skia
width = currentX;
- textBlob = s_textBlobBuilder.Build();
+ textBlob = textBlobBuilder.Build();
}
return new GlyphRunImpl(textBlob);
diff --git a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
index 6347c64aed..01b7449b64 100644
--- a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
@@ -51,7 +51,8 @@ namespace Avalonia.Skia
_grContext = createInfo.GrContext;
_gpu = createInfo.Gpu;
- _surface = _gpu?.TryCreateSurface(PixelSize, createInfo.Session);
+ if (!createInfo.DisableManualFbo)
+ _surface = _gpu?.TryCreateSurface(PixelSize, createInfo.Session);
if (_surface == null)
_surface = new SkiaSurfaceWrapper(CreateSurface(createInfo.GrContext, PixelSize.Width, PixelSize.Height,
createInfo.Format));
@@ -220,6 +221,8 @@ namespace Avalonia.Skia
public ISkiaGpu Gpu;
public ISkiaGpuRenderSession Session;
+
+ public bool DisableManualFbo;
}
}
}
diff --git a/src/Windows/Avalonia.Win32/.gitignore b/src/Windows/Avalonia.Win32/.gitignore
new file mode 100644
index 0000000000..7882fa6540
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/.gitignore
@@ -0,0 +1 @@
+*.Generated.cs
diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
index 5889d919df..fe5f806fbe 100644
--- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
+++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
@@ -5,9 +5,11 @@
Avalonia.Win32
+
-
+
+
diff --git a/src/Windows/Avalonia.Win32/ClipboardImpl.cs b/src/Windows/Avalonia.Win32/ClipboardImpl.cs
index 7d9e0a8bd2..047b7c361f 100644
--- a/src/Windows/Avalonia.Win32/ClipboardImpl.cs
+++ b/src/Windows/Avalonia.Win32/ClipboardImpl.cs
@@ -12,10 +12,17 @@ namespace Avalonia.Win32
{
internal class ClipboardImpl : IClipboard
{
+ private const int OleRetryCount = 10;
+ private const int OleRetryDelay = 100;
+
private async Task OpenClipboard()
{
+ var i = OleRetryCount;
+
while (!UnmanagedMethods.OpenClipboard(IntPtr.Zero))
{
+ if (--i == 0)
+ throw new TimeoutException("Timeout opening clipboard.");
await Task.Delay(100);
}
@@ -72,20 +79,32 @@ namespace Avalonia.Win32
{
Dispatcher.UIThread.VerifyAccess();
var wrapper = new DataObject(data);
+ var i = OleRetryCount;
+
while (true)
{
- if (UnmanagedMethods.OleSetClipboard(wrapper) == 0)
+ var hr = UnmanagedMethods.OleSetClipboard(wrapper);
+
+ if (hr == 0)
break;
- await Task.Delay(100);
+
+ if (--i == 0)
+ Marshal.ThrowExceptionForHR(hr);
+
+ await Task.Delay(OleRetryDelay);
}
}
public async Task GetFormatsAsync()
{
Dispatcher.UIThread.VerifyAccess();
+ var i = OleRetryCount;
+
while (true)
{
- if (UnmanagedMethods.OleGetClipboard(out var dataObject) == 0)
+ var hr = UnmanagedMethods.OleGetClipboard(out var dataObject);
+
+ if (hr == 0)
{
var wrapper = new OleDataObject(dataObject);
var formats = wrapper.GetDataFormats().ToArray();
@@ -93,16 +112,23 @@ namespace Avalonia.Win32
return formats;
}
- await Task.Delay(100);
+ if (--i == 0)
+ Marshal.ThrowExceptionForHR(hr);
+
+ await Task.Delay(OleRetryDelay);
}
}
public async Task GetDataAsync(string format)
{
Dispatcher.UIThread.VerifyAccess();
+ var i = OleRetryCount;
+
while (true)
{
- if (UnmanagedMethods.OleGetClipboard(out var dataObject) == 0)
+ var hr = UnmanagedMethods.OleGetClipboard(out var dataObject);
+
+ if (hr == 0)
{
var wrapper = new OleDataObject(dataObject);
var rv = wrapper.Get(format);
@@ -110,7 +136,10 @@ namespace Avalonia.Win32
return rv;
}
- await Task.Delay(100);
+ if (--i == 0)
+ Marshal.ThrowExceptionForHR(hr);
+
+ await Task.Delay(OleRetryDelay);
}
}
}
diff --git a/src/Windows/Avalonia.Win32/Composition/CompositionBlurHost.cs b/src/Windows/Avalonia.Win32/Composition/CompositionBlurHost.cs
deleted file mode 100644
index 4c090e797c..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/CompositionBlurHost.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Avalonia.Win32
-{
- internal class CompositionBlurHost : IBlurHost
- {
- Windows.UI.Composition.Visual _blurVisual;
-
- public CompositionBlurHost(Windows.UI.Composition.Visual blurVisual)
- {
- _blurVisual = blurVisual;
- }
-
- public void SetBlur(bool enabled)
- {
- _blurVisual.IsVisible = enabled;
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs b/src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs
deleted file mode 100644
index e0dfdf282c..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs
+++ /dev/null
@@ -1,171 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using Avalonia.Logging;
-using Avalonia.OpenGL;
-using Avalonia.OpenGL.Angle;
-using Avalonia.OpenGL.Egl;
-using Windows.UI.Composition;
-using Windows.UI.Composition.Interop;
-using WinRT;
-
-namespace Avalonia.Win32
-{
- internal class CompositionConnector
- {
- private Compositor _compositor;
- private Windows.System.DispatcherQueueController _dispatcherQueueController;
- private CompositionGraphicsDevice _graphicsDevice;
-
- internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
- {
- DQTAT_COM_NONE = 0,
- DQTAT_COM_ASTA = 1,
- DQTAT_COM_STA = 2
- };
-
- internal enum DISPATCHERQUEUE_THREAD_TYPE
- {
- DQTYPE_THREAD_DEDICATED = 1,
- DQTYPE_THREAD_CURRENT = 2,
- };
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct DispatcherQueueOptions
- {
- public int dwSize;
-
- [MarshalAs(UnmanagedType.I4)]
- public DISPATCHERQUEUE_THREAD_TYPE threadType;
-
- [MarshalAs(UnmanagedType.I4)]
- public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
- };
-
- [DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
- internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options, out IntPtr dispatcherQueueController);
-
- public static CompositionConnector TryCreate(EglPlatformOpenGlInterface egl)
- {
- const int majorRequired = 10;
- const int buildRequired = 16299;
-
- var majorInstalled = Win32Platform.WindowsVersion.Major;
- var buildInstalled = Win32Platform.WindowsVersion.Build;
-
- if (majorInstalled >= majorRequired &&
- buildInstalled >= buildRequired)
- {
- try
- {
- return new CompositionConnector(egl);
- }
- catch (Exception e)
- {
- Logger.TryGet(LogEventLevel.Error, "WinUIComposition")?.Log(null, "Unable to initialize WinUI compositor: {0}", e);
-
- return null;
- }
- }
-
- var osVersionNotice = $"Windows {majorRequired} Build {buildRequired} is required. Your machine has Windows {majorInstalled} Build {buildInstalled} installed.";
-
- Logger.TryGet(LogEventLevel.Warning, "WinUIComposition")?.Log(null,
- $"Unable to initialize WinUI compositor: {osVersionNotice}");
-
- return null;
- }
-
- public CompositionConnector(EglPlatformOpenGlInterface egl)
- {
- EnsureDispatcherQueue();
-
- if (_dispatcherQueueController != null)
- _compositor = new Compositor();
-
- var interop = _compositor.As();
-
- var display = egl.Display as AngleWin32EglDisplay;
-
- _graphicsDevice = interop.CreateGraphicsDevice(display.GetDirect3DDevice());
- }
-
- public ICompositionDrawingSurfaceInterop InitialiseWindowCompositionTree(IntPtr hwnd, out Windows.UI.Composition.Visual surfaceVisual, out IBlurHost blurHost)
- {
- var target = CreateDesktopWindowTarget(hwnd);
-
- var surface = _graphicsDevice.CreateDrawingSurface(new Windows.Foundation.Size(0, 0),
- Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized,
- Windows.Graphics.DirectX.DirectXAlphaMode.Premultiplied);
-
- var surfaceInterop = surface.As();
-
- var brush = _compositor.CreateSurfaceBrush(surface);
- var visual = _compositor.CreateSpriteVisual();
-
- visual.Brush = brush;
- visual.RelativeSizeAdjustment = new System.Numerics.Vector2(1, 1);
-
- var container = _compositor.CreateContainerVisual();
-
- target.Root = container;
-
- var blur = CreateBlur();
-
- blurHost = new CompositionBlurHost(blur);
-
- container.Children.InsertAtTop(blur);
-
- container.Children.InsertAtTop(visual);
-
- visual.CompositeMode = CompositionCompositeMode.SourceOver;
-
- surfaceVisual = container;
-
- return surfaceInterop;
- }
-
- private SpriteVisual CreateBlur()
- {
- var blurEffect = new GaussianBlurEffect(new CompositionEffectSourceParameter("backdrop"));
-
- var backDropBrush = _compositor.CreateBackdropBrush();
-
- var saturateEffect = new SaturationEffect(blurEffect);
- var satEffectFactory = _compositor.CreateEffectFactory(saturateEffect);
- var satBrush = satEffectFactory.CreateBrush();
-
- satBrush.SetSourceParameter("backdrop", backDropBrush);
-
- var visual = _compositor.CreateSpriteVisual();
- visual.IsVisible = false;
-
- visual.RelativeSizeAdjustment = new System.Numerics.Vector2(1.0f, 1.0f);
- visual.Brush = satBrush;
-
- return visual;
- }
-
- private CompositionTarget CreateDesktopWindowTarget(IntPtr window)
- {
- var interop = _compositor.As();
-
- interop.CreateDesktopWindowTarget(window, false, out var windowTarget);
- return Windows.UI.Composition.Desktop.DesktopWindowTarget.FromAbi(windowTarget);
- }
-
- private void EnsureDispatcherQueue()
- {
- if (_dispatcherQueueController == null)
- {
- DispatcherQueueOptions options = new DispatcherQueueOptions();
- options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_NONE;
- options.threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT;
- options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));
-
- CreateDispatcherQueueController(options, out var queue);
- _dispatcherQueueController = Windows.System.DispatcherQueueController.FromAbi(queue);
- }
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/CompositionEglGlPlatformSurface.cs b/src/Windows/Avalonia.Win32/Composition/CompositionEglGlPlatformSurface.cs
deleted file mode 100644
index 441da93787..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/CompositionEglGlPlatformSurface.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using Avalonia.OpenGL;
-using Avalonia.OpenGL.Angle;
-using Avalonia.OpenGL.Egl;
-using Avalonia.OpenGL.Surfaces;
-using Windows.UI.Composition.Interop;
-
-namespace Avalonia.Win32
-{
- internal class CompositionEglGlPlatformSurface : EglGlPlatformSurfaceBase
- {
- private EglPlatformOpenGlInterface _egl;
- private readonly IEglWindowGlPlatformSurfaceInfo _info;
- private ICompositionDrawingSurfaceInterop _surfaceInterop;
- private Windows.UI.Composition.Visual _surface;
-
- public CompositionEglGlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info) : base()
- {
- _egl = egl;
- _info = info;
- }
-
- public IBlurHost AttachToCompositionTree(CompositionConnector connector, IntPtr hwnd)
- {
- using (_egl.PrimaryContext.MakeCurrent())
- {
- _surfaceInterop = connector.InitialiseWindowCompositionTree(hwnd, out _surface, out var blurHost);
- return blurHost;
- }
- }
-
- public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
- {
- return new CompositionRenderTarget(_egl, _surface, _surfaceInterop, _info);
- }
-
- class CompositionRenderTarget : EglPlatformSurfaceRenderTargetBase
- {
- private readonly EglPlatformOpenGlInterface _egl;
- private readonly IEglWindowGlPlatformSurfaceInfo _info;
- private PixelSize _currentSize;
- private readonly ICompositionDrawingSurfaceInterop _surfaceInterop;
- private static Guid s_Iid = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
- private Windows.UI.Composition.Visual _compositionVisual;
-
- public CompositionRenderTarget(EglPlatformOpenGlInterface egl,
- Windows.UI.Composition.Visual compositionVisual,
- ICompositionDrawingSurfaceInterop interopSurface,
- IEglWindowGlPlatformSurfaceInfo info)
- : base(egl)
- {
- _egl = egl;
- _surfaceInterop = interopSurface;
- _info = info;
- _currentSize = info.Size;
- _compositionVisual = compositionVisual;
-
- using (_egl.PrimaryContext.MakeCurrent())
- {
- _surfaceInterop.Resize(new POINT { X = _info.Size.Width, Y = _info.Size.Height });
- }
-
- _compositionVisual.Size = new System.Numerics.Vector2(_info.Size.Width, _info.Size.Height);
- }
-
- public override IGlPlatformSurfaceRenderingSession BeginDraw()
- {
- IntPtr texture;
- EglSurface surface;
-
- using (_egl.PrimaryEglContext.EnsureCurrent())
- {
- if (_info.Size != _currentSize)
- {
- _surfaceInterop.Resize(new POINT { X = _info.Size.Width, Y = _info.Size.Height });
- _compositionVisual.Size = new System.Numerics.Vector2(_info.Size.Width, _info.Size.Height);
- _currentSize = _info.Size;
- }
-
- var offset = new POINT();
-
- _surfaceInterop.BeginDraw(
- IntPtr.Zero,
- ref s_Iid,
- out texture, ref offset);
-
- surface = (_egl.Display as AngleWin32EglDisplay).WrapDirect3D11Texture(_egl, texture, offset.X, offset.Y, _info.Size.Width, _info.Size.Height);
- }
-
- return base.BeginDraw(surface, _info, () => { _surfaceInterop.EndDraw(); Marshal.Release(texture); surface.Dispose(); }, true);
- }
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/D2DEffects.cs b/src/Windows/Avalonia.Win32/Composition/D2DEffects.cs
deleted file mode 100644
index 1c761ee082..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/D2DEffects.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System;
-
-
-namespace Avalonia.Win32
-{
- class D2DEffects
- {
- public static readonly Guid CLSID_D2D12DAffineTransform = new Guid(0x6AA97485, 0x6354, 0x4CFC, 0x90, 0x8C, 0xE4, 0xA7, 0x4F, 0x62, 0xC9, 0x6C);
-
- public static readonly Guid CLSID_D2D13DPerspectiveTransform = new Guid(0xC2844D0B, 0x3D86, 0x46E7, 0x85, 0xBA, 0x52, 0x6C, 0x92, 0x40, 0xF3, 0xFB);
-
- public static readonly Guid CLSID_D2D13DTransform = new Guid(0xE8467B04, 0xEC61, 0x4B8A, 0xB5, 0xDE, 0xD4, 0xD7, 0x3D, 0xEB, 0xEA, 0x5A);
-
- public static readonly Guid CLSID_D2D1ArithmeticComposite = new Guid(0xFC151437, 0x049A, 0x4784, 0xA2, 0x4A, 0xF1, 0xC4, 0xDA, 0xF2, 0x09, 0x87);
-
- public static readonly Guid CLSID_D2D1Atlas = new Guid(0x913E2BE4, 0xFDCF, 0x4FE2, 0xA5, 0xF0, 0x24, 0x54, 0xF1, 0x4F, 0xF4, 0x08);
-
- public static readonly Guid CLSID_D2D1BitmapSource = new Guid(0x5FB6C24D, 0xC6DD, 0x4231, 0x94, 0x4, 0x50, 0xF4, 0xD5, 0xC3, 0x25, 0x2D);
-
- public static readonly Guid CLSID_D2D1Blend = new Guid(0x81C5B77B, 0x13F8, 0x4CDD, 0xAD, 0x20, 0xC8, 0x90, 0x54, 0x7A, 0xC6, 0x5D);
-
- public static readonly Guid CLSID_D2D1Border = new Guid(0x2A2D49C0, 0x4ACF, 0x43C7, 0x8C, 0x6A, 0x7C, 0x4A, 0x27, 0x87, 0x4D, 0x27);
-
- public static readonly Guid CLSID_D2D1Brightness = new Guid(0x8CEA8D1E, 0x77B0, 0x4986, 0xB3, 0xB9, 0x2F, 0x0C, 0x0E, 0xAE, 0x78, 0x87);
-
- public static readonly Guid CLSID_D2D1ColorManagement = new Guid(0x1A28524C, 0xFDD6, 0x4AA4, 0xAE, 0x8F, 0x83, 0x7E, 0xB8, 0x26, 0x7B, 0x37);
-
- public static readonly Guid CLSID_D2D1ColorMatrix = new Guid(0x921F03D6, 0x641C, 0x47DF, 0x85, 0x2D, 0xB4, 0xBB, 0x61, 0x53, 0xAE, 0x11);
-
- public static readonly Guid CLSID_D2D1Composite = new Guid(0x48FC9F51, 0xF6AC, 0x48F1, 0x8B, 0x58, 0x3B, 0x28, 0xAC, 0x46, 0xF7, 0x6D);
-
- public static readonly Guid CLSID_D2D1ConvolveMatrix = new Guid(0x407F8C08, 0x5533, 0x4331, 0xA3, 0x41, 0x23, 0xCC, 0x38, 0x77, 0x84, 0x3E);
-
- public static readonly Guid CLSID_D2D1Crop = new Guid(0xE23F7110, 0x0E9A, 0x4324, 0xAF, 0x47, 0x6A, 0x2C, 0x0C, 0x46, 0xF3, 0x5B);
-
- public static readonly Guid CLSID_D2D1DirectionalBlur = new Guid(0x174319A6, 0x58E9, 0x49B2, 0xBB, 0x63, 0xCA, 0xF2, 0xC8, 0x11, 0xA3, 0xDB);
-
- public static readonly Guid CLSID_D2D1DiscreteTransfer = new Guid(0x90866FCD, 0x488E, 0x454B, 0xAF, 0x06, 0xE5, 0x04, 0x1B, 0x66, 0xC3, 0x6C);
-
- public static readonly Guid CLSID_D2D1DisplacementMap = new Guid(0xEDC48364, 0x417, 0x4111, 0x94, 0x50, 0x43, 0x84, 0x5F, 0xA9, 0xF8, 0x90);
-
- public static readonly Guid CLSID_D2D1DistantDiffuse = new Guid(0x3E7EFD62, 0xA32D, 0x46D4, 0xA8, 0x3C, 0x52, 0x78, 0x88, 0x9A, 0xC9, 0x54);
-
- public static readonly Guid CLSID_D2D1DistantSpecular = new Guid(0x428C1EE5, 0x77B8, 0x4450, 0x8A, 0xB5, 0x72, 0x21, 0x9C, 0x21, 0xAB, 0xDA);
-
- public static readonly Guid CLSID_D2D1DpiCompensation = new Guid(0x6C26C5C7, 0x34E0, 0x46FC, 0x9C, 0xFD, 0xE5, 0x82, 0x37, 0x6, 0xE2, 0x28);
-
- public static readonly Guid CLSID_D2D1Flood = new Guid(0x61C23C20, 0xAE69, 0x4D8E, 0x94, 0xCF, 0x50, 0x07, 0x8D, 0xF6, 0x38, 0xF2);
-
- public static readonly Guid CLSID_D2D1GammaTransfer = new Guid(0x409444C4, 0xC419, 0x41A0, 0xB0, 0xC1, 0x8C, 0xD0, 0xC0, 0xA1, 0x8E, 0x42);
-
- public static readonly Guid CLSID_D2D1GaussianBlur = new Guid(0x1FEB6D69, 0x2FE6, 0x4AC9, 0x8C, 0x58, 0x1D, 0x7F, 0x93, 0xE7, 0xA6, 0xA5);
-
- public static readonly Guid CLSID_D2D1Scale = new Guid(0x9DAF9369, 0x3846, 0x4D0E, 0xA4, 0x4E, 0xC, 0x60, 0x79, 0x34, 0xA5, 0xD7);
-
- public static readonly Guid CLSID_D2D1Histogram = new Guid(0x881DB7D0, 0xF7EE, 0x4D4D, 0xA6, 0xD2, 0x46, 0x97, 0xAC, 0xC6, 0x6E, 0xE8);
-
- public static readonly Guid CLSID_D2D1HueRotation = new Guid(0x0F4458EC, 0x4B32, 0x491B, 0x9E, 0x85, 0xBD, 0x73, 0xF4, 0x4D, 0x3E, 0xB6);
-
- public static readonly Guid CLSID_D2D1LinearTransfer = new Guid(0xAD47C8FD, 0x63EF, 0x4ACC, 0x9B, 0x51, 0x67, 0x97, 0x9C, 0x03, 0x6C, 0x06);
-
- public static readonly Guid CLSID_D2D1LuminanceToAlpha = new Guid(0x41251AB7, 0x0BEB, 0x46F8, 0x9D, 0xA7, 0x59, 0xE9, 0x3F, 0xCC, 0xE5, 0xDE);
-
- public static readonly Guid CLSID_D2D1Morphology = new Guid(0xEAE6C40D, 0x626A, 0x4C2D, 0xBF, 0xCB, 0x39, 0x10, 0x01, 0xAB, 0xE2, 0x02);
-
- public static readonly Guid CLSID_D2D1OpacityMetadata = new Guid(0x6C53006A, 0x4450, 0x4199, 0xAA, 0x5B, 0xAD, 0x16, 0x56, 0xFE, 0xCE, 0x5E);
-
- public static readonly Guid CLSID_D2D1PointDiffuse = new Guid(0xB9E303C3, 0xC08C, 0x4F91, 0x8B, 0x7B, 0x38, 0x65, 0x6B, 0xC4, 0x8C, 0x20);
-
- public static readonly Guid CLSID_D2D1PointSpecular = new Guid(0x09C3CA26, 0x3AE2, 0x4F09, 0x9E, 0xBC, 0xED, 0x38, 0x65, 0xD5, 0x3F, 0x22);
-
- public static readonly Guid CLSID_D2D1Premultiply = new Guid(0x06EAB419, 0xDEED, 0x4018, 0x80, 0xD2, 0x3E, 0x1D, 0x47, 0x1A, 0xDE, 0xB2);
-
- public static readonly Guid CLSID_D2D1Saturation = new Guid(0x5CB2D9CF, 0x327D, 0x459F, 0xA0, 0xCE, 0x40, 0xC0, 0xB2, 0x08, 0x6B, 0xF7);
-
- public static readonly Guid CLSID_D2D1Shadow = new Guid(0xC67EA361, 0x1863, 0x4E69, 0x89, 0xDB, 0x69, 0x5D, 0x3E, 0x9A, 0x5B, 0x6B);
-
- public static readonly Guid CLSID_D2D1SpotDiffuse = new Guid(0x818A1105, 0x7932, 0x44F4, 0xAA, 0x86, 0x08, 0xAE, 0x7B, 0x2F, 0x2C, 0x93);
-
- public static readonly Guid CLSID_D2D1SpotSpecular = new Guid(0xEDAE421E, 0x7654, 0x4A37, 0x9D, 0xB8, 0x71, 0xAC, 0xC1, 0xBE, 0xB3, 0xC1);
-
- public static readonly Guid CLSID_D2D1TableTransfer = new Guid(0x5BF818C3, 0x5E43, 0x48CB, 0xB6, 0x31, 0x86, 0x83, 0x96, 0xD6, 0xA1, 0xD4);
-
- public static readonly Guid CLSID_D2D1Tile = new Guid(0xB0784138, 0x3B76, 0x4BC5, 0xB1, 0x3B, 0x0F, 0xA2, 0xAD, 0x02, 0x65, 0x9F);
-
- public static readonly Guid CLSID_D2D1Turbulence = new Guid(0xCF2BB6AE, 0x889A, 0x4AD7, 0xBA, 0x29, 0xA2, 0xFD, 0x73, 0x2C, 0x9F, 0xC9);
-
- public static readonly Guid CLSID_D2D1UnPremultiply = new Guid(0xFB9AC489, 0xAD8D, 0x41ED, 0x99, 0x99, 0xBB, 0x63, 0x47, 0xD1, 0x10, 0xF7);
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/EffectBase.cs b/src/Windows/Avalonia.Win32/Composition/EffectBase.cs
deleted file mode 100644
index ca5b15971e..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/EffectBase.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using Windows.Graphics.Effects;
-using Windows.Graphics.Effects.Interop;
-
-
-namespace Avalonia.Win32
-{
- abstract class EffectBase : IGraphicsEffect, IGraphicsEffectSource, global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop
- {
- private IGraphicsEffectSource[] _sources;
-
- public EffectBase(params IGraphicsEffectSource[] sources)
- {
- _sources = sources;
- }
-
- private IGraphicsEffectSource _source;
-
- public virtual string Name { get; set; }
-
- public abstract Guid EffectId { get; }
-
- public abstract uint PropertyCount { get; }
-
- public uint SourceCount => (uint)_sources.Length;
-
- public IGraphicsEffectSource GetSource(uint index)
- {
- if(index < _sources.Length)
- {
- return _sources[index];
- }
-
- return null;
- }
-
- public uint GetNamedPropertyMapping(string name, out GRAPHICS_EFFECT_PROPERTY_MAPPING mapping)
- {
- throw new NotImplementedException();
- }
-
- public abstract object GetProperty(uint index);
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/GRAPHICS_EFFECT_PROPERTY_MAPPING.cs b/src/Windows/Avalonia.Win32/Composition/GRAPHICS_EFFECT_PROPERTY_MAPPING.cs
deleted file mode 100644
index f5d5fc4ad3..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/GRAPHICS_EFFECT_PROPERTY_MAPPING.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Windows.Graphics.Effects.Interop
-{
- public enum GRAPHICS_EFFECT_PROPERTY_MAPPING
- {
- GRAPHICS_EFFECT_PROPERTY_MAPPING_UNKNOWN,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORX,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORY,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORZ,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORW,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_RECT_TO_VECTOR4,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_RADIANS_TO_DEGREES,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_COLORMATRIX_ALPHA_MODE,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_COLOR_TO_VECTOR3,
- GRAPHICS_EFFECT_PROPERTY_MAPPING_COLOR_TO_VECTOR4
- };
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/GaussianBlurEffect.cs b/src/Windows/Avalonia.Win32/Composition/GaussianBlurEffect.cs
deleted file mode 100644
index 342e68eeb4..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/GaussianBlurEffect.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using Windows.Graphics.Effects;
-
-namespace Avalonia.Win32
-{
- class GaussianBlurEffect : EffectBase
- {
- public GaussianBlurEffect(IGraphicsEffectSource source) : base(source)
- {
- }
-
- enum D2D1_GAUSSIANBLUR_OPTIMIZATION
- {
- D2D1_GAUSSIANBLUR_OPTIMIZATION_SPEED,
- D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED,
- D2D1_GAUSSIANBLUR_OPTIMIZATION_QUALITY,
- D2D1_GAUSSIANBLUR_OPTIMIZATION_FORCE_DWORD
- };
-
- enum D2D1_BORDER_MODE
- {
- D2D1_BORDER_MODE_SOFT,
- D2D1_BORDER_MODE_HARD,
- D2D1_BORDER_MODE_FORCE_DWORD
- };
-
- enum D2D1GaussianBlurProp
- {
- D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION,
- D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION,
- D2D1_GAUSSIANBLUR_PROP_BORDER_MODE,
- D2D1_GAUSSIANBLUR_PROP_FORCE_DWORD
- };
-
- public override Guid EffectId => D2DEffects.CLSID_D2D1GaussianBlur;
-
- public override uint PropertyCount => 3;
-
- public override object GetProperty(uint index)
- {
- switch ((D2D1GaussianBlurProp)index)
- {
- case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION:
- return 30.0f;
-
- case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION:
- return (uint)D2D1_GAUSSIANBLUR_OPTIMIZATION.D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED;
-
- case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_BORDER_MODE:
- return (uint)D2D1_BORDER_MODE.D2D1_BORDER_MODE_HARD;
- }
-
- return null;
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/IBlurHost.cs b/src/Windows/Avalonia.Win32/Composition/IBlurHost.cs
deleted file mode 100644
index 6ab470d81c..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/IBlurHost.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Avalonia.Win32
-{
- internal interface IBlurHost
- {
- void SetBlur(bool enabled);
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/ICompositionDrawingSurfaceInterop.cs b/src/Windows/Avalonia.Win32/Composition/ICompositionDrawingSurfaceInterop.cs
deleted file mode 100644
index 2eac796376..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/ICompositionDrawingSurfaceInterop.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using WinRT;
-
-namespace Windows.UI.Composition.Interop
-{
- public struct POINT
- {
- public int X;
- public int Y;
- }
-
- public struct RECT
- {
- public int left;
- public int top;
- public int right;
- public int bottom;
-
- public int Width => right - left;
- public int Height => bottom - top;
- }
-
- [WindowsRuntimeType]
- [Guid("FD04E6E3-FE0C-4C3C-AB19-A07601A576EE")]
- public interface ICompositionDrawingSurfaceInterop
- {
- void BeginDraw(IntPtr updateRect, ref Guid iid, out IntPtr updateObject, ref POINT point);
-
- void EndDraw();
-
- void Resize(POINT sizePixels);
-
- void ResumeDraw();
-
- void Scroll(RECT scrollRect, RECT clipRect, int offsetX, int offsetY);
-
- void SuspendDraw();
- }
-}
-
-namespace ABI.Windows.UI.Composition.Interop
-{
- using global::System;
- using global::System.Runtime.InteropServices;
- using global::Windows.UI.Composition;
- using global::Windows.UI.Composition.Interop;
-
- [Guid("FD04E6E3-FE0C-4C3C-AB19-A07601A576EE")]
- internal class ICompositionDrawingSurfaceInterop : global::Windows.UI.Composition.Interop.ICompositionDrawingSurfaceInterop
-
- {
- [Guid("FD04E6E3-FE0C-4C3C-AB19-A07601A576EE")]
- public unsafe struct Vftbl
- {
- public delegate int _BeginDraw(IntPtr ThisPtr, IntPtr updateRect, ref Guid iid, out IntPtr updateObject, ref POINT updateOffset);
- public delegate int _EndDraw(IntPtr ThisPtr);
- public delegate int _Resize(IntPtr ThisPtr, POINT sizePixels);
- public delegate int _ResumeDraw(IntPtr ThisPtr);
- public delegate int _Scroll(IntPtr ThisPtr, RECT scrollRect, RECT clipRect, int offsetX, int offsetY);
- public delegate int _SuspendDraw(IntPtr ThisPtr);
-
- internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
- public _BeginDraw BeginDraw;
- public _EndDraw EndDraw;
- public _Resize Resize;
- public _ResumeDraw ResumeDraw;
- public _Scroll Scroll;
- public _SuspendDraw SuspendDraw;
-
- public static readonly Vftbl AbiToProjectionVftable;
- public static readonly IntPtr AbiToProjectionVftablePtr;
-
- static Vftbl()
- {
- AbiToProjectionVftable = new Vftbl
- {
- IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
-
- BeginDraw = Do_Abi_BeginDraw,
- EndDraw = Do_Abi_EndDraw,
- Resize = Do_Abi_Resize
-
-
- };
- AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
- }
-
- private static int Do_Abi_BeginDraw(IntPtr ThisPtr, IntPtr updateRect, ref Guid iid, out IntPtr updateObject, ref POINT updateOffset)
- {
- updateObject = IntPtr.Zero;
- return 0;
- }
-
- private static int Do_Abi_EndDraw(IntPtr ThisPtr)
- {
- return 0;
- }
-
- private static int Do_Abi_Resize(IntPtr ThisPtr, POINT sizePixels)
- {
- return 0;
- }
- }
- internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr);
-
- public static implicit operator ICompositionDrawingSurfaceInterop(IObjectReference obj) => (obj != null) ? new ICompositionDrawingSurfaceInterop(obj) : null;
- protected readonly ObjectReference _obj;
- public IObjectReference ObjRef { get => _obj; }
- public IntPtr ThisPtr => _obj.ThisPtr;
- public ObjectReference AsInterface() => _obj.As();
- public A As() => _obj.AsType();
-
- public ICompositionDrawingSurfaceInterop(IObjectReference obj) : this(obj.As()) { }
- internal ICompositionDrawingSurfaceInterop(ObjectReference obj)
- {
- _obj = obj;
- }
-
- public void BeginDraw(IntPtr updateRect, ref Guid iid, out IntPtr updateObject, ref POINT point)
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.BeginDraw(ThisPtr, updateRect, ref iid, out updateObject, ref point));
- }
-
- public void EndDraw()
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.EndDraw(ThisPtr));
- }
-
- public void Resize(POINT sizePixels)
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.Resize(ThisPtr, sizePixels));
- }
-
- public void ResumeDraw()
- {
- throw new NotImplementedException();
- }
-
- public void Scroll(RECT scrollRect, RECT clipRect, int offsetX, int offsetY)
- {
- throw new NotImplementedException();
- }
-
- public void SuspendDraw()
- {
- throw new NotImplementedException();
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop.cs b/src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop.cs
deleted file mode 100644
index 1d4cd3450f..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using WinRT;
-
-namespace Windows.UI.Composition.Desktop
-{
- [WindowsRuntimeType]
- [Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
- public interface ICompositorDesktopInterop
- {
- void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test);
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop1.cs b/src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop1.cs
deleted file mode 100644
index 1c3f06d679..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop1.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using WinRT;
-
-namespace ABI.Windows.UI.Composition.Desktop
-{
- using global::System;
- using global::System.Runtime.InteropServices;
-
- [Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
- internal class ICompositorDesktopInterop : global::Windows.UI.Composition.Desktop.ICompositorDesktopInterop
-
- {
- [Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
- public struct Vftbl
- {
- public delegate int _CreateDesktopWindowTarget(IntPtr thisPtr, IntPtr hwndTarget, byte isTopMost, out IntPtr desktopWindowTarget);
-
- internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
- public _CreateDesktopWindowTarget CreateDesktopWindowTarget;
-
-
- public static readonly Vftbl AbiToProjectionVftable;
- public static readonly IntPtr AbiToProjectionVftablePtr;
-
- static Vftbl()
- {
- AbiToProjectionVftable = new Vftbl
- {
- IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
- CreateDesktopWindowTarget = Do_Abi_Create_Desktop_Window_Target
- };
- AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
- }
-
- private static int Do_Abi_Create_Desktop_Window_Target(IntPtr thisPtr, IntPtr hwndTarget, byte isTopMost, out IntPtr desktopWindowTarget)
- {
- try
- {
- ComWrappersSupport.FindObject(thisPtr).CreateDesktopWindowTarget(hwndTarget, isTopMost != 0, out desktopWindowTarget);
- return 0;
- }
- catch (Exception ex)
- {
- desktopWindowTarget = IntPtr.Zero;
- return Marshal.GetHRForException(ex);
- }
- }
- }
- internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr);
-
- public static implicit operator ICompositorDesktopInterop(IObjectReference obj) => (obj != null) ? new ICompositorDesktopInterop(obj) : null;
- protected readonly ObjectReference _obj;
- public IObjectReference ObjRef { get => _obj; }
- public IntPtr ThisPtr => _obj.ThisPtr;
- public ObjectReference AsInterface() => _obj.As();
- public A As() => _obj.AsType();
- public ICompositorDesktopInterop(IObjectReference obj) : this(obj.As()) { }
- internal ICompositorDesktopInterop(ObjectReference obj)
- {
- _obj = obj;
- }
-
- public void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test)
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.CreateDesktopWindowTarget(ThisPtr, hwndTarget, isTopmost ? (byte)1 : (byte)0, out test));
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/ICompositorInterop.cs b/src/Windows/Avalonia.Win32/Composition/ICompositorInterop.cs
deleted file mode 100644
index d9b25e497e..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/ICompositorInterop.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using WinRT;
-
-namespace Windows.UI.Composition.Interop
-{
- [WindowsRuntimeType]
- [Guid("25297D5C-3AD4-4C9C-B5CF-E36A38512330")]
- public interface ICompositorInterop
- {
- ICompositionSurface CreateCompositionSurfaceForHandle(IntPtr swapChain);
-
- ICompositionSurface CreateCompositionSurfaceForSwapChain(IntPtr swapChain);
-
- CompositionGraphicsDevice CreateGraphicsDevice(IntPtr renderingDevice);
- }
-}
-
-namespace ABI.Windows.UI.Composition.Interop
-{
- using global::System;
- using global::System.Runtime.InteropServices;
- using global::Windows.UI.Composition;
-
- [Guid("25297D5C-3AD4-4C9C-B5CF-E36A38512330")]
- internal class ICompositorInterop : global::Windows.UI.Composition.Interop.ICompositorInterop
-
- {
- [Guid("25297D5C-3AD4-4C9C-B5CF-E36A38512330")]
- public struct Vftbl
- {
- public delegate int _CreateCompositionSurfaceForHandle(IntPtr ThisPtr, IntPtr swapChain, out IntPtr result);
- public delegate int _CreateCompositionSurfaceForSwapChain(IntPtr ThisPtr, IntPtr swapChain, out IntPtr result);
- public delegate int _CreateGraphicsDevice(IntPtr ThisPtr, IntPtr renderingDevice, out IntPtr result);
-
- internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
- public _CreateCompositionSurfaceForHandle CreateCompositionSurfaceForHandle;
- public _CreateCompositionSurfaceForSwapChain CreateCompositionSurfaceForSwapChain;
- public _CreateGraphicsDevice CreateGraphicsDevice;
-
-
- public static readonly Vftbl AbiToProjectionVftable;
- public static readonly IntPtr AbiToProjectionVftablePtr;
-
- static Vftbl()
- {
- AbiToProjectionVftable = new Vftbl
- {
- IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
-
- CreateCompositionSurfaceForHandle = Do_Abi_Create_Composition_Surface_For_Handle,
- CreateCompositionSurfaceForSwapChain = Do_Abi_Create_Composition_Surface_For_SwapChain,
- CreateGraphicsDevice= Do_Abi_Create_Graphics_Device
- };
- AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
- }
-
- private static int Do_Abi_Create_Composition_Surface_For_Handle(IntPtr thisPtr, IntPtr swapChain, out IntPtr surface)
- {
- try
- {
- surface = IntPtr.Zero;
- //surface = ComWrappersSupport.FindObject(thisPtr).CreateCompositionSurfaceForHandle(swapChain);
- return 0;
- }
- catch (Exception ex)
- {
- surface = IntPtr.Zero;
- return Marshal.GetHRForException(ex);
- }
- }
-
- private static int Do_Abi_Create_Composition_Surface_For_SwapChain(IntPtr thisPtr, IntPtr swapChain, out IntPtr surface)
- {
- try
- {
- surface = IntPtr.Zero;
- //surface = ComWrappersSupport.FindObject(thisPtr).CreateCompositionSurfaceForSwapChain(swapChain);
- return 0;
- }
- catch (Exception ex)
- {
- surface = IntPtr.Zero;
- return Marshal.GetHRForException(ex);
- }
- }
-
- private static int Do_Abi_Create_Graphics_Device(IntPtr thisPtr, IntPtr renderingDevice, out IntPtr graphicsDevice)
- {
- try
- {
- graphicsDevice = ComWrappersSupport.FindObject(thisPtr).CreateGraphicsDevice(renderingDevice).ThisPtr;
- return 0;
- }
- catch (Exception ex)
- {
- graphicsDevice = IntPtr.Zero;
- return Marshal.GetHRForException(ex);
- }
- }
- }
- internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr);
-
- public static implicit operator ICompositorInterop(IObjectReference obj) => (obj != null) ? new ICompositorInterop(obj) : null;
- protected readonly ObjectReference _obj;
- public IObjectReference ObjRef { get => _obj; }
- public IntPtr ThisPtr => _obj.ThisPtr;
- public ObjectReference AsInterface() => _obj.As();
- public A As() => _obj.AsType();
- public ICompositorInterop(IObjectReference obj) : this(obj.As()) { }
- internal ICompositorInterop(ObjectReference obj)
- {
- _obj = obj;
- }
-
- public ICompositionSurface CreateCompositionSurfaceForHandle(IntPtr swapChain)
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.CreateCompositionSurfaceForHandle(ThisPtr, swapChain, out var compositionSurface));
-
- return null;
- }
-
- public ICompositionSurface CreateCompositionSurfaceForSwapChain(IntPtr swapChain)
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.CreateCompositionSurfaceForSwapChain(ThisPtr, swapChain, out var compositionSurface));
-
- return null;
- }
-
- public CompositionGraphicsDevice CreateGraphicsDevice(IntPtr renderingDevice)
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.CreateGraphicsDevice(ThisPtr, renderingDevice, out var graphicsDevice));
-
- return CompositionGraphicsDevice.FromAbi(graphicsDevice);
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop.cs b/src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop.cs
deleted file mode 100644
index 74d3939a98..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using WinRT;
-
-namespace Windows.Graphics.Effects.Interop
-{
- [WindowsRuntimeType]
- [Guid("2FC57384-A068-44D7-A331-30982FCF7177")]
- public interface IGraphicsEffectD2D1Interop
- {
- Guid EffectId { get; }
-
- uint GetNamedPropertyMapping(string name, out GRAPHICS_EFFECT_PROPERTY_MAPPING mapping);
-
- object GetProperty(uint index);
-
- uint PropertyCount { get; }
-
- IGraphicsEffectSource GetSource(uint index);
-
- uint SourceCount { get; }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop1.cs b/src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop1.cs
deleted file mode 100644
index 8466b05fb5..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop1.cs
+++ /dev/null
@@ -1,217 +0,0 @@
-using WinRT;
-
-namespace ABI.Windows.Graphics.Effects.Interop
-{
- using global::System;
- using global::System.Runtime.InteropServices;
-
- [Guid("2FC57384-A068-44D7-A331-30982FCF7177")]
- internal class IGraphicsEffectD2D1Interop : global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop
-
- {
- [Guid("2FC57384-A068-44D7-A331-30982FCF7177")]
- public struct Vftbl
- {
- public delegate int _GetEffectId(IntPtr thisPtr, out Guid guid);
- public delegate int _GetNamedPropertyMapping(IntPtr thisPtr, IntPtr name, IntPtr index, IntPtr mapping);
- public delegate int _GetProperty(IntPtr thisPtr, uint index, out IntPtr value);
- public unsafe delegate int _GetPropertyCount(IntPtr thisPtr, uint* count);
- public delegate int _GetSource(IntPtr thisPtr, uint index, out IntPtr source);
- public delegate int _GetSourceCount(IntPtr thisPtr, out uint count);
-
- internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
- public _GetEffectId GetEffectId;
- public _GetNamedPropertyMapping GetNamedPropertyMapping;
- public _GetPropertyCount GetPropertyCount;
- public _GetProperty GetProperty;
- public _GetSource GetSource;
- public _GetSourceCount GetSourceCount;
-
- public static readonly Vftbl AbiToProjectionVftable;
- public static readonly IntPtr AbiToProjectionVftablePtr;
-
- unsafe static Vftbl()
- {
- AbiToProjectionVftable = new Vftbl
- {
- IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
- GetEffectId = Do_Abi_Get_Effect_Id,
- GetNamedPropertyMapping = Do_Abi_Get_Property_Mapping,
- GetPropertyCount = Do_Abi_Get_Property_Count,
- GetProperty = Do_Abi_Get_Property,
- GetSource = Do_Abi_Get_Source,
- GetSourceCount = Do_Abi_Get_Source_Count
-
- };
- AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
- }
-
- private static int Do_Abi_Get_Effect_Id(IntPtr thisPtr, out Guid guid)
- {
- guid = default;
-
- try
- {
- guid = ComWrappersSupport.FindObject(thisPtr).EffectId;
- }
- catch (Exception ex)
- {
- return Marshal.GetHRForException(ex);
- }
-
- return 0;
- }
-
- private static int Do_Abi_Get_Property_Mapping(IntPtr thisPtr, IntPtr name, IntPtr index, IntPtr mapping)
- {
- try
- {
- ComWrappersSupport.FindObject(thisPtr).GetNamedPropertyMapping(MarshalString.FromAbi(name), out var mappingResult);
- }
- catch (Exception ex)
- {
- return Marshal.GetHRForException(ex);
- }
-
- return 0;
- }
-
- private static int Do_Abi_Get_Property(IntPtr thisPtr, uint index, out IntPtr value)
- {
- value = default;
-
- try
- {
- value = MarshalInspectable.CreateMarshaler(
- ComWrappersSupport.FindObject(thisPtr).GetProperty(index))
- .As(Guid.Parse("4BD682DD-7554-40E9-9A9B-82654EDE7E62"))
- .GetRef();
-
- }
- catch (Exception ex)
- {
- return Marshal.GetHRForException(ex);
- }
-
- return 0;
- }
-
- unsafe private static int Do_Abi_Get_Property_Count(IntPtr thisPtr, uint* count)
- {
-
- try
- {
- var res = ComWrappersSupport.FindObject(thisPtr).PropertyCount;
-
- if (count != null)
- {
- *count = res;
- }
- }
- catch (Exception ex)
- {
- return Marshal.GetHRForException(ex);
- }
-
- return 0;
- }
-
- private static int Do_Abi_Get_Source(IntPtr thisPtr, uint index, out IntPtr value)
- {
- value = default;
-
- try
- {
- var source = ComWrappersSupport.FindObject(thisPtr).GetSource(index);
-
- value = MarshalInterface.FromManaged(source);
- }
- catch (Exception ex)
- {
- return Marshal.GetHRForException(ex);
- }
-
- return 0;
- }
-
- private static int Do_Abi_Get_Source_Count(IntPtr thisPtr, out uint count)
- {
- count = default;
-
- try
- {
- count = ComWrappersSupport.FindObject(thisPtr).SourceCount;
- }
- catch (Exception ex)
- {
- return Marshal.GetHRForException(ex);
- }
-
- return 0;
- }
- }
- internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr);
-
- public static implicit operator IGraphicsEffectD2D1Interop(IObjectReference obj) => (obj != null) ? new IGraphicsEffectD2D1Interop(obj) : null;
- protected readonly ObjectReference _obj;
- public IObjectReference ObjRef { get => _obj; }
- public IntPtr ThisPtr => _obj.ThisPtr;
-
- public ObjectReference AsInterface() => _obj.As();
- public A As() => _obj.AsType();
- public IGraphicsEffectD2D1Interop(IObjectReference obj) : this(obj.As()) { }
- internal IGraphicsEffectD2D1Interop(ObjectReference obj)
- {
- _obj = obj;
- }
-
- public Guid EffectId
- {
- get
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.GetEffectId(ThisPtr, out Guid guid));
- return guid;
- }
- }
-
- public uint PropertyCount
- {
- get
- {
- unsafe
- {
- uint count = default;
- Marshal.ThrowExceptionForHR(_obj.Vftbl.GetPropertyCount(ThisPtr, &count));
- return count;
- }
- }
- }
-
- public uint SourceCount
- {
- get
- {
- Marshal.ThrowExceptionForHR(_obj.Vftbl.GetSourceCount(ThisPtr, out uint count));
- return count;
- }
- }
-
- public uint GetNamedPropertyMapping(string name, out global::Windows.Graphics.Effects.Interop.GRAPHICS_EFFECT_PROPERTY_MAPPING mapping)
- {
- throw new NotImplementedException();
- }
-
- public object GetProperty(uint index)
- {
- // Marshal.ThrowExceptionForHR(_obj.Vftbl.GetProperty(ThisPtr, index, out IntPtr value));
- throw new NotImplementedException();
- }
-
- public global::Windows.Graphics.Effects.IGraphicsEffectSource GetSource(uint index)
- {
- throw new NotImplementedException();
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Composition/SaturationEffect.cs b/src/Windows/Avalonia.Win32/Composition/SaturationEffect.cs
deleted file mode 100644
index 3495829f3a..0000000000
--- a/src/Windows/Avalonia.Win32/Composition/SaturationEffect.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-using Windows.Graphics.Effects;
-
-
-namespace Avalonia.Win32
-{
- class SaturationEffect : EffectBase
- {
- public SaturationEffect(IGraphicsEffectSource source) : base(source)
- {
- }
-
- enum D2D1_SATURATION_PROP
- {
- D2D1_SATURATION_PROP_SATURATION,
- D2D1_SATURATION_PROP_FORCE_DWORD
- };
-
- public override Guid EffectId => D2DEffects.CLSID_D2D1Saturation;
-
- public override uint PropertyCount => 1;
-
- public override object GetProperty(uint index)
- {
- switch ((D2D1_SATURATION_PROP)index)
- {
- case D2D1_SATURATION_PROP.D2D1_SATURATION_PROP_SATURATION:
- return 2.0f;
- }
-
- return null;
- }
- }
-}
-
diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index b164bcc611..b21741453c 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -1225,6 +1225,9 @@ namespace Avalonia.Win32.Interop
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string fileName);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr LoadLibraryEx(string fileName, IntPtr hFile, int flags);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
@@ -1382,6 +1385,9 @@ namespace Avalonia.Win32.Interop
[DllImport("dwmapi.dll")]
public static extern int DwmIsCompositionEnabled(out bool enabled);
+ [DllImport("dwmapi.dll")]
+ public static extern void DwmFlush();
+
[DllImport("dwmapi.dll")]
public static extern bool DwmDefWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref IntPtr plResult);
@@ -1613,6 +1619,12 @@ namespace Avalonia.Win32.Interop
public int X;
public int Y;
}
+
+ public struct SIZE
+ {
+ public int X;
+ public int Y;
+ }
public struct RECT
{
diff --git a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs
new file mode 100644
index 0000000000..5577664cc4
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Runtime.ConstrainedExecution;
+using System.Threading;
+using Avalonia.Threading;
+using Avalonia.Utilities;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+ internal class NonPumpingSyncContext : SynchronizationContext, IDisposable
+ {
+ private readonly SynchronizationContext _inner;
+
+ private NonPumpingSyncContext(SynchronizationContext inner)
+ {
+ _inner = inner;
+ SetWaitNotificationRequired();
+ SetSynchronizationContext(this);
+ }
+
+ public override void Post(SendOrPostCallback d, object state) => _inner.Post(d, state);
+ public override void Send(SendOrPostCallback d, object state) => _inner.Send(d, state);
+
+ [PrePrepareMethod]
+ public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
+ {
+ return UnmanagedMethods.WaitForMultipleObjectsEx(waitHandles.Length, waitHandles, waitAll,
+ millisecondsTimeout, false);
+ }
+
+ public void Dispose() => SetSynchronizationContext(_inner);
+
+ public static IDisposable Use()
+ {
+ var current = Current;
+ if (current == null)
+ {
+ if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
+ return null;
+ }
+ if (current is NonPumpingSyncContext)
+ return null;
+
+ return new NonPumpingSyncContext(current);
+ }
+
+ internal class HelperImpl : NonPumpingLockHelper.IHelperImpl
+ {
+ IDisposable NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use();
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs b/src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs
deleted file mode 100644
index a0160fcfbd..0000000000
--- a/src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using Avalonia.Threading;
-using Avalonia.Win32.Interop;
-
-namespace Avalonia.Win32
-{
- internal class NonPumpingWaitProvider : AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider
- {
- public int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
- {
- return UnmanagedMethods.WaitForMultipleObjectsEx(waitHandles.Length, waitHandles, waitAll,
- millisecondsTimeout, false);
- }
- }
-}
diff --git a/src/Windows/Avalonia.Win32/PopupImpl.cs b/src/Windows/Avalonia.Win32/PopupImpl.cs
index 7fb146899b..dd3fd1342c 100644
--- a/src/Windows/Avalonia.Win32/PopupImpl.cs
+++ b/src/Windows/Avalonia.Win32/PopupImpl.cs
@@ -17,8 +17,9 @@ namespace Avalonia.Win32
[ThreadStatic]
private static IntPtr s_parentHandle;
- public override void Show()
+ public override void Show(bool activate)
{
+ // Popups are always shown non-activated.
UnmanagedMethods.ShowWindow(Handle.Handle, UnmanagedMethods.ShowWindowCommand.ShowNoActivate);
// We need to steal focus if it's held by a child window of our toplevel window
diff --git a/src/Windows/Avalonia.Win32/Win32GlManager.cs b/src/Windows/Avalonia.Win32/Win32GlManager.cs
index 4363b5fd29..b51f80e397 100644
--- a/src/Windows/Avalonia.Win32/Win32GlManager.cs
+++ b/src/Windows/Avalonia.Win32/Win32GlManager.cs
@@ -3,6 +3,7 @@ using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.Win32.OpenGl;
+using Avalonia.Win32.WinRT.Composition;
namespace Avalonia.Win32
{
@@ -24,13 +25,8 @@ namespace Avalonia.Win32
var egl = EglPlatformOpenGlInterface.TryCreate(() => new AngleWin32EglDisplay());
if (egl is { } &&
- opts?.UseWindowsUIComposition == true)
- {
- var compositionConnector = CompositionConnector.TryCreate(egl);
-
- if (compositionConnector != null)
- AvaloniaLocator.CurrentMutable.BindToSelf(compositionConnector);
- }
+ opts?.UseWindowsUIComposition == true)
+ WinUICompositorConnection.TryCreateAndRegister(egl);
return egl;
}
diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs
index e854ceae0b..97eb0c6119 100644
--- a/src/Windows/Avalonia.Win32/Win32Platform.cs
+++ b/src/Windows/Avalonia.Win32/Win32Platform.cs
@@ -16,6 +16,7 @@ using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
+using Avalonia.Utilities;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
@@ -110,7 +111,7 @@ namespace Avalonia.Win32
.Bind().ToConstant(s_instance)
.Bind().ToSingleton()
.Bind().ToConstant(s_instance)
- .Bind().ToConstant(new NonPumpingWaitProvider())
+ .Bind().ToConstant(new NonPumpingSyncContext.HelperImpl())
.Bind().ToConstant(new WindowsMountedVolumeInfoProvider());
Win32GlManager.Initialize();
@@ -242,7 +243,7 @@ namespace Avalonia.Win32
public IWindowImpl CreateEmbeddableWindow()
{
var embedded = new EmbeddedWindowImpl();
- embedded.Show();
+ embedded.Show(true);
return embedded;
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
new file mode 100644
index 0000000000..bef5a55b06
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
@@ -0,0 +1,130 @@
+using System;
+
+namespace Avalonia.Win32.WinRT.Composition
+{
+ class D2DEffects
+ {
+ public static readonly Guid CLSID_D2D12DAffineTransform =
+ new Guid(0x6AA97485, 0x6354, 0x4CFC, 0x90, 0x8C, 0xE4, 0xA7, 0x4F, 0x62, 0xC9, 0x6C);
+
+ public static readonly Guid CLSID_D2D13DPerspectiveTransform =
+ new Guid(0xC2844D0B, 0x3D86, 0x46E7, 0x85, 0xBA, 0x52, 0x6C, 0x92, 0x40, 0xF3, 0xFB);
+
+ public static readonly Guid CLSID_D2D13DTransform =
+ new Guid(0xE8467B04, 0xEC61, 0x4B8A, 0xB5, 0xDE, 0xD4, 0xD7, 0x3D, 0xEB, 0xEA, 0x5A);
+
+ public static readonly Guid CLSID_D2D1ArithmeticComposite =
+ new Guid(0xFC151437, 0x049A, 0x4784, 0xA2, 0x4A, 0xF1, 0xC4, 0xDA, 0xF2, 0x09, 0x87);
+
+ public static readonly Guid CLSID_D2D1Atlas =
+ new Guid(0x913E2BE4, 0xFDCF, 0x4FE2, 0xA5, 0xF0, 0x24, 0x54, 0xF1, 0x4F, 0xF4, 0x08);
+
+ public static readonly Guid CLSID_D2D1BitmapSource =
+ new Guid(0x5FB6C24D, 0xC6DD, 0x4231, 0x94, 0x4, 0x50, 0xF4, 0xD5, 0xC3, 0x25, 0x2D);
+
+ public static readonly Guid CLSID_D2D1Blend =
+ new Guid(0x81C5B77B, 0x13F8, 0x4CDD, 0xAD, 0x20, 0xC8, 0x90, 0x54, 0x7A, 0xC6, 0x5D);
+
+ public static readonly Guid CLSID_D2D1Border =
+ new Guid(0x2A2D49C0, 0x4ACF, 0x43C7, 0x8C, 0x6A, 0x7C, 0x4A, 0x27, 0x87, 0x4D, 0x27);
+
+ public static readonly Guid CLSID_D2D1Brightness =
+ new Guid(0x8CEA8D1E, 0x77B0, 0x4986, 0xB3, 0xB9, 0x2F, 0x0C, 0x0E, 0xAE, 0x78, 0x87);
+
+ public static readonly Guid CLSID_D2D1ColorManagement =
+ new Guid(0x1A28524C, 0xFDD6, 0x4AA4, 0xAE, 0x8F, 0x83, 0x7E, 0xB8, 0x26, 0x7B, 0x37);
+
+ public static readonly Guid CLSID_D2D1ColorMatrix =
+ new Guid(0x921F03D6, 0x641C, 0x47DF, 0x85, 0x2D, 0xB4, 0xBB, 0x61, 0x53, 0xAE, 0x11);
+
+ public static readonly Guid CLSID_D2D1Composite =
+ new Guid(0x48FC9F51, 0xF6AC, 0x48F1, 0x8B, 0x58, 0x3B, 0x28, 0xAC, 0x46, 0xF7, 0x6D);
+
+ public static readonly Guid CLSID_D2D1ConvolveMatrix =
+ new Guid(0x407F8C08, 0x5533, 0x4331, 0xA3, 0x41, 0x23, 0xCC, 0x38, 0x77, 0x84, 0x3E);
+
+ public static readonly Guid CLSID_D2D1Crop =
+ new Guid(0xE23F7110, 0x0E9A, 0x4324, 0xAF, 0x47, 0x6A, 0x2C, 0x0C, 0x46, 0xF3, 0x5B);
+
+ public static readonly Guid CLSID_D2D1DirectionalBlur =
+ new Guid(0x174319A6, 0x58E9, 0x49B2, 0xBB, 0x63, 0xCA, 0xF2, 0xC8, 0x11, 0xA3, 0xDB);
+
+ public static readonly Guid CLSID_D2D1DiscreteTransfer =
+ new Guid(0x90866FCD, 0x488E, 0x454B, 0xAF, 0x06, 0xE5, 0x04, 0x1B, 0x66, 0xC3, 0x6C);
+
+ public static readonly Guid CLSID_D2D1DisplacementMap =
+ new Guid(0xEDC48364, 0x417, 0x4111, 0x94, 0x50, 0x43, 0x84, 0x5F, 0xA9, 0xF8, 0x90);
+
+ public static readonly Guid CLSID_D2D1DistantDiffuse =
+ new Guid(0x3E7EFD62, 0xA32D, 0x46D4, 0xA8, 0x3C, 0x52, 0x78, 0x88, 0x9A, 0xC9, 0x54);
+
+ public static readonly Guid CLSID_D2D1DistantSpecular =
+ new Guid(0x428C1EE5, 0x77B8, 0x4450, 0x8A, 0xB5, 0x72, 0x21, 0x9C, 0x21, 0xAB, 0xDA);
+
+ public static readonly Guid CLSID_D2D1DpiCompensation =
+ new Guid(0x6C26C5C7, 0x34E0, 0x46FC, 0x9C, 0xFD, 0xE5, 0x82, 0x37, 0x6, 0xE2, 0x28);
+
+ public static readonly Guid CLSID_D2D1Flood =
+ new Guid(0x61C23C20, 0xAE69, 0x4D8E, 0x94, 0xCF, 0x50, 0x07, 0x8D, 0xF6, 0x38, 0xF2);
+
+ public static readonly Guid CLSID_D2D1GammaTransfer =
+ new Guid(0x409444C4, 0xC419, 0x41A0, 0xB0, 0xC1, 0x8C, 0xD0, 0xC0, 0xA1, 0x8E, 0x42);
+
+ public static readonly Guid CLSID_D2D1GaussianBlur =
+ new Guid(0x1FEB6D69, 0x2FE6, 0x4AC9, 0x8C, 0x58, 0x1D, 0x7F, 0x93, 0xE7, 0xA6, 0xA5);
+
+ public static readonly Guid CLSID_D2D1Scale =
+ new Guid(0x9DAF9369, 0x3846, 0x4D0E, 0xA4, 0x4E, 0xC, 0x60, 0x79, 0x34, 0xA5, 0xD7);
+
+ public static readonly Guid CLSID_D2D1Histogram =
+ new Guid(0x881DB7D0, 0xF7EE, 0x4D4D, 0xA6, 0xD2, 0x46, 0x97, 0xAC, 0xC6, 0x6E, 0xE8);
+
+ public static readonly Guid CLSID_D2D1HueRotation =
+ new Guid(0x0F4458EC, 0x4B32, 0x491B, 0x9E, 0x85, 0xBD, 0x73, 0xF4, 0x4D, 0x3E, 0xB6);
+
+ public static readonly Guid CLSID_D2D1LinearTransfer =
+ new Guid(0xAD47C8FD, 0x63EF, 0x4ACC, 0x9B, 0x51, 0x67, 0x97, 0x9C, 0x03, 0x6C, 0x06);
+
+ public static readonly Guid CLSID_D2D1LuminanceToAlpha =
+ new Guid(0x41251AB7, 0x0BEB, 0x46F8, 0x9D, 0xA7, 0x59, 0xE9, 0x3F, 0xCC, 0xE5, 0xDE);
+
+ public static readonly Guid CLSID_D2D1Morphology =
+ new Guid(0xEAE6C40D, 0x626A, 0x4C2D, 0xBF, 0xCB, 0x39, 0x10, 0x01, 0xAB, 0xE2, 0x02);
+
+ public static readonly Guid CLSID_D2D1OpacityMetadata =
+ new Guid(0x6C53006A, 0x4450, 0x4199, 0xAA, 0x5B, 0xAD, 0x16, 0x56, 0xFE, 0xCE, 0x5E);
+
+ public static readonly Guid CLSID_D2D1PointDiffuse =
+ new Guid(0xB9E303C3, 0xC08C, 0x4F91, 0x8B, 0x7B, 0x38, 0x65, 0x6B, 0xC4, 0x8C, 0x20);
+
+ public static readonly Guid CLSID_D2D1PointSpecular =
+ new Guid(0x09C3CA26, 0x3AE2, 0x4F09, 0x9E, 0xBC, 0xED, 0x38, 0x65, 0xD5, 0x3F, 0x22);
+
+ public static readonly Guid CLSID_D2D1Premultiply =
+ new Guid(0x06EAB419, 0xDEED, 0x4018, 0x80, 0xD2, 0x3E, 0x1D, 0x47, 0x1A, 0xDE, 0xB2);
+
+ public static readonly Guid CLSID_D2D1Saturation =
+ new Guid(0x5CB2D9CF, 0x327D, 0x459F, 0xA0, 0xCE, 0x40, 0xC0, 0xB2, 0x08, 0x6B, 0xF7);
+
+ public static readonly Guid CLSID_D2D1Shadow =
+ new Guid(0xC67EA361, 0x1863, 0x4E69, 0x89, 0xDB, 0x69, 0x5D, 0x3E, 0x9A, 0x5B, 0x6B);
+
+ public static readonly Guid CLSID_D2D1SpotDiffuse =
+ new Guid(0x818A1105, 0x7932, 0x44F4, 0xAA, 0x86, 0x08, 0xAE, 0x7B, 0x2F, 0x2C, 0x93);
+
+ public static readonly Guid CLSID_D2D1SpotSpecular =
+ new Guid(0xEDAE421E, 0x7654, 0x4A37, 0x9D, 0xB8, 0x71, 0xAC, 0xC1, 0xBE, 0xB3, 0xC1);
+
+ public static readonly Guid CLSID_D2D1TableTransfer =
+ new Guid(0x5BF818C3, 0x5E43, 0x48CB, 0xB6, 0x31, 0x86, 0x83, 0x96, 0xD6, 0xA1, 0xD4);
+
+ public static readonly Guid CLSID_D2D1Tile =
+ new Guid(0xB0784138, 0x3B76, 0x4BC5, 0xB1, 0x3B, 0x0F, 0xA2, 0xAD, 0x02, 0x65, 0x9F);
+
+ public static readonly Guid CLSID_D2D1Turbulence =
+ new Guid(0xCF2BB6AE, 0x889A, 0x4AD7, 0xBA, 0x29, 0xA2, 0xFD, 0x73, 0x2C, 0x9F, 0xC9);
+
+ public static readonly Guid CLSID_D2D1UnPremultiply =
+ new Guid(0xFB9AC489, 0xAD8D, 0x41ED, 0x99, 0x99, 0xBB, 0x63, 0x47, 0xD1, 0x10, 0xF7);
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs
new file mode 100644
index 0000000000..4ae9c08410
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Numerics;
+using System.Reactive.Disposables;
+using System.Threading;
+using Avalonia.MicroCom;
+using Avalonia.OpenGL;
+using Avalonia.OpenGL.Egl;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32.WinRT.Composition
+{
+ public class WinUICompositedWindow : IDisposable
+ {
+ private EglContext _syncContext;
+ private readonly object _pumpLock;
+ private readonly IVisual _blurVisual;
+ private ICompositionTarget _compositionTarget;
+ private IVisual _contentVisual;
+ private ICompositionDrawingSurfaceInterop _surfaceInterop;
+ private PixelSize _size;
+
+ private static Guid IID_ID3D11Texture2D = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
+ private ICompositor _compositor;
+
+
+ internal WinUICompositedWindow(EglContext syncContext,
+ ICompositor compositor,
+ object pumpLock,
+ ICompositionTarget compositionTarget,
+ ICompositionDrawingSurfaceInterop surfaceInterop,
+ IVisual contentVisual, IVisual blurVisual)
+ {
+ _compositor = compositor.CloneReference();
+ _syncContext = syncContext;
+ _pumpLock = pumpLock;
+ _blurVisual = blurVisual.CloneReference();
+ _compositionTarget = compositionTarget.CloneReference();
+ _contentVisual = contentVisual.CloneReference();
+ _surfaceInterop = surfaceInterop.CloneReference();
+ }
+
+
+ public void ResizeIfNeeded(PixelSize size)
+ {
+ using (_syncContext.EnsureLocked())
+ {
+ if (_size != size)
+ {
+ _surfaceInterop.Resize(new UnmanagedMethods.POINT { X = size.Width, Y = size.Height });
+ _contentVisual.SetSize(new Vector2(size.Width, size.Height));
+ _size = size;
+ }
+ }
+ }
+
+ public unsafe IUnknown BeginDrawToTexture(out PixelPoint offset)
+ {
+ if (!_syncContext.IsCurrent)
+ throw new InvalidOperationException();
+
+ var iid = IID_ID3D11Texture2D;
+ void* pTexture;
+ var off = _surfaceInterop.BeginDraw(null, &iid, &pTexture);
+ offset = new PixelPoint(off.X, off.Y);
+ return MicroComRuntime.CreateProxyFor(pTexture, true);
+ }
+
+ public void EndDraw()
+ {
+ if (!_syncContext.IsCurrent)
+ throw new InvalidOperationException();
+ _surfaceInterop.EndDraw();
+ }
+
+ public void SetBlur(bool enable)
+ {
+ using (_syncContext.EnsureLocked())
+ _blurVisual.SetIsVisible(enable ? 1 : 0);
+ }
+
+ public IDisposable BeginTransaction()
+ {
+ Monitor.Enter(_pumpLock);
+ return Disposable.Create(() => Monitor.Exit(_pumpLock));
+ }
+
+ public void Dispose()
+ {
+ if (_syncContext == null)
+ {
+ _compositor.Dispose();
+ _blurVisual.Dispose();
+ _contentVisual.Dispose();
+ _surfaceInterop.Dispose();
+ _compositionTarget.Dispose();
+ }
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs
new file mode 100644
index 0000000000..2aa82436f6
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs
@@ -0,0 +1,238 @@
+using System;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Logging;
+using Avalonia.MicroCom;
+using Avalonia.OpenGL;
+using Avalonia.OpenGL.Angle;
+using Avalonia.OpenGL.Egl;
+using Avalonia.Rendering;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32.WinRT.Composition
+{
+ class WinUICompositorConnection : IRenderTimer
+ {
+ private readonly EglContext _syncContext;
+ private IntPtr _queue;
+ private ICompositor _compositor;
+ private ICompositor2 _compositor2;
+ private ICompositor5 _compositor5;
+ private ICompositorInterop _compositorInterop;
+ private AngleWin32EglDisplay _angle;
+ private ICompositionGraphicsDevice _device;
+ private EglPlatformOpenGlInterface _gl;
+ private ICompositorDesktopInterop _compositorDesktopInterop;
+ private ICompositionBrush _blurBrush;
+ private object _pumpLock = new object();
+
+ public WinUICompositorConnection(EglPlatformOpenGlInterface gl, object pumpLock)
+ {
+ _gl = gl;
+ _pumpLock = pumpLock;
+ _syncContext = _gl.PrimaryEglContext;
+ _angle = (AngleWin32EglDisplay)_gl.Display;
+ _compositor = NativeWinRTMethods.CreateInstance("Windows.UI.Composition.Compositor");
+ _compositor2 = _compositor.QueryInterface();
+ _compositor5 = _compositor.QueryInterface();
+ _compositorInterop = _compositor.QueryInterface();
+ _compositorDesktopInterop = _compositor.QueryInterface();
+ using var device = MicroComRuntime.CreateProxyFor(_angle.GetDirect3DDevice(), true);
+
+ _device = _compositorInterop.CreateGraphicsDevice(device);
+ _blurBrush = CreateBlurBrush();
+
+ }
+
+ public EglPlatformOpenGlInterface Egl => _gl;
+
+ static bool TryCreateAndRegisterCore(EglPlatformOpenGlInterface angle)
+ {
+ var tcs = new TaskCompletionSource();
+ var pumpLock = new object();
+ var th = new Thread(() =>
+ {
+ WinUICompositorConnection connect;
+ try
+ {
+ NativeWinRTMethods.CreateDispatcherQueueController(new NativeWinRTMethods.DispatcherQueueOptions
+ {
+ apartmentType = NativeWinRTMethods.DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_NONE,
+ dwSize = Marshal.SizeOf(),
+ threadType = NativeWinRTMethods.DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT
+ });
+ connect = new WinUICompositorConnection(angle, pumpLock);
+ AvaloniaLocator.CurrentMutable.BindToSelf(connect);
+ AvaloniaLocator.CurrentMutable.Bind().ToConstant(connect);
+ tcs.SetResult(true);
+
+ }
+ catch (Exception e)
+ {
+ tcs.SetException(e);
+ return;
+ }
+ connect.RunLoop();
+ })
+ {
+ IsBackground = true
+ };
+ th.SetApartmentState(ApartmentState.STA);
+ th.Start();
+ return tcs.Task.Result;
+ }
+
+ class RunLoopHandler : IAsyncActionCompletedHandler, IMicroComShadowContainer
+ {
+ private readonly WinUICompositorConnection _parent;
+ private Stopwatch _st = Stopwatch.StartNew();
+
+ public RunLoopHandler(WinUICompositorConnection parent)
+ {
+ _parent = parent;
+ }
+ public void Dispose()
+ {
+
+ }
+
+ public void Invoke(IAsyncAction asyncInfo, AsyncStatus asyncStatus)
+ {
+ _parent.Tick?.Invoke(_st.Elapsed);
+ using var act = _parent._compositor5.RequestCommitAsync();
+ act.SetCompleted(this);
+ }
+
+ public MicroComShadow Shadow { get; set; }
+ public void OnReferencedFromNative()
+ {
+ }
+
+ public void OnUnreferencedFromNative()
+ {
+ }
+ }
+
+ private void RunLoop()
+ {
+ {
+ var st = Stopwatch.StartNew();
+ using (var act = _compositor5.RequestCommitAsync())
+ act.SetCompleted(new RunLoopHandler(this));
+ while (true)
+ {
+ UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0);
+ lock (_pumpLock)
+ UnmanagedMethods.DispatchMessage(ref msg);
+ }
+ }
+ }
+
+ public static void TryCreateAndRegister(EglPlatformOpenGlInterface angle)
+ {
+ const int majorRequired = 10;
+ const int buildRequired = 17134;
+
+ var majorInstalled = Win32Platform.WindowsVersion.Major;
+ var buildInstalled = Win32Platform.WindowsVersion.Build;
+
+ if (majorInstalled >= majorRequired &&
+ buildInstalled >= buildRequired)
+ {
+ try
+ {
+ TryCreateAndRegisterCore(angle);
+ }
+ catch (Exception e)
+ {
+ Logger.TryGet(LogEventLevel.Error, "WinUIComposition")
+ ?.Log(null, "Unable to initialize WinUI compositor: {0}", e);
+
+ }
+ }
+
+ var osVersionNotice =
+ $"Windows {majorRequired} Build {buildRequired} is required. Your machine has Windows {majorInstalled} Build {buildInstalled} installed.";
+
+ Logger.TryGet(LogEventLevel.Warning, "WinUIComposition")?.Log(null,
+ $"Unable to initialize WinUI compositor: {osVersionNotice}");
+ }
+
+
+ public WinUICompositedWindow CreateWindow(IntPtr hWnd)
+ {
+ using var sc = _syncContext.EnsureLocked();
+ using var desktopTarget = _compositorDesktopInterop.CreateDesktopWindowTarget(hWnd, 0);
+ using var target = desktopTarget.QueryInterface();
+
+ using var drawingSurface = _device.CreateDrawingSurface(new UnmanagedMethods.SIZE(), DirectXPixelFormat.B8G8R8A8UIntNormalized,
+ DirectXAlphaMode.Premultiplied);
+ using var surface = drawingSurface.QueryInterface();
+ using var surfaceInterop = drawingSurface.QueryInterface();
+
+ using var surfaceBrush = _compositor.CreateSurfaceBrushWithSurface(surface);
+ using var brush = surfaceBrush.QueryInterface();
+
+ using var spriteVisual = _compositor.CreateSpriteVisual();
+ spriteVisual.SetBrush(brush);
+ using var visual = spriteVisual.QueryInterface();
+ using var visual2 = spriteVisual.QueryInterface();
+ using var container = _compositor.CreateContainerVisual();
+ using var containerVisual = container.QueryInterface();
+ using var containerVisual2 = container.QueryInterface();
+ containerVisual2.SetRelativeSizeAdjustment(new Vector2(1, 1));
+ using var containerChildren = container.Children;
+
+ target.SetRoot(containerVisual);
+
+ using var blur = CreateBlurVisual();
+
+ containerChildren.InsertAtTop(blur);
+ containerChildren.InsertAtTop(visual);
+
+ return new WinUICompositedWindow(_syncContext, _compositor, _pumpLock, target, surfaceInterop, visual, blur);
+ }
+
+
+ private unsafe ICompositionBrush CreateBlurBrush()
+ {
+ using var backDropParameterFactory = NativeWinRTMethods.CreateActivationFactory(
+ "Windows.UI.Composition.CompositionEffectSourceParameter");
+ using var backdropString = new HStringInterop("backdrop");
+ using var backDropParameter =
+ backDropParameterFactory.Create(backdropString.Handle);
+ using var backDropParameterAsSource = backDropParameter.QueryInterface();
+ var blurEffect = new WinUIGaussianBlurEffect(backDropParameterAsSource);
+ using var blurEffectFactory = _compositor.CreateEffectFactory(blurEffect);
+ using var backdrop = _compositor2.CreateBackdropBrush();
+ using var backdropBrush = backdrop.QueryInterface();
+
+
+ var saturateEffect = new SaturationEffect(blurEffect);
+ using var satEffectFactory = _compositor.CreateEffectFactory(saturateEffect);
+ using var sat = satEffectFactory.CreateBrush();
+ sat.SetSourceParameter(backdropString.Handle, backdropBrush);
+ return sat.QueryInterface();
+ }
+
+ private unsafe IVisual CreateBlurVisual()
+ {
+ using var spriteVisual = _compositor.CreateSpriteVisual();
+ using var visual = spriteVisual.QueryInterface();
+ using var visual2 = spriteVisual.QueryInterface();
+
+
+ spriteVisual.SetBrush(_blurBrush);
+ visual.SetIsVisible(0);
+ visual2.SetRelativeSizeAdjustment(new Vector2(1.0f, 1.0f));
+
+ return visual.CloneReference();
+ }
+
+
+ public event Action Tick;
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
new file mode 100644
index 0000000000..ea75a2f311
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
+using Avalonia.MicroCom;
+
+namespace Avalonia.Win32.WinRT.Composition
+{
+ abstract class WinUIEffectBase : WinRTInspectable, IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop
+ {
+ private IGraphicsEffectSource[] _sources;
+
+ public WinUIEffectBase(params IGraphicsEffectSource[] _sources)
+ {
+ this._sources = _sources.Select(e =>
+ {
+ if (e is WinUIEffectBase)
+ return e;
+ return e.CloneReference();
+ }).ToArray();
+ }
+
+ public IntPtr Name => IntPtr.Zero;
+
+ public void SetName(IntPtr name)
+ {
+
+ }
+
+ public abstract Guid EffectId { get; }
+ public unsafe void GetNamedPropertyMapping(IntPtr name, uint* index, GRAPHICS_EFFECT_PROPERTY_MAPPING* mapping) =>
+ throw new COMException("Not supported", unchecked((int)0x80004001));
+
+ public abstract uint PropertyCount { get; }
+ public abstract IPropertyValue GetProperty(uint index);
+
+ public IGraphicsEffectSource GetSource(uint index)
+ {
+ if (_sources == null || index> _sources.Length)
+ throw new COMException("Invalid index", unchecked((int)0x80070057));
+ return _sources[index];
+ }
+
+ public uint SourceCount => (uint)(_sources?.Length ?? 0);
+
+ public override void OnUnreferencedFromNative()
+ {
+ if (_sources == null)
+ return;
+
+ /*foreach(var s in _sources)
+ s.Dispose();*/
+ _sources = null;
+ }
+ }
+
+ class WinUIGaussianBlurEffect : WinUIEffectBase
+ {
+ public WinUIGaussianBlurEffect(IGraphicsEffectSource source) : base(source)
+ {
+ }
+
+ enum D2D1_GAUSSIANBLUR_OPTIMIZATION
+ {
+ D2D1_GAUSSIANBLUR_OPTIMIZATION_SPEED,
+ D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED,
+ D2D1_GAUSSIANBLUR_OPTIMIZATION_QUALITY,
+ D2D1_GAUSSIANBLUR_OPTIMIZATION_FORCE_DWORD
+ };
+
+ enum D2D1_BORDER_MODE
+ {
+ D2D1_BORDER_MODE_SOFT,
+ D2D1_BORDER_MODE_HARD,
+ D2D1_BORDER_MODE_FORCE_DWORD
+ };
+
+ enum D2D1GaussianBlurProp
+ {
+ D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION,
+ D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION,
+ D2D1_GAUSSIANBLUR_PROP_BORDER_MODE,
+ D2D1_GAUSSIANBLUR_PROP_FORCE_DWORD
+ };
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1GaussianBlur;
+
+ public override uint PropertyCount => 3;
+
+ public override IPropertyValue GetProperty(uint index)
+ {
+ switch ((D2D1GaussianBlurProp)index)
+ {
+ case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION:
+ return new WinRTPropertyValue(30.0f);
+
+ case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION:
+ return new WinRTPropertyValue((uint)D2D1_GAUSSIANBLUR_OPTIMIZATION
+ .D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED);
+
+ case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_BORDER_MODE:
+ return new WinRTPropertyValue((uint)D2D1_BORDER_MODE.D2D1_BORDER_MODE_HARD);
+ }
+
+ return null;
+ }
+ }
+
+ class SaturationEffect : WinUIEffectBase
+ {
+ public SaturationEffect(IGraphicsEffectSource source) : base(source)
+ {
+ }
+
+ enum D2D1_SATURATION_PROP
+ {
+ D2D1_SATURATION_PROP_SATURATION,
+ D2D1_SATURATION_PROP_FORCE_DWORD
+ };
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Saturation;
+
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue GetProperty(uint index)
+ {
+ switch ((D2D1_SATURATION_PROP)index)
+ {
+ case D2D1_SATURATION_PROP.D2D1_SATURATION_PROP_SATURATION:
+ return new WinRTPropertyValue(2.0f);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
new file mode 100644
index 0000000000..f59d50860a
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Runtime.InteropServices;
+using Avalonia.MicroCom;
+using Avalonia.OpenGL.Angle;
+using Avalonia.OpenGL.Egl;
+using Avalonia.OpenGL.Surfaces;
+using Avalonia.Utilities;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32.WinRT.Composition
+{
+ internal class WinUiCompositedWindowSurface : EglGlPlatformSurfaceBase, IBlurHost, IDisposable
+ {
+ private readonly WinUICompositorConnection _connection;
+ private EglPlatformOpenGlInterface _egl;
+ private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info;
+ private IRef _window;
+ private bool _enableBlur;
+
+ public WinUiCompositedWindowSurface(WinUICompositorConnection connection, IEglWindowGlPlatformSurfaceInfo info) : base()
+ {
+ _connection = connection;
+ _egl = connection.Egl;
+ _info = info;
+ }
+
+ public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
+ {
+ using (_egl.PrimaryContext.EnsureCurrent())
+ {
+ if (_window?.Item == null)
+ {
+ _window = RefCountable.Create(_connection.CreateWindow(_info.Handle));
+ _window.Item.SetBlur(_enableBlur);
+ }
+
+ return new CompositionRenderTarget(_egl, _window, _info);
+ }
+ }
+
+ class CompositionRenderTarget : EglPlatformSurfaceRenderTargetBase
+ {
+ private readonly EglPlatformOpenGlInterface _egl;
+ private readonly IRef _window;
+ private readonly IEglWindowGlPlatformSurfaceInfo _info;
+
+ public CompositionRenderTarget(EglPlatformOpenGlInterface egl,
+ IRef window,
+ IEglWindowGlPlatformSurfaceInfo info)
+ : base(egl)
+ {
+ _egl = egl;
+ _window = window.Clone();
+ _info = info;
+ _window.Item.ResizeIfNeeded(_info.Size);
+ }
+
+ public override IGlPlatformSurfaceRenderingSession BeginDraw()
+ {
+ var contextLock = _egl.PrimaryEglContext.EnsureCurrent();
+ IUnknown texture = null;
+ EglSurface surface = null;
+ IDisposable transaction = null;
+ var success = false;
+ try
+ {
+ if (_window?.Item == null)
+ throw new ObjectDisposedException(GetType().FullName);
+
+ var size = _info.Size;
+ transaction = _window.Item.BeginTransaction();
+ _window.Item.ResizeIfNeeded(size);
+ texture = _window.Item.BeginDrawToTexture(out var offset);
+
+ surface = ((AngleWin32EglDisplay) _egl.Display).WrapDirect3D11Texture(_egl,
+ texture.GetNativeIntPtr(),
+ offset.X, offset.Y, size.Width, size.Height);
+
+ var res = base.BeginDraw(surface, _info, () =>
+ {
+ surface?.Dispose();
+ texture?.Dispose();
+ _window.Item.EndDraw();
+ transaction?.Dispose();
+ contextLock?.Dispose();
+ }, true);
+ success = true;
+ return res;
+ }
+ finally
+ {
+ if (!success)
+ {
+ surface?.Dispose();
+ texture?.Dispose();
+ transaction?.Dispose();
+ contextLock.Dispose();
+ }
+ }
+ }
+ }
+
+ public void SetBlur(bool enable)
+ {
+ _enableBlur = enable;
+ _window?.Item?.SetBlur(enable);
+ }
+
+ public void Dispose()
+ {
+ using (_egl.PrimaryEglContext.EnsureLocked())
+ {
+ _window?.Dispose();
+ _window = null;
+ }
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
new file mode 100644
index 0000000000..81c0e3e185
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
@@ -0,0 +1,7 @@
+namespace Avalonia.Win32.WinRT
+{
+ public interface IBlurHost
+ {
+ void SetBlur(bool enable);
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs b/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs
new file mode 100644
index 0000000000..087bd2fd43
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Threading;
+using Avalonia.MicroCom;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32.WinRT
+{
+ internal static class NativeWinRTMethods
+ {
+ [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall,
+ PreserveSig = false)]
+ internal static extern unsafe IntPtr WindowsCreateString(
+ [MarshalAs(UnmanagedType.LPWStr)] string sourceString,
+ int length);
+
+ internal static IntPtr WindowsCreateString(string sourceString)
+ => WindowsCreateString(sourceString, sourceString.Length);
+
+ [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll",
+ CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
+ internal static extern unsafe IntPtr WindowsDeleteString(IntPtr hString);
+
+ [DllImport("Windows.UI.Composition", EntryPoint = "DllGetActivationFactory",
+ CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
+ private extern static IntPtr GetWindowsUICompositionActivationFactory(
+ IntPtr activatableClassId);
+
+ internal static IActivationFactory GetWindowsUICompositionActivationFactory(string className)
+ {//"Windows.UI.Composition.Compositor"
+ var s = WindowsCreateString(className);
+ var factory = GetWindowsUICompositionActivationFactory(s);
+ return MicroComRuntime.CreateProxyFor(factory, true);
+ }
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+ delegate int GetActivationFactoryDelegate(IntPtr classId, out IntPtr ppv);
+
+ internal static T CreateInstance(string fullName) where T : IUnknown
+ {
+ var s = WindowsCreateString(fullName);
+ EnsureRoInitialized();
+ var pUnk = RoActivateInstance(s);
+ using var unk = MicroComRuntime.CreateProxyFor(pUnk, true);
+ WindowsDeleteString(s);
+ return MicroComRuntime.QueryInterface(unk);
+ }
+
+ internal static TFactory CreateActivationFactory(string fullName) where TFactory : IUnknown
+ {
+ var s = WindowsCreateString(fullName);
+ EnsureRoInitialized();
+ var guid = MicroComRuntime.GetGuidFor(typeof(TFactory));
+ var pUnk = RoGetActivationFactory(s, ref guid);
+ using var unk = MicroComRuntime.CreateProxyFor(pUnk, true);
+ WindowsDeleteString(s);
+ return MicroComRuntime.QueryInterface(unk);
+ }
+
+ internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
+ {
+ DQTAT_COM_NONE = 0,
+ DQTAT_COM_ASTA = 1,
+ DQTAT_COM_STA = 2
+ };
+
+ internal enum DISPATCHERQUEUE_THREAD_TYPE
+ {
+ DQTYPE_THREAD_DEDICATED = 1,
+ DQTYPE_THREAD_CURRENT = 2,
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct DispatcherQueueOptions
+ {
+ public int dwSize;
+
+ [MarshalAs(UnmanagedType.I4)]
+ public DISPATCHERQUEUE_THREAD_TYPE threadType;
+
+ [MarshalAs(UnmanagedType.I4)]
+ public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
+ };
+
+ [DllImport("coremessaging.dll", PreserveSig = false)]
+ internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options);
+
+ internal enum RO_INIT_TYPE
+ {
+ RO_INIT_SINGLETHREADED = 0, // Single-threaded application
+ RO_INIT_MULTITHREADED = 1, // COM calls objects on any thread.
+ }
+
+ [DllImport("combase.dll", PreserveSig = false)]
+ private static extern void RoInitialize(RO_INIT_TYPE initType);
+
+ [DllImport("combase.dll", PreserveSig = false)]
+ private static extern IntPtr RoActivateInstance(IntPtr activatableClassId);
+
+ [DllImport("combase.dll", PreserveSig = false)]
+ private static extern IntPtr RoGetActivationFactory(IntPtr activatableClassId, ref Guid iid);
+
+ private static bool _initialized;
+ private static void EnsureRoInitialized()
+ {
+ if (_initialized)
+ return;
+ RoInitialize(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA ?
+ RO_INIT_TYPE.RO_INIT_SINGLETHREADED :
+ RO_INIT_TYPE.RO_INIT_MULTITHREADED);
+ _initialized = true;
+ }
+ }
+
+ class HStringInterop : IDisposable
+ {
+ private IntPtr _s;
+
+ public HStringInterop(string s)
+ {
+ _s = s == null ? IntPtr.Zero : NativeWinRTMethods.WindowsCreateString(s);
+ }
+
+ public IntPtr Handle => _s;
+
+ public void Dispose()
+ {
+ if (_s != IntPtr.Zero)
+ {
+ NativeWinRTMethods.WindowsDeleteString(_s);
+ _s = IntPtr.Zero;
+ }
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTColor.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTColor.cs
new file mode 100644
index 0000000000..786d698daa
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/WinRTColor.cs
@@ -0,0 +1,18 @@
+using System.Runtime.InteropServices;
+
+namespace Avalonia.Win32.WinRT
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct WinRTColor
+ {
+ public byte A;
+ public byte R;
+ public byte G;
+ public byte B;
+
+ public static WinRTColor FromArgb(byte a, byte r, byte g, byte b) => new WinRTColor()
+ {
+ A = a, R = r, G = g, B = b
+ };
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs
new file mode 100644
index 0000000000..d2ec957b8e
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Avalonia.MicroCom;
+
+namespace Avalonia.Win32.WinRT
+{
+ class WinRTInspectable : IInspectable, IMicroComShadowContainer
+ {
+ public virtual void Dispose()
+ {
+
+ }
+
+ public unsafe void GetIids(ulong* iidCount, Guid** iids)
+ {
+ var interfaces = GetType().GetInterfaces().Where(typeof(IUnknown).IsAssignableFrom)
+ .Select(MicroComRuntime.GetGuidFor).ToArray();
+ var mem = (Guid*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * interfaces.Length);
+ for (var c = 0; c < interfaces.Length; c++)
+ mem[c] = interfaces[c];
+ *iids = mem;
+ *iidCount = (ulong) interfaces.Length;
+ }
+
+ public IntPtr RuntimeClassName => NativeWinRTMethods.WindowsCreateString(GetType().FullName);
+ public TrustLevel TrustLevel => TrustLevel.BaseTrust;
+ public MicroComShadow Shadow { get; set; }
+ public virtual void OnReferencedFromNative()
+ {
+ }
+
+ public virtual void OnUnreferencedFromNative()
+ {
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
new file mode 100644
index 0000000000..684e7ff7b5
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Avalonia.Win32.WinRT
+{
+ class WinRTPropertyValue : WinRTInspectable, IPropertyValue
+ {
+ public WinRTPropertyValue(float f)
+ {
+ Type = PropertyType.Single;
+ Single = f;
+ }
+
+ public WinRTPropertyValue(uint u)
+ {
+ UInt32 = u;
+ Type = PropertyType.UInt32;
+ }
+
+ public PropertyType Type { get; }
+ public int IsNumericScalar { get; }
+ public byte UInt8 { get; }
+ public short Int16 { get; }
+ public ushort UInt16 { get; }
+ public int Int32 { get; }
+ public uint UInt32 { get; }
+ public long Int64 { get; }
+ public ulong UInt64 { get; }
+ public float Single { get; }
+ public double Double { get; }
+ public char Char16 { get; }
+ public int Boolean { get; }
+ public IntPtr String { get; }
+ public Guid Guid { get; }
+
+ private static COMException NotImplemented => new COMException("Not supported", unchecked((int)0x80004001));
+
+ public unsafe void GetDateTime(void* value) => throw NotImplemented;
+
+ public unsafe void GetTimeSpan(void* value) => throw NotImplemented;
+
+ public unsafe void GetPoint(void* value) => throw NotImplemented;
+
+ public unsafe void GetSize(void* value) => throw NotImplemented;
+
+ public unsafe void GetRect(void* value) => throw NotImplemented;
+
+ public unsafe byte* GetUInt8Array(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe short* GetInt16Array(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe ushort* GetUInt16Array(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe int* GetInt32Array(uint* __valueSize)
+ {
+ throw NotImplemented;
+ }
+
+ public unsafe uint* GetUInt32Array(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe long* GetInt64Array(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe ulong* GetUInt64Array(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe float* GetSingleArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe double* GetDoubleArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe char* GetChar16Array(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe int* GetBooleanArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe IntPtr* GetStringArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe void** GetInspectableArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe Guid* GetGuidArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe void* GetDateTimeArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe void* GetTimeSpanArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe void* GetPointArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe void* GetSizeArray(uint* __valueSize) => throw NotImplemented;
+
+ public unsafe void* GetRectArray(uint* __valueSize) => throw NotImplemented;
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/WinRT/winrt.idl b/src/Windows/Avalonia.Win32/WinRT/winrt.idl
new file mode 100644
index 0000000000..929377999c
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/WinRT/winrt.idl
@@ -0,0 +1,718 @@
+@clr-namespace Avalonia.Win32.WinRT
+@clr-access internal
+@clr-map FLOAT float
+@clr-map HSTRING IntPtr
+@clr-map Vector2 System.Numerics.Vector2
+@clr-map Vector3 System.Numerics.Vector3
+@clr-map Quaternion System.Numerics.Quaternion
+@clr-map Matrix4x4 System.Numerics.Matrix4x4
+@clr-map RECT Avalonia.Win32.Interop.UnmanagedMethods.RECT
+@clr-map SIZE Avalonia.Win32.Interop.UnmanagedMethods.SIZE
+@clr-map POINT Avalonia.Win32.Interop.UnmanagedMethods.POINT
+@clr-map HWND IntPtr
+@clr-map BOOL int
+@clr-map DWORD int
+@clr-map boolean int
+@clr-map BYTE byte
+@clr-map INT16 short
+@clr-map INT32 int
+@clr-map INT64 long
+@clr-map UINT16 ushort
+@clr-map UINT32 uint
+@clr-map UINT64 ulong
+@clr-map DOUBLE double
+@clr-map GUID System.Guid
+@clr-map WCHAR System.Char
+@clr-map Color Avalonia.Win32.WinRT.WinRTColor
+
+enum TrustLevel
+{
+ BaseTrust,
+ PartialTrust,
+ FullTrust
+}
+
+enum DirectXAlphaMode
+{
+ Unspecified,
+ Premultiplied,
+ Straight,
+ Ignore
+}
+
+enum DirectXPixelFormat
+{
+ Unknown = 0,
+ R32G32B32A32Typeless = 1,
+ R32G32B32A32Float = 2,
+ R32G32B32A32UInt = 3,
+ R32G32B32A32Int = 4,
+ R32G32B32Typeless = 5,
+ R32G32B32Float = 6,
+ R32G32B32UInt = 7,
+ R32G32B32Int = 8,
+ R16G16B16A16Typeless = 9,
+ R16G16B16A16Float = 10,
+ R16G16B16A16UIntNormalized = 11,
+ R16G16B16A16UInt = 12,
+ R16G16B16A16IntNormalized = 13,
+ R16G16B16A16Int = 14,
+ R32G32Typeless = 15,
+ R32G32Float = 16,
+ R32G32UInt = 17,
+ R32G32Int = 18,
+ R32G8X24Typeless = 19,
+ D32FloatS8X24UInt = 20,
+ R32FloatX8X24Typeless = 21,
+ X32TypelessG8X24UInt = 22,
+ R10G10B10A2Typeless = 23,
+ R10G10B10A2UIntNormalized = 24,
+ R10G10B10A2UInt = 25,
+ R11G11B10Float = 26,
+ R8G8B8A8Typeless = 27,
+ R8G8B8A8UIntNormalized = 28,
+ R8G8B8A8UIntNormalizedSrgb = 29,
+ R8G8B8A8UInt = 30,
+ R8G8B8A8IntNormalized = 31,
+ R8G8B8A8Int = 32,
+ R16G16Typeless = 33,
+ R16G16Float = 34,
+ R16G16UIntNormalized = 35,
+ R16G16UInt = 36,
+ R16G16IntNormalized = 37,
+ R16G16Int = 38,
+ R32Typeless = 39,
+ D32Float = 40,
+ R32Float = 41,
+ R32UInt = 42,
+ R32Int = 43,
+ R24G8Typeless = 44,
+ D24UIntNormalizedS8UInt = 45,
+ R24UIntNormalizedX8Typeless = 46,
+ X24TypelessG8UInt = 47,
+ R8G8Typeless = 48,
+ R8G8UIntNormalized = 49,
+ R8G8UInt = 50,
+ R8G8IntNormalized = 51,
+ R8G8Int = 52,
+ R16Typeless = 53,
+ R16Float = 54,
+ D16UIntNormalized = 55,
+ R16UIntNormalized = 56,
+ R16UInt = 57,
+ R16IntNormalized = 58,
+ R16Int = 59,
+ R8Typeless = 60,
+ R8UIntNormalized = 61,
+ R8UInt = 62,
+ R8IntNormalized = 63,
+ R8Int = 64,
+ A8UIntNormalized = 65,
+ R1UIntNormalized = 66,
+ R9G9B9E5SharedExponent = 67,
+ R8G8B8G8UIntNormalized = 68,
+ G8R8G8B8UIntNormalized = 69,
+ BC1Typeless = 70,
+ BC1UIntNormalized = 71,
+ BC1UIntNormalizedSrgb = 72,
+ BC2Typeless = 73,
+ BC2UIntNormalized = 74,
+ BC2UIntNormalizedSrgb = 75,
+ BC3Typeless = 76,
+ BC3UIntNormalized = 77,
+ BC3UIntNormalizedSrgb = 78,
+ BC4Typeless = 79,
+ BC4UIntNormalized = 80,
+ BC4IntNormalized = 81,
+ BC5Typeless = 82,
+ BC5UIntNormalized = 83,
+ BC5IntNormalized = 84,
+ B5G6R5UIntNormalized = 85,
+ B5G5R5A1UIntNormalized = 86,
+ B8G8R8A8UIntNormalized = 87,
+ B8G8R8X8UIntNormalized = 88,
+ R10G10B10XRBiasA2UIntNormalized = 89,
+ B8G8R8A8Typeless = 90,
+ B8G8R8A8UIntNormalizedSrgb = 91,
+ B8G8R8X8Typeless = 92,
+ B8G8R8X8UIntNormalizedSrgb = 93,
+ BC6HTypeless = 94,
+ BC6H16UnsignedFloat = 95,
+ BC6H16Float = 96,
+ BC7Typeless = 97,
+ BC7UIntNormalized = 98,
+ BC7UIntNormalizedSrgb = 99,
+ Ayuv = 100,
+ Y410 = 101,
+ Y416 = 102,
+ NV12 = 103,
+ P010 = 104,
+ P016 = 105,
+ Opaque420 = 106,
+ Yuy2 = 107,
+ Y210 = 108,
+ Y216 = 109,
+ NV11 = 110,
+ AI44 = 111,
+ IA44 = 112,
+ P8 = 113,
+ A8P8 = 114,
+ B4G4R4A4UIntNormalized = 115,
+ P208 = 130,
+ V208 = 131,
+ V408 = 132,
+}
+
+[uuid(AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90)]
+interface IInspectable : IUnknown
+{
+ HRESULT GetIids(ulong * iidCount, Guid ** iids);
+ HRESULT GetRuntimeClassName( [out] IntPtr* className);
+ HRESULT GetTrustLevel([out] TrustLevel * trustLevel);
+}
+
+enum PropertyType
+{
+ Empty = 0,
+ UInt8 = 1,
+ Int16 = 2,
+ UInt16 = 3,
+ Int32 = 4,
+ UInt32 = 5,
+ Int64 = 6,
+ UInt64 = 7,
+ Single = 8,
+ Double = 9,
+ Char16 = 10,
+ Boolean = 11,
+ String = 12,
+ Inspectable = 13,
+ DateTime = 14,
+ TimeSpan = 15,
+ Guid = 16,
+ Point = 17,
+ Size = 18,
+ Rect = 19,
+ OtherType = 20,
+ UInt8Array = 1025,
+ Int16Array = 1026,
+ UInt16Array = 1027,
+ Int32Array = 1028,
+ UInt32Array = 1029,
+ Int64Array = 1030,
+ UInt64Array = 1031,
+ SingleArray = 1032,
+ DoubleArray = 1033,
+ Char16Array = 1034,
+ BooleanArray = 1035,
+ StringArray = 1036,
+ InspectableArray = 1037,
+ DateTimeArray = 1038,
+ TimeSpanArray = 1039,
+ GuidArray = 1040,
+ PointArray = 1041,
+ SizeArray = 1042,
+ RectArray = 1043,
+ OtherTypeArray = 1044
+}
+
+[uuid(4BD682DD-7554-40E9-9A9B-82654EDE7E62)]
+interface IPropertyValue : IInspectable
+{
+ [propget] HRESULT Type([out] [retval] PropertyType* value);
+ [propget] HRESULT IsNumericScalar([out] [retval] boolean* value);
+ HRESULT GetUInt8([out] [retval] BYTE* value);
+ HRESULT GetInt16([out] [retval] INT16* value);
+ HRESULT GetUInt16([out] [retval] UINT16* value);
+ HRESULT GetInt32([out] [retval] INT32* value);
+ HRESULT GetUInt32([out] [retval] UINT32* value);
+ HRESULT GetInt64([out] [retval] INT64* value);
+ HRESULT GetUInt64([out] [retval] UINT64* value);
+ HRESULT GetSingle([out] [retval] FLOAT* value);
+ HRESULT GetDouble([out] [retval] DOUBLE* value);
+ HRESULT GetChar16([out] [retval] WCHAR* value);
+ HRESULT GetBoolean([out] [retval] boolean* value);
+ HRESULT GetString([out] [retval] HSTRING* value);
+ HRESULT GetGuid([out] [retval] GUID* value);
+ HRESULT GetDateTime( void* value);
+ HRESULT GetTimeSpan(void* value);
+ HRESULT GetPoint(void* value);
+ HRESULT GetSize(void* value);
+ HRESULT GetRect(void* value);
+ HRESULT GetUInt8Array([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] BYTE** value);
+ HRESULT GetInt16Array([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] INT16** value);
+ HRESULT GetUInt16Array([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] UINT16** value);
+ HRESULT GetInt32Array([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] INT32** value);
+ HRESULT GetUInt32Array([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] UINT32** value);
+ HRESULT GetInt64Array([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] INT64** value);
+ HRESULT GetUInt64Array([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] UINT64** value);
+ HRESULT GetSingleArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] FLOAT** value);
+ HRESULT GetDoubleArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] DOUBLE** value);
+ HRESULT GetChar16Array([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] WCHAR** value);
+ HRESULT GetBooleanArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] boolean** value);
+ HRESULT GetStringArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] HSTRING** value);
+ HRESULT GetInspectableArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] void*** value);
+ HRESULT GetGuidArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] GUID** value);
+ HRESULT GetDateTimeArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] void** value);
+ HRESULT GetTimeSpanArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] void** value);
+ HRESULT GetPointArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] void** value);
+ HRESULT GetSizeArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] void** value);
+ HRESULT GetRectArray([out] UINT32* __valueSize, [out] [size_is(, *__valueSize)] void** value);
+}
+
+enum AsyncStatus {
+ Started = 0,
+ Completed,
+ Canceled,
+ Error,
+}
+
+[uuid(A4ED5C81-76C9-40BD-8BE6-B1D90FB20AE7)]
+interface IAsyncActionCompletedHandler : IUnknown
+{
+ HRESULT Invoke([in] IAsyncAction* asyncInfo, [in] AsyncStatus asyncStatus);
+}
+
+[uuid(5A648006-843A-4DA9-865B-9D26E5DFAD7B)]
+interface IAsyncAction : IInspectable
+{
+ HRESULT SetCompleted([in] IAsyncActionCompletedHandler* handler);
+ HRESULT GetCompleted([out] [retval] IAsyncActionCompletedHandler** ppv);
+ HRESULT GetResults();
+}
+
+[uuid(603E88E4-A338-4FFE-A457-A5CFB9CEB899)]
+interface IDispatcherQueue : IInspectable
+{
+ //TODO
+}
+
+[uuid(22F34E66-50DB-4E36-A98D-61C01B384D20)]
+interface IDispatcherQueueController : IInspectable
+{
+ [propget] HRESULT DispatcherQueue([out] [retval] IDispatcherQueue** value);
+ HRESULT ShutdownQueueAsync([out] [retval] IAsyncAction** operation);
+}
+
+[uuid(00000035-0000-0000-C000-000000000046)]
+interface IActivationFactory : IInspectable
+{
+ HRESULT ActivateInstance([out, retval] IntPtr* instance);
+}
+
+[flags]
+enum CompositionBatchTypes
+{
+ None = 0x0,
+ Animation = 0x1,
+ Effect = 0x2,
+ InfiniteAnimation = 0x4,
+ AllAnimations = 0x5
+}
+
+[uuid(B403CA50-7F8C-4E83-985F-CC45060036D8)]
+interface ICompositor : IInspectable
+{
+ HRESULT CreateColorKeyFrameAnimation([out] [retval] void** result);
+ [overload("CreateColorBrush")] HRESULT CreateColorBrush([out] [retval]void** result);
+ [overload("CreateColorBrush")] HRESULT CreateColorBrushWithColor([in] Color* color, [out] [retval] ICompositionColorBrush** result);
+ HRESULT CreateContainerVisual([out] [retval] IContainerVisual** result);
+ HRESULT CreateCubicBezierEasingFunction([in] Vector2 controlPoint1, [in] Vector2 controlPoint2, [out] [retval] void** result);
+ [overload("CreateEffectFactory")] HRESULT CreateEffectFactory([in] IGraphicsEffect* graphicsEffect, [out] [retval] ICompositionEffectFactory** result);
+ [overload("CreateEffectFactory")] HRESULT CreateEffectFactoryWithProperties([in] void* graphicsEffect, [in] void* animatableProperties, [out] [retval] void** result);
+ [overload("CreateExpressionAnimation")] HRESULT CreateExpressionAnimation([out] [retval] void** result);
+ [overload("CreateExpressionAnimation")] HRESULT CreateExpressionAnimationWithExpression([in] HSTRING expression, [out] [retval] void** result);
+ [overload("CreateInsetClip")] HRESULT CreateInsetClip([out] [retval] void** result);
+ [overload("CreateInsetClip")] HRESULT CreateInsetClipWithInsets([in] FLOAT leftInset, [in] FLOAT topInset, [in] FLOAT rightInset, [in] FLOAT bottomInset, [out] [retval] void** result);
+ HRESULT CreateLinearEasingFunction([out] [retval] void** result);
+ HRESULT CreatePropertySet([out] [retval] void** result);
+ HRESULT CreateQuaternionKeyFrameAnimation([out] [retval] void** result);
+ HRESULT CreateScalarKeyFrameAnimation([out] [retval] void** result);
+ HRESULT CreateScopedBatch([in] CompositionBatchTypes batchType, [out] [retval] ICompositionScopedBatch** result);
+ HRESULT CreateSpriteVisual([out] [retval] ISpriteVisual** result);
+ HRESULT CreateSurfaceBrush([out] [retval] ICompositionSurfaceBrush** result);
+ HRESULT CreateSurfaceBrushWithSurface([in] ICompositionSurface* surface,
+ [out] [retval] ICompositionSurfaceBrush** result);
+ HRESULT CreateTargetForCurrentView([out] [retval] void** result);
+ HRESULT CreateVector2KeyFrameAnimation([out] [retval] void** result);
+ HRESULT CreateVector3KeyFrameAnimation([out] [retval] void** result);
+ HRESULT CreateVector4KeyFrameAnimation([out] [retval] void** result);
+ HRESULT GetCommitBatch([in] CompositionBatchTypes batchType, [out] [retval] void** result);
+}
+
+[uuid(735081DC-5E24-45DA-A38F-E32CC349A9A0)]
+interface ICompositor2 : IInspectable
+{
+ HRESULT CreateAmbientLight([out] [retval] void** result);
+ HRESULT CreateAnimationGroup([out] [retval] void** result);
+ HRESULT CreateBackdropBrush([out] [retval] ICompositionBackdropBrush** result);
+ HRESULT CreateDistantLight([out] [retval] void** result);
+ HRESULT CreateDropShadow([out] [retval] void** result);
+ HRESULT CreateImplicitAnimationCollection([out] [retval] void** result);
+ HRESULT CreateLayerVisual([out] [retval] void** result);
+ HRESULT CreateMaskBrush([out] [retval] void** result);
+ HRESULT CreateNineGridBrush([out] [retval] void** result);
+ HRESULT CreatePointLight([out] [retval] void** result);
+ HRESULT CreateSpotLight([out] [retval] void** result);
+ [overload("CreateStepEasingFunction")] HRESULT CreateStepEasingFunction([out] [retval] void** result);
+ [overload("CreateStepEasingFunction")] HRESULT CreateStepEasingFunctionWithStepCount([in] INT32 stepCount, [out] [retval] void** result);
+}
+
+[uuid(08E05581-1AD1-4F97-9757-402D76E4233B)]
+interface ISpriteVisual : IInspectable
+{
+ [propget] HRESULT GetBrush([out] [retval] ICompositionBrush** value);
+ [propput] HRESULT SetBrush([in] ICompositionBrush* value);
+}
+
+[uuid(FD04E6E3-FE0C-4C3C-AB19-A07601A576EE)]
+interface ICompositionDrawingSurfaceInterop : IUnknown
+{
+ HRESULT BeginDraw(RECT* updateRect, Guid* iid, void** updateObject, [out, retval]POINT* updateOffset);
+ HRESULT EndDraw();
+ HRESULT Resize(POINT sizePixels);
+ HRESULT Scroll(RECT * scrollRect, RECT * clipRect, int offsetX, int offsetY);
+ HRESULT ResumeDraw();
+ HRESULT SuspendDraw();
+};
+
+[uuid(A116FF71-F8BF-4C8A-9C98-70779A32A9C8)]
+interface ICompositionGraphicsDeviceInterop : IUnknown
+{
+ HRESULT GetRenderingDevice([out] IUnknown ** value);
+ HRESULT SetRenderingDevice([out] IUnknown * value);
+};
+
+[uuid(25297D5C-3AD4-4C9C-B5CF-E36A38512330)]
+interface ICompositorInterop : IUnknown
+{
+ HRESULT CreateCompositionSurfaceForHandle(IntPtr swapChain, [out] ICompositionSurface ** res);
+ HRESULT CreateCompositionSurfaceForSwapChain(IUnknown* swapChain, [out] ICompositionSurface ** result);
+ HRESULT CreateGraphicsDevice(IUnknown * renderingDevice, [out] ICompositionGraphicsDevice ** result);
+};
+
+[uuid(26f496a0-7f38-45fb-88f7-faaabe67dd59)]
+interface ISwapChainInterop : IUnknown
+{
+ HRESULT SetSwapChain(IUnknown * swapChain);
+};
+
+/*
+[uuid(2C9DB356-E70D-4642-8298-BC4AA5B4865C)]
+interface ICompositionCapabilitiesInteropFactory : IInspectable
+{
+ HRESULT GetForWindow(IntPtr hwnd, [out] ICompositionCapabilities ** result);
+}*/
+
+[uuid(29E691FA-4567-4DCA-B319-D0F207EB6807)]
+interface ICompositorDesktopInterop : IUnknown
+{
+ HRESULT CreateDesktopWindowTarget(HWND hwndTarget, BOOL isTopmost, [out] IDesktopWindowTarget ** result);
+ HRESULT EnsureOnThread(DWORD threadId);
+};
+
+
+[uuid(35DBF59E-E3F9-45B0-81E7-FE75F4145DC9)]
+interface IDesktopWindowTargetInterop : IUnknown
+{
+ HRESULT GetHWnd([out] IntPtr* value);
+};
+
+[uuid(37642806-F421-4FD0-9F82-23AE7C776182)]
+interface IDesktopWindowContentBridgeInterop : IUnknown
+{
+ HRESULT Initialize(ICompositor* compositor, HWND parentHwnd);
+ HRESULT GetHWnd([out] IntPtr* value);
+
+ HRESULT GetAppliedScaleFactor([out] float* value);
+};
+
+[uuid(FB22C6E1-80A2-4667-9936-DBEAF6EEFE95)]
+interface ICompositionGraphicsDevice : IInspectable
+{
+ HRESULT CreateDrawingSurface([in] SIZE sizePixels, [in] DirectXPixelFormat pixelFormat,
+ [in] DirectXAlphaMode alphaMode, [out] [retval] ICompositionDrawingSurface** result);
+ HRESULT AddRenderingDeviceReplaced(void* handler, void* token);
+ HRESULT RemoveRenderingDeviceReplaced([in] int token);
+}
+
+[uuid(1527540D-42C7-47A6-A408-668F79A90DFB)]
+interface ICompositionSurface : IInspectable
+{
+}
+
+[uuid(6329D6CA-3366-490E-9DB3-25312929AC51)]
+interface IDesktopWindowTarget : IInspectable
+{
+ [propget] HRESULT IsTopmost([out] [retval] int* value);
+}
+
+
+[uuid(A166C300-FAD0-4D11-9E67-E433162FF49E)]
+interface ICompositionDrawingSurface : IInspectable
+{
+ [propget] HRESULT GetAlphaMode([out] [retval] DirectXAlphaMode* value);
+ [propget] HRESULT GetPixelFormat([out] [retval] DirectXPixelFormat* value);
+ [propget] HRESULT GetSize([out] [retval] POINT* value);
+}
+
+enum CompositionBitmapInterpolationMode
+{
+ NearestNeighbor,
+ Linear,
+ MagLinearMinLinearMipLinear,
+ MagLinearMinLinearMipNearest,
+ MagLinearMinNearestMipLinear,
+ MagLinearMinNearestMipNearest,
+ MagNearestMinLinearMipLinear,
+ MagNearestMinLinearMipNearest,
+ MagNearestMinNearestMipLinear,
+ MagNearestMinNearestMipNearest,
+}
+
+enum CompositionStretch
+{
+ None,
+ Fill,
+ Uniform,
+ UniformToFill,
+}
+
+[uuid(AD016D79-1E4C-4C0D-9C29-83338C87C162)]
+interface ICompositionSurfaceBrush : IInspectable
+{
+ [propget] HRESULT BitmapInterpolationMode([out] [retval] CompositionBitmapInterpolationMode* value);
+ [propput] HRESULT BitmapInterpolationMode([in] CompositionBitmapInterpolationMode value);
+ [propget] HRESULT HorizontalAlignmentRatio([out] [retval] FLOAT* value);
+ [propput] HRESULT HorizontalAlignmentRatio([in] FLOAT value);
+ [propget] HRESULT Stretch([out] [retval] CompositionStretch* value);
+ [propput] HRESULT Stretch([in] CompositionStretch value);
+ [propget] HRESULT Surface([out] [retval] ICompositionSurface** value);
+ [propput] HRESULT Surface([in] ICompositionSurface* value);
+ [propget] HRESULT VerticalAlignmentRatio([out] [retval] FLOAT* value);
+ [propput] HRESULT VerticalAlignmentRatio([in] FLOAT value);
+}
+
+[uuid(AB0D7608-30C0-40E9-B568-B60A6BD1FB46)]
+interface ICompositionBrush : IInspectable
+{
+}
+
+enum CompositionBackfaceVisibility
+{
+ Inherit,
+ Visible,
+ Hidden
+}
+
+enum CompositionBorderMode
+{
+ Inherit,
+ Soft,
+ Hard
+}
+
+enum CompositionCompositeMode
+{
+ Inherit,
+ SourceOver,
+ DestinationInvert,
+ MinBlend,
+}
+
+[uuid(117E202D-A859-4C89-873B-C2AA566788E3)]
+interface IVisual : IInspectable
+{
+ [propget] HRESULT AnchorPoint([out] [retval] Vector2* value);
+ [propput] HRESULT AnchorPoint([in] Vector2 value);
+ [propget] HRESULT BackfaceVisibility([out] [retval] CompositionBackfaceVisibility* value);
+ [propput] HRESULT BackfaceVisibility([in] CompositionBackfaceVisibility value);
+ [propget] HRESULT BorderMode([out] [retval] CompositionBorderMode* value);
+ [propput] HRESULT BorderMode([in] CompositionBorderMode value);
+ [propget] HRESULT CenterPoint([out] [retval] Vector3* value);
+ [propput] HRESULT CenterPoint([in] Vector3 value);
+ [propget] HRESULT Clip([out] [retval]void** value);
+ [propput] HRESULT Clip([in] void* value);
+ [propget] HRESULT CompositeMode([out] [retval] CompositionCompositeMode* value);
+ [propput] HRESULT CompositeMode([in] CompositionCompositeMode value);
+ [propget] HRESULT IsVisible([out] [retval] boolean* value);
+ [propput] HRESULT IsVisible([in] boolean value);
+ [propget] HRESULT Offset([out] [retval] Vector3* value);
+ [propput] HRESULT Offset([in] Vector3 value);
+ [propget] HRESULT Opacity([out] [retval] FLOAT* value);
+ [propput] HRESULT Opacity([in] FLOAT value);
+ [propget] HRESULT Orientation([out] [retval] Quaternion* value);
+ [propput] HRESULT Orientation([in] Quaternion value);
+ [propget] HRESULT Parent([out] [retval] IContainerVisual** value);
+ [propget] HRESULT RotationAngle([out] [retval] FLOAT* value);
+ [propput] HRESULT RotationAngle([in] FLOAT value);
+ [propget] HRESULT RotationAngleInDegrees([out] [retval] FLOAT* value);
+ [propput] HRESULT RotationAngleInDegrees([in] FLOAT value);
+ [propget] HRESULT RotationAxis([out] [retval] Vector3* value);
+ [propput] HRESULT RotationAxis([in] Vector3 value);
+ [propget] HRESULT Scale([out] [retval] Vector3* value);
+ [propput] HRESULT Scale([in] Vector3 value);
+ [propget] HRESULT Size([out] [retval] Vector2* value);
+ [propput] HRESULT Size([in] Vector2 value);
+ [propget] HRESULT TransformMatrix([out] [retval] Matrix4x4* value);
+ [propput] HRESULT TransformMatrix([in] Matrix4x4 value);
+}
+
+[uuid(3052B611-56C3-4C3E-8BF3-F6E1AD473F06)]
+interface IVisual2 : IInspectable
+{
+ [propget] HRESULT ParentForTransform([out] [retval] IVisual** value);
+ [propput] HRESULT ParentForTransform([in] IVisual* value);
+ [propget] HRESULT RelativeOffsetAdjustment([out] [retval] Vector3* value);
+ [propput] HRESULT RelativeOffsetAdjustment([in] Vector3 value);
+ [propget] HRESULT RelativeSizeAdjustment([out] [retval] Vector2* value);
+ [propput] HRESULT RelativeSizeAdjustment([in] Vector2 value);
+}
+
+[uuid(02F6BC74-ED20-4773-AFE6-D49B4A93DB32)]
+interface IContainerVisual : IInspectable
+{
+ [propget] HRESULT GetChildren([out] [retval] IVisualCollection** value);
+}
+
+[uuid(8B745505-FD3E-4A98-84A8-E949468C6BCB)]
+interface IVisualCollection : IInspectable
+{
+ [propget] HRESULT GetCount([out] [retval] INT32* value);
+ HRESULT InsertAbove([in] IVisual* newChild, [in] IVisual* sibling);
+ HRESULT InsertAtBottom([in] IVisual* newChild);
+ HRESULT InsertAtTop([in] IVisual* newChild);
+ HRESULT InsertBelow([in] IVisual* newChild, [in] IVisual* sibling);
+ HRESULT Remove([in] IVisual* child);
+ HRESULT RemoveAll();
+}
+
+[uuid(A1BEA8BA-D726-4663-8129-6B5E7927FFA6)]
+interface ICompositionTarget : IInspectable
+{
+ [propget] HRESULT Root([out] [retval] IVisual** value);
+ [propput] HRESULT Root([in] IVisual* value);
+}
+
+
+[uuid(CB51C0CE-8FE6-4636-B202-861FAA07D8F3)]
+interface IGraphicsEffect : IInspectable
+{
+ [propget] HRESULT Name([out] [retval] HSTRING* name);
+ [propput] HRESULT Name([in] HSTRING name);
+}
+
+[uuid(2D8F9DDC-4339-4EB9-9216-F9DEB75658A2)]
+interface IGraphicsEffectSource : IInspectable
+{
+}
+
+enum GRAPHICS_EFFECT_PROPERTY_MAPPING
+{
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_UNKNOWN,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORX,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORY,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORZ,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORW,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_RECT_TO_VECTOR4,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_RADIANS_TO_DEGREES,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_COLORMATRIX_ALPHA_MODE,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_COLOR_TO_VECTOR3,
+ GRAPHICS_EFFECT_PROPERTY_MAPPING_COLOR_TO_VECTOR4
+}
+
+[uuid(2FC57384-A068-44D7-A331-30982FCF7177)]
+interface IGraphicsEffectD2D1Interop : IUnknown
+{
+ HRESULT GetEffectId([out] Guid* id);
+ HRESULT GetNamedPropertyMapping(IntPtr name, uint* index, GRAPHICS_EFFECT_PROPERTY_MAPPING* mapping);
+ HRESULT GetPropertyCount([out] uint* count);
+ HRESULT GetProperty(uint index, [out]IPropertyValue** value);
+ HRESULT GetSource(uint index, [out, retval] IGraphicsEffectSource** source);
+ HRESULT GetSourceCount([retval]uint *count);
+};
+
+[uuid(858AB13A-3292-4E4E-B3BB-2B6C6544A6EE)]
+interface ICompositionEffectSourceParameter : IInspectable
+{
+ [propget] HRESULT Name([out] [retval] HSTRING* value);
+}
+
+[uuid(B3D9F276-ABA3-4724-ACF3-D0397464DB1C)]
+interface ICompositionEffectSourceParameterFactory : IInspectable
+{
+ HRESULT Create([in] HSTRING name, [out] [retval] ICompositionEffectSourceParameter** instance);
+}
+
+enum CompositionEffectFactoryLoadStatus
+{
+ Success = 0,
+ EffectTooComplex = 1,
+ Pending = 2,
+ Other = -1
+}
+
+[uuid(BE5624AF-BA7E-4510-9850-41C0B4FF74DF)]
+interface ICompositionEffectFactory : IInspectable
+{
+ HRESULT CreateBrush([out] [retval] ICompositionEffectBrush** result);
+ [propget] HRESULT ExtendedError([out] [retval] int* value);
+ [propget] HRESULT LoadStatus([out] [retval] CompositionEffectFactoryLoadStatus* value);
+}
+
+[uuid(BF7F795E-83CC-44BF-A447-3E3C071789EC)]
+interface ICompositionEffectBrush : IInspectable
+{
+ HRESULT GetSourceParameter([in] HSTRING name, [out] [retval] ICompositionBrush** result);
+ HRESULT SetSourceParameter([in] HSTRING name, [in] ICompositionBrush* source);
+}
+
+[uuid(C5ACAE58-3898-499E-8D7F-224E91286A5D)]
+interface ICompositionBackdropBrush : IInspectable
+{
+}
+
+[uuid(2B264C5E-BF35-4831-8642-CF70C20FFF2F)]
+interface ICompositionColorBrush : IInspectable
+{
+ [propget] HRESULT Color([out] [retval] Color* value);
+ [propput] HRESULT Color([in] Color value);
+}
+
+[uuid(0D00DAD0-FB07-46FD-8C72-6280D1A3D1DD)]
+interface ICompositionScopedBatch : IInspectable
+{
+ [propget] HRESULT IsActive([out] [retval] boolean* value);
+ [propget] HRESULT IsEnded([out] [retval] boolean* value);
+ HRESULT End();
+ HRESULT Resume();
+ HRESULT Suspend();
+ [eventadd] HRESULT AddCompleted([in] void* handler, [out] [retval] int* token);
+ [eventremove] HRESULT RemoveCompleted([in] int token);
+}
+
+[uuid(48EA31AD-7FCD-4076-A79C-90CC4B852C9B)]
+interface ICompositor5 : IInspectable
+{
+ [propget] HRESULT GetComment([out] [retval] HSTRING* value);
+ [propput] HRESULT SetComment([in] HSTRING value);
+ [propget] HRESULT GetGlobalPlaybackRate([out] [retval] FLOAT* value);
+ [propput] HRESULT SetGlobalPlaybackRate([in] FLOAT value);
+ HRESULT CreateBounceScalarAnimation([out] [retval] void** result);
+ HRESULT CreateBounceVector2Animation([out] [retval] void** result);
+ HRESULT CreateBounceVector3Animation([out] [retval] void** result);
+ HRESULT CreateContainerShape([out] [retval] void** result);
+ HRESULT CreateEllipseGeometry([out] [retval] void** result);
+ HRESULT CreateLineGeometry([out] [retval] void** result);
+ [overload("CreatePathGeometry")] HRESULT CreatePathGeometry([out] [retval] void** result);
+ [overload("CreatePathGeometry")] HRESULT CreatePathGeometryWithPath([in] void* path, [out] [retval] void** result);
+ HRESULT CreatePathKeyFrameAnimation([out] [retval] void** result);
+ HRESULT CreateRectangleGeometry([out] [retval] void** result);
+ HRESULT CreateRoundedRectangleGeometry([out] [retval] void** result);
+ HRESULT CreateShapeVisual([out] [retval] void** result);
+ [overload("CreateSpriteShape")] HRESULT CreateSpriteShape([out] [retval] void** result);
+ [overload("CreateSpriteShape")] HRESULT CreateSpriteShapeWithGeometry([in] void* geometry, [out] [retval] void** result);
+ HRESULT CreateViewBox([out] [retval] void** result);
+ HRESULT RequestCommitAsync([out] [retval] IAsyncAction** operation);
+}
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
index d770f4b211..e7d16f731c 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
@@ -65,23 +65,10 @@ namespace Avalonia.Win32
return IntPtr.Zero;
}
- // Based on https://github.com/dotnet/wpf/blob/master/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs#L4270-L4337
- // We need to enable parent window before destroying child window to prevent OS from activating a random window behind us.
- // This is described here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow#remarks
- // Our window closed callback will set enabled state to a correct value after child window gets destroyed.
- // We need to verify if parent is still alive (perhaps it got destroyed somehow).
- if (_parent != null && IsWindow(_parent._hwnd))
- {
- var wasActive = GetActiveWindow() == _hwnd;
-
- _parent.SetEnabled(true);
+ BeforeCloseCleanup(false);
- // We also need to activate our parent window since again OS might try to activate a window behind if it is not set.
- if (wasActive)
- {
- SetActiveWindow(_parent._hwnd);
- }
- }
+ // Used to distinguish between programmatic and regular close requests.
+ _isCloseRequested = true;
break;
}
@@ -361,6 +348,7 @@ namespace Avalonia.Win32
case WindowsMessage.WM_PAINT:
{
+ using(NonPumpingSyncContext.Use())
using (_rendererLock.Lock())
{
if (BeginPaint(_hwnd, out PAINTSTRUCT ps) != IntPtr.Zero)
@@ -378,6 +366,7 @@ namespace Avalonia.Win32
case WindowsMessage.WM_SIZE:
{
+ using(NonPumpingSyncContext.Use())
using (_rendererLock.Lock())
{
// Do nothing here, just block until the pending frame render is completed on the render thread
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 715c8fc01d..3c09d2b7a0 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -15,6 +15,8 @@ using Avalonia.Rendering;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using Avalonia.Win32.OpenGl;
+using Avalonia.Win32.WinRT;
+using Avalonia.Win32.WinRT.Composition;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32
@@ -81,6 +83,7 @@ namespace Avalonia.Win32
private POINT _maxTrackSize;
private WindowImpl _parent;
private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default;
+ private bool _isCloseRequested;
public WindowImpl()
{
@@ -107,7 +110,7 @@ namespace Avalonia.Win32
var glPlatform = AvaloniaLocator.Current.GetService();
- var compositionConnector = AvaloniaLocator.Current.GetService();
+ var compositionConnector = AvaloniaLocator.Current.GetService();
_isUsingComposition = compositionConnector is { } &&
glPlatform is EglPlatformOpenGlInterface egl &&
@@ -121,8 +124,8 @@ namespace Avalonia.Win32
{
if (_isUsingComposition)
{
- var cgl = new CompositionEglGlPlatformSurface(glPlatform as EglPlatformOpenGlInterface, this);
- _blurHost = cgl.AttachToCompositionTree(compositionConnector, _hwnd);
+ var cgl = new WinUiCompositedWindowSurface(compositionConnector, this);
+ _blurHost = cgl;
_gl = cgl;
@@ -240,7 +243,7 @@ namespace Avalonia.Win32
{
if (IsWindowVisible(_hwnd))
{
- ShowWindow(value);
+ ShowWindow(value, true);
}
else
{
@@ -452,9 +455,14 @@ namespace Avalonia.Win32
if (customRendererFactory != null)
return customRendererFactory.Create(root, loop);
- return Win32Platform.UseDeferredRendering ?
- (IRenderer)new DeferredRenderer(root, loop, rendererLock: _rendererLock) :
- new ImmediateRenderer(root);
+ return Win32Platform.UseDeferredRendering
+ ? _isUsingComposition
+ ? new DeferredRenderer(root, loop)
+ {
+ RenderOnlyOnRenderThread = true
+ }
+ : (IRenderer)new DeferredRenderer(root, loop, rendererLock: _rendererLock)
+ : new ImmediateRenderer(root);
}
public void Resize(Size value)
@@ -489,6 +497,8 @@ namespace Avalonia.Win32
public void Dispose()
{
+ (_gl as IDisposable)?.Dispose();
+
if (_dropTarget != null)
{
OleContext.Current?.UnregisterDragDrop(Handle);
@@ -497,6 +507,13 @@ namespace Avalonia.Win32
if (_hwnd != IntPtr.Zero)
{
+ // Detect if we are being closed programmatically - this would mean that WM_CLOSE was not called
+ // and we didn't prepare this window for destruction.
+ if (!_isCloseRequested)
+ {
+ BeforeCloseCleanup(true);
+ }
+
DestroyWindow(_hwnd);
_hwnd = IntPtr.Zero;
}
@@ -550,10 +567,11 @@ namespace Avalonia.Win32
UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide);
}
- public virtual void Show()
+ public virtual void Show(bool activate)
{
SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent != null ? _parent._hwnd : IntPtr.Zero);
- ShowWindow(_showWindowState);
+
+ ShowWindow(_showWindowState, activate);
}
public Action GotInputWhenDisabled { get; set; }
@@ -891,7 +909,7 @@ namespace Avalonia.Win32
ExtendClientAreaToDecorationsChanged?.Invoke(_isClientAreaExtended);
}
- private void ShowWindow(WindowState state)
+ private void ShowWindow(WindowState state, bool activate)
{
ShowWindowCommand? command;
@@ -901,7 +919,7 @@ namespace Avalonia.Win32
{
case WindowState.Minimized:
newWindowProperties.IsFullScreen = false;
- command = ShowWindowCommand.Minimize;
+ command = activate ? ShowWindowCommand.Minimize : ShowWindowCommand.ShowMinNoActive;
break;
case WindowState.Maximized:
newWindowProperties.IsFullScreen = false;
@@ -910,7 +928,8 @@ namespace Avalonia.Win32
case WindowState.Normal:
newWindowProperties.IsFullScreen = false;
- command = ShowWindowCommand.Restore;
+ command = IsWindowVisible(_hwnd) ? ShowWindowCommand.Restore :
+ activate ? ShowWindowCommand.Normal : ShowWindowCommand.ShowNoActivate;
break;
case WindowState.FullScreen:
@@ -939,6 +958,32 @@ namespace Avalonia.Win32
SetFocus(_hwnd);
}
}
+
+ private void BeforeCloseCleanup(bool isDisposing)
+ {
+ // Based on https://github.com/dotnet/wpf/blob/master/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs#L4270-L4337
+ // We need to enable parent window before destroying child window to prevent OS from activating a random window behind us (or last active window).
+ // This is described here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow#remarks
+ // We need to verify if parent is still alive (perhaps it got destroyed somehow).
+ if (_parent != null && IsWindow(_parent._hwnd))
+ {
+ var wasActive = GetActiveWindow() == _hwnd;
+
+ // We can only set enabled state if we are not disposing - generally Dispose happens after enabled state has been set.
+ // Ignoring this would cause us to enable a window that might be disabled.
+ if (!isDisposing)
+ {
+ // Our window closed callback will set enabled state to a correct value after child window gets destroyed.
+ _parent.SetEnabled(true);
+ }
+
+ // We also need to activate our parent window since again OS might try to activate a window behind if it is not set.
+ if (wasActive)
+ {
+ SetActiveWindow(_parent._hwnd);
+ }
+ }
+ }
private void MaximizeWithoutCoveringTaskbar()
{
diff --git a/src/tools/MicroComGenerator/AstParser.cs b/src/tools/MicroComGenerator/AstParser.cs
index 732c0496b3..388a8eb018 100644
--- a/src/tools/MicroComGenerator/AstParser.cs
+++ b/src/tools/MicroComGenerator/AstParser.cs
@@ -13,7 +13,8 @@ namespace MicroComGenerator
while (!parser.Eof)
{
var attrs = ParseLocalAttributes(ref parser);
-
+ if (parser.TryConsume(";"))
+ continue;
if (parser.TryParseKeyword("enum"))
idl.Enums.Add(ParseEnum(attrs, ref parser));
else if (parser.TryParseKeyword("struct"))
@@ -64,7 +65,7 @@ namespace MicroComGenerator
static AstAttributes ParseLocalAttributes(ref TokenParser parser)
{
var rv = new AstAttributes();
- if (parser.TryConsume("["))
+ while (parser.TryConsume("["))
{
while (!parser.TryConsume("]") && !parser.Eof)
{
@@ -78,7 +79,7 @@ namespace MicroComGenerator
if (parser.TryConsume(']'))
{
rv.Add(new AstAttributeNode(ident, null));
- return rv;
+ break;
}
// No value, next attribute
else if (parser.TryConsume(','))
diff --git a/src/tools/MicroComGenerator/CSharpGen.InterfaceGen.cs b/src/tools/MicroComGenerator/CSharpGen.InterfaceGen.cs
index 91ece81bd0..adb8faf938 100644
--- a/src/tools/MicroComGenerator/CSharpGen.InterfaceGen.cs
+++ b/src/tools/MicroComGenerator/CSharpGen.InterfaceGen.cs
@@ -21,7 +21,7 @@ namespace MicroComGenerator
{
public string Name;
public string NativeType;
-
+ public AstAttributes Attributes { get; set; }
public virtual StatementSyntax CreateFixed(StatementSyntax inner) => inner;
public virtual void PreMarshal(List body)
@@ -161,6 +161,13 @@ namespace MicroComGenerator
return type;
}
+ Arg ConvertArg(AstInterfaceMemberArgumentNode node)
+ {
+ var arg = ConvertArg(node.Name, node.Type);
+ arg.Attributes = node.Attributes.Clone();
+ return arg;
+ }
+
Arg ConvertArg(string name, AstTypeNode type)
{
type = new AstTypeNode { Name = ConvertNativeType(type.Name), PointerLevel = type.PointerLevel };
@@ -190,12 +197,19 @@ namespace MicroComGenerator
List vtblCtor, int num)
{
// Prepare method information
- var args = member.Select(a => ConvertArg(a.Name, a.Type)).ToList();
+ if (member.Name == "GetRenderingDevice")
+ Console.WriteLine();
+ var args = member.Select(ConvertArg).ToList();
var returnArg = ConvertArg("__result", member.ReturnType);
bool isHresult = member.ReturnType.Name == "HRESULT";
bool isHresultLastArgumentReturn = isHresult
&& args.Count > 0
- && (args.Last().Name == "ppv" || args.Last().Name == "retOut" || args.Last().Name == "ret")
+ && (args.Last().Name == "ppv"
+ || args.Last().Name == "retOut"
+ || args.Last().Name == "ret"
+ || args.Last().Attributes.HasAttribute("out")
+ || args.Last().Attributes.HasAttribute("retval")
+ )
&& ((member.Last().Type.PointerLevel > 0
&& !IsInterface(member.Last().Type))
|| member.Last().Type.PointerLevel == 2);
@@ -334,16 +348,27 @@ namespace MicroComGenerator
BlockSyntax backBodyBlock = Block().AddStatements(backPreMarshal.ToArray()).AddStatements(backCallStatement);
+ var exceptions = new List()
+ {
+ CatchClause(
+ CatchDeclaration(ParseTypeName("System.Exception"), Identifier("__exception__")), null,
+ Block(
+ ParseStatement(
+ "Avalonia.MicroCom.MicroComRuntime.UnhandledException(__target, __exception__);"),
+ isHresult ? ParseStatement("return unchecked((int)0x80004005u);")
+ : isVoidReturn ? EmptyStatement() : ParseStatement("return default;")
+ ))
+ };
+
+ if (isHresult)
+ exceptions.Insert(0, CatchClause(
+ CatchDeclaration(ParseTypeName("System.Runtime.InteropServices.COMException"),
+ Identifier("__com_exception__")),
+ null, Block(ParseStatement("return __com_exception__.ErrorCode;"))));
+
backBodyBlock = Block(
TryStatement(
- SingletonList(CatchClause(
- CatchDeclaration(ParseTypeName("System.Exception"), Identifier("__exception__")), null,
- Block(
- ParseStatement(
- "Avalonia.MicroCom.MicroComRuntime.UnhandledException(__target, __exception__);"),
- isHresult ? ParseStatement("return unchecked((int)0x80004005u);")
- : isVoidReturn ? EmptyStatement() : ParseStatement("return default;")
- ))))
+ List(exceptions))
.WithBlock(Block(backBodyBlock))
);
if (isHresult)
diff --git a/src/tools/MicroComGenerator/CSharpGen.Utils.cs b/src/tools/MicroComGenerator/CSharpGen.Utils.cs
index 3a62220d12..da845b0ecd 100644
--- a/src/tools/MicroComGenerator/CSharpGen.Utils.cs
+++ b/src/tools/MicroComGenerator/CSharpGen.Utils.cs
@@ -68,10 +68,11 @@ namespace MicroComGenerator
bool IsPropertyRewriteCandidate(MethodDeclarationSyntax method)
{
- if(method.Identifier.Text.Contains("GetScaling"))
- Console.WriteLine();
- return (method.Identifier.Text.StartsWith("Get") &&
- method.ParameterList.Parameters.Count == 0);
+
+ return
+ method.ReturnType.ToFullString() != "void"
+ && method.Identifier.Text.StartsWith("Get")
+ && method.ParameterList.Parameters.Count == 0;
}
TypeDeclarationSyntax RewriteMethodsToProperties(T decl) where T : TypeDeclarationSyntax
diff --git a/src/tools/MicroComGenerator/CSharpGen.cs b/src/tools/MicroComGenerator/CSharpGen.cs
index 688036ffc2..ff4c351fd9 100644
--- a/src/tools/MicroComGenerator/CSharpGen.cs
+++ b/src/tools/MicroComGenerator/CSharpGen.cs
@@ -22,7 +22,11 @@ namespace MicroComGenerator
public CSharpGen(AstIdlNode idl)
{
_idl = idl.Clone();
- new AstRewriter().VisitAst(_idl);
+ new AstRewriter(_idl.Attributes.Where(a => a.Name == "clr-map")
+ .Select(x => x.Value.Trim().Split(' '))
+ .ToDictionary(x => x[0], x => x[1])
+ ).VisitAst(_idl);
+
_extraUsings = _idl.Attributes.Where(u => u.Name == "clr-using").Select(u => u.Value).ToList();
_namespace = _idl.GetAttribute("clr-namespace");
var visibilityString = _idl.GetAttribute("clr-access");
@@ -37,6 +41,13 @@ namespace MicroComGenerator
class AstRewriter : AstVisitor
{
+ private readonly Dictionary _typeMap = new Dictionary();
+
+ public AstRewriter(Dictionary typeMap)
+ {
+ _typeMap = typeMap;
+ }
+
void ConvertIntPtr(AstTypeNode type)
{
if (type.Name == "void" && type.PointerLevel > 0)
@@ -60,6 +71,9 @@ namespace MicroComGenerator
type.PointerLevel++;
type.IsLink = false;
}
+
+ if (_typeMap.TryGetValue(type.Name, out var mapped))
+ type.Name = mapped;
base.VisitType(type);
}
@@ -80,6 +94,10 @@ namespace MicroComGenerator
{
if (member.HasAttribute("intptr"))
ConvertIntPtr(member.ReturnType);
+ if (member.HasAttribute("propget") && !member.Name.StartsWith("Get"))
+ member.Name = "Get" + member.Name;
+ if (member.HasAttribute("propput") && !member.Name.StartsWith("Set"))
+ member.Name = "Set" + member.Name;
base.VisitInterfaceMember(member);
}
}
@@ -103,7 +121,8 @@ namespace MicroComGenerator
NamespaceDeclarationSyntax GenerateEnums(NamespaceDeclarationSyntax ns)
{
return ns.AddMembers(_idl.Enums.Select(e =>
- EnumDeclaration(e.Name)
+ {
+ var dec = EnumDeclaration(e.Name)
.WithModifiers(TokenList(Token(_visibility)))
.WithMembers(SeparatedList(e.Select(m =>
{
@@ -111,8 +130,11 @@ namespace MicroComGenerator
if (m.Value != null)
return member.WithEqualsValue(EqualsValueClause(ParseExpression(m.Value)));
return member;
- })))
- ).ToArray());
+ })));
+ if (e.HasAttribute("flags"))
+ dec = dec.AddAttribute("System.Flags");
+ return dec;
+ }).ToArray());
}
NamespaceDeclarationSyntax GenerateStructs(NamespaceDeclarationSyntax ns)
diff --git a/src/tools/MicroComGenerator/CppGen.cs b/src/tools/MicroComGenerator/CppGen.cs
index 68192ebffe..b053088ca9 100644
--- a/src/tools/MicroComGenerator/CppGen.cs
+++ b/src/tools/MicroComGenerator/CppGen.cs
@@ -14,7 +14,10 @@ namespace MicroComGenerator
name = "unsigned char";
else if(name == "uint")
name = "unsigned int";
- return name + new string('*', type.PointerLevel);
+
+ type = type.Clone();
+ type.Name = name;
+ return type.Format();
}
public static string GenerateCpp(AstIdlNode idl)
diff --git a/tests/Avalonia.Animation.UnitTests/Avalonia.Animation.UnitTests.csproj b/tests/Avalonia.Animation.UnitTests/Avalonia.Animation.UnitTests.csproj
index dd50eff2b6..5b686dea4c 100644
--- a/tests/Avalonia.Animation.UnitTests/Avalonia.Animation.UnitTests.csproj
+++ b/tests/Avalonia.Animation.UnitTests/Avalonia.Animation.UnitTests.csproj
@@ -10,6 +10,7 @@
+
diff --git a/tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj b/tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj
index 0d87f0eb03..badfd09430 100644
--- a/tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj
+++ b/tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj
@@ -10,6 +10,7 @@
+
@@ -17,4 +18,4 @@
-
\ No newline at end of file
+
diff --git a/tests/Avalonia.Benchmarks/Layout/ControlsBenchmark.cs b/tests/Avalonia.Benchmarks/Layout/ControlsBenchmark.cs
index 7170f6d7d4..3493dd0f53 100644
--- a/tests/Avalonia.Benchmarks/Layout/ControlsBenchmark.cs
+++ b/tests/Avalonia.Benchmarks/Layout/ControlsBenchmark.cs
@@ -17,7 +17,8 @@ namespace Avalonia.Benchmarks.Layout
_app = UnitTestApplication.Start(
TestServices.StyledWindow.With(
renderInterface: new NullRenderingPlatform(),
- threadingInterface: new NullThreadingPlatform()));
+ threadingInterface: new NullThreadingPlatform(),
+ standardCursorFactory: new NullCursorFactory()));
_root = new TestRoot(true, null)
{
diff --git a/tests/Avalonia.Benchmarks/NullCursorFactory.cs b/tests/Avalonia.Benchmarks/NullCursorFactory.cs
new file mode 100644
index 0000000000..012adce0f2
--- /dev/null
+++ b/tests/Avalonia.Benchmarks/NullCursorFactory.cs
@@ -0,0 +1,14 @@
+using System;
+using Avalonia.Input;
+using Avalonia.Platform;
+
+namespace Avalonia.Benchmarks
+{
+ internal class NullCursorFactory : IStandardCursorFactory
+ {
+ public IPlatformHandle GetCursor(StandardCursorType cursorType)
+ {
+ return new PlatformHandle(IntPtr.Zero, "null");
+ }
+ }
+}
diff --git a/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs b/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs
index f632d85c26..1570205456 100644
--- a/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs
+++ b/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs
@@ -28,7 +28,7 @@ namespace Avalonia.Benchmarks
public IGeometryImpl CreateRectangleGeometry(Rect rect)
{
- throw new NotImplementedException();
+ return new MockStreamGeometryImpl();
}
public IStreamGeometryImpl CreateStreamGeometry()
diff --git a/tests/Avalonia.Controls.DataGrid.UnitTests/Avalonia.Controls.DataGrid.UnitTests.csproj b/tests/Avalonia.Controls.DataGrid.UnitTests/Avalonia.Controls.DataGrid.UnitTests.csproj
index 396dfee691..c0c9303767 100644
--- a/tests/Avalonia.Controls.DataGrid.UnitTests/Avalonia.Controls.DataGrid.UnitTests.csproj
+++ b/tests/Avalonia.Controls.DataGrid.UnitTests/Avalonia.Controls.DataGrid.UnitTests.csproj
@@ -12,6 +12,7 @@
+
diff --git a/tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj b/tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj
index 7a6d77ef46..6b17427eda 100644
--- a/tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj
+++ b/tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj
@@ -12,6 +12,7 @@
+
diff --git a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
index 783215fb5d..c8a30a42e9 100644
--- a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
@@ -40,6 +40,7 @@ namespace Avalonia.Controls.UnitTests
Items = items,
SelectedIndex = 0,
};
+ var root = new TestRoot(target);
var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle;
Assert.NotNull(rectangle);
diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
index c179aef9ac..39a3250686 100644
--- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
@@ -79,7 +79,7 @@ namespace Avalonia.Controls.UnitTests
{
using (Application())
{
- popupImpl.Setup(x => x.Show()).Verifiable();
+ popupImpl.Setup(x => x.Show(true)).Verifiable();
popupImpl.Setup(x => x.Hide()).Verifiable();
var sut = new ContextMenu();
@@ -99,7 +99,7 @@ namespace Avalonia.Controls.UnitTests
_mouse.Click(target);
Assert.False(sut.IsOpen);
- popupImpl.Verify(x => x.Show(), Times.Once);
+ popupImpl.Verify(x => x.Show(true), Times.Once);
popupImpl.Verify(x => x.Hide(), Times.Once);
}
}
@@ -109,7 +109,7 @@ namespace Avalonia.Controls.UnitTests
{
using (Application())
{
- popupImpl.Setup(x => x.Show()).Verifiable();
+ popupImpl.Setup(x => x.Show(true)).Verifiable();
popupImpl.Setup(x => x.Hide()).Verifiable();
var sut = new ContextMenu();
@@ -130,7 +130,7 @@ namespace Avalonia.Controls.UnitTests
Assert.True(sut.IsOpen);
popupImpl.Verify(x => x.Hide(), Times.Once);
- popupImpl.Verify(x => x.Show(), Times.Exactly(2));
+ popupImpl.Verify(x => x.Show(true), Times.Exactly(2));
}
}
@@ -177,7 +177,7 @@ namespace Avalonia.Controls.UnitTests
{
using (Application())
{
- popupImpl.Setup(x => x.Show()).Verifiable();
+ popupImpl.Setup(x => x.Show(true)).Verifiable();
bool eventCalled = false;
var sut = new ContextMenu();
@@ -193,7 +193,7 @@ namespace Avalonia.Controls.UnitTests
Assert.True(eventCalled);
Assert.False(sut.IsOpen);
- popupImpl.Verify(x => x.Show(), Times.Never);
+ popupImpl.Verify(x => x.Show(true), Times.Never);
}
}
@@ -297,7 +297,7 @@ namespace Avalonia.Controls.UnitTests
{
using (Application())
{
- popupImpl.Setup(x => x.Show()).Verifiable();
+ popupImpl.Setup(x => x.Show(true)).Verifiable();
popupImpl.Setup(x => x.Hide()).Verifiable();
bool eventCalled = false;
@@ -321,7 +321,7 @@ namespace Avalonia.Controls.UnitTests
Assert.True(eventCalled);
Assert.True(sut.IsOpen);
- popupImpl.Verify(x => x.Show(), Times.Once());
+ popupImpl.Verify(x => x.Show(true), Times.Once());
popupImpl.Verify(x => x.Hide(), Times.Never);
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
index 84f212d1b3..8109b037c5 100644
--- a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
@@ -137,7 +137,7 @@ namespace Avalonia.Controls.UnitTests
var target = new TestWindowBase(windowImpl.Object);
target.IsVisible = true;
- windowImpl.Verify(x => x.Show());
+ windowImpl.Verify(x => x.Show(true));
}
}
diff --git a/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj b/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj
index 1cfc1a6ab8..c59e59be63 100644
--- a/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj
+++ b/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj
@@ -27,4 +27,5 @@
+
diff --git a/tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj b/tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj
index e346ce944d..42229ba456 100644
--- a/tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj
+++ b/tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj
@@ -7,6 +7,7 @@
+
@@ -22,4 +23,4 @@
-
\ No newline at end of file
+
diff --git a/tests/Avalonia.Layout.UnitTests/Avalonia.Layout.UnitTests.csproj b/tests/Avalonia.Layout.UnitTests/Avalonia.Layout.UnitTests.csproj
index 463bc50008..74cc6e292b 100644
--- a/tests/Avalonia.Layout.UnitTests/Avalonia.Layout.UnitTests.csproj
+++ b/tests/Avalonia.Layout.UnitTests/Avalonia.Layout.UnitTests.csproj
@@ -8,6 +8,7 @@
+
diff --git a/tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj b/tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj
index 27f3223c6c..d49a859b89 100644
--- a/tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj
+++ b/tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj
@@ -7,6 +7,7 @@
+
@@ -25,4 +26,4 @@
-
\ No newline at end of file
+
diff --git a/tests/Avalonia.Markup.UnitTests/Avalonia.Markup.UnitTests.csproj b/tests/Avalonia.Markup.UnitTests/Avalonia.Markup.UnitTests.csproj
index ec5b2f0ed1..7d1285c025 100644
--- a/tests/Avalonia.Markup.UnitTests/Avalonia.Markup.UnitTests.csproj
+++ b/tests/Avalonia.Markup.UnitTests/Avalonia.Markup.UnitTests.csproj
@@ -10,6 +10,7 @@
+
diff --git a/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_AttachedProperty.cs b/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_AttachedProperty.cs
index 45cf28773f..7c48a975ef 100644
--- a/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_AttachedProperty.cs
+++ b/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_AttachedProperty.cs
@@ -129,7 +129,7 @@ namespace Avalonia.Markup.UnitTests.Parsers
{
var data = new Class1();
- Assert.Throws(() => ExpressionObserverBuilder.Build(data, "(Owner)", typeResolver: _typeResolver));
+ Assert.Throws(() => ExpressionObserverBuilder.Build(data, "(Owner.)", typeResolver: _typeResolver));
}
[Fact]
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj
index ad3592294d..44b604197d 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj
@@ -10,6 +10,7 @@
+
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs
index 9ea2cd643a..20ed22e84f 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs
@@ -84,6 +84,54 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
}
+ [Fact]
+ public void SupportCastToTypeInExpression()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ var dataContext = new TestDataContext
+ {
+ StringProperty = "foobar"
+ };
+
+ window.DataContext = dataContext;
+
+ Assert.Equal(dataContext.StringProperty, contentControl.Content);
+ }
+ }
+
+ [Fact]
+ public void SupportCastToTypeInExpression_DifferentTypeEvaluatesToNull()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ var dataContext = "foo";
+
+ window.DataContext = dataContext;
+
+ Assert.Equal(null, contentControl.Content);
+ }
+ }
private class FooBar
{
public object Foo { get; } = null;
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
index 8a82ad048b..1cf9e0877d 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Globalization;
using System.Reactive.Subjects;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
+using Avalonia.Data.Converters;
using Avalonia.Data.Core;
using Avalonia.Markup.Data;
using Avalonia.UnitTests;
@@ -372,7 +374,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
";
- Assert.Throws(() => AvaloniaRuntimeXamlLoader.Load(xaml));
+ ThrowsXamlTransformException(() => AvaloniaRuntimeXamlLoader.Load(xaml));
}
}
@@ -390,7 +392,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
";
- Assert.Throws(() => AvaloniaRuntimeXamlLoader.Load(xaml));
+ ThrowsXamlTransformException(() => AvaloniaRuntimeXamlLoader.Load(xaml));
}
}
@@ -447,7 +449,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
";
- Assert.Throws(() => AvaloniaRuntimeXamlLoader.Load(xaml));
+ ThrowsXamlTransformException(() => AvaloniaRuntimeXamlLoader.Load(xaml));
}
}
@@ -597,7 +599,49 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
x:CompileBindings='true'>
";
- Assert.Throws(() => AvaloniaRuntimeXamlLoader.Load(xaml));
+ ThrowsXamlParseException(() => AvaloniaRuntimeXamlLoader.Load(xaml));
+ }
+ }
+
+ [Fact]
+ public void SupportParentInPath()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ Assert.Equal("foo", contentControl.Content);
+ }
+ }
+
+ [Fact]
+ public void SupportConverterWithParameter()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var textBlock = window.FindControl("textBlock");
+
+ window.DataContext = new TestDataContext() { StringProperty = "Foo" };
+
+ Assert.Equal("Foo+Bar", textBlock.Text);
}
}
@@ -613,26 +657,218 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
x:DataType='local:TestDataContext'
x:CompileBindings='notabool'>
";
- Assert.Throws(() => AvaloniaRuntimeXamlLoader.Load(xaml));
+ ThrowsXamlParseException(() => AvaloniaRuntimeXamlLoader.Load(xaml));
}
}
- }
+ [Fact]
+ public void SupportCastToTypeInExpression()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ var dataContext = new TestDataContext();
+
+ window.DataContext = dataContext;
+
+ Assert.Equal(dataContext, contentControl.Content);
+ }
+ }
+
+ [Fact]
+ public void SupportCastToTypeInExpression_DifferentTypeEvaluatesToNull()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ var dataContext = "foo";
+
+ window.DataContext = dataContext;
+
+ Assert.Equal(null, contentControl.Content);
+ }
+ }
+
+ [Fact]
+ public void SupportCastToTypeInExpressionWithProperty()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ var dataContext = new TestDataContext
+ {
+ StringProperty = "foobar"
+ };
+
+ window.DataContext = dataContext;
+
+ Assert.Equal(dataContext.StringProperty, contentControl.Content);
+ }
+ }
+
+ [Fact]
+ public void SupportCastToTypeInExpressionWithProperty1()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ var dataContext = new TestDataContext
+ {
+ StringProperty = "foobar"
+ };
+
+ window.DataContext = dataContext;
+
+ Assert.Equal(dataContext.StringProperty, contentControl.Content);
+ }
+ }
+
+ [Fact]
+ public void SupportCastToTypeInExpressionWithPropertyIndexer()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ var data = new TestData()
+ {
+ StringProperty = "Foo"
+ };
+ var dataContext = new TestDataContext
+ {
+ ObjectsArrayProperty = new object[] { data }
+ };
+
+ window.DataContext = dataContext;
+
+ Assert.Equal(data.StringProperty, contentControl.Content);
+ }
+ }
+
+ [Fact]
+ public void SupportCastToTypeInExpressionWithProperty_DifferentTypeEvaluatesToNull()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var contentControl = window.FindControl("contentControl");
+
+ var dataContext = new TestDataContext
+ {
+ StringProperty = "foobar"
+ };
+
+ window.DataContext = dataContext;
+
+ Assert.Equal(dataContext.StringProperty, contentControl.Content);
+
+ window.DataContext = "foo";
+
+ Assert.Equal(null, contentControl.Content);
+ }
+ }
+
+ void Throws(string type, Action cb)
+ {
+ try
+ {
+ cb();
+ }
+ catch (Exception e) when (e.GetType().Name == type)
+ {
+ return;
+ }
+
+ throw new Exception("Expected " + type);
+ }
+
+ void ThrowsXamlParseException(Action cb) => Throws("XamlParseException", cb);
+ void ThrowsXamlTransformException(Action cb) => Throws("XamlTransformException", cb);
+ }
+
public interface INonIntegerIndexer
{
- string this[string key] {get; set;}
+ string this[string key] { get; set; }
}
public interface INonIntegerIndexerDerived : INonIntegerIndexer
- {}
+ { }
public interface IHasProperty
{
- string StringProperty {get; set; }
+ string StringProperty { get; set; }
}
public interface IHasPropertyDerived : IHasProperty
- {}
+ { }
+
+ public class AppendConverter : IValueConverter
+ {
+ public static IValueConverter Instance { get; } = new AppendConverter();
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ => string.Format("{0}+{1}", value, parameter);
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ => throw new NotImplementedException();
+
+ }
+
+ public class TestData
+ {
+ public string StringProperty { get; set; }
+ }
public class TestDataContext : IHasPropertyDerived
{
@@ -646,6 +882,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
public string[] ArrayProperty { get; set; }
+ public object[] ObjectsArrayProperty { get; set; }
+
public List ListProperty { get; set; } = new List();
public NonIntegerIndexer NonIntegerIndexerProperty { get; set; } = new NonIntegerIndexer();
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs
index 47a73cb360..9152131ab3 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs
@@ -345,6 +345,23 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
Assert.Equal(0xff506070, brush.Color.ToUint32());
}
+ [Fact]
+ public void DynamicResource_Can_Be_Assigned_To_Resource_Property_In_Application()
+ {
+ var xaml = @"
+
+
+ #ff506070
+
+
+";
+
+ var application = (Application)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var brush = (SolidColorBrush)application.Resources["brush"];
+
+ Assert.Equal(0xff506070, brush.Color.ToUint32());
+ }
[Fact]
public void DynamicResource_Can_Be_Assigned_To_ItemTemplate_Property()
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ShapeTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ShapeTests.cs
new file mode 100644
index 0000000000..bd577e84f8
--- /dev/null
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ShapeTests.cs
@@ -0,0 +1,24 @@
+using Avalonia.Controls;
+using Avalonia.Media;
+using Xunit;
+
+namespace Avalonia.Markup.Xaml.UnitTests.Xaml
+{
+ public class ShapeTests : XamlTestBase
+ {
+ [Fact]
+ public void Can_Specify_DashStyle_In_XAML()
+ {
+ var xaml = @"
+
+
+
+
+";
+
+ var target = AvaloniaRuntimeXamlLoader.Parse(xaml);
+
+ Assert.NotNull(target);
+ }
+ }
+}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
index 67e46d25c3..77a4932ccc 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
@@ -295,8 +295,27 @@ namespace Avalonia.Markup.Xaml.UnitTests
Assert.Equal("Test", templated.Text);
}
}
+
+ [Fact]
+ public void Should_Work_With_Base_Property()
+ {
+ var parsed = (ListBox)AvaloniaRuntimeXamlLoader.Load(@"
+
+
+
+
+
+
+");
+
+ Assert.NotNull(parsed.ItemTemplate);
+ }
}
-
+
public class XamlIlBugTestsEventHandlerCodeBehind : Window
{
public object SavedContext;
diff --git a/tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj b/tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj
index 65df5e7cb0..14d0f4debf 100644
--- a/tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj
+++ b/tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj
@@ -29,4 +29,5 @@
+
diff --git a/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj b/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj
index 584eaf6fa9..ef69865e32 100644
--- a/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj
+++ b/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj
@@ -8,6 +8,7 @@
+
@@ -23,4 +24,4 @@
-
\ No newline at end of file
+
diff --git a/tests/Avalonia.Styling.UnitTests/Avalonia.Styling.UnitTests.csproj b/tests/Avalonia.Styling.UnitTests/Avalonia.Styling.UnitTests.csproj
index 2b7f6263a7..a07ec050a6 100644
--- a/tests/Avalonia.Styling.UnitTests/Avalonia.Styling.UnitTests.csproj
+++ b/tests/Avalonia.Styling.UnitTests/Avalonia.Styling.UnitTests.csproj
@@ -11,6 +11,7 @@
+
diff --git a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
index 6b5c7a66ff..d4abf9416a 100644
--- a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
+++ b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
@@ -28,4 +28,5 @@
+
diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs
index 9ec8ca2d36..8a24a8366f 100644
--- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs
+++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs
@@ -58,7 +58,7 @@ namespace Avalonia.UnitTests
windowImpl.Object.Resized?.Invoke(clientSize);
});
- windowImpl.Setup(x => x.Show()).Callback(() =>
+ windowImpl.Setup(x => x.Show(true)).Callback(() =>
{
windowImpl.Object.Activated?.Invoke();
});
diff --git a/tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj b/tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj
index aee54e87a9..13a04be5db 100644
--- a/tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj
+++ b/tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj
@@ -13,6 +13,7 @@
+
diff --git a/tests/Avalonia.Visuals.UnitTests/Media/PathSegmentTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/PathSegmentTests.cs
new file mode 100644
index 0000000000..0737b4dc88
--- /dev/null
+++ b/tests/Avalonia.Visuals.UnitTests/Media/PathSegmentTests.cs
@@ -0,0 +1,34 @@
+using Avalonia.Media;
+using Xunit;
+
+namespace Avalonia.Visuals.UnitTests.Media
+{
+ public class PathSegmentTests
+ {
+ [Fact]
+ public void PathSegment_Triggers_Invalidation_On_Property_Change()
+ {
+ var targetSegment = new ArcSegment()
+ {
+ Size = new Size(10, 10),
+ Point = new Point(5, 5)
+ };
+
+ var target = new PathGeometry
+ {
+ Figures = new PathFigures
+ {
+ new PathFigure { IsClosed = false, Segments = new PathSegments { targetSegment } }
+ }
+ };
+
+ var changed = false;
+
+ target.Changed += (s, e) => changed = true;
+
+ targetSegment.Size = new Size(20, 20);
+
+ Assert.True(changed);
+ }
+ }
+}
diff --git a/tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs
index 418ac7576b..c2a1a5f9e4 100644
--- a/tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs
@@ -1,4 +1,5 @@
-using Avalonia.Media;
+using Avalonia.Collections;
+using Avalonia.Media;
using Avalonia.Media.Immutable;
using Xunit;
@@ -39,7 +40,20 @@ namespace Avalonia.Visuals.UnitTests.Media
var raised = false;
target.Invalidated += (s, e) => raised = true;
- dashes.Dashes = new[] { 0.1, 0.2 };
+ dashes.Dashes = new AvaloniaList { 0.1, 0.2 };
+
+ Assert.True(raised);
+ }
+
+ [Fact]
+ public void Adding_DashStyle_Dashes_Raises_Invalidated()
+ {
+ var dashes = new DashStyle();
+ var target = new Pen { DashStyle = dashes };
+ var raised = false;
+
+ target.Invalidated += (s, e) => raised = true;
+ dashes.Dashes.Add(0.3);
Assert.True(raised);
}
diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTests.cs b/tests/Avalonia.Visuals.UnitTests/VisualTests.cs
index 447a68aa69..38131fbfca 100644
--- a/tests/Avalonia.Visuals.UnitTests/VisualTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/VisualTests.cs
@@ -235,6 +235,25 @@ namespace Avalonia.Visuals.UnitTests
Assert.Equal(new Point(100, 100), point);
}
+ [Fact]
+ public void TransformToVisual_With_NonInvertible_RenderTransform_Should_Work()
+ {
+ var child = new Decorator
+ {
+ Width = 100,
+ Height = 100,
+ RenderTransform = new ScaleTransform() { ScaleX = 0, ScaleY = 0 }
+ };
+ var root = new TestRoot() { Child = child, Width = 400, Height = 400 };
+
+ root.Measure(Size.Infinity);
+ root.Arrange(new Rect(new Point(), root.DesiredSize));
+
+ var tr = root.TransformToVisual(child);
+
+ Assert.Null(tr);
+ }
+
[Fact]
public void Should_Not_Log_Binding_Error_When_Not_Attached_To_Logical_Tree()
{