From a4544be13451f40e26344608bb008f3c80552fd9 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 13:53:38 -0300 Subject: [PATCH 01/98] Add WndProcs to handle extended frame windows. --- .../Interop/UnmanagedMethods.cs | 3 + .../Avalonia.Win32/WindowImpl.WndProc.cs | 155 +++++++++++++++++- 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index ba3775200b..b66de8e0a8 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1311,6 +1311,9 @@ namespace Avalonia.Win32.Interop [DllImport("dwmapi.dll")] public static extern int DwmIsCompositionEnabled(out bool enabled); + [DllImport("dwmapi.dll")] + public static extern bool DwmDefWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref IntPtr plResult); + [DllImport("dwmapi.dll")] public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs index 50e71aeebe..55b5db3bba 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs @@ -12,11 +12,164 @@ using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32 { + public partial class WindowImpl + { + private int LEFTEXTENDWIDTH = 4; + private int RIGHTEXTENDWIDTH = 4; + private int BOTTOMEXTENDWIDTH = 4; + private int TOPEXTENDWIDTH = 100; + + // Hit test the frame for resizing and moving. + HitTestValues HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam) + { + // Get the point coordinates for the hit test. + var ptMouse = PointFromLParam(lParam); + + // Get the window rectangle. + GetWindowRect(hWnd, out var rcWindow); + + // Get the frame rectangle, adjusted for the style without a caption. + RECT rcFrame = new RECT(); + AdjustWindowRectEx(ref rcFrame, (uint)(WindowStyles.WS_OVERLAPPEDWINDOW & ~WindowStyles.WS_CAPTION), false, 0); + + // Determine if the hit test is for resizing. Default middle (1,1). + ushort uRow = 1; + ushort uCol = 1; + bool fOnResizeBorder = false; + + // Determine if the point is at the top or bottom of the window. + if (ptMouse.Y >= rcWindow.top && ptMouse.Y < rcWindow.top + TOPEXTENDWIDTH) + { + fOnResizeBorder = (ptMouse.Y < (rcWindow.top - rcFrame.top)); + uRow = 0; + } + else if (ptMouse.Y < rcWindow.bottom && ptMouse.Y >= rcWindow.bottom - BOTTOMEXTENDWIDTH) + { + uRow = 2; + } + + // Determine if the point is at the left or right of the window. + if (ptMouse.X >= rcWindow.left && ptMouse.X < rcWindow.left + LEFTEXTENDWIDTH) + { + uCol = 0; // left side + } + else if (ptMouse.X < rcWindow.right && ptMouse.X >= rcWindow.right - RIGHTEXTENDWIDTH) + { + uCol = 2; // right side + } + + // Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT) + HitTestValues[][] hitTests = new[] + { + new []{ HitTestValues.HTTOPLEFT, fOnResizeBorder ? HitTestValues.HTTOP : HitTestValues.HTCAPTION, HitTestValues.HTTOPRIGHT }, + new []{ HitTestValues.HTLEFT, HitTestValues.HTNOWHERE, HitTestValues.HTRIGHT }, + new []{ HitTestValues.HTBOTTOMLEFT, HitTestValues.HTBOTTOM, HitTestValues.HTBOTTOMRIGHT }, + }; + + System.Diagnostics.Debug.WriteLine(hitTests[uRow][uCol]); + + return hitTests[uRow][uCol]; + } + + protected virtual unsafe IntPtr CustomCaptionProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref bool callDwp) + { + IntPtr lRet = IntPtr.Zero; + + callDwp = !DwmDefWindowProc(hWnd, msg, wParam, lParam, ref lRet); + + MARGINS margins = new MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyBottomHeight = 0, cyTopHeight = 100 }; + RECT border_thickness = new RECT(); + + switch ((WindowsMessage)msg) + { + case WindowsMessage.WM_ACTIVATE: + { + if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) + { + AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); + border_thickness.left *= -1; + border_thickness.top *= -1; + } + else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) + { + border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; + } + + LEFTEXTENDWIDTH = border_thickness.left; + RIGHTEXTENDWIDTH = border_thickness.right; + BOTTOMEXTENDWIDTH = border_thickness.bottom; + + // Extend the frame into the client area. + margins.cxLeftWidth = border_thickness.left; + margins.cxRightWidth = border_thickness.right; + margins.cyBottomHeight = border_thickness.bottom; + margins.cyTopHeight = border_thickness.top; + + var hr = DwmExtendFrameIntoClientArea(hWnd, ref margins); + + //if (hr < 0) + { + // Handle the error. + } + + lRet = IntPtr.Zero; + callDwp = true; + break; + } + + case WindowsMessage.WM_NCCALCSIZE: + { + if (ToInt32(wParam) == 1) + { + lRet = IntPtr.Zero; + callDwp = false; + } + break; + } + + case WindowsMessage.WM_NCHITTEST: + if (lRet == IntPtr.Zero) + { + lRet = (IntPtr)HitTestNCA(hWnd, wParam, lParam); + + if (((HitTestValues)lRet) != HitTestValues.HTNOWHERE) + { + callDwp = false; + } + } + break; + } + + return lRet; + } + } + + public partial class WindowImpl + { + protected virtual unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) + { + IntPtr lRet = IntPtr.Zero; + bool callDwp = true; + + if (DwmIsCompositionEnabled(out bool enabled) == 0) + { + lRet = CustomCaptionProc(hWnd, msg, wParam, lParam, ref callDwp); + } + + if (callDwp) + { + lRet = AppWndProc(hWnd, msg, wParam, lParam); + } + + return lRet; + } + } + public partial class WindowImpl { [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")] - protected virtual unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) + protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { const double wheelDelta = 120.0; uint timestamp = unchecked((uint)GetMessageTime()); From 9b9b2d8330ba870c77bb4b9b3b77d1ed5e57fcfc Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 15:12:32 -0300 Subject: [PATCH 02/98] fallback transparency should be null so that it doesnt hit test. --- src/Avalonia.Controls/TopLevel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 5d34444eb8..0a3e758423 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -399,7 +399,7 @@ namespace Avalonia.Controls } else { - _transparencyFallbackBorder.Background = Brushes.Transparent; + _transparencyFallbackBorder.Background = null; } } From 9a60bbf528c5c5f4a1034a60fb497e8be0810e63 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 15:13:13 -0300 Subject: [PATCH 03/98] render hit test non-client area. --- .../Avalonia.Win32/WindowImpl.WndProc.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs index 55b5db3bba..bc13fb83e9 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs @@ -98,13 +98,14 @@ namespace Avalonia.Win32 LEFTEXTENDWIDTH = border_thickness.left; RIGHTEXTENDWIDTH = border_thickness.right; BOTTOMEXTENDWIDTH = border_thickness.bottom; + TOPEXTENDWIDTH = border_thickness.top; // Extend the frame into the client area. margins.cxLeftWidth = border_thickness.left; margins.cxRightWidth = border_thickness.right; margins.cyBottomHeight = border_thickness.bottom; margins.cyTopHeight = border_thickness.top; - + var hr = DwmExtendFrameIntoClientArea(hWnd, ref margins); //if (hr < 0) @@ -132,6 +133,21 @@ namespace Avalonia.Win32 { lRet = (IntPtr)HitTestNCA(hWnd, wParam, lParam); + uint timestamp = unchecked((uint)GetMessageTime()); + + if (((HitTestValues)lRet) == HitTestValues.HTCAPTION) + { + var position = PointToClient(PointFromLParam(lParam)); + + var visual = (_owner as Window).Renderer.HitTestFirst(position, _owner as Window, null); + + if(visual != null) + { + lRet = (IntPtr)HitTestValues.HTCLIENT; + } + + } + if (((HitTestValues)lRet) != HitTestValues.HTNOWHERE) { callDwp = false; From 1d12a4c044f95d8419eff874040e4717a0d61538 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 15:39:46 -0300 Subject: [PATCH 04/98] working win32 non-client area hit testing. --- src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs index bc13fb83e9..dedef2ded3 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs @@ -138,8 +138,16 @@ namespace Avalonia.Win32 if (((HitTestValues)lRet) == HitTestValues.HTCAPTION) { var position = PointToClient(PointFromLParam(lParam)); - - var visual = (_owner as Window).Renderer.HitTestFirst(position, _owner as Window, null); + + var visual = (_owner as Window).Renderer.HitTestFirst(position, _owner as Window, x => + { + if(x is IInputElement ie && !ie.IsHitTestVisible) + { + return false; + } + + return true; + }); if(visual != null) { From 1168dd186d5d5bd0e470994c06ff20de21c31bc0 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 16:54:20 -0300 Subject: [PATCH 05/98] add client area extending api to window. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 6 ++ src/Avalonia.Controls/Window.cs | 62 +++++++++++++++ .../Remote/PreviewerWindowImpl.cs | 6 ++ src/Avalonia.DesignerSupport/Remote/Stubs.cs | 6 ++ src/Avalonia.Native/WindowImpl.cs | 6 ++ src/Avalonia.X11/X11Window.cs | 6 ++ .../Avalonia.Win32/WindowImpl.WndProc.cs | 77 ++++++++++--------- 7 files changed, 134 insertions(+), 35 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index cf31d30332..9c4808a41c 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -94,5 +94,11 @@ namespace Avalonia.Platform /// /// void SetMinMaxSize(Size minSize, Size maxSize); + + bool ExtendClientAreaToDecorationsHint { get; set; } + + Action ExtendClientAreaToDecorationsChanged { get; set; } + + Thickness ExtendedMargins { get; } } } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index ff7cc41e3b..04b48d7f9f 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -71,6 +71,8 @@ namespace Avalonia.Controls { private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>(); + private bool _isExtendedIntoWindowDecorations; + /// /// Defines the property. /// @@ -87,6 +89,29 @@ namespace Avalonia.Controls o => o.HasSystemDecorations, (o, v) => o.HasSystemDecorations = v); + /// + /// Defines the property. + /// + public static readonly StyledProperty ExtendClientAreaToDecorationsHintProperty = + AvaloniaProperty.Register(nameof(ExtendClientAreaToDecorationsHint), false); + + + /// + /// Defines the property. + /// + public static readonly DirectProperty IsExtendedIntoWindowDecorationsProperty = + AvaloniaProperty.RegisterDirect(nameof(IsExtendedIntoWindowDecorations), + o => o.IsExtendedIntoWindowDecorations, + unsetValue: false); + + /// + /// Defines the property. + /// + public static readonly DirectProperty WindowDecorationMarginsProperty = + AvaloniaProperty.RegisterDirect(nameof(WindowDecorationMargins), + o => o.WindowDecorationMargins); + + /// /// Defines the property. /// @@ -164,6 +189,9 @@ namespace Avalonia.Controls WindowStateProperty.Changed.AddClassHandler( (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; }); + ExtendClientAreaToDecorationsHintProperty.Changed.AddClassHandler( + (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.ExtendClientAreaToDecorationsHint = (bool)e.NewValue; }); + MinWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight))); MinHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight))); MaxWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight))); @@ -189,6 +217,7 @@ namespace Avalonia.Controls impl.GotInputWhenDisabled = OnGotInputWhenDisabled; impl.WindowStateChanged = HandleWindowStateChanged; _maxPlatformClientSize = PlatformImpl?.MaxAutoSizeHint ?? default(Size); + impl.ExtendClientAreaToDecorationsChanged = ExtendClientAreaToDecorationsChanged; this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x)); PlatformImpl?.ShowTaskbarIcon(ShowInTaskbar); @@ -237,6 +266,32 @@ namespace Avalonia.Controls } } + /// + /// Gets or sets if the ClientArea is Extended into the Window Decorations (chrome or border). + /// + public bool ExtendClientAreaToDecorationsHint + { + get { return GetValue(ExtendClientAreaToDecorationsHintProperty); } + set { SetValue(ExtendClientAreaToDecorationsHintProperty, value); } + } + + /// + /// Gets if the ClientArea is Extended into the Window Decorations. + /// + public bool IsExtendedIntoWindowDecorations + { + get => _isExtendedIntoWindowDecorations; + private set => SetAndRaise(IsExtendedIntoWindowDecorationsProperty, ref _isExtendedIntoWindowDecorations, value); + } + + private Thickness _windowDecorationMargins; + + public Thickness WindowDecorationMargins + { + get => _windowDecorationMargins; + private set => SetAndRaise(WindowDecorationMarginsProperty, ref _windowDecorationMargins, value); + } + /// /// Sets the system decorations (title bar, border, etc) /// @@ -435,6 +490,13 @@ namespace Avalonia.Controls } } + protected virtual void ExtendClientAreaToDecorationsChanged(bool isExtended) + { + IsExtendedIntoWindowDecorations = isExtended; + + WindowDecorationMargins = PlatformImpl.ExtendedMargins; + } + /// /// Hides the window but does not close it. /// diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index cd64af60e2..441a79531a 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -84,6 +84,12 @@ namespace Avalonia.DesignerSupport.Remote public IScreenImpl Screen { get; } = new ScreenStub(); public Action GotInputWhenDisabled { get; set; } + + public bool ExtendClientAreaToDecorationsHint { get; set; } + + public Action ExtendClientAreaToDecorationsChanged { get; set; } + + public Thickness ExtendedMargins { get; } = new Thickness(); public void Activate() { diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index b001bc1b76..f962382575 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -39,6 +39,12 @@ namespace Avalonia.DesignerSupport.Remote public Action TransparencyLevelChanged { get; set; } + public bool ExtendClientAreaToDecorationsHint { get; set; } + + public Action ExtendClientAreaToDecorationsChanged { get; set; } + + public Thickness ExtendedMargins { get; } = new Thickness(); + public WindowStub(IWindowImpl parent = null) { if (parent != null) diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index e91445000a..3495c4b392 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -98,6 +98,12 @@ namespace Avalonia.Native public Action WindowStateChanged { get; set; } + public bool ExtendClientAreaToDecorationsHint { get; set; } + + public Action ExtendClientAreaToDecorationsChanged { get; set; } + + public Thickness ExtendedMargins { get; } = new Thickness(); + public void ShowTaskbarIcon(bool value) { // NO OP On OSX diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 90064cb28d..ac9048adad 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -311,6 +311,12 @@ namespace Avalonia.X11 set => _transparencyHelper.TransparencyLevelChanged = value; } + public bool ExtendClientAreaToDecorationsHint { get; set; } + + public Action ExtendClientAreaToDecorationsChanged { get; set; } + + public Thickness ExtendedMargins { get; } = new Thickness(); + public Action Closed { get; set; } public Action PositionChanged { get; set; } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs index dedef2ded3..3ce34250fa 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs @@ -14,11 +14,6 @@ namespace Avalonia.Win32 { public partial class WindowImpl { - private int LEFTEXTENDWIDTH = 4; - private int RIGHTEXTENDWIDTH = 4; - private int BOTTOMEXTENDWIDTH = 4; - private int TOPEXTENDWIDTH = 100; - // Hit test the frame for resizing and moving. HitTestValues HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam) { @@ -32,28 +27,40 @@ namespace Avalonia.Win32 RECT rcFrame = new RECT(); AdjustWindowRectEx(ref rcFrame, (uint)(WindowStyles.WS_OVERLAPPEDWINDOW & ~WindowStyles.WS_CAPTION), false, 0); + RECT border_thickness = new RECT(); + if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) + { + AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); + border_thickness.left *= -1; + border_thickness.top *= -1; + } + else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) + { + border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; + } + // Determine if the hit test is for resizing. Default middle (1,1). ushort uRow = 1; ushort uCol = 1; bool fOnResizeBorder = false; // Determine if the point is at the top or bottom of the window. - if (ptMouse.Y >= rcWindow.top && ptMouse.Y < rcWindow.top + TOPEXTENDWIDTH) + if (ptMouse.Y >= rcWindow.top && ptMouse.Y < rcWindow.top + border_thickness.top) { fOnResizeBorder = (ptMouse.Y < (rcWindow.top - rcFrame.top)); uRow = 0; } - else if (ptMouse.Y < rcWindow.bottom && ptMouse.Y >= rcWindow.bottom - BOTTOMEXTENDWIDTH) + else if (ptMouse.Y < rcWindow.bottom && ptMouse.Y >= rcWindow.bottom - border_thickness.bottom) { uRow = 2; } // Determine if the point is at the left or right of the window. - if (ptMouse.X >= rcWindow.left && ptMouse.X < rcWindow.left + LEFTEXTENDWIDTH) + if (ptMouse.X >= rcWindow.left && ptMouse.X < rcWindow.left + border_thickness.left) { uCol = 0; // left side } - else if (ptMouse.X < rcWindow.right && ptMouse.X >= rcWindow.right - RIGHTEXTENDWIDTH) + else if (ptMouse.X < rcWindow.right && ptMouse.X >= rcWindow.right - border_thickness.right) { uCol = 2; // right side } @@ -66,8 +73,6 @@ namespace Avalonia.Win32 new []{ HitTestValues.HTBOTTOMLEFT, HitTestValues.HTBOTTOM, HitTestValues.HTBOTTOMRIGHT }, }; - System.Diagnostics.Debug.WriteLine(hitTests[uRow][uCol]); - return hitTests[uRow][uCol]; } @@ -84,35 +89,37 @@ namespace Avalonia.Win32 { case WindowsMessage.WM_ACTIVATE: { - if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) - { - AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); - border_thickness.left *= -1; - border_thickness.top *= -1; - } - else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) - { - border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; - } + if (!_isClientAreaExtended) + { + if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) + { + AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); + border_thickness.left *= -1; + border_thickness.top *= -1; + } + else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) + { + border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; + } - LEFTEXTENDWIDTH = border_thickness.left; - RIGHTEXTENDWIDTH = border_thickness.right; - BOTTOMEXTENDWIDTH = border_thickness.bottom; - TOPEXTENDWIDTH = border_thickness.top; + // Extend the frame into the client area. + margins.cxLeftWidth = border_thickness.left; + margins.cxRightWidth = border_thickness.right; + margins.cyBottomHeight = border_thickness.bottom; + margins.cyTopHeight = border_thickness.top; - // Extend the frame into the client area. - margins.cxLeftWidth = border_thickness.left; - margins.cxRightWidth = border_thickness.right; - margins.cyBottomHeight = border_thickness.bottom; - margins.cyTopHeight = border_thickness.top; + var hr = DwmExtendFrameIntoClientArea(hWnd, ref margins); - var hr = DwmExtendFrameIntoClientArea(hWnd, ref margins); + //if (hr < 0) + { + // Handle the error. + } - //if (hr < 0) - { - // Handle the error. - } + _isClientAreaExtended = true; + _extendedMargins = new Thickness(margins.cxLeftWidth / Scaling, margins.cyTopHeight / Scaling, margins.cxRightWidth / Scaling, margins.cyBottomHeight / Scaling); + ExtendClientAreaToDecorationsChanged?.Invoke(true); + } lRet = IntPtr.Zero; callDwp = true; break; From d2bc5505c5eb8ea51533ffe295c696b9009702ea Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 16:54:42 -0300 Subject: [PATCH 06/98] Add win32 impl for client extending based on property value. --- .../Avalonia.Win32/WindowImpl.WndProc.cs | 54 ++++------------- src/Windows/Avalonia.Win32/WindowImpl.cs | 59 ++++++++++++++++++- 2 files changed, 70 insertions(+), 43 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs index 3ce34250fa..e9664d234f 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs @@ -80,50 +80,20 @@ namespace Avalonia.Win32 { IntPtr lRet = IntPtr.Zero; - callDwp = !DwmDefWindowProc(hWnd, msg, wParam, lParam, ref lRet); - - MARGINS margins = new MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyBottomHeight = 0, cyTopHeight = 100 }; - RECT border_thickness = new RECT(); - + callDwp = !DwmDefWindowProc(hWnd, msg, wParam, lParam, ref lRet); + switch ((WindowsMessage)msg) { - case WindowsMessage.WM_ACTIVATE: - { - if (!_isClientAreaExtended) - { - if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) - { - AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); - border_thickness.left *= -1; - border_thickness.top *= -1; - } - else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) - { - border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; - } - - // Extend the frame into the client area. - margins.cxLeftWidth = border_thickness.left; - margins.cxRightWidth = border_thickness.right; - margins.cyBottomHeight = border_thickness.bottom; - margins.cyTopHeight = border_thickness.top; - - var hr = DwmExtendFrameIntoClientArea(hWnd, ref margins); - - //if (hr < 0) - { - // Handle the error. - } - - _isClientAreaExtended = true; - _extendedMargins = new Thickness(margins.cxLeftWidth / Scaling, margins.cyTopHeight / Scaling, margins.cxRightWidth / Scaling, margins.cyBottomHeight / Scaling); - ExtendClientAreaToDecorationsChanged?.Invoke(true); - - } - lRet = IntPtr.Zero; - callDwp = true; - break; - } + //case WindowsMessage.WM_ACTIVATE: + // { + // if (!_isClientAreaExtended) + // { + // ExtendClientArea(); + // } + // lRet = IntPtr.Zero; + // callDwp = true; + // break; + // } case WindowsMessage.WM_NCCALCSIZE: { diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 6024dc01da..6cacd0b6cc 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -40,6 +40,7 @@ namespace Avalonia.Win32 private SavedWindowInfo _savedWindowInfo; private bool _isFullScreenActive; + private bool _isClientAreaExtended; #if USE_MANAGED_DRAG private readonly ManagedWindowResizeDragHelper _managedDrag; @@ -68,6 +69,7 @@ namespace Avalonia.Win32 private Size _maxSize; private POINT _maxTrackSize; private WindowImpl _parent; + private bool _extendClientAreaToDecorationsHint; public WindowImpl() { @@ -664,6 +666,43 @@ namespace Avalonia.Win32 TaskBarList.MarkFullscreen(_hwnd, fullscreen); } + private void ExtendClientArea () + { + if (!_isClientAreaExtended) + { + RECT border_thickness = new RECT(); + MARGINS margins = new MARGINS(); + + if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) + { + AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); + border_thickness.left *= -1; + border_thickness.top *= -1; + } + else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) + { + border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; + } + + // Extend the frame into the client area. + margins.cxLeftWidth = border_thickness.left; + margins.cxRightWidth = border_thickness.right; + margins.cyBottomHeight = border_thickness.bottom; + margins.cyTopHeight = border_thickness.top; + + var hr = DwmExtendFrameIntoClientArea(_hwnd, ref margins); + + //if (hr < 0) + { + // Handle the error. + } + + _isClientAreaExtended = true; + _extendedMargins = new Thickness(margins.cxLeftWidth / Scaling, margins.cyTopHeight / Scaling, margins.cxRightWidth / Scaling, margins.cyBottomHeight / Scaling); + ExtendClientAreaToDecorationsChanged?.Invoke(true); + } + } + private void ShowWindow(WindowState state) { ShowWindowCommand command; @@ -904,7 +943,25 @@ namespace Avalonia.Win32 } } - IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; + IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; + + public bool ExtendClientAreaToDecorationsHint + { + get => _extendClientAreaToDecorationsHint; + set + { + _extendClientAreaToDecorationsHint = true; + + ExtendClientArea(); + // TODO Trigger transition. + } + } + + public Action ExtendClientAreaToDecorationsChanged { get; set; } + + private Thickness _extendedMargins; + + public Thickness ExtendedMargins => _extendedMargins; private struct SavedWindowInfo { From d43108d442e09b61c53b173d2537428f503da8ee Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 16:55:32 -0300 Subject: [PATCH 07/98] only report extended if we were able to. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 6cacd0b6cc..af1e8e06ce 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -692,14 +692,12 @@ namespace Avalonia.Win32 var hr = DwmExtendFrameIntoClientArea(_hwnd, ref margins); - //if (hr < 0) + if (hr == 0) { - // Handle the error. + _isClientAreaExtended = true; + _extendedMargins = new Thickness(margins.cxLeftWidth / Scaling, margins.cyTopHeight / Scaling, margins.cxRightWidth / Scaling, margins.cyBottomHeight / Scaling); + ExtendClientAreaToDecorationsChanged?.Invoke(true); } - - _isClientAreaExtended = true; - _extendedMargins = new Thickness(margins.cxLeftWidth / Scaling, margins.cyTopHeight / Scaling, margins.cxRightWidth / Scaling, margins.cyBottomHeight / Scaling); - ExtendClientAreaToDecorationsChanged?.Invoke(true); } } From 3a1486be5622a53c8340cd8bcef8a34d34afd9ed Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 17:06:00 -0300 Subject: [PATCH 08/98] check composition is allowed before allowing extended windows. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index af1e8e06ce..7474bdd10a 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -670,6 +670,11 @@ namespace Avalonia.Win32 { if (!_isClientAreaExtended) { + if(DwmIsCompositionEnabled(out bool compositionEnabled) < 0 || !compositionEnabled) + { + return; + } + RECT border_thickness = new RECT(); MARGINS margins = new MARGINS(); From f7f1ed56a4fcad21f9989e35b02fad0bf83c9e40 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 17:06:30 -0300 Subject: [PATCH 09/98] separate WndProcs --- .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 518 ++++++++++++++ .../WindowImpl.CustomCaptionProc.cs | 117 ++++ .../Avalonia.Win32/WindowImpl.WndProc.cs | 644 +----------------- 3 files changed, 636 insertions(+), 643 deletions(-) create mode 100644 src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs create mode 100644 src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs new file mode 100644 index 0000000000..b81634dce0 --- /dev/null +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -0,0 +1,518 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Input.Raw; +using Avalonia.Win32.Input; +using static Avalonia.Win32.Interop.UnmanagedMethods; + +namespace Avalonia.Win32 +{ + public partial class WindowImpl + { + [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", + Justification = "Using Win32 naming for consistency.")] + protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) + { + const double wheelDelta = 120.0; + uint timestamp = unchecked((uint)GetMessageTime()); + + RawInputEventArgs e = null; + + switch ((WindowsMessage)msg) + { + case WindowsMessage.WM_ACTIVATE: + { + var wa = (WindowActivate)(ToInt32(wParam) & 0xffff); + + switch (wa) + { + case WindowActivate.WA_ACTIVE: + case WindowActivate.WA_CLICKACTIVE: + { + Activated?.Invoke(); + break; + } + + case WindowActivate.WA_INACTIVE: + { + Deactivated?.Invoke(); + break; + } + } + + return IntPtr.Zero; + } + + case WindowsMessage.WM_NCCALCSIZE: + { + if (ToInt32(wParam) == 1 && !HasFullDecorations || _isClientAreaExtended) + { + return IntPtr.Zero; + } + + break; + } + + case WindowsMessage.WM_CLOSE: + { + bool? preventClosing = Closing?.Invoke(); + if (preventClosing == true) + { + return IntPtr.Zero; + } + + break; + } + + case WindowsMessage.WM_DESTROY: + { + //Window doesn't exist anymore + _hwnd = IntPtr.Zero; + //Remove root reference to this class, so unmanaged delegate can be collected + s_instances.Remove(this); + Closed?.Invoke(); + + _mouseDevice.Dispose(); + _touchDevice?.Dispose(); + //Free other resources + Dispose(); + return IntPtr.Zero; + } + + case WindowsMessage.WM_DPICHANGED: + { + var dpi = ToInt32(wParam) & 0xffff; + var newDisplayRect = Marshal.PtrToStructure(lParam); + _scaling = dpi / 96.0; + ScalingChanged?.Invoke(_scaling); + SetWindowPos(hWnd, + IntPtr.Zero, + newDisplayRect.left, + newDisplayRect.top, + newDisplayRect.right - newDisplayRect.left, + newDisplayRect.bottom - newDisplayRect.top, + SetWindowPosFlags.SWP_NOZORDER | + SetWindowPosFlags.SWP_NOACTIVATE); + return IntPtr.Zero; + } + + case WindowsMessage.WM_KEYDOWN: + case WindowsMessage.WM_SYSKEYDOWN: + { + e = new RawKeyEventArgs( + WindowsKeyboardDevice.Instance, + timestamp, + _owner, + RawKeyEventType.KeyDown, + KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)), + WindowsKeyboardDevice.Instance.Modifiers); + break; + } + + case WindowsMessage.WM_MENUCHAR: + { + // mute the system beep + return (IntPtr)((int)MenuCharParam.MNC_CLOSE << 16); + } + + case WindowsMessage.WM_KEYUP: + case WindowsMessage.WM_SYSKEYUP: + { + e = new RawKeyEventArgs( + WindowsKeyboardDevice.Instance, + timestamp, + _owner, + RawKeyEventType.KeyUp, + KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)), + WindowsKeyboardDevice.Instance.Modifiers); + break; + } + case WindowsMessage.WM_CHAR: + { + // Ignore control chars + if (ToInt32(wParam) >= 32) + { + e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _owner, + new string((char)ToInt32(wParam), 1)); + } + + break; + } + + case WindowsMessage.WM_LBUTTONDOWN: + case WindowsMessage.WM_RBUTTONDOWN: + case WindowsMessage.WM_MBUTTONDOWN: + case WindowsMessage.WM_XBUTTONDOWN: + { + if (ShouldIgnoreTouchEmulatedMessage()) + { + break; + } + + e = new RawPointerEventArgs( + _mouseDevice, + timestamp, + _owner, + (WindowsMessage)msg switch + { + WindowsMessage.WM_LBUTTONDOWN => RawPointerEventType.LeftButtonDown, + WindowsMessage.WM_RBUTTONDOWN => RawPointerEventType.RightButtonDown, + WindowsMessage.WM_MBUTTONDOWN => RawPointerEventType.MiddleButtonDown, + WindowsMessage.WM_XBUTTONDOWN => + HighWord(ToInt32(wParam)) == 1 ? + RawPointerEventType.XButton1Down : + RawPointerEventType.XButton2Down + }, + DipFromLParam(lParam), GetMouseModifiers(wParam)); + break; + } + + case WindowsMessage.WM_LBUTTONUP: + case WindowsMessage.WM_RBUTTONUP: + case WindowsMessage.WM_MBUTTONUP: + case WindowsMessage.WM_XBUTTONUP: + { + if (ShouldIgnoreTouchEmulatedMessage()) + { + break; + } + + e = new RawPointerEventArgs( + _mouseDevice, + timestamp, + _owner, + (WindowsMessage)msg switch + { + WindowsMessage.WM_LBUTTONUP => RawPointerEventType.LeftButtonUp, + WindowsMessage.WM_RBUTTONUP => RawPointerEventType.RightButtonUp, + WindowsMessage.WM_MBUTTONUP => RawPointerEventType.MiddleButtonUp, + WindowsMessage.WM_XBUTTONUP => + HighWord(ToInt32(wParam)) == 1 ? + RawPointerEventType.XButton1Up : + RawPointerEventType.XButton2Up, + }, + DipFromLParam(lParam), GetMouseModifiers(wParam)); + break; + } + + case WindowsMessage.WM_MOUSEMOVE: + { + if (ShouldIgnoreTouchEmulatedMessage()) + { + break; + } + + if (!_trackingMouse) + { + var tm = new TRACKMOUSEEVENT + { + cbSize = Marshal.SizeOf(), + dwFlags = 2, + hwndTrack = _hwnd, + dwHoverTime = 0, + }; + + TrackMouseEvent(ref tm); + } + + e = new RawPointerEventArgs( + _mouseDevice, + timestamp, + _owner, + RawPointerEventType.Move, + DipFromLParam(lParam), GetMouseModifiers(wParam)); + + break; + } + + case WindowsMessage.WM_MOUSEWHEEL: + { + e = new RawMouseWheelEventArgs( + _mouseDevice, + timestamp, + _owner, + PointToClient(PointFromLParam(lParam)), + new Vector(0, (ToInt32(wParam) >> 16) / wheelDelta), GetMouseModifiers(wParam)); + break; + } + + case WindowsMessage.WM_MOUSEHWHEEL: + { + e = new RawMouseWheelEventArgs( + _mouseDevice, + timestamp, + _owner, + PointToClient(PointFromLParam(lParam)), + new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0), GetMouseModifiers(wParam)); + break; + } + + case WindowsMessage.WM_MOUSELEAVE: + { + _trackingMouse = false; + e = new RawPointerEventArgs( + _mouseDevice, + timestamp, + _owner, + RawPointerEventType.LeaveWindow, + new Point(-1, -1), WindowsKeyboardDevice.Instance.Modifiers); + break; + } + + case WindowsMessage.WM_NCLBUTTONDOWN: + case WindowsMessage.WM_NCRBUTTONDOWN: + case WindowsMessage.WM_NCMBUTTONDOWN: + case WindowsMessage.WM_NCXBUTTONDOWN: + { + e = new RawPointerEventArgs( + _mouseDevice, + timestamp, + _owner, + (WindowsMessage)msg switch + { + WindowsMessage.WM_NCLBUTTONDOWN => RawPointerEventType + .NonClientLeftButtonDown, + WindowsMessage.WM_NCRBUTTONDOWN => RawPointerEventType.RightButtonDown, + WindowsMessage.WM_NCMBUTTONDOWN => RawPointerEventType.MiddleButtonDown, + WindowsMessage.WM_NCXBUTTONDOWN => + HighWord(ToInt32(wParam)) == 1 ? + RawPointerEventType.XButton1Down : + RawPointerEventType.XButton2Down, + }, + PointToClient(PointFromLParam(lParam)), GetMouseModifiers(wParam)); + break; + } + case WindowsMessage.WM_TOUCH: + { + var touchInputCount = wParam.ToInt32(); + + var pTouchInputs = stackalloc TOUCHINPUT[touchInputCount]; + var touchInputs = new Span(pTouchInputs, touchInputCount); + + if (GetTouchInputInfo(lParam, (uint)touchInputCount, pTouchInputs, Marshal.SizeOf())) + { + foreach (var touchInput in touchInputs) + { + Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time, + _owner, + touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_UP) ? + RawPointerEventType.TouchEnd : + touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_DOWN) ? + RawPointerEventType.TouchBegin : + RawPointerEventType.TouchUpdate, + PointToClient(new PixelPoint(touchInput.X / 100, touchInput.Y / 100)), + WindowsKeyboardDevice.Instance.Modifiers, + touchInput.Id)); + } + + CloseTouchInputHandle(lParam); + return IntPtr.Zero; + } + + break; + } + case WindowsMessage.WM_NCPAINT: + { + if (!HasFullDecorations) + { + return IntPtr.Zero; + } + + break; + } + + case WindowsMessage.WM_NCACTIVATE: + { + if (!HasFullDecorations) + { + return new IntPtr(1); + } + + break; + } + + case WindowsMessage.WM_PAINT: + { + using (_rendererLock.Lock()) + { + if (BeginPaint(_hwnd, out PAINTSTRUCT ps) != IntPtr.Zero) + { + var f = Scaling; + var r = ps.rcPaint; + Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f, + (r.bottom - r.top) / f)); + EndPaint(_hwnd, ref ps); + } + } + + return IntPtr.Zero; + } + + case WindowsMessage.WM_SIZE: + { + using (_rendererLock.Lock()) + { + // Do nothing here, just block until the pending frame render is completed on the render thread + } + + var size = (SizeCommand)wParam; + + if (Resized != null && + (size == SizeCommand.Restored || + size == SizeCommand.Maximized)) + { + var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16); + Resized(clientSize / Scaling); + } + + var windowState = size == SizeCommand.Maximized ? + WindowState.Maximized : + (size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal); + + if (windowState != _lastWindowState) + { + _lastWindowState = windowState; + WindowStateChanged?.Invoke(windowState); + } + + return IntPtr.Zero; + } + + case WindowsMessage.WM_MOVE: + { + PositionChanged?.Invoke(new PixelPoint((short)(ToInt32(lParam) & 0xffff), + (short)(ToInt32(lParam) >> 16))); + return IntPtr.Zero; + } + + case WindowsMessage.WM_GETMINMAXINFO: + { + MINMAXINFO mmi = Marshal.PtrToStructure(lParam); + + if (_minSize.Width > 0) + { + mmi.ptMinTrackSize.X = + (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); + } + + if (_minSize.Height > 0) + { + mmi.ptMinTrackSize.Y = + (int)((_minSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + } + + if (!double.IsInfinity(_maxSize.Width) && _maxSize.Width > 0) + { + mmi.ptMaxTrackSize.X = + (int)((_maxSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); + } + + if (!double.IsInfinity(_maxSize.Height) && _maxSize.Height > 0) + { + mmi.ptMaxTrackSize.Y = + (int)((_maxSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + } + + Marshal.StructureToPtr(mmi, lParam, true); + return IntPtr.Zero; + } + + case WindowsMessage.WM_DISPLAYCHANGE: + { + (Screen as ScreenImpl)?.InvalidateScreensCache(); + return IntPtr.Zero; + } + } + +#if USE_MANAGED_DRAG + if (_managedDrag.PreprocessInputEvent(ref e)) + return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); +#endif + + if (e != null && Input != null) + { + Input(e); + + if (e.Handled) + { + return IntPtr.Zero; + } + } + + using (_rendererLock.Lock()) + { + return DefWindowProc(hWnd, msg, wParam, lParam); + } + } + + private static int ToInt32(IntPtr ptr) + { + if (IntPtr.Size == 4) + return ptr.ToInt32(); + + return (int)(ptr.ToInt64() & 0xffffffff); + } + + private static int HighWord(int param) => param >> 16; + + private Point DipFromLParam(IntPtr lParam) + { + return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / Scaling; + } + + private PixelPoint PointFromLParam(IntPtr lParam) + { + return new PixelPoint((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)); + } + + private bool ShouldIgnoreTouchEmulatedMessage() + { + if (!_multitouch) + { + return false; + } + + // MI_WP_SIGNATURE + // https://docs.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages + const long marker = 0xFF515700L; + + var info = GetMessageExtraInfo().ToInt64(); + return (info & marker) == marker; + } + + private static RawInputModifiers GetMouseModifiers(IntPtr wParam) + { + var keys = (ModifierKeys)ToInt32(wParam); + var modifiers = WindowsKeyboardDevice.Instance.Modifiers; + + if (keys.HasFlagCustom(ModifierKeys.MK_LBUTTON)) + { + modifiers |= RawInputModifiers.LeftMouseButton; + } + + if (keys.HasFlagCustom(ModifierKeys.MK_RBUTTON)) + { + modifiers |= RawInputModifiers.RightMouseButton; + } + + if (keys.HasFlagCustom(ModifierKeys.MK_MBUTTON)) + { + modifiers |= RawInputModifiers.MiddleMouseButton; + } + + if (keys.HasFlagCustom(ModifierKeys.MK_XBUTTON1)) + { + modifiers |= RawInputModifiers.XButton1MouseButton; + } + + if (keys.HasFlagCustom(ModifierKeys.MK_XBUTTON2)) + { + modifiers |= RawInputModifiers.XButton2MouseButton; + } + + return modifiers; + } + } +} diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs new file mode 100644 index 0000000000..faf83c6c9b --- /dev/null +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Avalonia.Win32 +{ + public partial class WindowImpl + { + // Hit test the frame for resizing and moving. + HitTestValues HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam) + { + // Get the point coordinates for the hit test. + var ptMouse = PointFromLParam(lParam); + + // Get the window rectangle. + GetWindowRect(hWnd, out var rcWindow); + + // Get the frame rectangle, adjusted for the style without a caption. + RECT rcFrame = new RECT(); + AdjustWindowRectEx(ref rcFrame, (uint)(WindowStyles.WS_OVERLAPPEDWINDOW & ~WindowStyles.WS_CAPTION), false, 0); + + RECT border_thickness = new RECT(); + if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) + { + AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); + border_thickness.left *= -1; + border_thickness.top *= -1; + } + else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) + { + border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; + } + + // Determine if the hit test is for resizing. Default middle (1,1). + ushort uRow = 1; + ushort uCol = 1; + bool fOnResizeBorder = false; + + // Determine if the point is at the top or bottom of the window. + if (ptMouse.Y >= rcWindow.top && ptMouse.Y < rcWindow.top + border_thickness.top) + { + fOnResizeBorder = (ptMouse.Y < (rcWindow.top - rcFrame.top)); + uRow = 0; + } + else if (ptMouse.Y < rcWindow.bottom && ptMouse.Y >= rcWindow.bottom - border_thickness.bottom) + { + uRow = 2; + } + + // Determine if the point is at the left or right of the window. + if (ptMouse.X >= rcWindow.left && ptMouse.X < rcWindow.left + border_thickness.left) + { + uCol = 0; // left side + } + else if (ptMouse.X < rcWindow.right && ptMouse.X >= rcWindow.right - border_thickness.right) + { + uCol = 2; // right side + } + + // Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT) + HitTestValues[][] hitTests = new[] + { + new []{ HitTestValues.HTTOPLEFT, fOnResizeBorder ? HitTestValues.HTTOP : HitTestValues.HTCAPTION, HitTestValues.HTTOPRIGHT }, + new []{ HitTestValues.HTLEFT, HitTestValues.HTNOWHERE, HitTestValues.HTRIGHT }, + new []{ HitTestValues.HTBOTTOMLEFT, HitTestValues.HTBOTTOM, HitTestValues.HTBOTTOMRIGHT }, + }; + + return hitTests[uRow][uCol]; + } + + protected virtual IntPtr CustomCaptionProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref bool callDwp) + { + IntPtr lRet = IntPtr.Zero; + + callDwp = !DwmDefWindowProc(hWnd, msg, wParam, lParam, ref lRet); + + switch ((WindowsMessage)msg) + { + case WindowsMessage.WM_NCHITTEST: + if (lRet == IntPtr.Zero) + { + lRet = (IntPtr)HitTestNCA(hWnd, wParam, lParam); + + uint timestamp = unchecked((uint)GetMessageTime()); + + if (((HitTestValues)lRet) == HitTestValues.HTCAPTION) + { + var position = PointToClient(PointFromLParam(lParam)); + + var visual = (_owner as Window).Renderer.HitTestFirst(position, _owner as Window, x => + { + if (x is IInputElement ie && !ie.IsHitTestVisible) + { + return false; + } + + return true; + }); + + if (visual != null) + { + lRet = (IntPtr)HitTestValues.HTCLIENT; + } + } + + if (((HitTestValues)lRet) != HitTestValues.HTNOWHERE) + { + callDwp = false; + } + } + break; + } + + return lRet; + } + } +} diff --git a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs index e9664d234f..bb6ab180cf 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs @@ -12,139 +12,6 @@ using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32 { - public partial class WindowImpl - { - // Hit test the frame for resizing and moving. - HitTestValues HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam) - { - // Get the point coordinates for the hit test. - var ptMouse = PointFromLParam(lParam); - - // Get the window rectangle. - GetWindowRect(hWnd, out var rcWindow); - - // Get the frame rectangle, adjusted for the style without a caption. - RECT rcFrame = new RECT(); - AdjustWindowRectEx(ref rcFrame, (uint)(WindowStyles.WS_OVERLAPPEDWINDOW & ~WindowStyles.WS_CAPTION), false, 0); - - RECT border_thickness = new RECT(); - if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) - { - AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); - border_thickness.left *= -1; - border_thickness.top *= -1; - } - else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) - { - border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; - } - - // Determine if the hit test is for resizing. Default middle (1,1). - ushort uRow = 1; - ushort uCol = 1; - bool fOnResizeBorder = false; - - // Determine if the point is at the top or bottom of the window. - if (ptMouse.Y >= rcWindow.top && ptMouse.Y < rcWindow.top + border_thickness.top) - { - fOnResizeBorder = (ptMouse.Y < (rcWindow.top - rcFrame.top)); - uRow = 0; - } - else if (ptMouse.Y < rcWindow.bottom && ptMouse.Y >= rcWindow.bottom - border_thickness.bottom) - { - uRow = 2; - } - - // Determine if the point is at the left or right of the window. - if (ptMouse.X >= rcWindow.left && ptMouse.X < rcWindow.left + border_thickness.left) - { - uCol = 0; // left side - } - else if (ptMouse.X < rcWindow.right && ptMouse.X >= rcWindow.right - border_thickness.right) - { - uCol = 2; // right side - } - - // Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT) - HitTestValues[][] hitTests = new[] - { - new []{ HitTestValues.HTTOPLEFT, fOnResizeBorder ? HitTestValues.HTTOP : HitTestValues.HTCAPTION, HitTestValues.HTTOPRIGHT }, - new []{ HitTestValues.HTLEFT, HitTestValues.HTNOWHERE, HitTestValues.HTRIGHT }, - new []{ HitTestValues.HTBOTTOMLEFT, HitTestValues.HTBOTTOM, HitTestValues.HTBOTTOMRIGHT }, - }; - - return hitTests[uRow][uCol]; - } - - protected virtual unsafe IntPtr CustomCaptionProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref bool callDwp) - { - IntPtr lRet = IntPtr.Zero; - - callDwp = !DwmDefWindowProc(hWnd, msg, wParam, lParam, ref lRet); - - switch ((WindowsMessage)msg) - { - //case WindowsMessage.WM_ACTIVATE: - // { - // if (!_isClientAreaExtended) - // { - // ExtendClientArea(); - // } - // lRet = IntPtr.Zero; - // callDwp = true; - // break; - // } - - case WindowsMessage.WM_NCCALCSIZE: - { - if (ToInt32(wParam) == 1) - { - lRet = IntPtr.Zero; - callDwp = false; - } - break; - } - - case WindowsMessage.WM_NCHITTEST: - if (lRet == IntPtr.Zero) - { - lRet = (IntPtr)HitTestNCA(hWnd, wParam, lParam); - - uint timestamp = unchecked((uint)GetMessageTime()); - - if (((HitTestValues)lRet) == HitTestValues.HTCAPTION) - { - var position = PointToClient(PointFromLParam(lParam)); - - var visual = (_owner as Window).Renderer.HitTestFirst(position, _owner as Window, x => - { - if(x is IInputElement ie && !ie.IsHitTestVisible) - { - return false; - } - - return true; - }); - - if(visual != null) - { - lRet = (IntPtr)HitTestValues.HTCLIENT; - } - - } - - if (((HitTestValues)lRet) != HitTestValues.HTNOWHERE) - { - callDwp = false; - } - } - break; - } - - return lRet; - } - } - public partial class WindowImpl { protected virtual unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) @@ -152,7 +19,7 @@ namespace Avalonia.Win32 IntPtr lRet = IntPtr.Zero; bool callDwp = true; - if (DwmIsCompositionEnabled(out bool enabled) == 0) + if (_isClientAreaExtended) { lRet = CustomCaptionProc(hWnd, msg, wParam, lParam, ref callDwp); } @@ -165,513 +32,4 @@ namespace Avalonia.Win32 return lRet; } } - - public partial class WindowImpl - { - [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", - Justification = "Using Win32 naming for consistency.")] - protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) - { - const double wheelDelta = 120.0; - uint timestamp = unchecked((uint)GetMessageTime()); - - RawInputEventArgs e = null; - - switch ((WindowsMessage)msg) - { - case WindowsMessage.WM_ACTIVATE: - { - var wa = (WindowActivate)(ToInt32(wParam) & 0xffff); - - switch (wa) - { - case WindowActivate.WA_ACTIVE: - case WindowActivate.WA_CLICKACTIVE: - { - Activated?.Invoke(); - break; - } - - case WindowActivate.WA_INACTIVE: - { - Deactivated?.Invoke(); - break; - } - } - - return IntPtr.Zero; - } - - case WindowsMessage.WM_NCCALCSIZE: - { - if (ToInt32(wParam) == 1 && !HasFullDecorations) - { - return IntPtr.Zero; - } - - break; - } - - case WindowsMessage.WM_CLOSE: - { - bool? preventClosing = Closing?.Invoke(); - if (preventClosing == true) - { - return IntPtr.Zero; - } - - break; - } - - case WindowsMessage.WM_DESTROY: - { - //Window doesn't exist anymore - _hwnd = IntPtr.Zero; - //Remove root reference to this class, so unmanaged delegate can be collected - s_instances.Remove(this); - Closed?.Invoke(); - - _mouseDevice.Dispose(); - _touchDevice?.Dispose(); - //Free other resources - Dispose(); - return IntPtr.Zero; - } - - case WindowsMessage.WM_DPICHANGED: - { - var dpi = ToInt32(wParam) & 0xffff; - var newDisplayRect = Marshal.PtrToStructure(lParam); - _scaling = dpi / 96.0; - ScalingChanged?.Invoke(_scaling); - SetWindowPos(hWnd, - IntPtr.Zero, - newDisplayRect.left, - newDisplayRect.top, - newDisplayRect.right - newDisplayRect.left, - newDisplayRect.bottom - newDisplayRect.top, - SetWindowPosFlags.SWP_NOZORDER | - SetWindowPosFlags.SWP_NOACTIVATE); - return IntPtr.Zero; - } - - case WindowsMessage.WM_KEYDOWN: - case WindowsMessage.WM_SYSKEYDOWN: - { - e = new RawKeyEventArgs( - WindowsKeyboardDevice.Instance, - timestamp, - _owner, - RawKeyEventType.KeyDown, - KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)), - WindowsKeyboardDevice.Instance.Modifiers); - break; - } - - case WindowsMessage.WM_MENUCHAR: - { - // mute the system beep - return (IntPtr)((int)MenuCharParam.MNC_CLOSE << 16); - } - - case WindowsMessage.WM_KEYUP: - case WindowsMessage.WM_SYSKEYUP: - { - e = new RawKeyEventArgs( - WindowsKeyboardDevice.Instance, - timestamp, - _owner, - RawKeyEventType.KeyUp, - KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)), - WindowsKeyboardDevice.Instance.Modifiers); - break; - } - case WindowsMessage.WM_CHAR: - { - // Ignore control chars - if (ToInt32(wParam) >= 32) - { - e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _owner, - new string((char)ToInt32(wParam), 1)); - } - - break; - } - - case WindowsMessage.WM_LBUTTONDOWN: - case WindowsMessage.WM_RBUTTONDOWN: - case WindowsMessage.WM_MBUTTONDOWN: - case WindowsMessage.WM_XBUTTONDOWN: - { - if (ShouldIgnoreTouchEmulatedMessage()) - { - break; - } - - e = new RawPointerEventArgs( - _mouseDevice, - timestamp, - _owner, - (WindowsMessage)msg switch - { - WindowsMessage.WM_LBUTTONDOWN => RawPointerEventType.LeftButtonDown, - WindowsMessage.WM_RBUTTONDOWN => RawPointerEventType.RightButtonDown, - WindowsMessage.WM_MBUTTONDOWN => RawPointerEventType.MiddleButtonDown, - WindowsMessage.WM_XBUTTONDOWN => - HighWord(ToInt32(wParam)) == 1 ? - RawPointerEventType.XButton1Down : - RawPointerEventType.XButton2Down - }, - DipFromLParam(lParam), GetMouseModifiers(wParam)); - break; - } - - case WindowsMessage.WM_LBUTTONUP: - case WindowsMessage.WM_RBUTTONUP: - case WindowsMessage.WM_MBUTTONUP: - case WindowsMessage.WM_XBUTTONUP: - { - if (ShouldIgnoreTouchEmulatedMessage()) - { - break; - } - - e = new RawPointerEventArgs( - _mouseDevice, - timestamp, - _owner, - (WindowsMessage)msg switch - { - WindowsMessage.WM_LBUTTONUP => RawPointerEventType.LeftButtonUp, - WindowsMessage.WM_RBUTTONUP => RawPointerEventType.RightButtonUp, - WindowsMessage.WM_MBUTTONUP => RawPointerEventType.MiddleButtonUp, - WindowsMessage.WM_XBUTTONUP => - HighWord(ToInt32(wParam)) == 1 ? - RawPointerEventType.XButton1Up : - RawPointerEventType.XButton2Up, - }, - DipFromLParam(lParam), GetMouseModifiers(wParam)); - break; - } - - case WindowsMessage.WM_MOUSEMOVE: - { - if (ShouldIgnoreTouchEmulatedMessage()) - { - break; - } - - if (!_trackingMouse) - { - var tm = new TRACKMOUSEEVENT - { - cbSize = Marshal.SizeOf(), - dwFlags = 2, - hwndTrack = _hwnd, - dwHoverTime = 0, - }; - - TrackMouseEvent(ref tm); - } - - e = new RawPointerEventArgs( - _mouseDevice, - timestamp, - _owner, - RawPointerEventType.Move, - DipFromLParam(lParam), GetMouseModifiers(wParam)); - - break; - } - - case WindowsMessage.WM_MOUSEWHEEL: - { - e = new RawMouseWheelEventArgs( - _mouseDevice, - timestamp, - _owner, - PointToClient(PointFromLParam(lParam)), - new Vector(0, (ToInt32(wParam) >> 16) / wheelDelta), GetMouseModifiers(wParam)); - break; - } - - case WindowsMessage.WM_MOUSEHWHEEL: - { - e = new RawMouseWheelEventArgs( - _mouseDevice, - timestamp, - _owner, - PointToClient(PointFromLParam(lParam)), - new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0), GetMouseModifiers(wParam)); - break; - } - - case WindowsMessage.WM_MOUSELEAVE: - { - _trackingMouse = false; - e = new RawPointerEventArgs( - _mouseDevice, - timestamp, - _owner, - RawPointerEventType.LeaveWindow, - new Point(-1, -1), WindowsKeyboardDevice.Instance.Modifiers); - break; - } - - case WindowsMessage.WM_NCLBUTTONDOWN: - case WindowsMessage.WM_NCRBUTTONDOWN: - case WindowsMessage.WM_NCMBUTTONDOWN: - case WindowsMessage.WM_NCXBUTTONDOWN: - { - e = new RawPointerEventArgs( - _mouseDevice, - timestamp, - _owner, - (WindowsMessage)msg switch - { - WindowsMessage.WM_NCLBUTTONDOWN => RawPointerEventType - .NonClientLeftButtonDown, - WindowsMessage.WM_NCRBUTTONDOWN => RawPointerEventType.RightButtonDown, - WindowsMessage.WM_NCMBUTTONDOWN => RawPointerEventType.MiddleButtonDown, - WindowsMessage.WM_NCXBUTTONDOWN => - HighWord(ToInt32(wParam)) == 1 ? - RawPointerEventType.XButton1Down : - RawPointerEventType.XButton2Down, - }, - PointToClient(PointFromLParam(lParam)), GetMouseModifiers(wParam)); - break; - } - case WindowsMessage.WM_TOUCH: - { - var touchInputCount = wParam.ToInt32(); - - var pTouchInputs = stackalloc TOUCHINPUT[touchInputCount]; - var touchInputs = new Span(pTouchInputs, touchInputCount); - - if (GetTouchInputInfo(lParam, (uint)touchInputCount, pTouchInputs, Marshal.SizeOf())) - { - foreach (var touchInput in touchInputs) - { - Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time, - _owner, - touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_UP) ? - RawPointerEventType.TouchEnd : - touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_DOWN) ? - RawPointerEventType.TouchBegin : - RawPointerEventType.TouchUpdate, - PointToClient(new PixelPoint(touchInput.X / 100, touchInput.Y / 100)), - WindowsKeyboardDevice.Instance.Modifiers, - touchInput.Id)); - } - - CloseTouchInputHandle(lParam); - return IntPtr.Zero; - } - - break; - } - case WindowsMessage.WM_NCPAINT: - { - if (!HasFullDecorations) - { - return IntPtr.Zero; - } - - break; - } - - case WindowsMessage.WM_NCACTIVATE: - { - if (!HasFullDecorations) - { - return new IntPtr(1); - } - - break; - } - - case WindowsMessage.WM_PAINT: - { - using (_rendererLock.Lock()) - { - if (BeginPaint(_hwnd, out PAINTSTRUCT ps) != IntPtr.Zero) - { - var f = Scaling; - var r = ps.rcPaint; - Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f, - (r.bottom - r.top) / f)); - EndPaint(_hwnd, ref ps); - } - } - - return IntPtr.Zero; - } - - case WindowsMessage.WM_SIZE: - { - using (_rendererLock.Lock()) - { - // Do nothing here, just block until the pending frame render is completed on the render thread - } - - var size = (SizeCommand)wParam; - - if (Resized != null && - (size == SizeCommand.Restored || - size == SizeCommand.Maximized)) - { - var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16); - Resized(clientSize / Scaling); - } - - var windowState = size == SizeCommand.Maximized ? - WindowState.Maximized : - (size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal); - - if (windowState != _lastWindowState) - { - _lastWindowState = windowState; - WindowStateChanged?.Invoke(windowState); - } - - return IntPtr.Zero; - } - - case WindowsMessage.WM_MOVE: - { - PositionChanged?.Invoke(new PixelPoint((short)(ToInt32(lParam) & 0xffff), - (short)(ToInt32(lParam) >> 16))); - return IntPtr.Zero; - } - - case WindowsMessage.WM_GETMINMAXINFO: - { - MINMAXINFO mmi = Marshal.PtrToStructure(lParam); - - _maxTrackSize = mmi.ptMaxTrackSize; - - if (_minSize.Width > 0) - { - mmi.ptMinTrackSize.X = - (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); - } - - if (_minSize.Height > 0) - { - mmi.ptMinTrackSize.Y = - (int)((_minSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom); - } - - if (!double.IsInfinity(_maxSize.Width) && _maxSize.Width > 0) - { - mmi.ptMaxTrackSize.X = - (int)((_maxSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); - } - - if (!double.IsInfinity(_maxSize.Height) && _maxSize.Height > 0) - { - mmi.ptMaxTrackSize.Y = - (int)((_maxSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom); - } - - Marshal.StructureToPtr(mmi, lParam, true); - return IntPtr.Zero; - } - - case WindowsMessage.WM_DISPLAYCHANGE: - { - (Screen as ScreenImpl)?.InvalidateScreensCache(); - return IntPtr.Zero; - } - } - -#if USE_MANAGED_DRAG - if (_managedDrag.PreprocessInputEvent(ref e)) - return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); -#endif - - if (e != null && Input != null) - { - Input(e); - - if (e.Handled) - { - return IntPtr.Zero; - } - } - - using (_rendererLock.Lock()) - { - return DefWindowProc(hWnd, msg, wParam, lParam); - } - } - - private static int ToInt32(IntPtr ptr) - { - if (IntPtr.Size == 4) - return ptr.ToInt32(); - - return (int)(ptr.ToInt64() & 0xffffffff); - } - - private static int HighWord(int param) => param >> 16; - - private Point DipFromLParam(IntPtr lParam) - { - return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / Scaling; - } - - private PixelPoint PointFromLParam(IntPtr lParam) - { - return new PixelPoint((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)); - } - - private bool ShouldIgnoreTouchEmulatedMessage() - { - if (!_multitouch) - { - return false; - } - - // MI_WP_SIGNATURE - // https://docs.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages - const long marker = 0xFF515700L; - - var info = GetMessageExtraInfo().ToInt64(); - return (info & marker) == marker; - } - - private static RawInputModifiers GetMouseModifiers(IntPtr wParam) - { - var keys = (ModifierKeys)ToInt32(wParam); - var modifiers = WindowsKeyboardDevice.Instance.Modifiers; - - if (keys.HasFlagCustom(ModifierKeys.MK_LBUTTON)) - { - modifiers |= RawInputModifiers.LeftMouseButton; - } - - if (keys.HasFlagCustom(ModifierKeys.MK_RBUTTON)) - { - modifiers |= RawInputModifiers.RightMouseButton; - } - - if (keys.HasFlagCustom(ModifierKeys.MK_MBUTTON)) - { - modifiers |= RawInputModifiers.MiddleMouseButton; - } - - if (keys.HasFlagCustom(ModifierKeys.MK_XBUTTON1)) - { - modifiers |= RawInputModifiers.XButton1MouseButton; - } - - if (keys.HasFlagCustom(ModifierKeys.MK_XBUTTON2)) - { - modifiers |= RawInputModifiers.XButton2MouseButton; - } - - return modifiers; - } - } } From b83d85362150a5ef2729dd589b1902d012084a80 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 17:08:28 -0300 Subject: [PATCH 10/98] TransparencyFallback layer needs to obey ExtendedClient margins to not cover titlebar. --- src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml | 2 +- src/Avalonia.Themes.Default/OverlayPopupHost.xaml | 2 +- src/Avalonia.Themes.Default/PopupRoot.xaml | 2 +- src/Avalonia.Themes.Default/Window.xaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml b/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml index 9ffe51fae8..f0e884832f 100644 --- a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml +++ b/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml @@ -4,7 +4,7 @@ - + - + - + - + Date: Wed, 20 May 2020 17:24:27 -0300 Subject: [PATCH 11/98] fix embeddable control root. --- src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml | 2 +- src/Avalonia.Themes.Default/OverlayPopupHost.xaml | 2 +- src/Avalonia.Themes.Default/PopupRoot.xaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml b/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml index f0e884832f..9ffe51fae8 100644 --- a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml +++ b/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml @@ -4,7 +4,7 @@ - + - + - + Date: Wed, 20 May 2020 17:29:07 -0300 Subject: [PATCH 12/98] fix build --- src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index faf83c6c9b..6716691872 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; using System.Text; +using Avalonia.Controls; +using Avalonia.Input; +using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32 { From 68e8541f7534a0c5191c1255aaf801472cb219fa Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 20 May 2020 17:57:21 -0300 Subject: [PATCH 13/98] use thickness as the ExtendClientArea hint. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 2 +- src/Avalonia.Controls/Window.cs | 10 +++++----- .../Remote/PreviewerWindowImpl.cs | 2 +- src/Avalonia.DesignerSupport/Remote/Stubs.cs | 2 +- src/Avalonia.Native/WindowImpl.cs | 2 +- src/Avalonia.X11/X11Window.cs | 2 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 19 +++++++++---------- 7 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 9c4808a41c..604c3a61aa 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -95,7 +95,7 @@ namespace Avalonia.Platform /// void SetMinMaxSize(Size minSize, Size maxSize); - bool ExtendClientAreaToDecorationsHint { get; set; } + Thickness ExtendClientAreaToDecorationsHint { get; set; } Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 04b48d7f9f..cbb69fbeb7 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -92,8 +92,8 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly StyledProperty ExtendClientAreaToDecorationsHintProperty = - AvaloniaProperty.Register(nameof(ExtendClientAreaToDecorationsHint), false); + public static readonly StyledProperty ExtendClientAreaToDecorationsHintProperty = + AvaloniaProperty.Register(nameof(ExtendClientAreaToDecorationsHint), default); /// @@ -109,7 +109,7 @@ namespace Avalonia.Controls /// public static readonly DirectProperty WindowDecorationMarginsProperty = AvaloniaProperty.RegisterDirect(nameof(WindowDecorationMargins), - o => o.WindowDecorationMargins); + o => o.WindowDecorationMargins); /// @@ -190,7 +190,7 @@ namespace Avalonia.Controls (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; }); ExtendClientAreaToDecorationsHintProperty.Changed.AddClassHandler( - (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.ExtendClientAreaToDecorationsHint = (bool)e.NewValue; }); + (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.ExtendClientAreaToDecorationsHint = (Thickness)e.NewValue; }); MinWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight))); MinHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight))); @@ -269,7 +269,7 @@ namespace Avalonia.Controls /// /// Gets or sets if the ClientArea is Extended into the Window Decorations (chrome or border). /// - public bool ExtendClientAreaToDecorationsHint + public Thickness ExtendClientAreaToDecorationsHint { get { return GetValue(ExtendClientAreaToDecorationsHintProperty); } set { SetValue(ExtendClientAreaToDecorationsHintProperty, value); } diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 441a79531a..26c3bed86d 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -85,7 +85,7 @@ namespace Avalonia.DesignerSupport.Remote public IScreenImpl Screen { get; } = new ScreenStub(); public Action GotInputWhenDisabled { get; set; } - public bool ExtendClientAreaToDecorationsHint { get; set; } + public Thickness ExtendClientAreaToDecorationsHint { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index f962382575..605e0e45a8 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -39,7 +39,7 @@ namespace Avalonia.DesignerSupport.Remote public Action TransparencyLevelChanged { get; set; } - public bool ExtendClientAreaToDecorationsHint { get; set; } + public Thickness ExtendClientAreaToDecorationsHint { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 3495c4b392..2e81a66d1f 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -98,7 +98,7 @@ namespace Avalonia.Native public Action WindowStateChanged { get; set; } - public bool ExtendClientAreaToDecorationsHint { get; set; } + public Thickness ExtendClientAreaToDecorationsHint { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index ac9048adad..4bff5b9b03 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -311,7 +311,7 @@ namespace Avalonia.X11 set => _transparencyHelper.TransparencyLevelChanged = value; } - public bool ExtendClientAreaToDecorationsHint { get; set; } + public Thickness ExtendClientAreaToDecorationsHint { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 7474bdd10a..fe8f175a5e 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -69,7 +69,7 @@ namespace Avalonia.Win32 private Size _maxSize; private POINT _maxTrackSize; private WindowImpl _parent; - private bool _extendClientAreaToDecorationsHint; + private Thickness _extendClientAreaToDecorationsHint; public WindowImpl() { @@ -666,7 +666,7 @@ namespace Avalonia.Win32 TaskBarList.MarkFullscreen(_hwnd, fullscreen); } - private void ExtendClientArea () + private void ExtendClientArea (Thickness thickness) { if (!_isClientAreaExtended) { @@ -690,10 +690,10 @@ namespace Avalonia.Win32 } // Extend the frame into the client area. - margins.cxLeftWidth = border_thickness.left; - margins.cxRightWidth = border_thickness.right; - margins.cyBottomHeight = border_thickness.bottom; - margins.cyTopHeight = border_thickness.top; + margins.cxLeftWidth = thickness.Left == -1 ? border_thickness.left : (int)(thickness.Left * Scaling); + margins.cxRightWidth = thickness.Right == -1 ? border_thickness.right : (int)(thickness.Right * Scaling); + margins.cyBottomHeight = thickness.Bottom == -1 ? border_thickness.bottom : (int)(thickness.Bottom * Scaling); + margins.cyTopHeight = thickness.Top == -1 ? border_thickness.top : (int)(thickness.Top * Scaling); var hr = DwmExtendFrameIntoClientArea(_hwnd, ref margins); @@ -948,15 +948,14 @@ namespace Avalonia.Win32 IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; - public bool ExtendClientAreaToDecorationsHint + public Thickness ExtendClientAreaToDecorationsHint { get => _extendClientAreaToDecorationsHint; set { - _extendClientAreaToDecorationsHint = true; + _extendClientAreaToDecorationsHint = value; - ExtendClientArea(); - // TODO Trigger transition. + ExtendClientArea(value); } } From 29661b45bad93b1b27ce4177e80ecd0d513c3d09 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 09:33:17 -0300 Subject: [PATCH 14/98] add handler for DWM_COMPOSITION_CHANGED. --- src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index 6716691872..a55a22c3c3 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -79,6 +79,10 @@ namespace Avalonia.Win32 switch ((WindowsMessage)msg) { + case WindowsMessage.WM_DWMCOMPOSITIONCHANGED: + // TODO handle composition changed. + break; + case WindowsMessage.WM_NCHITTEST: if (lRet == IntPtr.Zero) { From aea6f7bff9f915e5113438c9c53d6b6e47757693 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 09:33:40 -0300 Subject: [PATCH 15/98] Revert "use thickness as the ExtendClientArea hint." This reverts commit 42673554085035e8a8a3435bc623ceb29f72e4db. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 2 +- src/Avalonia.Controls/Window.cs | 10 +++++----- .../Remote/PreviewerWindowImpl.cs | 2 +- src/Avalonia.DesignerSupport/Remote/Stubs.cs | 2 +- src/Avalonia.Native/WindowImpl.cs | 2 +- src/Avalonia.X11/X11Window.cs | 2 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 19 ++++++++++--------- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 604c3a61aa..9c4808a41c 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -95,7 +95,7 @@ namespace Avalonia.Platform /// void SetMinMaxSize(Size minSize, Size maxSize); - Thickness ExtendClientAreaToDecorationsHint { get; set; } + bool ExtendClientAreaToDecorationsHint { get; set; } Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index cbb69fbeb7..04b48d7f9f 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -92,8 +92,8 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly StyledProperty ExtendClientAreaToDecorationsHintProperty = - AvaloniaProperty.Register(nameof(ExtendClientAreaToDecorationsHint), default); + public static readonly StyledProperty ExtendClientAreaToDecorationsHintProperty = + AvaloniaProperty.Register(nameof(ExtendClientAreaToDecorationsHint), false); /// @@ -109,7 +109,7 @@ namespace Avalonia.Controls /// public static readonly DirectProperty WindowDecorationMarginsProperty = AvaloniaProperty.RegisterDirect(nameof(WindowDecorationMargins), - o => o.WindowDecorationMargins); + o => o.WindowDecorationMargins); /// @@ -190,7 +190,7 @@ namespace Avalonia.Controls (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; }); ExtendClientAreaToDecorationsHintProperty.Changed.AddClassHandler( - (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.ExtendClientAreaToDecorationsHint = (Thickness)e.NewValue; }); + (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.ExtendClientAreaToDecorationsHint = (bool)e.NewValue; }); MinWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight))); MinHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight))); @@ -269,7 +269,7 @@ namespace Avalonia.Controls /// /// Gets or sets if the ClientArea is Extended into the Window Decorations (chrome or border). /// - public Thickness ExtendClientAreaToDecorationsHint + public bool ExtendClientAreaToDecorationsHint { get { return GetValue(ExtendClientAreaToDecorationsHintProperty); } set { SetValue(ExtendClientAreaToDecorationsHintProperty, value); } diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 26c3bed86d..441a79531a 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -85,7 +85,7 @@ namespace Avalonia.DesignerSupport.Remote public IScreenImpl Screen { get; } = new ScreenStub(); public Action GotInputWhenDisabled { get; set; } - public Thickness ExtendClientAreaToDecorationsHint { get; set; } + public bool ExtendClientAreaToDecorationsHint { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 605e0e45a8..f962382575 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -39,7 +39,7 @@ namespace Avalonia.DesignerSupport.Remote public Action TransparencyLevelChanged { get; set; } - public Thickness ExtendClientAreaToDecorationsHint { get; set; } + public bool ExtendClientAreaToDecorationsHint { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 2e81a66d1f..3495c4b392 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -98,7 +98,7 @@ namespace Avalonia.Native public Action WindowStateChanged { get; set; } - public Thickness ExtendClientAreaToDecorationsHint { get; set; } + public bool ExtendClientAreaToDecorationsHint { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 4bff5b9b03..ac9048adad 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -311,7 +311,7 @@ namespace Avalonia.X11 set => _transparencyHelper.TransparencyLevelChanged = value; } - public Thickness ExtendClientAreaToDecorationsHint { get; set; } + public bool ExtendClientAreaToDecorationsHint { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index fe8f175a5e..7474bdd10a 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -69,7 +69,7 @@ namespace Avalonia.Win32 private Size _maxSize; private POINT _maxTrackSize; private WindowImpl _parent; - private Thickness _extendClientAreaToDecorationsHint; + private bool _extendClientAreaToDecorationsHint; public WindowImpl() { @@ -666,7 +666,7 @@ namespace Avalonia.Win32 TaskBarList.MarkFullscreen(_hwnd, fullscreen); } - private void ExtendClientArea (Thickness thickness) + private void ExtendClientArea () { if (!_isClientAreaExtended) { @@ -690,10 +690,10 @@ namespace Avalonia.Win32 } // Extend the frame into the client area. - margins.cxLeftWidth = thickness.Left == -1 ? border_thickness.left : (int)(thickness.Left * Scaling); - margins.cxRightWidth = thickness.Right == -1 ? border_thickness.right : (int)(thickness.Right * Scaling); - margins.cyBottomHeight = thickness.Bottom == -1 ? border_thickness.bottom : (int)(thickness.Bottom * Scaling); - margins.cyTopHeight = thickness.Top == -1 ? border_thickness.top : (int)(thickness.Top * Scaling); + margins.cxLeftWidth = border_thickness.left; + margins.cxRightWidth = border_thickness.right; + margins.cyBottomHeight = border_thickness.bottom; + margins.cyTopHeight = border_thickness.top; var hr = DwmExtendFrameIntoClientArea(_hwnd, ref margins); @@ -948,14 +948,15 @@ namespace Avalonia.Win32 IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; - public Thickness ExtendClientAreaToDecorationsHint + public bool ExtendClientAreaToDecorationsHint { get => _extendClientAreaToDecorationsHint; set { - _extendClientAreaToDecorationsHint = value; + _extendClientAreaToDecorationsHint = true; - ExtendClientArea(value); + ExtendClientArea(); + // TODO Trigger transition. } } From 37e4e68b9d31f5c016ea4c672f9f7906f0e416fd Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 11:19:20 -0300 Subject: [PATCH 16/98] add hints for further control over chrome. --- .../Platform/ExtendClientAreaChromeHints.cs | 17 +++++ src/Avalonia.Controls/Platform/IWindowImpl.cs | 6 +- src/Avalonia.Controls/Window.cs | 14 +++- .../Remote/PreviewerWindowImpl.cs | 14 +++- src/Avalonia.DesignerSupport/Remote/Stubs.cs | 14 +++- src/Avalonia.Native/WindowImpl.cs | 14 +++- src/Avalonia.X11/X11Window.cs | 14 +++- .../Interop/UnmanagedMethods.cs | 6 ++ src/Windows/Avalonia.Win32/WindowImpl.cs | 74 +++++++++++++++---- 9 files changed, 144 insertions(+), 29 deletions(-) create mode 100644 src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs diff --git a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs new file mode 100644 index 0000000000..af33e3093b --- /dev/null +++ b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs @@ -0,0 +1,17 @@ +using System; + +namespace Avalonia.Platform +{ + [Flags] + public enum ExtendClientAreaChromeHints + { + Default = SystemTitleBar | SystemChromeButtons, + NoChrome, + SystemTitleBar = 0x01, + SystemChromeButtons = 0x02, + ManagedChromeButtons = 0x04, + PreferSystemChromeButtons = 0x08, + AdaptiveChromeWithTitleBar = SystemTitleBar | PreferSystemChromeButtons, + AdaptiveChromeWithoutTitleBar = PreferSystemChromeButtons, + } +} diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 9c4808a41c..d7bf93a603 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -95,7 +95,11 @@ namespace Avalonia.Platform /// void SetMinMaxSize(Size minSize, Size maxSize); - bool ExtendClientAreaToDecorationsHint { get; set; } + void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint); + + bool IsClientAreaExtendedToDecorations { get; } + + void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints); Action ExtendClientAreaToDecorationsChanged { get; set; } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 04b48d7f9f..85935d3d2a 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -95,6 +95,9 @@ namespace Avalonia.Controls public static readonly StyledProperty ExtendClientAreaToDecorationsHintProperty = AvaloniaProperty.Register(nameof(ExtendClientAreaToDecorationsHint), false); + public static readonly StyledProperty ExtendClientAreaChromeHintsProperty = + AvaloniaProperty.Register(nameof(ExtendClientAreaChromeHints), ExtendClientAreaChromeHints.Default); + /// /// Defines the property. @@ -190,7 +193,10 @@ namespace Avalonia.Controls (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; }); ExtendClientAreaToDecorationsHintProperty.Changed.AddClassHandler( - (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.ExtendClientAreaToDecorationsHint = (bool)e.NewValue; }); + (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaToDecorationsHint((bool)e.NewValue); }); + + ExtendClientAreaChromeHintsProperty.Changed.AddClassHandler( + (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaChromeHints((ExtendClientAreaChromeHints)e.NewValue); }); MinWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight))); MinHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight))); @@ -275,6 +281,12 @@ namespace Avalonia.Controls set { SetValue(ExtendClientAreaToDecorationsHintProperty, value); } } + public ExtendClientAreaChromeHints ExtendClientAreaChromeHints + { + get => GetValue(ExtendClientAreaChromeHintsProperty); + set => SetValue(ExtendClientAreaChromeHintsProperty, value); + } + /// /// Gets if the ClientArea is Extended into the Window Decorations. /// diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 441a79531a..06c7ac6411 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -83,14 +83,14 @@ namespace Avalonia.DesignerSupport.Remote } public IScreenImpl Screen { get; } = new ScreenStub(); - public Action GotInputWhenDisabled { get; set; } - - public bool ExtendClientAreaToDecorationsHint { get; set; } + public Action GotInputWhenDisabled { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } public Thickness ExtendedMargins { get; } = new Thickness(); + public bool IsClientAreaExtendedToDecorations { get; } + public void Activate() { } @@ -130,5 +130,13 @@ namespace Avalonia.DesignerSupport.Remote public void SetEnabled(bool enable) { } + + public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) + { + } + + public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) + { + } } } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index f962382575..6f5a0e6051 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -37,9 +37,7 @@ namespace Avalonia.DesignerSupport.Remote public WindowState WindowState { get; set; } public Action WindowStateChanged { get; set; } - public Action TransparencyLevelChanged { get; set; } - - public bool ExtendClientAreaToDecorationsHint { get; set; } + public Action TransparencyLevelChanged { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } @@ -146,6 +144,14 @@ namespace Avalonia.DesignerSupport.Remote { } + public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) + { + } + + public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) + { + } + public IPopupPositioner PopupPositioner { get; } public Action GotInputWhenDisabled { get; set; } @@ -157,6 +163,8 @@ namespace Avalonia.DesignerSupport.Remote } public WindowTransparencyLevel TransparencyLevel { get; private set; } + + public bool IsClientAreaExtendedToDecorations { get; } } class ClipboardStub : IClipboard diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 3495c4b392..47c8291803 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -96,14 +96,22 @@ namespace Avalonia.Native } } - public Action WindowStateChanged { get; set; } - - public bool ExtendClientAreaToDecorationsHint { get; set; } + public Action WindowStateChanged { get; set; } public Action ExtendClientAreaToDecorationsChanged { get; set; } public Thickness ExtendedMargins { get; } = new Thickness(); + public bool IsClientAreaExtendedToDecorations { get; } + + public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) + { + } + + public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) + { + } + public void ShowTaskbarIcon(bool value) { // NO OP On OSX diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index ac9048adad..d64f993299 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -309,14 +309,14 @@ namespace Avalonia.X11 { get => _transparencyHelper.TransparencyLevelChanged; set => _transparencyHelper.TransparencyLevelChanged = value; - } - - public bool ExtendClientAreaToDecorationsHint { get; set; } + } public Action ExtendClientAreaToDecorationsChanged { get; set; } public Thickness ExtendedMargins { get; } = new Thickness(); + public bool IsClientAreaExtendedToDecorations { get; } + public Action Closed { get; set; } public Action PositionChanged { get; set; } @@ -1041,6 +1041,14 @@ namespace Avalonia.X11 _disabled = !enable; } + public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) + { + } + + public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) + { + } + public Action GotInputWhenDisabled { get; set; } public void SetIcon(IWindowIconImpl icon) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index b66de8e0a8..6f843324f2 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -989,6 +989,12 @@ namespace Avalonia.Win32.Interop } } + [DllImport("user32.dll")] + public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); + + [DllImport("user32.dll")] + public static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable); + [DllImport("user32.dll", SetLastError = true)] public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 7474bdd10a..7c720b5612 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -41,6 +41,7 @@ namespace Avalonia.Win32 private SavedWindowInfo _savedWindowInfo; private bool _isFullScreenActive; private bool _isClientAreaExtended; + private Thickness _extendedMargins; #if USE_MANAGED_DRAG private readonly ManagedWindowResizeDragHelper _managedDrag; @@ -666,7 +667,7 @@ namespace Avalonia.Win32 TaskBarList.MarkFullscreen(_hwnd, fullscreen); } - private void ExtendClientArea () + private void ExtendClientArea (ExtendClientAreaChromeHints hints) { if (!_isClientAreaExtended) { @@ -683,6 +684,16 @@ namespace Avalonia.Win32 AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); border_thickness.left *= -1; border_thickness.top *= -1; + + border_thickness.left = 1; + border_thickness.bottom = 1; + border_thickness.right = 1; + + if (!hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar)) + { + border_thickness.top = 1; + } + } else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) { @@ -697,6 +708,19 @@ namespace Avalonia.Win32 var hr = DwmExtendFrameIntoClientArea(_hwnd, ref margins); + if(!hints.HasFlag(ExtendClientAreaChromeHints.SystemChromeButtons) || + (hints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChromeButtons) && + !hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar))) + { + var style = GetStyle(); + + style &= ~(WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_MAXIMIZEBOX | WindowStyles.WS_SYSMENU); + + SetStyle(style); + + DisableCloseButton(_hwnd); + } + if (hr == 0) { _isClientAreaExtended = true; @@ -854,9 +878,10 @@ namespace Avalonia.Win32 // Otherwise it will still show in the taskbar. } + WindowStyles style; if ((oldProperties.IsResizable != newProperties.IsResizable) || forceChanges) { - var style = GetStyle(); + style = GetStyle(); if (newProperties.IsResizable) { @@ -877,7 +902,7 @@ namespace Avalonia.Win32 if ((oldProperties.Decorations != newProperties.Decorations) || forceChanges) { - var style = GetStyle(); + style = GetStyle(); const WindowStyles fullDecorationFlags = WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU; @@ -922,7 +947,26 @@ namespace Avalonia.Win32 SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); } - } + } + } + + private const int MF_BYCOMMAND = 0x0; + private const int MF_BYPOSITION = 0x400; + private const int MF_REMOVE = 0x1000; + private const int MF_ENABLED = 0x0; + private const int MF_GRAYED = 0x1; + private const int MF_DISABLED = 0x2; + private const int SC_CLOSE = 0xF060; + + void DisableCloseButton(IntPtr hwnd) + { + EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + } + void EnableCloseButton(IntPtr hwnd) + { + EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE, + MF_BYCOMMAND | MF_ENABLED); } #if USE_MANAGED_DRAG @@ -946,23 +990,23 @@ namespace Avalonia.Win32 } } - IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; + IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; - public bool ExtendClientAreaToDecorationsHint + public void SetExtendClientAreaToDecorationsHint(bool hint) { - get => _extendClientAreaToDecorationsHint; - set - { - _extendClientAreaToDecorationsHint = true; + ExtendClientArea(_extendChromeHints); + } - ExtendClientArea(); - // TODO Trigger transition. - } + private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default; + + public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) + { + _extendChromeHints = hints; } - public Action ExtendClientAreaToDecorationsChanged { get; set; } + public bool IsClientAreaExtendedToDecorations => _isClientAreaExtended; - private Thickness _extendedMargins; + public Action ExtendClientAreaToDecorationsChanged { get; set; } public Thickness ExtendedMargins => _extendedMargins; From 73d50254483ef97afa84b875892684d3587d0393 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 13:35:50 -0300 Subject: [PATCH 17/98] Add a readonly offscreen margin, to get the portion of the window that is offscreen. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 2 ++ src/Avalonia.Controls/Window.cs | 16 ++++++++- .../Remote/PreviewerWindowImpl.cs | 2 ++ src/Avalonia.DesignerSupport/Remote/Stubs.cs | 2 ++ src/Avalonia.Native/WindowImpl.cs | 2 ++ src/Avalonia.X11/X11Window.cs | 2 ++ .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 5 +++ src/Windows/Avalonia.Win32/WindowImpl.cs | 36 ++++++++++++++++++- 8 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index d7bf93a603..999f4f4201 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -104,5 +104,7 @@ namespace Avalonia.Platform Action ExtendClientAreaToDecorationsChanged { get; set; } Thickness ExtendedMargins { get; } + + Thickness OffScreenMargin { get; } } } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 85935d3d2a..54e2fbb629 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -113,7 +113,11 @@ namespace Avalonia.Controls public static readonly DirectProperty WindowDecorationMarginsProperty = AvaloniaProperty.RegisterDirect(nameof(WindowDecorationMargins), o => o.WindowDecorationMargins); - + + public static readonly DirectProperty OffScreenMarginProperty = + AvaloniaProperty.RegisterDirect(nameof(OffScreenMargin), + o => o.OffScreenMargin); + /// /// Defines the property. @@ -304,6 +308,14 @@ namespace Avalonia.Controls private set => SetAndRaise(WindowDecorationMarginsProperty, ref _windowDecorationMargins, value); } + private Thickness _offScreenMargin; + + public Thickness OffScreenMargin + { + get => _offScreenMargin; + private set => SetAndRaise(OffScreenMarginProperty, ref _offScreenMargin, value); + } + /// /// Sets the system decorations (title bar, border, etc) /// @@ -507,6 +519,8 @@ namespace Avalonia.Controls IsExtendedIntoWindowDecorations = isExtended; WindowDecorationMargins = PlatformImpl.ExtendedMargins; + + OffScreenMargin = PlatformImpl.OffScreenMargin; } /// diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 06c7ac6411..da7cbf815a 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -91,6 +91,8 @@ namespace Avalonia.DesignerSupport.Remote public bool IsClientAreaExtendedToDecorations { get; } + public Thickness OffScreenMargin { get; } = new Thickness(); + public void Activate() { } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 6f5a0e6051..6859c408dd 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -43,6 +43,8 @@ namespace Avalonia.DesignerSupport.Remote public Thickness ExtendedMargins { get; } = new Thickness(); + public Thickness OffScreenMargin { get; } = new Thickness(); + public WindowStub(IWindowImpl parent = null) { if (parent != null) diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 47c8291803..cbea340246 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -102,6 +102,8 @@ namespace Avalonia.Native public Thickness ExtendedMargins { get; } = new Thickness(); + public Thickness OffScreenMargin { get; } = new Thickness(); + public bool IsClientAreaExtendedToDecorations { get; } public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index d64f993299..086863796c 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -315,6 +315,8 @@ namespace Avalonia.X11 public Thickness ExtendedMargins { get; } = new Thickness(); + public Thickness OffScreenMargin { get; } = new Thickness(); + public bool IsClientAreaExtendedToDecorations { get; } public Action Closed { get; set; } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index b81634dce0..0c2160de2b 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -374,6 +374,11 @@ namespace Avalonia.Win32 if (windowState != _lastWindowState) { _lastWindowState = windowState; + + UpdateExtendMargins(); + + ExtendClientAreaToDecorationsChanged?.Invoke(true); + WindowStateChanged?.Invoke(windowState); } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 7c720b5612..fd7084ea29 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -42,7 +42,8 @@ namespace Avalonia.Win32 private bool _isFullScreenActive; private bool _isClientAreaExtended; private Thickness _extendedMargins; - + private Thickness _offScreenMargin; + #if USE_MANAGED_DRAG private readonly ManagedWindowResizeDragHelper _managedDrag; #endif @@ -667,6 +668,37 @@ namespace Avalonia.Win32 TaskBarList.MarkFullscreen(_hwnd, fullscreen); } + private MARGINS UpdateExtendMargins() + { + RECT borderThickness = new RECT(); + RECT borderCaptionThickness = new RECT(); + + AdjustWindowRectEx(ref borderCaptionThickness, (uint)(GetStyle()), false, 0); + AdjustWindowRectEx(ref borderThickness, (uint)(GetStyle() & ~WindowStyles.WS_CAPTION), false, 0); + borderThickness.left *= -1; + borderThickness.top *= -1; + borderCaptionThickness.left *= -1; + borderCaptionThickness.top *= -1; + + _extendedMargins = new Thickness(1 / Scaling, borderCaptionThickness.top / Scaling, 1 / Scaling, 1 / Scaling); + + if (WindowState == WindowState.Maximized) + { + _offScreenMargin = new Thickness(borderThickness.left / Scaling, borderThickness.top / Scaling, borderThickness.right / Scaling, borderThickness.bottom / Scaling); + } + else + { + _offScreenMargin = new Thickness(); + } + + MARGINS margins = new MARGINS(); + margins.cxLeftWidth = 1; + margins.cxRightWidth = 1; + margins.cyBottomHeight = 1; + margins.cyTopHeight = borderThickness.top; + return margins; + } + private void ExtendClientArea (ExtendClientAreaChromeHints hints) { if (!_isClientAreaExtended) @@ -1010,6 +1042,8 @@ namespace Avalonia.Win32 public Thickness ExtendedMargins => _extendedMargins; + public Thickness OffScreenMargin => _offScreenMargin; + private struct SavedWindowInfo { public WindowStyles Style { get; set; } From bd717d8b5c7f4fb9aff2996ff6c225d5221462b7 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 13:41:57 -0300 Subject: [PATCH 18/98] calculate extend metrics in function. --- .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 2 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 39 ++++--------------- 2 files changed, 9 insertions(+), 32 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 0c2160de2b..5ffed48f2d 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -375,7 +375,7 @@ namespace Avalonia.Win32 { _lastWindowState = windowState; - UpdateExtendMargins(); + UpdateExtendMargins(_extendChromeHints); ExtendClientAreaToDecorationsChanged?.Invoke(true); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index fd7084ea29..e10ce99bc4 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -668,7 +668,7 @@ namespace Avalonia.Win32 TaskBarList.MarkFullscreen(_hwnd, fullscreen); } - private MARGINS UpdateExtendMargins() + private MARGINS UpdateExtendMargins(ExtendClientAreaChromeHints hints) { RECT borderThickness = new RECT(); RECT borderCaptionThickness = new RECT(); @@ -680,6 +680,11 @@ namespace Avalonia.Win32 borderCaptionThickness.left *= -1; borderCaptionThickness.top *= -1; + if (!hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar)) + { + borderCaptionThickness.top = 1; + } + _extendedMargins = new Thickness(1 / Scaling, borderCaptionThickness.top / Scaling, 1 / Scaling, 1 / Scaling); if (WindowState == WindowState.Maximized) @@ -695,7 +700,7 @@ namespace Avalonia.Win32 margins.cxLeftWidth = 1; margins.cxRightWidth = 1; margins.cyBottomHeight = 1; - margins.cyTopHeight = borderThickness.top; + margins.cyTopHeight = borderCaptionThickness.top; return margins; } @@ -708,35 +713,7 @@ namespace Avalonia.Win32 return; } - RECT border_thickness = new RECT(); - MARGINS margins = new MARGINS(); - - if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) - { - AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); - border_thickness.left *= -1; - border_thickness.top *= -1; - - border_thickness.left = 1; - border_thickness.bottom = 1; - border_thickness.right = 1; - - if (!hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar)) - { - border_thickness.top = 1; - } - - } - else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) - { - border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; - } - - // Extend the frame into the client area. - margins.cxLeftWidth = border_thickness.left; - margins.cxRightWidth = border_thickness.right; - margins.cyBottomHeight = border_thickness.bottom; - margins.cyTopHeight = border_thickness.top; + var margins = UpdateExtendMargins(hints); var hr = DwmExtendFrameIntoClientArea(_hwnd, ref margins); From 693487313d8dfd3f5c41ca68fa8f631bb9fadb62 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 15:05:28 -0300 Subject: [PATCH 19/98] fix hit testing. --- .../WindowImpl.CustomCaptionProc.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index a55a22c3c3..fee6bb90bf 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -1,6 +1,5 @@ using System; -using System.Collections.Generic; -using System.Text; +using System.Diagnostics; using Avalonia.Controls; using Avalonia.Input; using static Avalonia.Win32.Interop.UnmanagedMethods; @@ -34,6 +33,11 @@ namespace Avalonia.Win32 border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; } + if (_extendTitleBarHint >= 0) + { + border_thickness.top = (int)(_extendedMargins.Top * Scaling); + } + // Determine if the hit test is for resizing. Default middle (1,1). ushort uRow = 1; ushort uCol = 1; @@ -86,11 +90,13 @@ namespace Avalonia.Win32 case WindowsMessage.WM_NCHITTEST: if (lRet == IntPtr.Zero) { - lRet = (IntPtr)HitTestNCA(hWnd, wParam, lParam); + var hittestResult = HitTestNCA(hWnd, wParam, lParam); + + lRet = (IntPtr)hittestResult; uint timestamp = unchecked((uint)GetMessageTime()); - if (((HitTestValues)lRet) == HitTestValues.HTCAPTION) + if (hittestResult == HitTestValues.HTCAPTION) { var position = PointToClient(PointFromLParam(lParam)); @@ -106,11 +112,12 @@ namespace Avalonia.Win32 if (visual != null) { - lRet = (IntPtr)HitTestValues.HTCLIENT; + hittestResult = HitTestValues.HTCLIENT; + lRet = (IntPtr)hittestResult; } } - if (((HitTestValues)lRet) != HitTestValues.HTNOWHERE) + if (hittestResult != HitTestValues.HTNOWHERE) { callDwp = false; } From a838129ff9b153dda37f65e817dc4b84451e29de Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 15:08:03 -0300 Subject: [PATCH 20/98] Configurable titlebar height. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 32 +++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index e10ce99bc4..e18ee26996 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -680,12 +680,26 @@ namespace Avalonia.Win32 borderCaptionThickness.left *= -1; borderCaptionThickness.top *= -1; - if (!hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar)) + bool wantsTitleBar = hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar) || _extendTitleBarHint == -1; + + if (!wantsTitleBar) { borderCaptionThickness.top = 1; } - _extendedMargins = new Thickness(1 / Scaling, borderCaptionThickness.top / Scaling, 1 / Scaling, 1 / Scaling); + MARGINS margins = new MARGINS(); + margins.cxLeftWidth = 1; + margins.cxRightWidth = 1; + margins.cyBottomHeight = 1; + + if (_extendTitleBarHint != -1) + { + borderCaptionThickness.top = (int)(_extendTitleBarHint * Scaling); + } + + margins.cyTopHeight = hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar) ? borderCaptionThickness.top : 1; + + _extendedMargins = new Thickness(0, borderCaptionThickness.top / Scaling, 0, 0); if (WindowState == WindowState.Maximized) { @@ -696,11 +710,6 @@ namespace Avalonia.Win32 _offScreenMargin = new Thickness(); } - MARGINS margins = new MARGINS(); - margins.cxLeftWidth = 1; - margins.cxRightWidth = 1; - margins.cyBottomHeight = 1; - margins.cyTopHeight = borderCaptionThickness.top; return margins; } @@ -732,8 +741,7 @@ namespace Avalonia.Win32 if (hr == 0) { - _isClientAreaExtended = true; - _extendedMargins = new Thickness(margins.cxLeftWidth / Scaling, margins.cyTopHeight / Scaling, margins.cxRightWidth / Scaling, margins.cyBottomHeight / Scaling); + _isClientAreaExtended = true; ExtendClientAreaToDecorationsChanged?.Invoke(true); } } @@ -1013,6 +1021,12 @@ namespace Avalonia.Win32 _extendChromeHints = hints; } + private double _extendTitleBarHint = -1; + public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) + { + _extendTitleBarHint = titleBarHeight; + } + public bool IsClientAreaExtendedToDecorations => _isClientAreaExtended; public Action ExtendClientAreaToDecorationsChanged { get; set; } From d587096e88438306965755b07de13d6f5c9cf6a0 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 15:08:33 -0300 Subject: [PATCH 21/98] Add TitleBarHeight Hint. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 2 ++ src/Avalonia.Controls/Window.cs | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 999f4f4201..15315063fe 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -101,6 +101,8 @@ namespace Avalonia.Platform void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints); + void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight); + Action ExtendClientAreaToDecorationsChanged { get; set; } Thickness ExtendedMargins { get; } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 54e2fbb629..12b61fce23 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -98,6 +98,9 @@ namespace Avalonia.Controls public static readonly StyledProperty ExtendClientAreaChromeHintsProperty = AvaloniaProperty.Register(nameof(ExtendClientAreaChromeHints), ExtendClientAreaChromeHints.Default); + public static readonly StyledProperty ExtendClientAreaTitleBarHeightHintProperty = + AvaloniaProperty.Register(nameof(ExtendClientAreaTitleBarHeightHint), -1); + /// /// Defines the property. @@ -202,6 +205,9 @@ namespace Avalonia.Controls ExtendClientAreaChromeHintsProperty.Changed.AddClassHandler( (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaChromeHints((ExtendClientAreaChromeHints)e.NewValue); }); + ExtendClientAreaTitleBarHeightHintProperty.Changed.AddClassHandler( + (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaTitleBarHeightHint((double)e.NewValue); }); + MinWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight))); MinHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight))); MaxWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight))); @@ -291,6 +297,12 @@ namespace Avalonia.Controls set => SetValue(ExtendClientAreaChromeHintsProperty, value); } + public double ExtendClientAreaTitleBarHeightHint + { + get => GetValue(ExtendClientAreaTitleBarHeightHintProperty); + set => SetValue(ExtendClientAreaTitleBarHeightHintProperty, value); + } + /// /// Gets if the ClientArea is Extended into the Window Decorations. /// From 72e24625a02e54ca1283ca009a1e4f2d800484c8 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 15:08:48 -0300 Subject: [PATCH 22/98] Stubs for TitleBarHeight Hint. --- src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs | 4 ++++ src/Avalonia.DesignerSupport/Remote/Stubs.cs | 4 ++++ src/Avalonia.Native/WindowImpl.cs | 4 ++++ src/Avalonia.X11/X11Window.cs | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index da7cbf815a..0f35545d13 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -140,5 +140,9 @@ namespace Avalonia.DesignerSupport.Remote public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) { } + + public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) + { + } } } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 6859c408dd..400ecda405 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -154,6 +154,10 @@ namespace Avalonia.DesignerSupport.Remote { } + public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) + { + } + public IPopupPositioner PopupPositioner { get; } public Action GotInputWhenDisabled { get; set; } diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index cbea340246..532869e751 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -114,6 +114,10 @@ namespace Avalonia.Native { } + public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) + { + } + public void ShowTaskbarIcon(bool value) { // NO OP On OSX diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 086863796c..0a58e03c2f 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -1051,6 +1051,10 @@ namespace Avalonia.X11 { } + public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) + { + } + public Action GotInputWhenDisabled { get; set; } public void SetIcon(IWindowIconImpl icon) From df41ca8f6e1875e742b381cf4a9be842c232f8f8 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 15:42:23 -0300 Subject: [PATCH 23/98] Allow extend hints to be changed at runtime. --- .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 11 ++-- src/Windows/Avalonia.Win32/WindowImpl.cs | 60 ++++++++++++------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 5ffed48f2d..18283432e4 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -373,13 +373,16 @@ namespace Avalonia.Win32 if (windowState != _lastWindowState) { - _lastWindowState = windowState; + _lastWindowState = windowState; - UpdateExtendMargins(_extendChromeHints); + WindowStateChanged?.Invoke(windowState); - ExtendClientAreaToDecorationsChanged?.Invoke(true); + if (_isClientAreaExtended) + { + UpdateExtendMargins(); - WindowStateChanged?.Invoke(windowState); + ExtendClientAreaToDecorationsChanged?.Invoke(true); + } } return IntPtr.Zero; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index e18ee26996..a88a342b00 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -668,7 +668,7 @@ namespace Avalonia.Win32 TaskBarList.MarkFullscreen(_hwnd, fullscreen); } - private MARGINS UpdateExtendMargins(ExtendClientAreaChromeHints hints) + private MARGINS UpdateExtendMargins() { RECT borderThickness = new RECT(); RECT borderCaptionThickness = new RECT(); @@ -680,7 +680,7 @@ namespace Avalonia.Win32 borderCaptionThickness.left *= -1; borderCaptionThickness.top *= -1; - bool wantsTitleBar = hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar) || _extendTitleBarHint == -1; + bool wantsTitleBar = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar) || _extendTitleBarHint == -1; if (!wantsTitleBar) { @@ -697,7 +697,7 @@ namespace Avalonia.Win32 borderCaptionThickness.top = (int)(_extendTitleBarHint * Scaling); } - margins.cyTopHeight = hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar) ? borderCaptionThickness.top : 1; + margins.cyTopHeight = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar) ? borderCaptionThickness.top : 1; _extendedMargins = new Thickness(0, borderCaptionThickness.top / Scaling, 0, 0); @@ -713,22 +713,32 @@ namespace Avalonia.Win32 return margins; } - private void ExtendClientArea (ExtendClientAreaChromeHints hints) + private void ExtendClientArea () { - if (!_isClientAreaExtended) + if (DwmIsCompositionEnabled(out bool compositionEnabled) < 0 || !compositionEnabled) { - if(DwmIsCompositionEnabled(out bool compositionEnabled) < 0 || !compositionEnabled) - { - return; - } + _isClientAreaExtended = false; + return; + } - var margins = UpdateExtendMargins(hints); + GetWindowRect(_hwnd, out var rcClient); - var hr = DwmExtendFrameIntoClientArea(_hwnd, ref margins); + // Inform the application of the frame change. + SetWindowPos(_hwnd, + IntPtr.Zero, + rcClient.left, rcClient.top, + rcClient.Width, rcClient.Height, + SetWindowPosFlags.SWP_FRAMECHANGED); + + if(_isClientAreaExtended) + { + var margins = UpdateExtendMargins(); - if(!hints.HasFlag(ExtendClientAreaChromeHints.SystemChromeButtons) || - (hints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChromeButtons) && - !hints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar))) + DwmExtendFrameIntoClientArea(_hwnd, ref margins); + + if(!_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemChromeButtons) || + (_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChromeButtons) && + !_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar))) { var style = GetStyle(); @@ -738,13 +748,17 @@ namespace Avalonia.Win32 DisableCloseButton(_hwnd); } + } + else + { + var margins = new MARGINS(); + DwmExtendFrameIntoClientArea(_hwnd, ref margins); - if (hr == 0) - { - _isClientAreaExtended = true; - ExtendClientAreaToDecorationsChanged?.Invoke(true); - } + _offScreenMargin = new Thickness(); + _extendedMargins = new Thickness(); } + + ExtendClientAreaToDecorationsChanged?.Invoke(true); } private void ShowWindow(WindowState state) @@ -1011,7 +1025,9 @@ namespace Avalonia.Win32 public void SetExtendClientAreaToDecorationsHint(bool hint) { - ExtendClientArea(_extendChromeHints); + _isClientAreaExtended = hint; + + ExtendClientArea(); } private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default; @@ -1019,12 +1035,16 @@ namespace Avalonia.Win32 public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) { _extendChromeHints = hints; + + ExtendClientArea(); } private double _extendTitleBarHint = -1; public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) { _extendTitleBarHint = titleBarHeight; + + ExtendClientArea(); } public bool IsClientAreaExtendedToDecorations => _isClientAreaExtended; From 454cc06184ae1dc459732905679f9661d65f15e9 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 16:26:51 -0300 Subject: [PATCH 24/98] Add a WindowCustomization page to the control catalog. --- samples/ControlCatalog/MainView.xaml | 1 + samples/ControlCatalog/MainWindow.xaml | 8 ++- .../Pages/WindowCustomizationsPage.xaml | 13 ++++ .../Pages/WindowCustomizationsPage.xaml.cs | 19 ++++++ .../ViewModels/MainWindowViewModel.cs | 60 +++++++++++++++++++ 5 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml create mode 100644 samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml.cs diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index fef68bb5f5..5e0495adf5 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -61,6 +61,7 @@ + diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 76422bc130..4c3a00a402 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -7,7 +7,11 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:ControlCatalog.ViewModels" xmlns:v="clr-namespace:ControlCatalog.Views" - x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}" Background="{DynamicResource SystemControlPageBackgroundAltHighBrush}"> + ExtendClientAreaToDecorationsHint="{Binding ExtendClientAreaEnabled}" + ExtendClientAreaChromeHints="{Binding ChromeHints}" + ExtendClientAreaTitleBarHeightHint="{Binding TitleBarHeight}" + x:Name="MainWindow" + x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}" Background="{x:Null}"> @@ -61,7 +65,7 @@ - + diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml new file mode 100644 index 0000000000..168b504b40 --- /dev/null +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml.cs b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml.cs new file mode 100644 index 0000000000..d8d4f3f371 --- /dev/null +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml.cs @@ -0,0 +1,19 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace ControlCatalog.Pages +{ + public class WindowCustomizationsPage : UserControl + { + public WindowCustomizationsPage() + { + this.InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index 0257b4ce66..26b7e1bea8 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -3,6 +3,8 @@ using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.Notifications; using Avalonia.Dialogs; +using Avalonia.Platform; +using System; using ReactiveUI; namespace ControlCatalog.ViewModels @@ -62,8 +64,66 @@ namespace ControlCatalog.ViewModels WindowState.Maximized, WindowState.FullScreen, }; + + this.WhenAnyValue(x => x.SystemChromeButtonsEnabled, x => x.SystemTitleBarEnabled) + .Subscribe(x => + { + ChromeHints = ExtendClientAreaChromeHints.NoChrome; + + if(x.Item1) + { + ChromeHints |= ExtendClientAreaChromeHints.SystemChromeButtons; + } + + if(x.Item2) + { + ChromeHints |= ExtendClientAreaChromeHints.SystemTitleBar; + } + }); + } + + private ExtendClientAreaChromeHints _chromeHints; + + public ExtendClientAreaChromeHints ChromeHints + { + get { return _chromeHints; } + set { this.RaiseAndSetIfChanged(ref _chromeHints, value); } + } + + + private bool _extendClientAreaEnabled; + + public bool ExtendClientAreaEnabled + { + get { return _extendClientAreaEnabled; } + set { this.RaiseAndSetIfChanged(ref _extendClientAreaEnabled, value); } } + private bool _systemTitleBarEnabled; + + public bool SystemTitleBarEnabled + { + get { return _systemTitleBarEnabled; } + set { this.RaiseAndSetIfChanged(ref _systemTitleBarEnabled, value); } + } + + private bool _systemChromeButtonsEnabled; + + public bool SystemChromeButtonsEnabled + { + get { return _systemChromeButtonsEnabled; } + set { this.RaiseAndSetIfChanged(ref _systemChromeButtonsEnabled, value); } + } + + private double _titleBarHeight; + + public double TitleBarHeight + { + get { return _titleBarHeight; } + set { this.RaiseAndSetIfChanged(ref _titleBarHeight, value); } + } + + public WindowState WindowState { get { return _windowState; } From 1ce5fdfd03744932edcba0d7ef1654a4e454565e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 16:27:33 -0300 Subject: [PATCH 25/98] Update when caption buttons are turned on or off. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index a88a342b00..d09e3196da 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -748,6 +748,16 @@ namespace Avalonia.Win32 DisableCloseButton(_hwnd); } + else + { + var style = GetStyle(); + + style |= (WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_MAXIMIZEBOX | WindowStyles.WS_SYSMENU); + + SetStyle(style); + + EnableCloseButton(_hwnd); + } } else { @@ -756,6 +766,14 @@ namespace Avalonia.Win32 _offScreenMargin = new Thickness(); _extendedMargins = new Thickness(); + + var style = GetStyle(); + + style |= (WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_MAXIMIZEBOX | WindowStyles.WS_SYSMENU); + + SetStyle(style); + + EnableCloseButton(_hwnd); } ExtendClientAreaToDecorationsChanged?.Invoke(true); From 6e809937c6eaaeeb7ce8ba827a7962820a8074d3 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 16:27:57 -0300 Subject: [PATCH 26/98] NoChome is 0 --- src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs index af33e3093b..e98124b2d8 100644 --- a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs +++ b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs @@ -4,9 +4,9 @@ namespace Avalonia.Platform { [Flags] public enum ExtendClientAreaChromeHints - { - Default = SystemTitleBar | SystemChromeButtons, + { NoChrome, + Default = SystemTitleBar | SystemChromeButtons, SystemTitleBar = 0x01, SystemChromeButtons = 0x02, ManagedChromeButtons = 0x04, From d4fa9ad406354c917ec7b15ee1be3340db0b64c1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 16:36:49 -0300 Subject: [PATCH 27/98] Move transparency to window customizations page. --- samples/ControlCatalog/MainView.xaml.cs | 7 ------- samples/ControlCatalog/MainWindow.xaml | 1 + .../Pages/WindowCustomizationsPage.xaml | 5 +++++ .../ControlCatalog/ViewModels/MainWindowViewModel.cs | 12 ++++++++++++ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs index d6d4a71ad3..b0c205246e 100644 --- a/samples/ControlCatalog/MainView.xaml.cs +++ b/samples/ControlCatalog/MainView.xaml.cs @@ -58,13 +58,6 @@ namespace ControlCatalog if (VisualRoot is Window window) window.SystemDecorations = (SystemDecorations)decorations.SelectedIndex; }; - - var transparencyLevels = this.Find("TransparencyLevels"); - transparencyLevels.SelectionChanged += (sender, e) => - { - if (VisualRoot is Window window) - window.TransparencyLevelHint = (WindowTransparencyLevel)transparencyLevels.SelectedIndex; - }; } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 4c3a00a402..e92339416b 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -10,6 +10,7 @@ ExtendClientAreaToDecorationsHint="{Binding ExtendClientAreaEnabled}" ExtendClientAreaChromeHints="{Binding ChromeHints}" ExtendClientAreaTitleBarHeightHint="{Binding TitleBarHeight}" + TransparencyLevelHint="{Binding TransparencyLevel}" x:Name="MainWindow" x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}" Background="{x:Null}"> diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml index 168b504b40..44973f5b79 100644 --- a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml @@ -9,5 +9,10 @@ + + None + Transparent + Blur + diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index 26b7e1bea8..80231a4c15 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -80,6 +80,18 @@ namespace ControlCatalog.ViewModels ChromeHints |= ExtendClientAreaChromeHints.SystemTitleBar; } }); + + SystemTitleBarEnabled = true; + SystemChromeButtonsEnabled = true; + TitleBarHeight = -1; + } + + private int _transparencyLevel; + + public int TransparencyLevel + { + get { return _transparencyLevel; } + set { this.RaiseAndSetIfChanged(ref _transparencyLevel, value); } } private ExtendClientAreaChromeHints _chromeHints; From bb83df834a6e524935b31edf0f263ba4fc2b102a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 16:55:19 -0300 Subject: [PATCH 28/98] fully working client area extension demo --- samples/ControlCatalog/MainWindow.xaml | 32 ++++++++++++------- .../Pages/WindowCustomizationsPage.xaml | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index e92339416b..661975d0b5 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -61,20 +61,28 @@ - + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml index 44973f5b79..2f9c2d3938 100644 --- a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml @@ -4,7 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="ControlCatalog.Pages.WindowCustomizationsPage"> - + From ae40af4d99a3e29551fe7aee6a85cdbc4da5ae4d Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 17:57:21 -0300 Subject: [PATCH 29/98] fix layout. --- samples/ControlCatalog/MainWindow.xaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 661975d0b5..a6750f6444 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -66,8 +66,9 @@ - - + + + @@ -78,11 +79,12 @@ - + + - + From d32c9b25394fc8611d3172b14955d82eb421039e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 May 2020 17:58:45 -0300 Subject: [PATCH 30/98] only show titlebar content when in dwm mode. --- samples/ControlCatalog/MainWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index a6750f6444..b110451421 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -80,7 +80,7 @@ - + From e93554d0da4544784fb7fac35e12abb50853d66a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 22 May 2020 14:38:59 -0300 Subject: [PATCH 31/98] Add managed CaptionButtonsControl. --- .../Chrome/CaptionButtons.cs | 89 +++++++++++++++++++ .../Primitives/ChromeOverlayLayer.cs | 37 ++++++++ .../Primitives/VisualLayerManager.cs | 15 +++- .../Properties/AssemblyInfo.cs | 1 + .../CaptionButtons.xaml | 70 +++++++++++++++ src/Avalonia.Themes.Default/DefaultTheme.xaml | 1 + 6 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/Avalonia.Controls/Chrome/CaptionButtons.cs create mode 100644 src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs create mode 100644 src/Avalonia.Themes.Default/CaptionButtons.xaml diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs new file mode 100644 index 0000000000..20a42aadf6 --- /dev/null +++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Reactive.Disposables; +using System.Text; +using Avalonia.Controls.Primitives; +using Avalonia.VisualTree; + +namespace Avalonia.Controls.Chrome +{ + public class CaptionButtons : TemplatedControl + { + private CompositeDisposable _disposables; + private Window _hostWindow; + + public CaptionButtons(Window hostWindow) + { + _hostWindow = hostWindow; + } + + public void Attach() + { + if (_disposables == null) + { + var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + + layer.Children.Add(this); + + _disposables = new CompositeDisposable + { + _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) + .Subscribe(x => + { + Height = x.Top; + }), + + + _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) + .Subscribe(x => InvalidateSize()), + + _hostWindow.GetObservable(Window.OffScreenMarginProperty) + .Subscribe(x => InvalidateSize()), + + _hostWindow.GetObservable(Window.WindowStateProperty) + .Subscribe(x => + { + PseudoClasses.Set(":minimized", x == WindowState.Minimized); + PseudoClasses.Set(":normal", x == WindowState.Normal); + PseudoClasses.Set(":maximized", x == WindowState.Maximized); + PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); + }) + }; + } + } + + void InvalidateSize () + { + Margin = new Thickness(1, _hostWindow.OffScreenMargin.Top, 1, 1); + Height = _hostWindow.WindowDecorationMargins.Top - _hostWindow.OffScreenMargin.Top; + } + + public void Detach() + { + if (_disposables != null) + { + var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + + layer.Children.Remove(this); + + _disposables.Dispose(); + _disposables = null; + } + } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + var closeButton = e.NameScope.Find("PART_CloseButton"); + var restoreButton = e.NameScope.Find("PART_RestoreButton"); + var minimiseButton = e.NameScope.Find("PART_MinimiseButton"); + var fullScreenButton = e.NameScope.Find("PART_FullScreenButton"); + + closeButton.PointerPressed += (sender, e) => _hostWindow.Close(); + restoreButton.PointerPressed += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; + minimiseButton.PointerPressed += (sender, e) => _hostWindow.WindowState = WindowState.Minimized; + fullScreenButton.PointerPressed += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen; + } + } +} diff --git a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs new file mode 100644 index 0000000000..5deb9ac408 --- /dev/null +++ b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs @@ -0,0 +1,37 @@ +using System.Linq; +using Avalonia.Rendering; +using Avalonia.VisualTree; + +namespace Avalonia.Controls.Primitives +{ + public class ChromeOverlayLayer : Canvas, ICustomSimpleHitTest + { + public Size AvailableSize { get; private set; } + + public static ChromeOverlayLayer GetOverlayLayer(IVisual visual) + { + foreach (var v in visual.GetVisualAncestors()) + if (v is VisualLayerManager vlm) + if (vlm.OverlayLayer != null) + return vlm.ChromeOverlayLayer; + + if (visual is TopLevel tl) + { + var layers = tl.GetVisualDescendants().OfType().FirstOrDefault(); + return layers?.ChromeOverlayLayer; + } + + return null; + } + + public bool HitTest(Point point) => Children.HitTestCustom(point); + + protected override Size ArrangeOverride(Size finalSize) + { + // We are saving it here since child controls might need to know the entire size of the overlay + // and Bounds won't be updated in time + AvailableSize = finalSize; + return base.ArrangeOverride(finalSize); + } + } +} diff --git a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs index 86aeb5c62a..3084d7fa72 100644 --- a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs +++ b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs @@ -6,7 +6,9 @@ namespace Avalonia.Controls.Primitives public class VisualLayerManager : Decorator { private const int AdornerZIndex = int.MaxValue - 100; - private const int OverlayZIndex = int.MaxValue - 99; + private const int ChromeZIndex = int.MaxValue - 99; + private const int OverlayZIndex = int.MaxValue - 98; + private ILogicalRoot _logicalRoot; private readonly List _layers = new List(); @@ -24,6 +26,17 @@ namespace Avalonia.Controls.Primitives } } + public ChromeOverlayLayer ChromeOverlayLayer + { + get + { + var rv = FindLayer(); + if (rv == null) + AddLayer(rv = new ChromeOverlayLayer(), ChromeZIndex); + return rv; + } + } + public OverlayLayer OverlayLayer { get diff --git a/src/Avalonia.Controls/Properties/AssemblyInfo.cs b/src/Avalonia.Controls/Properties/AssemblyInfo.cs index 060db46212..672fbe294e 100644 --- a/src/Avalonia.Controls/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Controls/Properties/AssemblyInfo.cs @@ -13,3 +13,4 @@ using Avalonia.Metadata; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Shapes")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Templates")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Notifications")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Chrome")] diff --git a/src/Avalonia.Themes.Default/CaptionButtons.xaml b/src/Avalonia.Themes.Default/CaptionButtons.xaml new file mode 100644 index 0000000000..0cc0d6b9cd --- /dev/null +++ b/src/Avalonia.Themes.Default/CaptionButtons.xaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml index 94d26e798b..97cff5d94b 100644 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml @@ -9,6 +9,7 @@ + From 6e1ccb6333bfaa04556c7486fbca0d458671be58 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 22 May 2020 14:39:16 -0300 Subject: [PATCH 32/98] Add acrylic blur option to control catalog. --- samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml index 2f9c2d3938..f2513da8ec 100644 --- a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml @@ -13,6 +13,7 @@ None Transparent Blur + AcrylicBlur From 1e798be7848f9120e69db73a36b9247fe3b2e4c0 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 22 May 2020 15:04:01 -0300 Subject: [PATCH 33/98] insert managed chrome when extend client area is enabled and hint flag is set. --- .../Pages/WindowCustomizationsPage.xaml | 1 + .../ViewModels/MainWindowViewModel.cs | 16 ++++++++- src/Avalonia.Controls/Window.cs | 34 +++++++++++++++++-- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml index f2513da8ec..cea8e4b94e 100644 --- a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml @@ -8,6 +8,7 @@ + None diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index 80231a4c15..b3ea25e470 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -65,7 +65,7 @@ namespace ControlCatalog.ViewModels WindowState.FullScreen, }; - this.WhenAnyValue(x => x.SystemChromeButtonsEnabled, x => x.SystemTitleBarEnabled) + this.WhenAnyValue(x => x.SystemChromeButtonsEnabled, x=>x.ManagedChromeButtonsEnabled, x => x.SystemTitleBarEnabled) .Subscribe(x => { ChromeHints = ExtendClientAreaChromeHints.NoChrome; @@ -76,6 +76,11 @@ namespace ControlCatalog.ViewModels } if(x.Item2) + { + ChromeHints |= ExtendClientAreaChromeHints.ManagedChromeButtons; + } + + if(x.Item3) { ChromeHints |= ExtendClientAreaChromeHints.SystemTitleBar; } @@ -127,6 +132,15 @@ namespace ControlCatalog.ViewModels set { this.RaiseAndSetIfChanged(ref _systemChromeButtonsEnabled, value); } } + private bool _managedChromeButtonsEnabled; + + public bool ManagedChromeButtonsEnabled + { + get { return _managedChromeButtonsEnabled; } + set { this.RaiseAndSetIfChanged(ref _managedChromeButtonsEnabled, value); } + } + + private double _titleBarHeight; public double TitleBarHeight diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 12b61fce23..8d66e03f98 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using System.Linq; using System.Reactive.Linq; using System.Threading.Tasks; +using Avalonia.Controls.Chrome; using Avalonia.Controls.Platform; using Avalonia.Data; using Avalonia.Input; @@ -69,7 +70,8 @@ namespace Avalonia.Controls /// public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot { - private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>(); + private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>(); + private CaptionButtons _managedCaptions; private bool _isExtendedIntoWindowDecorations; @@ -203,7 +205,15 @@ namespace Avalonia.Controls (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaToDecorationsHint((bool)e.NewValue); }); ExtendClientAreaChromeHintsProperty.Changed.AddClassHandler( - (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaChromeHints((ExtendClientAreaChromeHints)e.NewValue); }); + (w, e) => + { + if (w.PlatformImpl != null) + { + w.PlatformImpl.SetExtendClientAreaChromeHints((ExtendClientAreaChromeHints)e.NewValue); + } + + w.HandleChromeHintsChanged((ExtendClientAreaChromeHints)e.NewValue); + }); ExtendClientAreaTitleBarHeightHintProperty.Changed.AddClassHandler( (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaTitleBarHeightHint((double)e.NewValue); }); @@ -897,6 +907,26 @@ namespace Avalonia.Controls base.HandleResized(clientSize); } + private void HandleChromeHintsChanged (ExtendClientAreaChromeHints hints) + { + if(hints.HasFlag(ExtendClientAreaChromeHints.ManagedChromeButtons)) + { + if(_managedCaptions == null) + { + _managedCaptions = new CaptionButtons(this); + } + + _managedCaptions.Attach(); + } + else + { + if(_managedCaptions != null) + { + _managedCaptions.Detach(); + } + } + } + /// /// Raises the event. /// From fbe25123cea123da785f6047bbbdefd637b6ce0e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 22 May 2020 16:14:41 -0300 Subject: [PATCH 34/98] When system captions are disabled on win32 and window is maximized border will not be hidden offscreen. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index d09e3196da..4c694b8b55 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -701,7 +701,11 @@ namespace Avalonia.Win32 _extendedMargins = new Thickness(0, borderCaptionThickness.top / Scaling, 0, 0); - if (WindowState == WindowState.Maximized) + if (WindowState == WindowState.Maximized && !_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemChromeButtons)) + { + _offScreenMargin = new Thickness(); + } + else if (WindowState == WindowState.Maximized) { _offScreenMargin = new Thickness(borderThickness.left / Scaling, borderThickness.top / Scaling, borderThickness.right / Scaling, borderThickness.bottom / Scaling); } From 4152b2e365da44e03955346ec98988a67661930e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 22 May 2020 17:18:34 -0300 Subject: [PATCH 35/98] Decorations Margin shouldnt include the border margin other wise users have to do subtractions. --- src/Avalonia.Controls/Chrome/CaptionButtons.cs | 2 +- src/Avalonia.Controls/Window.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs index 20a42aadf6..556c759825 100644 --- a/src/Avalonia.Controls/Chrome/CaptionButtons.cs +++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs @@ -55,7 +55,7 @@ namespace Avalonia.Controls.Chrome void InvalidateSize () { Margin = new Thickness(1, _hostWindow.OffScreenMargin.Top, 1, 1); - Height = _hostWindow.WindowDecorationMargins.Top - _hostWindow.OffScreenMargin.Top; + Height = _hostWindow.WindowDecorationMargins.Top; } public void Detach() diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 8d66e03f98..d63b1350bc 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -540,7 +540,11 @@ namespace Avalonia.Controls { IsExtendedIntoWindowDecorations = isExtended; - WindowDecorationMargins = PlatformImpl.ExtendedMargins; + WindowDecorationMargins = new Thickness( + PlatformImpl.ExtendedMargins.Left, + PlatformImpl.ExtendedMargins.Top - PlatformImpl.OffScreenMargin.Top, + PlatformImpl.ExtendedMargins.Right, + PlatformImpl.ExtendedMargins.Bottom); OffScreenMargin = PlatformImpl.OffScreenMargin; } From 9e812454159520abd19d819165a422934b0ee6d1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 22 May 2020 17:27:33 -0300 Subject: [PATCH 36/98] extend api only allows to turn titlebar on or off to maintain window integrity, and decoration margins dont include border margins. --- .../Platform/ExtendClientAreaChromeHints.cs | 7 ++- src/Avalonia.Controls/Window.cs | 6 +-- .../CaptionButtons.xaml | 2 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 43 ++----------------- 4 files changed, 9 insertions(+), 49 deletions(-) diff --git a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs index e98124b2d8..075e4ba436 100644 --- a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs +++ b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs @@ -6,11 +6,10 @@ namespace Avalonia.Platform public enum ExtendClientAreaChromeHints { NoChrome, - Default = SystemTitleBar | SystemChromeButtons, + Default = SystemTitleBar, SystemTitleBar = 0x01, - SystemChromeButtons = 0x02, - ManagedChromeButtons = 0x04, - PreferSystemChromeButtons = 0x08, + ManagedChromeButtons = 0x02, + PreferSystemChromeButtons = 0x04, AdaptiveChromeWithTitleBar = SystemTitleBar | PreferSystemChromeButtons, AdaptiveChromeWithoutTitleBar = PreferSystemChromeButtons, } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index d63b1350bc..8d66e03f98 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -540,11 +540,7 @@ namespace Avalonia.Controls { IsExtendedIntoWindowDecorations = isExtended; - WindowDecorationMargins = new Thickness( - PlatformImpl.ExtendedMargins.Left, - PlatformImpl.ExtendedMargins.Top - PlatformImpl.OffScreenMargin.Top, - PlatformImpl.ExtendedMargins.Right, - PlatformImpl.ExtendedMargins.Bottom); + WindowDecorationMargins = PlatformImpl.ExtendedMargins; OffScreenMargin = PlatformImpl.OffScreenMargin; } diff --git a/src/Avalonia.Themes.Default/CaptionButtons.xaml b/src/Avalonia.Themes.Default/CaptionButtons.xaml index 0cc0d6b9cd..8ee8a3b0dd 100644 --- a/src/Avalonia.Themes.Default/CaptionButtons.xaml +++ b/src/Avalonia.Themes.Default/CaptionButtons.xaml @@ -5,7 +5,7 @@ - + - @@ -27,13 +24,13 @@ - + - + @@ -42,13 +39,13 @@ - + - + diff --git a/src/Avalonia.Themes.Default/TitleBar.xaml b/src/Avalonia.Themes.Default/TitleBar.xaml new file mode 100644 index 0000000000..856b90857c --- /dev/null +++ b/src/Avalonia.Themes.Default/TitleBar.xaml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/src/Avalonia.Themes.Fluent/CaptionButtons.xaml b/src/Avalonia.Themes.Fluent/CaptionButtons.xaml new file mode 100644 index 0000000000..20efcafcfd --- /dev/null +++ b/src/Avalonia.Themes.Fluent/CaptionButtons.xaml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Styles> diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.xaml b/src/Avalonia.Themes.Fluent/FluentTheme.xaml index 49b2d9561b..a1f8d97c97 100644 --- a/src/Avalonia.Themes.Fluent/FluentTheme.xaml +++ b/src/Avalonia.Themes.Fluent/FluentTheme.xaml @@ -7,7 +7,8 @@ - + + @@ -36,6 +37,7 @@ + diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml new file mode 100644 index 0000000000..6512ee342c --- /dev/null +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index fee6bb90bf..d4d7528ef4 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -90,6 +90,10 @@ namespace Avalonia.Win32 case WindowsMessage.WM_NCHITTEST: if (lRet == IntPtr.Zero) { + if(WindowState == WindowState.FullScreen) + { + return (IntPtr)HitTestValues.HTCLIENT; + } var hittestResult = HitTestNCA(hWnd, wParam, lParam); lRet = (IntPtr)hittestResult; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 9139a8ccbd..bed6922076 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -181,6 +181,11 @@ namespace Avalonia.Win32 { get { + if(_isFullScreenActive) + { + return WindowState.FullScreen; + } + var placement = default(WINDOWPLACEMENT); GetWindowPlacement(_hwnd, ref placement); From a2cf709164e87c40793fe8daf0ad4d2bc469a75e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 8 Jun 2020 15:04:21 -0300 Subject: [PATCH 59/98] fix xaml error. --- src/Avalonia.Themes.Fluent/CaptionButtons.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Fluent/CaptionButtons.xaml b/src/Avalonia.Themes.Fluent/CaptionButtons.xaml index 20efcafcfd..e5177bbdad 100644 --- a/src/Avalonia.Themes.Fluent/CaptionButtons.xaml +++ b/src/Avalonia.Themes.Fluent/CaptionButtons.xaml @@ -64,4 +64,4 @@ - Styles> + From b0b7a65531d51bc30e4a272a3d47dfc369a260a1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 8 Jun 2020 15:08:48 -0300 Subject: [PATCH 60/98] hide certain caption buttons in fullscreen mode. --- src/Avalonia.Themes.Fluent/CaptionButtons.xaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Avalonia.Themes.Fluent/CaptionButtons.xaml b/src/Avalonia.Themes.Fluent/CaptionButtons.xaml index e5177bbdad..7ed27a1747 100644 --- a/src/Avalonia.Themes.Fluent/CaptionButtons.xaml +++ b/src/Avalonia.Themes.Fluent/CaptionButtons.xaml @@ -64,4 +64,7 @@ + From 6e47b625cfe3fa61f170b494909232ff5580a10c Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 8 Jun 2020 15:49:36 -0300 Subject: [PATCH 61/98] fix animations --- .../ControlCatalog/ViewModels/MainWindowViewModel.cs | 10 ++++++---- src/Avalonia.Controls/Chrome/TitleBar.cs | 3 +++ src/Avalonia.Themes.Fluent/TitleBar.xaml | 7 ++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index 939f44d772..27ea1ffb15 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -68,22 +68,24 @@ namespace ControlCatalog.ViewModels this.WhenAnyValue(x => x.SystemChromeButtonsEnabled, x=>x.ManagedChromeButtonsEnabled, x => x.SystemTitleBarEnabled) .Subscribe(x => { - ChromeHints = ExtendClientAreaChromeHints.NoChrome | ExtendClientAreaChromeHints.OSXThickTitleBar; + var hints = ExtendClientAreaChromeHints.NoChrome | ExtendClientAreaChromeHints.OSXThickTitleBar; if(x.Item1) { - ChromeHints |= ExtendClientAreaChromeHints.SystemChromeButtons; + hints |= ExtendClientAreaChromeHints.SystemChromeButtons; } if(x.Item2) { - ChromeHints |= ExtendClientAreaChromeHints.ManagedChromeButtons; + hints |= ExtendClientAreaChromeHints.ManagedChromeButtons; } if(x.Item3) { - ChromeHints |= ExtendClientAreaChromeHints.SystemTitleBar; + hints |= ExtendClientAreaChromeHints.SystemTitleBar; } + + ChromeHints = hints; }); SystemTitleBarEnabled = true; diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index 23eefb5d1b..d4ac5cd855 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -2,6 +2,7 @@ using System.Reactive.Disposables; using Avalonia.Controls.Primitives; using Avalonia.Input; +using Avalonia.LogicalTree; using Avalonia.Media; namespace Avalonia.Controls.Chrome @@ -63,6 +64,8 @@ namespace Avalonia.Controls.Chrome PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); }) }; + + _captionButtons?.Attach(_hostWindow); } } diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml index 6512ee342c..f7d9f1df10 100644 --- a/src/Avalonia.Themes.Fluent/TitleBar.xaml +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -30,15 +30,13 @@ - - - + - - - - From 765bd84c3e64f623201dd486dc9c51f43d11ab17 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 9 Jun 2020 13:35:58 -0300 Subject: [PATCH 63/98] polish managed titlebar. --- .../Chrome/CaptionButtons.cs | 18 ------- src/Avalonia.Controls/Chrome/TitleBar.cs | 34 +++++-------- src/Avalonia.Themes.Fluent/TitleBar.xaml | 12 +++-- src/Windows/Avalonia.Win32/WindowImpl.cs | 48 +++++++++++-------- 4 files changed, 49 insertions(+), 63 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs index 618c3c4fb2..99db4e550b 100644 --- a/src/Avalonia.Controls/Chrome/CaptionButtons.cs +++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs @@ -20,18 +20,6 @@ namespace Avalonia.Controls.Chrome _disposables = new CompositeDisposable { - _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) - .Subscribe(x => - { - Height = x.Top; - }), - - _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) - .Subscribe(x => InvalidateSize()), - - _hostWindow.GetObservable(Window.OffScreenMarginProperty) - .Subscribe(x => InvalidateSize()), - _hostWindow.GetObservable(Window.WindowStateProperty) .Subscribe(x => { @@ -44,12 +32,6 @@ namespace Avalonia.Controls.Chrome } } - void InvalidateSize () - { - Margin = new Thickness(1, _hostWindow.OffScreenMargin.Top, 1, 1); - Height = _hostWindow.WindowDecorationMargins.Top; - } - public void Detach() { if (_disposables != null) diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index d4ac5cd855..b0ae25892e 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -18,21 +18,6 @@ namespace Avalonia.Controls.Chrome _hostWindow = hostWindow; } - public TitleBar() - { - - } - - protected override Size MeasureOverride(Size availableSize) - { - return base.MeasureOverride(availableSize); - } - - protected override Size ArrangeOverride(Size finalSize) - { - return base.ArrangeOverride(finalSize); - } - public void Attach() { if (_disposables == null) @@ -44,10 +29,7 @@ namespace Avalonia.Controls.Chrome _disposables = new CompositeDisposable { _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) - .Subscribe(x => - { - Height = x.Top; - }), + .Subscribe(x => InvalidateSize()), _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) .Subscribe(x => InvalidateSize()), @@ -71,8 +53,16 @@ namespace Avalonia.Controls.Chrome void InvalidateSize() { - Margin = new Thickness(1, _hostWindow.OffScreenMargin.Top, 1, 1); - Height = _hostWindow.WindowDecorationMargins.Top; + Margin = new Thickness( + _hostWindow.OffScreenMargin.Left, + _hostWindow.OffScreenMargin.Top, + _hostWindow.OffScreenMargin.Right, + _hostWindow.OffScreenMargin.Bottom); + + if (_hostWindow.WindowState != WindowState.FullScreen) + { + Height = _hostWindow.WindowDecorationMargins.Top; + } } public void Detach() @@ -94,7 +84,7 @@ namespace Avalonia.Controls.Chrome { base.OnApplyTemplate(e); - _captionButtons = e.NameScope.Find("PART_CaptionButtons"); + _captionButtons = e.NameScope.Find("PART_CaptionButtons"); _captionButtons.Attach(_hostWindow); } diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml index 5083f4c15a..db4dbe95a2 100644 --- a/src/Avalonia.Themes.Fluent/TitleBar.xaml +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -5,23 +5,27 @@ + + diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index bed6922076..5ffcc2034c 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -671,6 +671,8 @@ namespace Avalonia.Win32 } TaskBarList.MarkFullscreen(_hwnd, fullscreen); + + ExtendClientArea(); } private MARGINS UpdateExtendMargins() @@ -724,33 +726,41 @@ namespace Avalonia.Win32 { _isClientAreaExtended = false; return; - } - - GetWindowRect(_hwnd, out var rcClient); + } - // Inform the application of the frame change. - SetWindowPos(_hwnd, - IntPtr.Zero, - rcClient.left, rcClient.top, - rcClient.Width, rcClient.Height, - SetWindowPosFlags.SWP_FRAMECHANGED); - - if(_isClientAreaExtended) + if (!_isClientAreaExtended || WindowState == WindowState.FullScreen) { - var margins = UpdateExtendMargins(); - - DwmExtendFrameIntoClientArea(_hwnd, ref margins); + _extendedMargins = new Thickness(0, 0, 0, 0); + _offScreenMargin = new Thickness(); } else { - var margins = new MARGINS(); - DwmExtendFrameIntoClientArea(_hwnd, ref margins); + GetWindowRect(_hwnd, out var rcClient); - _offScreenMargin = new Thickness(); - _extendedMargins = new Thickness(); + // Inform the application of the frame change. + SetWindowPos(_hwnd, + IntPtr.Zero, + rcClient.left, rcClient.top, + rcClient.Width, rcClient.Height, + SetWindowPosFlags.SWP_FRAMECHANGED); + + if (_isClientAreaExtended) + { + var margins = UpdateExtendMargins(); + + DwmExtendFrameIntoClientArea(_hwnd, ref margins); + } + else + { + var margins = new MARGINS(); + DwmExtendFrameIntoClientArea(_hwnd, ref margins); + + _offScreenMargin = new Thickness(); + _extendedMargins = new Thickness(); + } } - ExtendClientAreaToDecorationsChanged?.Invoke(true); + ExtendClientAreaToDecorationsChanged?.Invoke(_isClientAreaExtended); } private void ShowWindow(WindowState state) From df7f6a4fdb6da342dd2106e93c669f4bca5f66fe Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 10 Jun 2020 20:57:56 -0300 Subject: [PATCH 64/98] fix titlebar sizing. --- src/Avalonia.Controls/Chrome/TitleBar.cs | 5 +++++ src/Avalonia.Themes.Fluent/TitleBar.xaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index b0ae25892e..aeac9b76d4 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -62,6 +62,11 @@ namespace Avalonia.Controls.Chrome if (_hostWindow.WindowState != WindowState.FullScreen) { Height = _hostWindow.WindowDecorationMargins.Top; + + if (_captionButtons != null) + { + _captionButtons.Height = Height; + } } } diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml index db4dbe95a2..3c194e5d44 100644 --- a/src/Avalonia.Themes.Fluent/TitleBar.xaml +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -15,7 +15,7 @@ - + From 3ba935c2071d1a28c0efb129af9367396822094f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 14 Jun 2020 13:50:57 -0300 Subject: [PATCH 65/98] fix managed titlebar sizing. --- src/Avalonia.Controls/Chrome/TitleBar.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index aeac9b76d4..5b938c6830 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -48,6 +48,8 @@ namespace Avalonia.Controls.Chrome }; _captionButtons?.Attach(_hostWindow); + + InvalidateSize(); } } From e1de29cf540f14c0e162aad5cc30925b4ca1614a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 14 Jun 2020 15:31:44 -0300 Subject: [PATCH 66/98] fix titlebar and caption buttons --- src/Avalonia.Controls/Chrome/TitleBar.cs | 10 ++++++--- .../CaptionButtons.xaml | 21 ++++++++++++------- src/Avalonia.Themes.Fluent/TitleBar.xaml | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index 5b938c6830..8e8010d3d4 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -1,9 +1,6 @@ using System; using System.Reactive.Disposables; using Avalonia.Controls.Primitives; -using Avalonia.Input; -using Avalonia.LogicalTree; -using Avalonia.Media; namespace Avalonia.Controls.Chrome { @@ -18,6 +15,11 @@ namespace Avalonia.Controls.Chrome _hostWindow = hostWindow; } + public TitleBar() + { + + } + public void Attach() { if (_disposables == null) @@ -94,6 +96,8 @@ namespace Avalonia.Controls.Chrome _captionButtons = e.NameScope.Find("PART_CaptionButtons"); _captionButtons.Attach(_hostWindow); + + InvalidateSize(); } } } diff --git a/src/Avalonia.Themes.Default/CaptionButtons.xaml b/src/Avalonia.Themes.Default/CaptionButtons.xaml index 8d6d6fb6fc..c47ab05fd6 100644 --- a/src/Avalonia.Themes.Default/CaptionButtons.xaml +++ b/src/Avalonia.Themes.Default/CaptionButtons.xaml @@ -1,6 +1,11 @@ - - - + - + - + @@ -43,7 +48,7 @@ - + diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml index 3c194e5d44..45798d3fa1 100644 --- a/src/Avalonia.Themes.Fluent/TitleBar.xaml +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -5,7 +5,7 @@ - - + - + - + - + - + @@ -69,4 +64,7 @@ - + + diff --git a/src/Avalonia.Themes.Default/TitleBar.xaml b/src/Avalonia.Themes.Default/TitleBar.xaml index 856b90857c..45798d3fa1 100644 --- a/src/Avalonia.Themes.Default/TitleBar.xaml +++ b/src/Avalonia.Themes.Default/TitleBar.xaml @@ -5,15 +5,49 @@ + + + + + + + + + + + + From 50ec4da4cd3b08a53f60b2ec5c5c8e4e008d5b15 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 16 Jun 2020 15:01:53 -0300 Subject: [PATCH 69/98] dont keep capture when minimising. --- src/Avalonia.Controls/Chrome/CaptionButtons.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs index 99db4e550b..58f5b09c0d 100644 --- a/src/Avalonia.Controls/Chrome/CaptionButtons.cs +++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs @@ -54,10 +54,10 @@ namespace Avalonia.Controls.Chrome var minimiseButton = e.NameScope.Find("PART_MinimiseButton"); var fullScreenButton = e.NameScope.Find("PART_FullScreenButton"); - closeButton.PointerPressed += (sender, e) => _hostWindow.Close(); - restoreButton.PointerPressed += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; - minimiseButton.PointerPressed += (sender, e) => _hostWindow.WindowState = WindowState.Minimized; - fullScreenButton.PointerPressed += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen; + closeButton.PointerReleased += (sender, e) => _hostWindow.Close(); + restoreButton.PointerReleased += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; + minimiseButton.PointerReleased += (sender, e) => _hostWindow.WindowState = WindowState.Minimized; + fullScreenButton.PointerReleased += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen; } } } From 28fdb43ae0fc0710122637f7fb20f23fd74aa9b3 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Jun 2020 17:25:30 -0300 Subject: [PATCH 70/98] windowimpl tells window then managed chrome is required. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 2 ++ src/Avalonia.Controls/Window.cs | 36 ++++++++----------- src/Windows/Avalonia.Win32/WindowImpl.cs | 4 ++- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 15315063fe..55fe8c328b 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -104,6 +104,8 @@ namespace Avalonia.Platform void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight); Action ExtendClientAreaToDecorationsChanged { get; set; } + + bool NeedsManagedDecorations { get; } Thickness ExtendedMargins { get; } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 3bbe0ce4e1..d1ad33e9e8 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -211,8 +211,6 @@ namespace Avalonia.Controls { w.PlatformImpl.SetExtendClientAreaChromeHints((ExtendClientAreaChromeHints)e.NewValue); } - - w.HandleChromeHintsChanged((ExtendClientAreaChromeHints)e.NewValue); }); ExtendClientAreaTitleBarHeightHintProperty.Changed.AddClassHandler( @@ -543,6 +541,20 @@ namespace Avalonia.Controls WindowDecorationMargins = PlatformImpl.ExtendedMargins; OffScreenMargin = PlatformImpl.OffScreenMargin; + + if(PlatformImpl.NeedsManagedDecorations) + { + if (_managedTitleBar == null) + { + _managedTitleBar = new TitleBar(this); + _managedTitleBar.Attach(); + } + } + else + { + _managedTitleBar?.Detach(); + _managedTitleBar = null; + } } /// @@ -907,26 +919,6 @@ namespace Avalonia.Controls base.HandleResized(clientSize); } - private void HandleChromeHintsChanged (ExtendClientAreaChromeHints hints) - { - if(hints.HasFlag(ExtendClientAreaChromeHints.ManagedChromeButtons)) - { - if(_managedTitleBar == null) - { - _managedTitleBar = new TitleBar(this); - } - - _managedTitleBar.Attach(); - } - else - { - if(_managedTitleBar != null) - { - _managedTitleBar.Detach(); - } - } - } - /// /// Raises the event. /// diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index b3c8387950..250b0cf029 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -1057,7 +1057,9 @@ namespace Avalonia.Win32 public bool IsClientAreaExtendedToDecorations => _isClientAreaExtended; - public Action ExtendClientAreaToDecorationsChanged { get; set; } + public Action ExtendClientAreaToDecorationsChanged { get; set; } + + public bool NeedsManagedDecorations => _isClientAreaExtended && _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChromeButtons); public Thickness ExtendedMargins => _extendedMargins; From 42cb926e92269d15c8b49260a3af36bd0571f502 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Jun 2020 17:38:40 -0300 Subject: [PATCH 71/98] indicate if managed decorations are needed via platform. --- src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs | 2 ++ src/Avalonia.DesignerSupport/Remote/Stubs.cs | 2 ++ src/Avalonia.Native/WindowImpl.cs | 2 ++ src/Avalonia.X11/X11Window.cs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index c03ccf902a..dce24df9d9 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -88,6 +88,8 @@ namespace Avalonia.DesignerSupport.Remote public Thickness OffScreenMargin { get; } = new Thickness(); + public bool NeedsManagedDecorations => false; + public void Activate() { } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index cb0a9cd524..84c52d6fbf 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -172,6 +172,8 @@ namespace Avalonia.DesignerSupport.Remote public WindowTransparencyLevel TransparencyLevel { get; private set; } public bool IsClientAreaExtendedToDecorations { get; } + + public bool NeedsManagedDecorations => false; } class ClipboardStub : IClipboard diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 898cf2dea8..ce312b30d2 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -181,6 +181,8 @@ namespace Avalonia.Native ExtendClientAreaToDecorationsChanged?.Invoke(_isExtended); } + public bool NeedsManagedDecorations => false; + public void ShowTaskbarIcon(bool value) { // NO OP On OSX diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 24392f61d6..56ac7c833e 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -1127,5 +1127,7 @@ namespace Avalonia.X11 } public WindowTransparencyLevel TransparencyLevel => _transparencyHelper.CurrentLevel; + + public bool NeedsManagedDecorations => false; } } From 2cc40e3c6ab6958116d66d97f6bf8a3aab3c4a87 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Jun 2020 17:39:00 -0300 Subject: [PATCH 72/98] add a prefer managed chrome to demo page --- .../Pages/WindowCustomizationsPage.xaml | 1 + .../ViewModels/MainWindowViewModel.cs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml index cea8e4b94e..e3fdbeaa69 100644 --- a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml @@ -9,6 +9,7 @@ + None diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index 27ea1ffb15..2dab49cf0a 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -65,7 +65,7 @@ namespace ControlCatalog.ViewModels WindowState.FullScreen, }; - this.WhenAnyValue(x => x.SystemChromeButtonsEnabled, x=>x.ManagedChromeButtonsEnabled, x => x.SystemTitleBarEnabled) + this.WhenAnyValue(x => x.SystemChromeButtonsEnabled, x=>x.ManagedChromeButtonsEnabled, x => x.SystemTitleBarEnabled, x=>x.PreferSystemChromeButtonsEnabled) .Subscribe(x => { var hints = ExtendClientAreaChromeHints.NoChrome | ExtendClientAreaChromeHints.OSXThickTitleBar; @@ -85,6 +85,11 @@ namespace ControlCatalog.ViewModels hints |= ExtendClientAreaChromeHints.SystemTitleBar; } + if(x.Item4) + { + hints |= ExtendClientAreaChromeHints.PreferSystemChromeButtons; + } + ChromeHints = hints; }); @@ -142,6 +147,13 @@ namespace ControlCatalog.ViewModels set { this.RaiseAndSetIfChanged(ref _managedChromeButtonsEnabled, value); } } + private bool _preferSystemChromeButtonsEnabled; + + public bool PreferSystemChromeButtonsEnabled + { + get { return _preferSystemChromeButtonsEnabled; } + set { this.RaiseAndSetIfChanged(ref _preferSystemChromeButtonsEnabled, value); } + } private double _titleBarHeight; From 122821317f14cc968b78c61b342f36cf762b0c9e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Jun 2020 17:44:34 -0300 Subject: [PATCH 73/98] remove unused hint flags. --- .../Pages/WindowCustomizationsPage.xaml | 6 +- .../ViewModels/MainWindowViewModel.cs | 71 +++++-------------- .../Platform/ExtendClientAreaChromeHints.cs | 11 +-- 3 files changed, 22 insertions(+), 66 deletions(-) diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml index e3fdbeaa69..db2a8a465a 100644 --- a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml @@ -6,10 +6,8 @@ x:Class="ControlCatalog.Pages.WindowCustomizationsPage"> - - - - + + None diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index 2dab49cf0a..e8dd12269b 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -16,6 +16,12 @@ namespace ControlCatalog.ViewModels private bool _isMenuItemChecked = true; private WindowState _windowState; private WindowState[] _windowStates; + private int _transparencyLevel; + private ExtendClientAreaChromeHints _chromeHints; + private bool _extendClientAreaEnabled; + private bool _systemTitleBarEnabled; + private bool _preferSystemChromeEnabled; + private double _titleBarHeight; public MainWindowViewModel(IManagedNotificationManager notificationManager) { @@ -65,27 +71,17 @@ namespace ControlCatalog.ViewModels WindowState.FullScreen, }; - this.WhenAnyValue(x => x.SystemChromeButtonsEnabled, x=>x.ManagedChromeButtonsEnabled, x => x.SystemTitleBarEnabled, x=>x.PreferSystemChromeButtonsEnabled) + this.WhenAnyValue(x => x.SystemTitleBarEnabled, x=>x.PreferSystemChromeEnabled) .Subscribe(x => { var hints = ExtendClientAreaChromeHints.NoChrome | ExtendClientAreaChromeHints.OSXThickTitleBar; if(x.Item1) - { - hints |= ExtendClientAreaChromeHints.SystemChromeButtons; - } - - if(x.Item2) - { - hints |= ExtendClientAreaChromeHints.ManagedChromeButtons; - } - - if(x.Item3) { hints |= ExtendClientAreaChromeHints.SystemTitleBar; } - if(x.Item4) + if(x.Item2) { hints |= ExtendClientAreaChromeHints.PreferSystemChromeButtons; } @@ -93,69 +89,39 @@ namespace ControlCatalog.ViewModels ChromeHints = hints; }); - SystemTitleBarEnabled = true; - SystemChromeButtonsEnabled = true; + SystemTitleBarEnabled = true; TitleBarHeight = -1; - } - - private int _transparencyLevel; + } public int TransparencyLevel { get { return _transparencyLevel; } set { this.RaiseAndSetIfChanged(ref _transparencyLevel, value); } - } - - private ExtendClientAreaChromeHints _chromeHints; + } public ExtendClientAreaChromeHints ChromeHints { get { return _chromeHints; } set { this.RaiseAndSetIfChanged(ref _chromeHints, value); } - } - - - private bool _extendClientAreaEnabled; + } public bool ExtendClientAreaEnabled { get { return _extendClientAreaEnabled; } set { this.RaiseAndSetIfChanged(ref _extendClientAreaEnabled, value); } - } - - private bool _systemTitleBarEnabled; + } public bool SystemTitleBarEnabled { get { return _systemTitleBarEnabled; } set { this.RaiseAndSetIfChanged(ref _systemTitleBarEnabled, value); } - } - - private bool _systemChromeButtonsEnabled; + } - public bool SystemChromeButtonsEnabled + public bool PreferSystemChromeEnabled { - get { return _systemChromeButtonsEnabled; } - set { this.RaiseAndSetIfChanged(ref _systemChromeButtonsEnabled, value); } - } - - private bool _managedChromeButtonsEnabled; - - public bool ManagedChromeButtonsEnabled - { - get { return _managedChromeButtonsEnabled; } - set { this.RaiseAndSetIfChanged(ref _managedChromeButtonsEnabled, value); } - } - - private bool _preferSystemChromeButtonsEnabled; - - public bool PreferSystemChromeButtonsEnabled - { - get { return _preferSystemChromeButtonsEnabled; } - set { this.RaiseAndSetIfChanged(ref _preferSystemChromeButtonsEnabled, value); } - } - - private double _titleBarHeight; + get { return _preferSystemChromeEnabled; } + set { this.RaiseAndSetIfChanged(ref _preferSystemChromeEnabled, value); } + } public double TitleBarHeight { @@ -163,7 +129,6 @@ namespace ControlCatalog.ViewModels set { this.RaiseAndSetIfChanged(ref _titleBarHeight, value); } } - public WindowState WindowState { get { return _windowState; } diff --git a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs index 022b609699..fb6a4056db 100644 --- a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs +++ b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs @@ -8,14 +8,7 @@ namespace Avalonia.Platform NoChrome, Default = SystemTitleBar, SystemTitleBar = 0x01, - ManagedChromeButtons = 0x02, - SystemChromeButtons = 0x04, - - OSXThickTitleBar = 0x08, - - PreferSystemChromeButtons = 0x10, - - AdaptiveChromeWithTitleBar = SystemTitleBar | PreferSystemChromeButtons, - AdaptiveChromeWithoutTitleBar = PreferSystemChromeButtons, + PreferSystemChromeButtons = 0x02, + OSXThickTitleBar = 0x08, } } From ce6beb8851aa0cdb1c1601a69b56a277cfcfe5f6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Jun 2020 17:59:06 -0300 Subject: [PATCH 74/98] add some documentation. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 30 +++++++++++++++++++ src/Avalonia.Native/WindowImpl.cs | 13 ++++---- src/Windows/Avalonia.Win32/WindowImpl.cs | 22 ++++++++------ 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 55fe8c328b..43647dc7d0 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -95,20 +95,50 @@ namespace Avalonia.Platform /// void SetMinMaxSize(Size minSize, Size maxSize); + /// + /// Sets if the ClientArea is extended into the non-client area. + /// + /// true to enable, false to disable void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint); + /// + /// Gets a value to indicate if the platform was able to extend client area to non-client area. + /// bool IsClientAreaExtendedToDecorations { get; } + /// + /// Sets hints that configure how the client area extends. + /// + /// void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints); + /// + /// Sets how big the non-client titlebar area should be. + /// + /// -1 for platform default, otherwise the height in DIPs. void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight); + /// + /// Gets or Sets an action that is called whenever one of the extend client area properties changed. + /// Action ExtendClientAreaToDecorationsChanged { get; set; } + /// + /// Gets a flag that indicates if Managed decorations i.e. caption buttons are required. + /// This property is used when is set. + /// bool NeedsManagedDecorations { get; } + /// + /// Gets a thickness that describes the amount each side of the non-client area extends into the client area. + /// It includes the titlebar. + /// Thickness ExtendedMargins { get; } + /// + /// Gets a thickness that describes the margin around the window that is offscreen. + /// This may happen when a window is maximized and is set. + /// Thickness OffScreenMargin { get; } } } diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index ce312b30d2..ef2bd32bfc 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -137,7 +137,7 @@ namespace Avalonia.Native return false; } - + private void InvalidateExtendedMargins () { if(WindowState == WindowState.FullScreen) @@ -152,6 +152,7 @@ namespace Avalonia.Native ExtendClientAreaToDecorationsChanged?.Invoke(_isExtended); } + /// public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) { _isExtended = extendIntoClientAreaHint; @@ -161,16 +162,13 @@ namespace Avalonia.Native InvalidateExtendedMargins(); } + /// public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) - { - if(hints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChromeButtons)) - { - hints |= ExtendClientAreaChromeHints.SystemChromeButtons; - } - + { _native.SetExtendClientAreaHints ((AvnExtendClientAreaChromeHints)hints); } + /// public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) { _extendTitleBarHeight = titleBarHeight; @@ -181,6 +179,7 @@ namespace Avalonia.Native ExtendClientAreaToDecorationsChanged?.Invoke(_isExtended); } + /// public bool NeedsManagedDecorations => false; public void ShowTaskbarIcon(bool value) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 250b0cf029..6025f96d22 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -45,7 +45,8 @@ namespace Avalonia.Win32 private bool _isClientAreaExtended; private Thickness _extendedMargins; private Thickness _offScreenMargin; - + private double _extendTitleBarHint = -1; + #if USE_MANAGED_DRAG private readonly ManagedWindowResizeDragHelper _managedDrag; #endif @@ -73,8 +74,8 @@ namespace Avalonia.Win32 private Size _minSize; private Size _maxSize; private POINT _maxTrackSize; - private WindowImpl _parent; - private bool _extendClientAreaToDecorationsHint; + private WindowImpl _parent; + private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default; public WindowImpl() { @@ -1036,9 +1037,7 @@ namespace Avalonia.Win32 _isClientAreaExtended = hint; ExtendClientArea(); - } - - private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default; + } public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) { @@ -1046,8 +1045,8 @@ namespace Avalonia.Win32 ExtendClientArea(); } - - private double _extendTitleBarHint = -1; + + /// public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) { _extendTitleBarHint = titleBarHeight; @@ -1055,14 +1054,19 @@ namespace Avalonia.Win32 ExtendClientArea(); } + /// public bool IsClientAreaExtendedToDecorations => _isClientAreaExtended; + /// public Action ExtendClientAreaToDecorationsChanged { get; set; } - + + /// public bool NeedsManagedDecorations => _isClientAreaExtended && _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChromeButtons); + /// public Thickness ExtendedMargins => _extendedMargins; + /// public Thickness OffScreenMargin => _offScreenMargin; private struct SavedWindowInfo From aa4dfc54953855395fb8ed132c5542329c1f1c4f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Jun 2020 18:17:13 -0300 Subject: [PATCH 75/98] rename flags and fix win32 implementation. --- .../ViewModels/MainWindowViewModel.cs | 4 +- .../Platform/ExtendClientAreaChromeHints.cs | 6 +-- src/Windows/Avalonia.Win32/WindowImpl.cs | 50 ++++++++----------- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index e8dd12269b..4356a032fa 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -78,12 +78,12 @@ namespace ControlCatalog.ViewModels if(x.Item1) { - hints |= ExtendClientAreaChromeHints.SystemTitleBar; + hints |= ExtendClientAreaChromeHints.SystemChrome; } if(x.Item2) { - hints |= ExtendClientAreaChromeHints.PreferSystemChromeButtons; + hints |= ExtendClientAreaChromeHints.PreferSystemChrome; } ChromeHints = hints; diff --git a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs index fb6a4056db..deb9e417ab 100644 --- a/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs +++ b/src/Avalonia.Controls/Platform/ExtendClientAreaChromeHints.cs @@ -6,9 +6,9 @@ namespace Avalonia.Platform public enum ExtendClientAreaChromeHints { NoChrome, - Default = SystemTitleBar, - SystemTitleBar = 0x01, - PreferSystemChromeButtons = 0x02, + Default = SystemChrome, + SystemChrome = 0x01, + PreferSystemChrome = 0x02, OSXThickTitleBar = 0x08, } } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 6025f96d22..4b64eabc26 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -694,7 +694,7 @@ namespace Avalonia.Win32 borderCaptionThickness.left *= -1; borderCaptionThickness.top *= -1; - bool wantsTitleBar = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar) || _extendTitleBarHint == -1; + bool wantsTitleBar = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemChrome) || _extendTitleBarHint == -1; if (!wantsTitleBar) { @@ -711,7 +711,7 @@ namespace Avalonia.Win32 borderCaptionThickness.top = (int)(_extendTitleBarHint * Scaling); } - margins.cyTopHeight = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemTitleBar) ? borderCaptionThickness.top : 1; + margins.cyTopHeight = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemChrome) && !_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChrome) ? borderCaptionThickness.top : 1; if (WindowState == WindowState.Maximized) { @@ -727,7 +727,7 @@ namespace Avalonia.Win32 return margins; } - private void ExtendClientArea () + private void ExtendClientArea() { if (DwmIsCompositionEnabled(out bool compositionEnabled) < 0 || !compositionEnabled) { @@ -735,36 +735,28 @@ namespace Avalonia.Win32 return; } - if (!_isClientAreaExtended || WindowState == WindowState.FullScreen) + GetWindowRect(_hwnd, out var rcClient); + + // Inform the application of the frame change. + SetWindowPos(_hwnd, + IntPtr.Zero, + rcClient.left, rcClient.top, + rcClient.Width, rcClient.Height, + SetWindowPosFlags.SWP_FRAMECHANGED); + + if (_isClientAreaExtended && WindowState != WindowState.FullScreen) { - _extendedMargins = new Thickness(0, 0, 0, 0); - _offScreenMargin = new Thickness(); + var margins = UpdateExtendMargins(); + + DwmExtendFrameIntoClientArea(_hwnd, ref margins); } else { - GetWindowRect(_hwnd, out var rcClient); - - // Inform the application of the frame change. - SetWindowPos(_hwnd, - IntPtr.Zero, - rcClient.left, rcClient.top, - rcClient.Width, rcClient.Height, - SetWindowPosFlags.SWP_FRAMECHANGED); - - if (_isClientAreaExtended) - { - var margins = UpdateExtendMargins(); + var margins = new MARGINS(); + DwmExtendFrameIntoClientArea(_hwnd, ref margins); - DwmExtendFrameIntoClientArea(_hwnd, ref margins); - } - else - { - var margins = new MARGINS(); - DwmExtendFrameIntoClientArea(_hwnd, ref margins); - - _offScreenMargin = new Thickness(); - _extendedMargins = new Thickness(); - } + _offScreenMargin = new Thickness(); + _extendedMargins = new Thickness(); } ExtendClientAreaToDecorationsChanged?.Invoke(_isClientAreaExtended); @@ -1061,7 +1053,7 @@ namespace Avalonia.Win32 public Action ExtendClientAreaToDecorationsChanged { get; set; } /// - public bool NeedsManagedDecorations => _isClientAreaExtended && _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChromeButtons); + public bool NeedsManagedDecorations => _isClientAreaExtended && _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChrome); /// public Thickness ExtendedMargins => _extendedMargins; From 466f015836721450bc8337c751f4130f5509ac46 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Jun 2020 18:26:02 -0300 Subject: [PATCH 76/98] fix up osx implementation. --- native/Avalonia.Native/inc/avalonia-native.h | 11 +++++------ native/Avalonia.Native/src/OSX/window.mm | 14 ++++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 8b905ea8d2..97ab4ffefb 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -207,12 +207,11 @@ enum AvnMenuItemToggleType enum AvnExtendClientAreaChromeHints { - AvnChromeHintsNoChrome, - AvnChromeHintsSystemTitleBar = 0x01, - AvnChromeHintsManagedChromeButtons = 0x02, - AvnChromeHintsSystemChromeButtons = 0x04, - AvnChromeHintsOSXThickTitleBar = 0x08, - AvnChromeHintsDefault = AvnChromeHintsSystemTitleBar | AvnChromeHintsSystemChromeButtons, + AvnNoChrome = 0, + AvnSystemChrome = 0x01, + AvnPreferSystemChrome = 0x02, + AvnOSXThickTitleBar = 0x08, + AvnDefaultChrome = AvnSystemChrome, }; AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 265f500bae..551c5afea9 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -488,7 +488,7 @@ private: WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl) { _isClientAreaExtended = false; - _extendClientHints = AvnChromeHintsDefault; + _extendClientHints = AvnDefaultChrome; _fullScreenActive = false; _canResize = true; _decorations = SystemDecorationsFull; @@ -511,7 +511,7 @@ private: { if(_isClientAreaExtended) { - [button setHidden: !(_extendClientHints & AvnChromeHintsSystemChromeButtons)]; + [button setHidden: !((_extendClientHints & AvnSystemChrome)) || (_extendClientHints & AvnPreferSystemChrome)]; } else { @@ -599,7 +599,7 @@ private: if(_lastWindowState == FullScreen) { // we exited fs. - if(_extendClientHints & AvnChromeHintsOSXThickTitleBar) + if(_extendClientHints & AvnOSXThickTitleBar) { Window.toolbar = [NSToolbar new]; Window.toolbar.showsBaselineSeparator = false; @@ -612,7 +612,7 @@ private: else if(state == FullScreen) { // we entered fs. - if(_extendClientHints & AvnChromeHintsOSXThickTitleBar) + if(_extendClientHints & AvnOSXThickTitleBar) { Window.toolbar = nullptr; } @@ -815,7 +815,9 @@ private: [Window setTitlebarAppearsTransparent:true]; - if(_extendClientHints & AvnChromeHintsSystemTitleBar) + auto wantsTitleBar = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); + + if (wantsTitleBar) { [StandardContainer ShowTitleBar:true]; } @@ -824,7 +826,7 @@ private: [StandardContainer ShowTitleBar:false]; } - if(_extendClientHints & AvnChromeHintsOSXThickTitleBar) + if(_extendClientHints & AvnOSXThickTitleBar) { Window.toolbar = [NSToolbar new]; Window.toolbar.showsBaselineSeparator = false; From c8cede080f174514f89357f0bc05db3bf8e328ff Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Jun 2020 18:32:08 -0300 Subject: [PATCH 77/98] fix hiding and showing traffic lights. --- native/Avalonia.Native/src/OSX/window.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 551c5afea9..269d71a25a 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -511,7 +511,9 @@ private: { if(_isClientAreaExtended) { - [button setHidden: !((_extendClientHints & AvnSystemChrome)) || (_extendClientHints & AvnPreferSystemChrome)]; + auto wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); + + [button setHidden: !wantsChrome]; } else { From 8c41ab4db65b35182b0d5d4b3c23e6d85c4dac31 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Sat, 27 Jun 2020 21:28:02 -0700 Subject: [PATCH 78/98] Update Avalonia to renamed XamlX branch. --- .../Avalonia.Build.Tasks.csproj | 6 +- .../XamlCompilerTaskExecutor.Helpers.cs | 2 +- .../XamlCompilerTaskExecutor.cs | 47 +++---- .../Avalonia.Markup.Xaml.csproj | 4 +- .../XamlIl/AvaloniaXamlIlRuntimeCompiler.cs | 36 +++--- .../AvaloniaXamlIlCompiler.cs | 75 +++++------ .../AvaloniaXamlIlLanguage.cs | 78 ++++++------ .../Transformers/AddNameScopeRegistration.cs | 98 ++++++++------- ...AvaloniaBindingExtensionHackTransformer.cs | 10 +- .../AvaloniaXamlIlAvaloniaPropertyResolver.cs | 10 +- ...IlConstructorServiceProviderTransformer.cs | 28 +++-- ...olTemplateTargetTypeMetadataTransformer.cs | 28 ++--- ...aloniaXamlIlDesignPropertiesTransformer.cs | 26 ++-- .../AvaloniaXamlIlMetadataRemover.cs | 8 +- .../AvaloniaXamlIlSelectorTransformer.cs | 118 +++++++++--------- .../AvaloniaXamlIlSetterTransformer.cs | 68 +++++----- ...mlIlTransformInstanceAttachedProperties.cs | 78 ++++++------ ...amlIlTransitionsTypeMetadataTransformer.cs | 12 +- .../AvaloniaXamlIlWellKnownTypes.cs | 96 +++++++------- .../IgnoredDirectivesTransformer.cs | 14 +-- .../Transformers/XNameTransformer.cs | 19 ++- .../XamlIlAvaloniaPropertyHelper.cs | 103 +++++++-------- .../Avalonia.Markup.Xaml/XamlIl/xamlil.github | 2 +- 23 files changed, 510 insertions(+), 456 deletions(-) diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj index 582e4499c5..49e793cfda 100644 --- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj +++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj @@ -21,10 +21,10 @@ XamlIlExtensions/%(RecursiveDir)%(FileName)%(Extension) - + XamlIl/%(RecursiveDir)%(FileName)%(Extension) - + XamlIl.Cecil/%(RecursiveDir)%(FileName)%(Extension) @@ -44,7 +44,7 @@ - + diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs index f94f10f792..5a2c74e16f 100644 --- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs +++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs @@ -5,7 +5,7 @@ using Avalonia.Utilities; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; -using XamlIl.TypeSystem; +using XamlX.TypeSystem; namespace Avalonia.Build.Tasks { diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs index 30e8f120d7..b8e521100d 100644 --- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs +++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs @@ -7,17 +7,18 @@ using System.Text; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; using Microsoft.Build.Framework; using Mono.Cecil; -using XamlIl.TypeSystem; using Avalonia.Utilities; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; -using XamlIl; -using XamlIl.Ast; -using XamlIl.Parsers; -using XamlIl.Transform; +using XamlX; +using XamlX.Ast; +using XamlX.Parsers; +using XamlX.Transform; +using XamlX.TypeSystem; using FieldAttributes = Mono.Cecil.FieldAttributes; using MethodAttributes = Mono.Cecil.MethodAttributes; using TypeAttributes = Mono.Cecil.TypeAttributes; +using XamlX.IL; namespace Avalonia.Build.Tasks { @@ -51,11 +52,11 @@ namespace Avalonia.Build.Tasks // Nothing to do return new CompileResult(true); - var xamlLanguage = AvaloniaXamlIlLanguage.Configure(typeSystem); - var compilerConfig = new XamlIlTransformerConfiguration(typeSystem, + var (xamlLanguage , emitConfig) = AvaloniaXamlIlLanguage.Configure(typeSystem); + var compilerConfig = new TransformerConfiguration(typeSystem, typeSystem.TargetAssembly, xamlLanguage, - XamlIlXmlnsMappings.Resolve(typeSystem, xamlLanguage), + XamlXmlnsMappings.Resolve(typeSystem, xamlLanguage), AvaloniaXamlIlLanguage.CustomValueConverter); @@ -63,10 +64,10 @@ namespace Avalonia.Build.Tasks TypeAttributes.Class, asm.MainModule.TypeSystem.Object); asm.MainModule.Types.Add(contextDef); - var contextClass = XamlIlContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem, - xamlLanguage); + var contextClass = XamlILContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem, + xamlLanguage, emitConfig); - var compiler = new AvaloniaXamlIlCompiler(compilerConfig, contextClass) { EnableIlVerification = verifyIl }; + var compiler = new AvaloniaXamlIlCompiler(compilerConfig, emitConfig, contextClass) { EnableIlVerification = verifyIl }; var editorBrowsableAttribute = typeSystem .GetTypeReference(typeSystem.FindType("System.ComponentModel.EditorBrowsableAttribute")) @@ -126,35 +127,35 @@ namespace Avalonia.Build.Tasks // StreamReader is needed here to handle BOM var xaml = new StreamReader(new MemoryStream(res.FileContents)).ReadToEnd(); - var parsed = XDocumentXamlIlParser.Parse(xaml); + var parsed = XDocumentXamlParser.Parse(xaml); - var initialRoot = (XamlIlAstObjectNode)parsed.Root; + var initialRoot = (XamlAstObjectNode)parsed.Root; - var precompileDirective = initialRoot.Children.OfType() + var precompileDirective = initialRoot.Children.OfType() .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Precompile"); if (precompileDirective != null) { - var precompileText = (precompileDirective.Values[0] as XamlIlAstTextNode)?.Text.Trim() + var precompileText = (precompileDirective.Values[0] as XamlAstTextNode)?.Text.Trim() .ToLowerInvariant(); if (precompileText == "false") continue; if (precompileText != "true") - throw new XamlIlParseException("Invalid value for x:Precompile", precompileDirective); + throw new XamlParseException("Invalid value for x:Precompile", precompileDirective); } - var classDirective = initialRoot.Children.OfType() + var classDirective = initialRoot.Children.OfType() .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class"); - IXamlIlType classType = null; + IXamlType classType = null; if (classDirective != null) { - if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlIlAstTextNode tn)) - throw new XamlIlParseException("x:Class should have a string value", classDirective); + if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlAstTextNode tn)) + throw new XamlParseException("x:Class should have a string value", classDirective); classType = typeSystem.TargetAssembly.FindType(tn.Text); if (classType == null) - throw new XamlIlParseException($"Unable to find type `{tn.Text}`", classDirective); + throw new XamlParseException($"Unable to find type `{tn.Text}`", classDirective); compiler.OverrideRootType(parsed, - new XamlIlAstClrTypeReference(classDirective, classType, false)); + new XamlAstClrTypeReference(classDirective, classType, false)); initialRoot.Children.Remove(classDirective); } @@ -323,7 +324,7 @@ namespace Avalonia.Build.Tasks catch (Exception e) { int lineNumber = 0, linePosition = 0; - if (e is XamlIlParseException xe) + if (e is XamlParseException xe) { lineNumber = xe.LineNumber; linePosition = xe.LinePosition; diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 985a6b9f5a..48f4b75e90 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -58,8 +58,8 @@ - - + + diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs index 5a5da518d0..88da8dcc9e 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs @@ -10,12 +10,15 @@ using System.Runtime.InteropServices; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; using Avalonia.Markup.Xaml.XamlIl.Runtime; using Avalonia.Platform; -using XamlIl.Transform; -using XamlIl.TypeSystem; +using XamlX.Transform; +using XamlX.TypeSystem; +using XamlX.IL; +using XamlX.Emit; #if RUNTIME_XAML_CECIL using TypeAttributes = Mono.Cecil.TypeAttributes; using Mono.Cecil; -using XamlIl.Ast; +using XamlX.Ast; +using XamlX.IL.Cecil; #endif namespace Avalonia.Markup.Xaml.XamlIl { @@ -24,9 +27,10 @@ namespace Avalonia.Markup.Xaml.XamlIl #if !RUNTIME_XAML_CECIL private static SreTypeSystem _sreTypeSystem; private static ModuleBuilder _sreBuilder; - private static IXamlIlType _sreContextType; - private static XamlIlLanguageTypeMappings _sreMappings; - private static XamlIlXmlnsMappings _sreXmlns; + private static IXamlType _sreContextType; + private static XamlLanguageTypeMappings _sreMappings; + private static XamlLanguageEmitMappings _sreEmitMappings; + private static XamlXmlnsMappings _sreXmlns; private static AssemblyBuilder _sreAsm; private static bool _sreCanSave; @@ -82,13 +86,14 @@ namespace Avalonia.Markup.Xaml.XamlIl } if (_sreMappings == null) - _sreMappings = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem); + (_sreMappings, _sreEmitMappings) = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem); if (_sreXmlns == null) - _sreXmlns = XamlIlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings); + _sreXmlns = XamlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings); if (_sreContextType == null) - _sreContextType = XamlIlContextDefinition.GenerateContextClass( + _sreContextType = XamlILContextDefinition.GenerateContextClass( _sreTypeSystem.CreateTypeBuilder( - _sreBuilder.DefineType("XamlIlContext")), _sreTypeSystem, _sreMappings); + _sreBuilder.DefineType("XamlIlContext")), _sreTypeSystem, _sreMappings, + _sreEmitMappings); } @@ -115,12 +120,13 @@ namespace Avalonia.Markup.Xaml.XamlIl InitializeSre(); var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly); - var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_sreTypeSystem, asm, + var compiler = new AvaloniaXamlIlCompiler(new TransformerConfiguration(_sreTypeSystem, asm, _sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter), + _sreEmitMappings, _sreContextType) { EnableIlVerification = true }; var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri); - IXamlIlType overrideType = null; + IXamlType overrideType = null; if (rootInstance != null) { overrideType = _sreTypeSystem.GetType(rootInstance.GetType()); @@ -203,6 +209,7 @@ namespace Avalonia.Markup.Xaml.XamlIl private static string _cecilEmitDir; private static CecilTypeSystem _cecilTypeSystem; private static XamlIlLanguageTypeMappings _cecilMappings; + private static XamlLanguageEmitMappings _cecilEmitMappings; private static XamlIlXmlnsMappings _cecilXmlns; private static bool _cecilInitialized; @@ -215,7 +222,7 @@ namespace Avalonia.Markup.Xaml.XamlIl Directory.CreateDirectory(_cecilEmitDir); var refs = new[] {path}.Concat(File.ReadAllLines(path + ".refs")); _cecilTypeSystem = new CecilTypeSystem(refs); - _cecilMappings = AvaloniaXamlIlLanguage.Configure(_cecilTypeSystem); + (_cecilMappings, _cecilEmitMappings) = AvaloniaXamlIlLanguage.Configure(_cecilTypeSystem); _cecilXmlns = XamlIlXmlnsMappings.Resolve(_cecilTypeSystem, _cecilMappings); _cecilInitialized = true; } @@ -226,7 +233,7 @@ namespace Avalonia.Markup.Xaml.XamlIl if (uri == null) throw new InvalidOperationException("Please, go away"); InitializeCecil(); - IXamlIlType overrideType = null; + IXamlType overrideType = null; if (rootInstance != null) { overrideType = _cecilTypeSystem.GetType(rootInstance.GetType().FullName); @@ -261,6 +268,7 @@ namespace Avalonia.Markup.Xaml.XamlIl localAssembly == null ? null : _cecilTypeSystem.FindAssembly(localAssembly.GetName().Name), _cecilMappings, XamlIlXmlnsMappings.Resolve(_cecilTypeSystem, _cecilMappings), AvaloniaXamlIlLanguage.CustomValueConverter), + _cecilEmitMappings, _cecilTypeSystem.CreateTypeBuilder(contextDef)); compiler.ParseAndCompile(xaml, uri.ToString(), tb, overrideType); var asmPath = Path.Combine(_cecilEmitDir, safeUri + ".dll"); diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs index b84f50fa8d..1e7128e75c 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -1,29 +1,32 @@ using System.Collections.Generic; using System.Linq; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; -using XamlIl; -using XamlIl.Ast; -using XamlIl.Parsers; -using XamlIl.Transform; -using XamlIl.Transform.Transformers; -using XamlIl.TypeSystem; +using XamlX; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.Parsers; +using XamlX.Transform; +using XamlX.Transform.Transformers; +using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions { - class AvaloniaXamlIlCompiler : XamlIlCompiler + class AvaloniaXamlIlCompiler : XamlILCompiler { - private readonly XamlIlTransformerConfiguration _configuration; - private readonly IXamlIlType _contextType; + private readonly TransformerConfiguration _configuration; + private readonly IXamlType _contextType; private readonly AvaloniaXamlIlDesignPropertiesTransformer _designTransformer; - private AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration) : base(configuration, true) + private AvaloniaXamlIlCompiler(TransformerConfiguration configuration, XamlLanguageEmitMappings emitMappings) + : base(configuration, emitMappings, true) { _configuration = configuration; - void InsertAfter(params IXamlIlAstTransformer[] t) + void InsertAfter(params IXamlAstTransformer[] t) => Transformers.InsertRange(Transformers.FindIndex(x => x is T) + 1, t); - void InsertBefore(params IXamlIlAstTransformer[] t) + void InsertBefore(params IXamlAstTransformer[] t) => Transformers.InsertRange(Transformers.FindIndex(x => x is T), t); @@ -37,12 +40,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions // Targeted - InsertBefore(new AvaloniaXamlIlTransformInstanceAttachedProperties()); - InsertAfter(new AvaloniaXamlIlAvaloniaPropertyResolver()); + InsertBefore(new AvaloniaXamlIlTransformInstanceAttachedProperties()); + InsertAfter(new AvaloniaXamlIlAvaloniaPropertyResolver()); - InsertBefore( + InsertBefore( new AvaloniaXamlIlSelectorTransformer(), new AvaloniaXamlIlSetterTransformer(), new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(), @@ -55,17 +58,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions Transformers.Add(new AddNameScopeRegistration()); Transformers.Add(new AvaloniaXamlIlMetadataRemover()); + Emitters.Add(new AvaloniaNameScopeRegistrationXamlIlNodeEmitter()); } - public AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration, - IXamlIlTypeBuilder contextTypeBuilder) : this(configuration) + public AvaloniaXamlIlCompiler(TransformerConfiguration configuration, + XamlLanguageEmitMappings emitMappings, + IXamlTypeBuilder contextTypeBuilder) + : this(configuration, emitMappings) { _contextType = CreateContextType(contextTypeBuilder); } - public AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration, - IXamlIlType contextType) : this(configuration) + public AvaloniaXamlIlCompiler(TransformerConfiguration configuration, + XamlLanguageEmitMappings emitMappings, + IXamlType contextType) : this(configuration, emitMappings) { _contextType = contextType; } @@ -79,37 +86,35 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions set => _designTransformer.IsDesignMode = value; } - public void ParseAndCompile(string xaml, string baseUri, IFileSource fileSource, IXamlIlTypeBuilder tb, IXamlIlType overrideRootType) + public void ParseAndCompile(string xaml, string baseUri, IFileSource fileSource, IXamlTypeBuilder tb, IXamlType overrideRootType) { - var parsed = XDocumentXamlIlParser.Parse(xaml, new Dictionary + var parsed = XDocumentXamlParser.Parse(xaml, new Dictionary { {XamlNamespaces.Blend2008, XamlNamespaces.Blend2008} }); - var rootObject = (XamlIlAstObjectNode)parsed.Root; + var rootObject = (XamlAstObjectNode)parsed.Root; var classDirective = rootObject.Children - .OfType().FirstOrDefault(x => + .OfType().FirstOrDefault(x => x.Namespace == XamlNamespaces.Xaml2006 && x.Name == "Class"); var rootType = classDirective != null ? - new XamlIlAstClrTypeReference(classDirective, - _configuration.TypeSystem.GetType(((XamlIlAstTextNode)classDirective.Values[0]).Text), + new XamlAstClrTypeReference(classDirective, + _configuration.TypeSystem.GetType(((XamlAstTextNode)classDirective.Values[0]).Text), false) : - XamlIlTypeReferenceResolver.ResolveType(CreateTransformationContext(parsed, true), - (XamlIlAstXmlTypeReference)rootObject.Type, true); + TypeReferenceResolver.ResolveType(CreateTransformationContext(parsed, true), + (XamlAstXmlTypeReference)rootObject.Type, true); if (overrideRootType != null) { - - if (!rootType.Type.IsAssignableFrom(overrideRootType)) - throw new XamlIlLoadException( + throw new XamlX.XamlLoadException( $"Unable to substitute {rootType.Type.GetFqn()} with {overrideRootType.GetFqn()}", rootObject); - rootType = new XamlIlAstClrTypeReference(rootObject, overrideRootType, false); + rootType = new XamlAstClrTypeReference(rootObject, overrideRootType, false); } OverrideRootType(parsed, rootType); @@ -119,17 +124,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions } - public void OverrideRootType(XamlIlDocument doc, IXamlIlAstTypeReference newType) + public void OverrideRootType(XamlDocument doc, IXamlAstTypeReference newType) { - var root = (XamlIlAstObjectNode)doc.Root; + var root = (XamlAstObjectNode)doc.Root; var oldType = root.Type; if (oldType.Equals(newType)) return; root.Type = newType; - foreach (var child in root.Children.OfType()) + foreach (var child in root.Children.OfType()) { - if (child.Property is XamlIlAstNamePropertyReference prop) + if (child.Property is XamlAstNamePropertyReference prop) { if (prop.DeclaringType.Equals(oldType)) prop.DeclaringType = newType; diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs index a1fe6976b7..e1e360cd37 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; -using XamlIl; -using XamlIl.Ast; -using XamlIl.Transform; -using XamlIl.TypeSystem; +using XamlX; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.Transform; +using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions { @@ -17,12 +19,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions class AvaloniaXamlIlLanguage { - public static XamlIlLanguageTypeMappings Configure(IXamlIlTypeSystem typeSystem) + public static (XamlLanguageTypeMappings language, XamlLanguageEmitMappings emit) Configure(IXamlTypeSystem typeSystem) { var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers"); var assignBindingAttribute = typeSystem.GetType("Avalonia.Data.AssignBindingAttribute"); var bindingType = typeSystem.GetType("Avalonia.Data.IBinding"); - var rv = new XamlIlLanguageTypeMappings(typeSystem) + var rv = new XamlLanguageTypeMappings(typeSystem) { SupportInitialize = typeSystem.GetType("System.ComponentModel.ISupportInitialize"), XmlnsAttributes = @@ -51,18 +53,22 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions }, InnerServiceProviderFactoryMethod = runtimeHelpers.FindMethod(m => m.Name == "CreateInnerServiceProviderV1"), - ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.Emit, }; rv.CustomAttributeResolver = new AttributeResolver(typeSystem, rv); - rv.ContextTypeBuilderCallback = (b, c) => EmitNameScopeField(rv, typeSystem, b, c); - return rv; + + var emit = new XamlLanguageEmitMappings + { + ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.Emit, + ContextTypeBuilderCallback = (b, c) => EmitNameScopeField(rv, typeSystem, b, c) + }; + return (rv, emit); } public const string ContextNameScopeFieldName = "AvaloniaNameScope"; - private static void EmitNameScopeField(XamlIlLanguageTypeMappings mappings, - IXamlIlTypeSystem typeSystem, - IXamlIlTypeBuilder typebuilder, IXamlIlEmitter constructor) + private static void EmitNameScopeField(XamlLanguageTypeMappings mappings, + IXamlTypeSystem typeSystem, + IXamlTypeBuilder typebuilder, IXamlILEmitter constructor) { var nameScopeType = typeSystem.FindType("Avalonia.Controls.INameScope"); @@ -78,23 +84,23 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions } - class AttributeResolver : IXamlIlCustomAttributeResolver + class AttributeResolver : IXamlCustomAttributeResolver { - private readonly IXamlIlType _typeConverterAttribute; + private readonly IXamlType _typeConverterAttribute; - private readonly List> _converters = - new List>(); + private readonly List> _converters = + new List>(); - private readonly IXamlIlType _avaloniaList; - private readonly IXamlIlType _avaloniaListConverter; + private readonly IXamlType _avaloniaList; + private readonly IXamlType _avaloniaListConverter; - public AttributeResolver(IXamlIlTypeSystem typeSystem, XamlIlLanguageTypeMappings mappings) + public AttributeResolver(IXamlTypeSystem typeSystem, XamlLanguageTypeMappings mappings) { _typeConverterAttribute = mappings.TypeConverterAttributes.First(); - void AddType(IXamlIlType type, IXamlIlType conv) - => _converters.Add(new KeyValuePair(type, conv)); + void AddType(IXamlType type, IXamlType conv) + => _converters.Add(new KeyValuePair(type, conv)); void Add(string type, string conv) => AddType(typeSystem.GetType(type), typeSystem.GetType(conv)); @@ -113,7 +119,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions _avaloniaListConverter = typeSystem.GetType("Avalonia.Collections.AvaloniaListConverter`1"); } - IXamlIlType LookupConverter(IXamlIlType type) + IXamlType LookupConverter(IXamlType type) { foreach(var p in _converters) if (p.Key.Equals(type)) @@ -123,15 +129,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return null; } - class ConstructedAttribute : IXamlIlCustomAttribute + class ConstructedAttribute : IXamlCustomAttribute { - public bool Equals(IXamlIlCustomAttribute other) => false; + public bool Equals(IXamlCustomAttribute other) => false; - public IXamlIlType Type { get; } + public IXamlType Type { get; } public List Parameters { get; } public Dictionary Properties { get; } - public ConstructedAttribute(IXamlIlType type, List parameters, Dictionary properties) + public ConstructedAttribute(IXamlType type, List parameters, Dictionary properties) { Type = type; Parameters = parameters ?? new List(); @@ -139,7 +145,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions } } - public IXamlIlCustomAttribute GetCustomAttribute(IXamlIlType type, IXamlIlType attributeType) + public IXamlCustomAttribute GetCustomAttribute(IXamlType type, IXamlType attributeType) { if (attributeType.Equals(_typeConverterAttribute)) { @@ -151,25 +157,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return null; } - public IXamlIlCustomAttribute GetCustomAttribute(IXamlIlProperty property, IXamlIlType attributeType) + public IXamlCustomAttribute GetCustomAttribute(IXamlProperty property, IXamlType attributeType) { return null; } } - public static bool CustomValueConverter(XamlIlAstTransformationContext context, - IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode result) + public static bool CustomValueConverter(AstTransformationContext context, + IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result) { if (type.FullName == "System.TimeSpan" - && node is XamlIlAstTextNode tn + && node is XamlAstTextNode tn && !tn.Text.Contains(":")) { var seconds = double.Parse(tn.Text, CultureInfo.InvariantCulture); - result = new XamlIlStaticOrTargetedReturnMethodCallNode(tn, + result = new XamlStaticOrTargetedReturnMethodCallNode(tn, type.FindMethod("FromSeconds", type, false, context.Configuration.WellKnownTypes.Double), new[] { - new XamlIlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds) + new XamlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds) }); return true; } @@ -178,9 +184,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions { var scope = context.ParentNodes().OfType().FirstOrDefault(); if (scope == null) - throw new XamlIlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node); - if (!(node is XamlIlAstTextNode text)) - throw new XamlIlLoadException("Property should be a text node", node); + throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node); + if (!(node is XamlAstTextNode text)) + throw new XamlX.XamlLoadException("Property should be a text node", node); result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text); return true; } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs index 805b733feb..970e1ea15e 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs @@ -1,33 +1,35 @@ using System; using System.Linq; -using XamlIl.Ast; -using XamlIl.Transform; -using XamlIl.TypeSystem; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.Transform; +using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AddNameScopeRegistration : IXamlIlAstTransformer + class AddNameScopeRegistration : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlIlPropertyAssignmentNode pa + if (node is XamlPropertyAssignmentNode pa && pa.Property.Name == "Name" && pa.Property.DeclaringType.FullName == "Avalonia.StyledElement") { - if (context.ParentNodes().FirstOrDefault() is XamlIlManipulationGroupNode mg + if (context.ParentNodes().FirstOrDefault() is XamlManipulationGroupNode mg && mg.Children.OfType().Any()) return node; - IXamlIlAstValueNode value = null; + IXamlAstValueNode value = null; for (var c = 0; c < pa.Values.Count; c++) if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String)) { value = pa.Values[c]; - if (!(value is XamlIlAstTextNode)) + if (!(value is XamlAstTextNode)) { - var local = new XamlIlAstCompilerLocalNode(value); + var local = new XamlAstCompilerLocalNode(value); // Wrap original in local initialization - pa.Values[c] = new XamlIlAstLocalInitializationNodeEmitter(value, value, local); + pa.Values[c] = new XamlAstLocalInitializationNodeEmitter(value, value, local); // Use local value = local; } @@ -36,20 +38,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } if (value != null) - return new XamlIlManipulationGroupNode(pa) + return new XamlManipulationGroupNode(pa) { Children = { pa, - new AvaloniaNameScopeRegistrationXamlIlNode(value, context.GetAvaloniaTypes()) + new AvaloniaNameScopeRegistrationXamlIlNode(value) } }; } if (!context.ParentNodes().Any() - && node is XamlIlValueWithManipulationNode mnode) + && node is XamlValueWithManipulationNode mnode) { - mnode.Manipulation = new XamlIlManipulationGroupNode(mnode, + mnode.Manipulation = new XamlManipulationGroupNode(mnode, new[] { mnode.Manipulation, @@ -59,17 +61,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers return node; } - class HandleRootObjectScopeNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode + class HandleRootObjectScopeNode : XamlAstNode, IXamlAstManipulationNode, IXamlAstEmitableNode { private readonly AvaloniaXamlIlWellKnownTypes _types; - public HandleRootObjectScopeNode(IXamlIlLineInfo lineInfo, + public HandleRootObjectScopeNode(IXamlLineInfo lineInfo, AvaloniaXamlIlWellKnownTypes types) : base(lineInfo) { _types = types; } - public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public XamlILNodeEmitResult Emit(XamlEmitContext context, IXamlILEmitter codeGen) { var next = codeGen.DefineLabel(); var scopeField = context.RuntimeContext.ContextType.Fields.First(f => @@ -91,49 +93,55 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers .EmitCall(_types.INameScopeComplete, true); } - return XamlIlNodeEmitResult.Void(1); + return XamlILNodeEmitResult.Void(1); } } } - class AvaloniaNameScopeRegistrationXamlIlNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode + class AvaloniaNameScopeRegistrationXamlIlNode : XamlAstNode, IXamlAstManipulationNode { - private readonly AvaloniaXamlIlWellKnownTypes _types; - public IXamlIlAstValueNode Name { get; set; } + public IXamlAstValueNode Name { get; set; } - public AvaloniaNameScopeRegistrationXamlIlNode(IXamlIlAstValueNode name, AvaloniaXamlIlWellKnownTypes types) : base(name) + public AvaloniaNameScopeRegistrationXamlIlNode(IXamlAstValueNode name) : base(name) { - _types = types; Name = name; } - public override void VisitChildren(IXamlIlAstVisitor visitor) - => Name = (IXamlIlAstValueNode)Name.Visit(visitor); + public override void VisitChildren(IXamlAstVisitor visitor) + => Name = (IXamlAstValueNode)Name.Visit(visitor); + } - public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + class AvaloniaNameScopeRegistrationXamlIlNodeEmitter : IXamlAstLocalsNodeEmitter + { + public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContextWithLocals context, IXamlILEmitter codeGen) { - var scopeField = context.RuntimeContext.ContextType.Fields.First(f => - f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName); - - using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) + if (node is AvaloniaNameScopeRegistrationXamlIlNode registration) { - codeGen - // var target = {pop} - .Stloc(targetLoc.Local) - // _context.NameScope.Register(Name, target) - .Ldloc(context.ContextLocal) - .Ldfld(scopeField); - - context.Emit(Name, codeGen, Name.Type.GetClrType()); - - codeGen - .Ldloc(targetLoc.Local) - .EmitCall(_types.INameScopeRegister, true); - } + var scopeField = context.RuntimeContext.ContextType.Fields.First(f => + f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName); + + using (var targetLoc = context.GetLocalOfType(context.Configuration.WellKnownTypes.Object)) + { - return XamlIlNodeEmitResult.Void(1); + codeGen + // var target = {pop} + .Stloc(targetLoc.Local) + // _context.NameScope.Register(Name, target) + .Ldloc(context.ContextLocal) + .Ldfld(scopeField); + + context.Emit(registration.Name, codeGen, registration.Name.Type.GetClrType()); + + codeGen + .Ldloc(targetLoc.Local) + .EmitCall(context.GetAvaloniaTypes().INameScopeRegister, true); + } + + return XamlILNodeEmitResult.Void(1); + } + return default; } } } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaBindingExtensionHackTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaBindingExtensionHackTransformer.cs index c89106312f..0846bc5faf 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaBindingExtensionHackTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaBindingExtensionHackTransformer.cs @@ -1,16 +1,16 @@ -using XamlIl.Ast; -using XamlIl.Transform; +using XamlX.Ast; +using XamlX.Transform; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AvaloniaBindingExtensionHackTransformer : IXamlIlAstTransformer + class AvaloniaBindingExtensionHackTransformer : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { // Our code base expects XAML parser to prefer `FooExtension` to `Foo` even with `` syntax // This is the legacy of Portable.Xaml, so we emulate that behavior here - if (node is XamlIlAstXmlTypeReference tref + if (node is XamlAstXmlTypeReference tref && tref.Name == "Binding" && tref.XmlNamespace == "https://github.com/avaloniaui") tref.IsMarkupExtension = true; diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs index 74f5c29f6a..9219a39ddc 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs @@ -1,14 +1,14 @@ using System.Linq; -using XamlIl.Ast; -using XamlIl.Transform; +using XamlX.Ast; +using XamlX.Transform; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AvaloniaXamlIlAvaloniaPropertyResolver : IXamlIlAstTransformer + class AvaloniaXamlIlAvaloniaPropertyResolver : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlIlAstClrProperty prop) + if (node is XamlAstClrProperty prop) { var n = prop.Name + "Property"; var field = diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs index 7e8f296b44..35e2624ff9 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs @@ -1,15 +1,17 @@ using System.Linq; -using XamlIl.Ast; -using XamlIl.Transform; -using XamlIl.TypeSystem; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.Transform; +using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AvaloniaXamlIlConstructorServiceProviderTransformer : IXamlIlAstTransformer + class AvaloniaXamlIlConstructorServiceProviderTransformer : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlIlAstObjectNode on && on.Arguments.Count == 0) + if (node is XamlAstObjectNode on && on.Arguments.Count == 0) { var ctors = on.Type.GetClrType().Constructors; if (!ctors.Any(c => c.IsPublic && !c.IsStatic && c.Parameters.Count == 0)) @@ -27,20 +29,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers return node; } - class InjectServiceProviderNode : XamlIlAstNode, IXamlIlAstValueNode,IXamlIlAstNodeNeedsParentStack, - IXamlIlAstEmitableNode + class InjectServiceProviderNode : XamlAstNode, IXamlAstValueNode,IXamlAstNodeNeedsParentStack, + IXamlAstEmitableNode { - public InjectServiceProviderNode(IXamlIlType type, IXamlIlLineInfo lineInfo) : base(lineInfo) + public InjectServiceProviderNode(IXamlType type, IXamlLineInfo lineInfo) : base(lineInfo) { - Type = new XamlIlAstClrTypeReference(lineInfo, type, false); + Type = new XamlAstClrTypeReference(lineInfo, type, false); } - public IXamlIlAstTypeReference Type { get; } + public IXamlAstTypeReference Type { get; } public bool NeedsParentStack => true; - public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public XamlILNodeEmitResult Emit(XamlEmitContext context, IXamlILEmitter codeGen) { codeGen.Ldloc(context.ContextLocal); - return XamlIlNodeEmitResult.Type(0, Type.GetClrType()); + return XamlILNodeEmitResult.Type(0, Type.GetClrType()); } } } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs index 40386924c3..f95d086bf6 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs @@ -1,29 +1,29 @@ using System.Linq; -using XamlIl.Ast; -using XamlIl.Transform; -using XamlIl.TypeSystem; +using XamlX.Ast; +using XamlX.Transform; +using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer : IXamlIlAstTransformer + class AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (!(node is XamlIlAstObjectNode on + if (!(node is XamlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Markup.Xaml.Templates.ControlTemplate")) return node; - var tt = on.Children.OfType().FirstOrDefault(ch => + var tt = on.Children.OfType().FirstOrDefault(ch => ch.Property.GetClrProperty().Name == "TargetType"); if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlTargetTypeMetadataNode) // Deja vu. I've just been in this place before return node; - IXamlIlAstTypeReference targetType; + IXamlAstTypeReference targetType; var templatableBaseType = context.Configuration.TypeSystem.GetType("Avalonia.Controls.Control"); - if ((tt?.Values.FirstOrDefault() is XamlIlTypeExtensionNode tn)) + if ((tt?.Values.FirstOrDefault() is XamlTypeExtensionNode tn)) { targetType = tn.Value; } @@ -33,11 +33,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers .FirstOrDefault(); if (parentScope?.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style) targetType = parentScope.TargetType; - else if (context.ParentNodes().Skip(1).FirstOrDefault() is XamlIlAstObjectNode directParentNode + else if (context.ParentNodes().Skip(1).FirstOrDefault() is XamlAstObjectNode directParentNode && templatableBaseType.IsAssignableFrom(directParentNode.Type.GetClrType())) targetType = directParentNode.Type; else - targetType = new XamlIlAstClrTypeReference(node, + targetType = new XamlAstClrTypeReference(node, templatableBaseType, false); } @@ -48,9 +48,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } } - class AvaloniaXamlIlTargetTypeMetadataNode : XamlIlValueWithSideEffectNodeBase + class AvaloniaXamlIlTargetTypeMetadataNode : XamlValueWithSideEffectNodeBase { - public IXamlIlAstTypeReference TargetType { get; set; } + public IXamlAstTypeReference TargetType { get; set; } public ScopeTypes ScopeType { get; } public enum ScopeTypes @@ -60,7 +60,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers Transitions } - public AvaloniaXamlIlTargetTypeMetadataNode(IXamlIlAstValueNode value, IXamlIlAstTypeReference targetType, + public AvaloniaXamlIlTargetTypeMetadataNode(IXamlAstValueNode value, IXamlAstTypeReference targetType, ScopeTypes type) : base(value, value) { diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs index 9cc4c5cf11..3096be522f 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs @@ -1,12 +1,12 @@ using System.Collections.Generic; using System.Linq; -using XamlIl; -using XamlIl.Ast; -using XamlIl.Transform; +using XamlX; +using XamlX.Ast; +using XamlX.Transform; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AvaloniaXamlIlDesignPropertiesTransformer : IXamlIlAstTransformer + class AvaloniaXamlIlDesignPropertiesTransformer : IXamlAstTransformer { public bool IsDesignMode { get; set; } @@ -17,14 +17,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers }; private const string AvaloniaNs = "https://github.com/avaloniaui"; - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlIlAstObjectNode on) + if (node is XamlAstObjectNode on) { for (var c=0; c() + var pn = on.Children.OfType() .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector"); if (pn == null) return node; if (pn.Values.Count != 1) - throw new XamlIlParseException("Selector property should should have exactly one value", node); + throw new XamlParseException("Selector property should should have exactly one value", node); if (pn.Values[0] is XamlIlSelectorNode) //Deja vu. I've just been in this place before return node; - if (!(pn.Values[0] is XamlIlAstTextNode tn)) - throw new XamlIlParseException("Selector property should be a text node", node); + if (!(pn.Values[0] is XamlAstTextNode tn)) + throw new XamlParseException("Selector property should be a text node", node); var selectorType = pn.Property.GetClrProperty().Getter.ReturnType; var initialNode = new XamlIlSelectorInitialNode(node, selectorType); XamlIlSelectorNode Create(IEnumerable syntax, - Func typeResolver) + Func typeResolver) { XamlIlSelectorNode result = initialNode; XamlIlOrSelectorNode results = null; @@ -63,18 +67,18 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers var type = result?.TargetType; if (type == null) - throw new XamlIlParseException("Property selectors must be applied to a type.", node); + throw new XamlParseException("Property selectors must be applied to a type.", node); var targetProperty = type.GetAllProperties().FirstOrDefault(p => p.Name == property.Property); if (targetProperty == null) - throw new XamlIlParseException($"Cannot find '{property.Property}' on '{type}", node); + throw new XamlParseException($"Cannot find '{property.Property}' on '{type}", node); - if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, - new XamlIlAstTextNode(node, property.Value, context.Configuration.WellKnownTypes.String), + if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, + new XamlAstTextNode(node, property.Value, context.Configuration.WellKnownTypes.String), targetProperty.PropertyType, out var typedValue)) - throw new XamlIlParseException( + throw new XamlParseException( $"Cannot convert '{property.Value}' to '{targetProperty.PropertyType.GetFqn()}", node); @@ -100,7 +104,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers result = initialNode; break; default: - throw new XamlIlParseException($"Unsupported selector grammar '{i.GetType()}'.", node); + throw new XamlParseException($"Unsupported selector grammar '{i.GetType()}'.", node); } } @@ -119,15 +123,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } catch (Exception e) { - throw new XamlIlParseException("Unable to parse selector: " + e.Message, node); + throw new XamlParseException("Unable to parse selector: " + e.Message, node); } var selector = Create(parsed, (p, n) - => XamlIlTypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true)); + => TypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true)); pn.Values[0] = selector; return new AvaloniaXamlIlTargetTypeMetadataNode(on, - new XamlIlAstClrTypeReference(selector, selector.TargetType, false), + new XamlAstClrTypeReference(selector, selector.TargetType, false), AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style); } @@ -135,32 +139,32 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers - abstract class XamlIlSelectorNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode + abstract class XamlIlSelectorNode : XamlAstNode, IXamlAstValueNode, IXamlAstEmitableNode { protected XamlIlSelectorNode Previous { get; } - public abstract IXamlIlType TargetType { get; } + public abstract IXamlType TargetType { get; } public XamlIlSelectorNode(XamlIlSelectorNode previous, - IXamlIlLineInfo info = null, - IXamlIlType selectorType = null) : base(info ?? previous) + IXamlLineInfo info = null, + IXamlType selectorType = null) : base(info ?? previous) { Previous = previous; - Type = selectorType == null ? previous.Type : new XamlIlAstClrTypeReference(this, selectorType, false); + Type = selectorType == null ? previous.Type : new XamlAstClrTypeReference(this, selectorType, false); } - public IXamlIlAstTypeReference Type { get; } + public IXamlAstTypeReference Type { get; } - public virtual XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public virtual XamlILNodeEmitResult Emit(XamlEmitContext context, IXamlILEmitter codeGen) { if (Previous != null) context.Emit(Previous, codeGen, Type.GetClrType()); DoEmit(context, codeGen); - return XamlIlNodeEmitResult.Type(0, Type.GetClrType()); + return XamlILNodeEmitResult.Type(0, Type.GetClrType()); } - protected abstract void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen); + protected abstract void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen); - protected void EmitCall(XamlIlEmitContext context, IXamlIlEmitter codeGen, Func method) + protected void EmitCall(XamlEmitContext context, IXamlILEmitter codeGen, Func method) { var selectors = context.Configuration.TypeSystem.GetType("Avalonia.Styling.Selectors"); var found = selectors.FindMethod(m => m.IsStatic && m.Parameters.Count > 0 && method(m)); @@ -170,27 +174,27 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers class XamlIlSelectorInitialNode : XamlIlSelectorNode { - public XamlIlSelectorInitialNode(IXamlIlLineInfo info, - IXamlIlType selectorType) : base(null, info, selectorType) + public XamlIlSelectorInitialNode(IXamlLineInfo info, + IXamlType selectorType) : base(null, info, selectorType) { } - public override IXamlIlType TargetType => null; - protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) => codeGen.Ldnull(); + public override IXamlType TargetType => null; + protected override void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen) => codeGen.Ldnull(); } class XamlIlTypeSelector : XamlIlSelectorNode { public bool Concrete { get; } - public XamlIlTypeSelector(XamlIlSelectorNode previous, IXamlIlType type, bool concrete) : base(previous) + public XamlIlTypeSelector(XamlIlSelectorNode previous, IXamlType type, bool concrete) : base(previous) { TargetType = type; Concrete = concrete; } - public override IXamlIlType TargetType { get; } - protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public override IXamlType TargetType { get; } + protected override void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen) { var name = Concrete ? "OfType" : "Is"; codeGen.Ldtype(TargetType); @@ -217,8 +221,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } - public override IXamlIlType TargetType => Previous?.TargetType; - protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public override IXamlType TargetType => Previous?.TargetType; + protected override void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen) { codeGen.Ldstr(String); var name = _type.ToString(); @@ -242,8 +246,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers _type = type; } - public override IXamlIlType TargetType => null; - protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public override IXamlType TargetType => null; + protected override void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen) { var name = _type.ToString(); EmitCall(context, codeGen, @@ -260,8 +264,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers Argument = argument; } - public override IXamlIlType TargetType => Previous?.TargetType; - protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public override IXamlType TargetType => Previous?.TargetType; + protected override void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen) { context.Emit(Argument, codeGen, Type.GetClrType()); EmitCall(context, codeGen, @@ -272,22 +276,22 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers class XamlIlPropertyEqualsSelector : XamlIlSelectorNode { public XamlIlPropertyEqualsSelector(XamlIlSelectorNode previous, - IXamlIlProperty property, - IXamlIlAstValueNode value) + IXamlProperty property, + IXamlAstValueNode value) : base(previous) { Property = property; Value = value; } - public IXamlIlProperty Property { get; set; } - public IXamlIlAstValueNode Value { get; set; } + public IXamlProperty Property { get; set; } + public IXamlAstValueNode Value { get; set; } - public override IXamlIlType TargetType => Previous?.TargetType; - protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public override IXamlType TargetType => Previous?.TargetType; + protected override void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen) { if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property)) - throw new XamlIlLoadException( + throw new XamlLoadException( $"{Property.Name} of {(Property.Setter ?? Property.Getter).DeclaringType.GetFqn()} doesn't seem to be an AvaloniaProperty", this); context.Emit(Value, codeGen, context.Configuration.WellKnownTypes.Object); @@ -302,7 +306,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers class XamlIlOrSelectorNode : XamlIlSelectorNode { List _selectors = new List(); - public XamlIlOrSelectorNode(IXamlIlLineInfo info, IXamlIlType selectorType) : base(null, info, selectorType) + public XamlIlOrSelectorNode(IXamlLineInfo info, IXamlType selectorType) : base(null, info, selectorType) { } @@ -311,11 +315,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers _selectors.Add(node); } - public override IXamlIlType TargetType + public override IXamlType TargetType { get { - IXamlIlType result = null; + IXamlType result = null; foreach (var selector in _selectors) { @@ -340,10 +344,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } } - protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + protected override void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen) { if (_selectors.Count == 0) - throw new XamlIlLoadException("Invalid selector count", this); + throw new XamlLoadException("Invalid selector count", this); if (_selectors.Count == 1) { _selectors[0].Emit(context, codeGen); diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index 629e2562d3..ddb394645d 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -1,64 +1,68 @@ using System; using System.Collections.Generic; using System.Linq; -using XamlIl; -using XamlIl.Ast; -using XamlIl.Transform; -using XamlIl.Transform.Transformers; -using XamlIl.TypeSystem; +using XamlX; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.Transform; +using XamlX.Transform.Transformers; +using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AvaloniaXamlIlSetterTransformer : IXamlIlAstTransformer + using XamlParseException = XamlX.XamlParseException; + using XamlLoadException = XamlX.XamlLoadException; + class AvaloniaXamlIlSetterTransformer : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (!(node is XamlIlAstObjectNode on + if (!(node is XamlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Setter")) return node; - var parent = context.ParentNodes().OfType() + var parent = context.ParentNodes().OfType() .FirstOrDefault(p => p.Type.GetClrType().FullName == "Avalonia.Styling.Style"); if (parent == null) - throw new XamlIlParseException( + throw new XamlParseException( "Avalonia.Styling.Setter is only valid inside Avalonia.Styling.Style", node); - var selectorProperty = parent.Children.OfType() + var selectorProperty = parent.Children.OfType() .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector"); if (selectorProperty == null) - throw new XamlIlParseException( + throw new XamlParseException( "Can not find parent Style Selector", node); var selector = selectorProperty.Values.FirstOrDefault() as XamlIlSelectorNode; if (selector?.TargetType == null) - throw new XamlIlParseException( + throw new XamlParseException( "Can not resolve parent Style Selector type", node); - var property = @on.Children.OfType() + var property = @on.Children.OfType() .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property"); if (property == null) - throw new XamlIlParseException("Setter without a property is not valid", node); + throw new XamlParseException("Setter without a property is not valid", node); - var propertyName = property.Values.OfType().FirstOrDefault()?.Text; + var propertyName = property.Values.OfType().FirstOrDefault()?.Text; if (propertyName == null) - throw new XamlIlParseException("Setter.Property must be a string", node); + throw new XamlParseException("Setter.Property must be a string", node); var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName, - new XamlIlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0]); - property.Values = new List + new XamlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0]); + property.Values = new List { avaloniaPropertyNode }; var valueProperty = on.Children - .OfType().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value"); - if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlIlAstTextNode) + .OfType().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value"); + if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlAstTextNode) { var propType = avaloniaPropertyNode.AvaloniaPropertyType; - if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0], + if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0], propType, out var converted)) - throw new XamlIlParseException( + throw new XamlParseException( $"Unable to convert property value to {propType.GetFqn()}", valueProperty.Values[0]); @@ -69,9 +73,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers return node; } - class SetterValueProperty : XamlIlAstClrProperty + class SetterValueProperty : XamlAstClrProperty { - public SetterValueProperty(IXamlIlLineInfo line, IXamlIlType setterType, IXamlIlType targetType, + public SetterValueProperty(IXamlLineInfo line, IXamlType setterType, IXamlType targetType, AvaloniaXamlIlWellKnownTypes types) : base(line, "Value", setterType, null) { @@ -82,21 +86,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers Setters.Add(new XamlIlDirectCallPropertySetter(method, targetType)); } - class XamlIlDirectCallPropertySetter : IXamlIlPropertySetter + class XamlIlDirectCallPropertySetter : IXamlPropertySetter, IXamlEmitablePropertySetter { - private readonly IXamlIlMethod _method; - private readonly IXamlIlType _type; - public IXamlIlType TargetType { get; } + private readonly IXamlMethod _method; + private readonly IXamlType _type; + public IXamlType TargetType { get; } public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters(); - public IReadOnlyList Parameters { get; } - public void Emit(IXamlIlEmitter codegen) + public IReadOnlyList Parameters { get; } + public void Emit(IXamlILEmitter codegen) { if (_type.IsValueType) codegen.Box(_type); codegen.EmitCall(_method, true); } - public XamlIlDirectCallPropertySetter(IXamlIlMethod method, IXamlIlType type) + public XamlIlDirectCallPropertySetter(IXamlMethod method, IXamlType type) { _method = method; _type = type; diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs index 548f0161d6..8e194e9385 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs @@ -1,20 +1,22 @@ using System.Collections.Generic; using System.Linq; -using XamlIl; -using XamlIl.Ast; -using XamlIl.Transform; -using XamlIl.TypeSystem; +using XamlX; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.Transform; +using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AvaloniaXamlIlTransformInstanceAttachedProperties : IXamlIlAstTransformer + class AvaloniaXamlIlTransformInstanceAttachedProperties : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlIlAstNamePropertyReference prop - && prop.TargetType is XamlIlAstClrTypeReference targetRef - && prop.DeclaringType is XamlIlAstClrTypeReference declaringRef) + if (node is XamlAstNamePropertyReference prop + && prop.TargetType is XamlAstClrTypeReference targetRef + && prop.DeclaringType is XamlAstClrTypeReference declaringRef) { // Target and declared type aren't assignable but both inherit from AvaloniaObject var avaloniaObject = context.Configuration.TypeSystem.FindType("Avalonia.AvaloniaObject"); @@ -70,21 +72,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers return node; } - class AvaloniaAttachedInstanceProperty : XamlIlAstClrProperty, IXamlIlAvaloniaProperty + class AvaloniaAttachedInstanceProperty : XamlAstClrProperty, IXamlIlAvaloniaProperty { - private readonly XamlIlTransformerConfiguration _config; - private readonly IXamlIlType _declaringType; - private readonly IXamlIlType _avaloniaPropertyType; - private readonly IXamlIlType _avaloniaObject; - private readonly IXamlIlField _field; - - public AvaloniaAttachedInstanceProperty(XamlIlAstNamePropertyReference prop, - XamlIlTransformerConfiguration config, - IXamlIlType declaringType, - IXamlIlType type, - IXamlIlType avaloniaPropertyType, - IXamlIlType avaloniaObject, - IXamlIlField field) : base(prop, prop.Name, + private readonly TransformerConfiguration _config; + private readonly IXamlType _declaringType; + private readonly IXamlType _avaloniaPropertyType; + private readonly IXamlType _avaloniaObject; + private readonly IXamlField _field; + + public AvaloniaAttachedInstanceProperty(XamlAstNamePropertyReference prop, + TransformerConfiguration config, + IXamlType declaringType, + IXamlType type, + IXamlType avaloniaPropertyType, + IXamlType avaloniaObject, + IXamlField field) : base(prop, prop.Name, declaringType, null) @@ -104,11 +106,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers Getter = new GetterMethod(this); } - public IXamlIlType PropertyType { get; } + public IXamlType PropertyType { get; } - public IXamlIlField AvaloniaProperty => _field; + public IXamlField AvaloniaProperty => _field; - class SetterMethod : IXamlIlPropertySetter + class SetterMethod : IXamlPropertySetter, IXamlEmitablePropertySetter { private readonly AvaloniaAttachedInstanceProperty _parent; @@ -118,10 +120,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers Parameters = new[] {_parent._avaloniaObject, _parent.PropertyType}; } - public IXamlIlType TargetType => _parent.DeclaringType; + public IXamlType TargetType => _parent.DeclaringType; public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters(); - public IReadOnlyList Parameters { get; } - public void Emit(IXamlIlEmitter emitter) + public IReadOnlyList Parameters { get; } + public void Emit(IXamlILEmitter emitter) { var so = _parent._config.WellKnownTypes.Object; var method = _parent._avaloniaObject @@ -133,7 +135,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers && m.Parameters[2].IsEnum ); if (method == null) - throw new XamlIlTypeSystemException( + throw new XamlTypeSystemException( "Unable to find SetValue(AvaloniaProperty, object, BindingPriority) on AvaloniaObject"); using (var loc = emitter.LocalsPool.GetLocal(_parent.PropertyType)) emitter @@ -150,7 +152,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } } - class GetterMethod : IXamlIlCustomEmitMethod + class GetterMethod : IXamlCustomEmitMethod { public GetterMethod(AvaloniaAttachedInstanceProperty parent) { @@ -163,16 +165,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public bool IsPublic => true; public bool IsStatic => true; public string Name { get; protected set; } - public IXamlIlType DeclaringType { get; } - public IXamlIlMethod MakeGenericMethod(IReadOnlyList typeArguments) + public IXamlType DeclaringType { get; } + public IXamlMethod MakeGenericMethod(IReadOnlyList typeArguments) => throw new System.NotSupportedException(); - public bool Equals(IXamlIlMethod other) => + public bool Equals(IXamlMethod other) => other is GetterMethod m && m.Name == Name && m.DeclaringType.Equals(DeclaringType); - public IXamlIlType ReturnType => Parent.PropertyType; - public IReadOnlyList Parameters { get; } - public void EmitCall(IXamlIlEmitter emitter) + public IXamlType ReturnType => Parent.PropertyType; + public IReadOnlyList Parameters { get; } + public void EmitCall(IXamlILEmitter emitter) { var method = Parent._avaloniaObject .FindMethod(m => m.IsPublic && !m.IsStatic && m.Name == "GetValue" @@ -180,7 +182,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers m.Parameters.Count == 1 && m.Parameters[0].Equals(Parent._avaloniaPropertyType)); if (method == null) - throw new XamlIlTypeSystemException( + throw new XamlTypeSystemException( "Unable to find T GetValue(AvaloniaProperty) on AvaloniaObject"); emitter .Ldsfld(Parent._field) diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs index c4136f4824..4be2fc6f60 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs @@ -1,17 +1,17 @@ -using XamlIl.Ast; -using XamlIl.Transform; +using XamlX.Ast; +using XamlX.Transform; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class AvaloniaXamlIlTransitionsTypeMetadataTransformer : IXamlIlAstTransformer + class AvaloniaXamlIlTransitionsTypeMetadataTransformer : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlIlAstObjectNode on) + if (node is XamlAstObjectNode on) { foreach (var ch in on.Children) { - if (ch is XamlIlAstXamlPropertyValueNode pn + if (ch is XamlAstXamlPropertyValueNode pn && pn.Property.GetClrProperty().Getter?.ReturnType.Equals(context.GetAvaloniaTypes().Transitions) == true) { for (var c = 0; c < pn.Values.Count; c++) diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index 1efae902c6..366ef9de10 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -1,52 +1,54 @@ -using XamlIl.Transform; -using XamlIl.TypeSystem; +using XamlX.Emit; +using XamlX.IL; +using XamlX.Transform; +using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { class AvaloniaXamlIlWellKnownTypes { - public IXamlIlType AvaloniaObject { get; } - public IXamlIlType IAvaloniaObject { get; } - public IXamlIlType BindingPriority { get; } - public IXamlIlType AvaloniaObjectExtensions { get; } - public IXamlIlType AvaloniaProperty { get; } - public IXamlIlType AvaloniaPropertyT { get; } - public IXamlIlType IBinding { get; } - public IXamlIlMethod AvaloniaObjectBindMethod { get; } - public IXamlIlMethod AvaloniaObjectSetValueMethod { get; } - public IXamlIlType IDisposable { get; } - public XamlIlTypeWellKnownTypes XamlIlTypes { get; } - public XamlIlLanguageTypeMappings XamlIlMappings { get; } - public IXamlIlType Transitions { get; } - public IXamlIlType AssignBindingAttribute { get; } - public IXamlIlType UnsetValueType { get; } - public IXamlIlType StyledElement { get; } - public IXamlIlType NameScope { get; } - public IXamlIlMethod NameScopeSetNameScope { get; } - public IXamlIlType INameScope { get; } - public IXamlIlMethod INameScopeRegister { get; } - public IXamlIlMethod INameScopeComplete { get; } + public IXamlType AvaloniaObject { get; } + public IXamlType IAvaloniaObject { get; } + public IXamlType BindingPriority { get; } + public IXamlType AvaloniaObjectExtensions { get; } + public IXamlType AvaloniaProperty { get; } + public IXamlType AvaloniaPropertyT { get; } + public IXamlType IBinding { get; } + public IXamlMethod AvaloniaObjectBindMethod { get; } + public IXamlMethod AvaloniaObjectSetValueMethod { get; } + public IXamlType IDisposable { get; } + public XamlTypeWellKnownTypes XamlIlTypes { get; } + public XamlLanguageTypeMappings XamlIlMappings { get; } + public IXamlType Transitions { get; } + public IXamlType AssignBindingAttribute { get; } + public IXamlType UnsetValueType { get; } + public IXamlType StyledElement { get; } + public IXamlType NameScope { get; } + public IXamlMethod NameScopeSetNameScope { get; } + public IXamlType INameScope { get; } + public IXamlMethod INameScopeRegister { get; } + public IXamlMethod INameScopeComplete { get; } - public AvaloniaXamlIlWellKnownTypes(XamlIlAstTransformationContext ctx) + public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration config) { - XamlIlTypes = ctx.Configuration.WellKnownTypes; - XamlIlMappings = ctx.Configuration.TypeMappings; - AvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObject"); - IAvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.IAvaloniaObject"); - AvaloniaObjectExtensions = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions"); - AvaloniaProperty = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"); - AvaloniaPropertyT = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty`1"); - BindingPriority = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.BindingPriority"); - IBinding = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.IBinding"); - IDisposable = ctx.Configuration.TypeSystem.GetType("System.IDisposable"); - Transitions = ctx.Configuration.TypeSystem.GetType("Avalonia.Animation.Transitions"); - AssignBindingAttribute = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.AssignBindingAttribute"); + XamlIlTypes = config.WellKnownTypes; + XamlIlMappings = config.TypeMappings; + AvaloniaObject = config.TypeSystem.GetType("Avalonia.AvaloniaObject"); + IAvaloniaObject = config.TypeSystem.GetType("Avalonia.IAvaloniaObject"); + AvaloniaObjectExtensions = config.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions"); + AvaloniaProperty = config.TypeSystem.GetType("Avalonia.AvaloniaProperty"); + AvaloniaPropertyT = config.TypeSystem.GetType("Avalonia.AvaloniaProperty`1"); + BindingPriority = config.TypeSystem.GetType("Avalonia.Data.BindingPriority"); + IBinding = config.TypeSystem.GetType("Avalonia.Data.IBinding"); + IDisposable = config.TypeSystem.GetType("System.IDisposable"); + Transitions = config.TypeSystem.GetType("Avalonia.Animation.Transitions"); + AssignBindingAttribute = config.TypeSystem.GetType("Avalonia.Data.AssignBindingAttribute"); AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, IAvaloniaObject, AvaloniaProperty, - IBinding, ctx.Configuration.WellKnownTypes.Object); - UnsetValueType = ctx.Configuration.TypeSystem.GetType("Avalonia.UnsetValueType"); - StyledElement = ctx.Configuration.TypeSystem.GetType("Avalonia.StyledElement"); - INameScope = ctx.Configuration.TypeSystem.GetType("Avalonia.Controls.INameScope"); + IBinding, config.WellKnownTypes.Object); + UnsetValueType = config.TypeSystem.GetType("Avalonia.UnsetValueType"); + StyledElement = config.TypeSystem.GetType("Avalonia.StyledElement"); + INameScope = config.TypeSystem.GetType("Avalonia.Controls.INameScope"); INameScopeRegister = INameScope.GetMethod( new FindMethodMethodSignature("Register", XamlIlTypes.Void, XamlIlTypes.String, XamlIlTypes.Object) @@ -58,7 +60,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { IsStatic = false, DeclaringOnly = true, IsExactMatch = true }); - NameScope = ctx.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScope"); + NameScope = config.TypeSystem.GetType("Avalonia.Controls.NameScope"); NameScopeSetNameScope = NameScope.GetMethod(new FindMethodMethodSignature("SetNameScope", XamlIlTypes.Void, StyledElement, INameScope) {IsStatic = true}); @@ -70,11 +72,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers static class AvaloniaXamlIlWellKnownTypesExtensions { - public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this XamlIlAstTransformationContext ctx) + public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this AstTransformationContext ctx) { if (ctx.TryGetItem(out var rv)) return rv; - ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx)); + ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx.Configuration)); + return rv; + } + + public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this XamlEmitContext ctx) + { + if (ctx.TryGetItem(out var rv)) + return rv; + ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx.Configuration)); return rv; } } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs index a79a4977ef..1f2508715e 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs @@ -1,17 +1,17 @@ using System.Linq; -using XamlIl; -using XamlIl.Ast; -using XamlIl.Transform; +using XamlX; +using XamlX.Ast; +using XamlX.Transform; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class IgnoredDirectivesTransformer : IXamlIlAstTransformer + class IgnoredDirectivesTransformer : IXamlAstTransformer { - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlIlAstObjectNode no) + if (node is XamlAstObjectNode no) { - foreach (var d in no.Children.OfType().ToList()) + foreach (var d in no.Children.OfType().ToList()) { if (d.Namespace == XamlNamespaces.Xaml2006) { diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs index dd64ab542a..f4eb7cf5f9 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs @@ -1,30 +1,29 @@ -using XamlIl; -using XamlIl.Ast; -using XamlIl.Transform; +using XamlX; +using XamlX.Ast; +using XamlX.Transform; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { - class XNameTransformer : IXamlIlAstTransformer + class XNameTransformer : IXamlAstTransformer { - /// /// Converts x:Name directives to regular Name assignments /// /// - public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlIlAstObjectNode on) + if (node is XamlAstObjectNode on) { for (var c =0; c< on.Children.Count;c++) { var ch = on.Children[c]; - if (ch is XamlIlAstXmlDirective d + if (ch is XamlAstXmlDirective d && d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Name") - on.Children[c] = new XamlIlAstXamlPropertyValueNode(d, - new XamlIlAstNamePropertyReference(d, on.Type, "Name", on.Type), + on.Children[c] = new XamlAstXamlPropertyValueNode(d, + new XamlAstNamePropertyReference(d, on.Type, "Name", on.Type), d.Values); } } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs index 6fc83cb5a5..a3a484d7f1 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs @@ -5,17 +5,22 @@ using System.Xml; using Avalonia.Markup.Xaml.Parsers; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; using Avalonia.Utilities; -using XamlIl; -using XamlIl.Ast; -using XamlIl.Transform; -using XamlIl.Transform.Transformers; -using XamlIl.TypeSystem; +using XamlX; +using XamlX.Ast; +using XamlX.Transform; +using XamlX.Transform.Transformers; +using XamlX.TypeSystem; +using XamlX.Emit; +using XamlX.IL; + +using XamlIlEmitContext = XamlX.Emit.XamlEmitContext; +using IXamlIlAstEmitableNode = XamlX.Emit.IXamlAstEmitableNode; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions { class XamlIlAvaloniaPropertyHelper { - public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, XamlIlAstClrProperty property) + public static bool Emit(XamlIlEmitContext context, IXamlILEmitter emitter, XamlAstClrProperty property) { if (property is IXamlIlAvaloniaProperty ap) { @@ -32,7 +37,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return true; } - public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, IXamlIlProperty property) + public static bool Emit(XamlIlEmitContext context, IXamlILEmitter emitter, IXamlProperty property) { var type = (property.Getter ?? property.Setter).DeclaringType; var name = property.Name + "Property"; @@ -44,16 +49,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return true; } - public static IXamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context, - string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo) + public static IXamlIlAvaloniaPropertyNode CreateNode(AstTransformationContext context, + string propertyName, IXamlAstTypeReference selectorTypeReference, IXamlLineInfo lineInfo) { - XamlIlAstNamePropertyReference forgedReference; + XamlAstNamePropertyReference forgedReference; var parser = new PropertyParser(); var parsedPropertyName = parser.Parse(new CharacterReader(propertyName.AsSpan())); if(parsedPropertyName.owner == null) - forgedReference = new XamlIlAstNamePropertyReference(lineInfo, selectorTypeReference, + forgedReference = new XamlAstNamePropertyReference(lineInfo, selectorTypeReference, propertyName, selectorTypeReference); else { @@ -62,19 +67,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions xmlOwner += ":"; xmlOwner += parsedPropertyName.owner; - var tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true); + var tref = TypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true); var propertyFieldName = parsedPropertyName.name + "Property"; var found = tref.Type.GetAllFields() .FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == propertyFieldName); if (found == null) - throw new XamlIlParseException( + throw new XamlX.XamlParseException( $"Unable to find {propertyFieldName} field on type {tref.Type.GetFullName()}", lineInfo); return new XamlIlAvaloniaPropertyFieldNode(context.GetAvaloniaTypes(), lineInfo, found); } var clrProperty = - ((XamlIlAstClrProperty)new XamlIlPropertyReferenceResolver().Transform(context, + ((XamlAstClrProperty)new PropertyReferenceResolver().Transform(context, forgedReference)); return new XamlIlAvaloniaPropertyNode(lineInfo, context.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"), @@ -82,40 +87,40 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions } } - interface IXamlIlAvaloniaPropertyNode : IXamlIlAstValueNode + interface IXamlIlAvaloniaPropertyNode : IXamlAstValueNode { - IXamlIlType AvaloniaPropertyType { get; } + IXamlType AvaloniaPropertyType { get; } } - class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode + class XamlIlAvaloniaPropertyNode : XamlAstNode, IXamlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode { - public XamlIlAvaloniaPropertyNode(IXamlIlLineInfo lineInfo, IXamlIlType type, XamlIlAstClrProperty property) : base(lineInfo) + public XamlIlAvaloniaPropertyNode(IXamlLineInfo lineInfo, IXamlType type, XamlAstClrProperty property) : base(lineInfo) { - Type = new XamlIlAstClrTypeReference(this, type, false); + Type = new XamlAstClrTypeReference(this, type, false); Property = property; AvaloniaPropertyType = Property.Getter?.ReturnType ?? Property.Setters.First().Parameters[0]; } - public XamlIlAstClrProperty Property { get; } + public XamlAstClrProperty Property { get; } - public IXamlIlAstTypeReference Type { get; } - public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public IXamlAstTypeReference Type { get; } + public XamlILNodeEmitResult Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) { if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property)) - throw new XamlIlLoadException(Property.Name + " is not an AvaloniaProperty", this); - return XamlIlNodeEmitResult.Type(0, Type.GetClrType()); + throw new XamlX.XamlLoadException(Property.Name + " is not an AvaloniaProperty", this); + return XamlILNodeEmitResult.Type(0, Type.GetClrType()); } - public IXamlIlType AvaloniaPropertyType { get; } + public IXamlType AvaloniaPropertyType { get; } } - class XamlIlAvaloniaPropertyFieldNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode + class XamlIlAvaloniaPropertyFieldNode : XamlAstNode, IXamlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode { - private readonly IXamlIlField _field; + private readonly IXamlField _field; public XamlIlAvaloniaPropertyFieldNode(AvaloniaXamlIlWellKnownTypes types, - IXamlIlLineInfo lineInfo, IXamlIlField field) : base(lineInfo) + IXamlLineInfo lineInfo, IXamlField field) : base(lineInfo) { _field = field; var avaloniaPropertyType = field.FieldType; @@ -130,7 +135,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions avaloniaPropertyType = avaloniaPropertyType.BaseType; } - throw new XamlIlParseException( + throw new XamlX.XamlParseException( $"{field.Name}'s type {field.FieldType} doesn't inherit from AvaloniaProperty, make sure to use typed properties", lineInfo); @@ -138,25 +143,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions - public IXamlIlAstTypeReference Type => new XamlIlAstClrTypeReference(this, _field.FieldType, false); - public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public IXamlAstTypeReference Type => new XamlAstClrTypeReference(this, _field.FieldType, false); + public XamlILNodeEmitResult Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) { codeGen.Ldsfld(_field); - return XamlIlNodeEmitResult.Type(0, _field.FieldType); + return XamlILNodeEmitResult.Type(0, _field.FieldType); } - public IXamlIlType AvaloniaPropertyType { get; } + public IXamlType AvaloniaPropertyType { get; } } interface IXamlIlAvaloniaProperty { - IXamlIlField AvaloniaProperty { get; } + IXamlField AvaloniaProperty { get; } } - class XamlIlAvaloniaProperty : XamlIlAstClrProperty, IXamlIlAvaloniaProperty + class XamlIlAvaloniaProperty : XamlAstClrProperty, IXamlIlAvaloniaProperty { - public IXamlIlField AvaloniaProperty { get; } - public XamlIlAvaloniaProperty(XamlIlAstClrProperty original, IXamlIlField field, + public IXamlField AvaloniaProperty { get; } + public XamlIlAvaloniaProperty(XamlAstClrProperty original, IXamlField field, AvaloniaXamlIlWellKnownTypes types) :base(original, original.Name, original.DeclaringType, original.Getter, original.Setters) { @@ -168,41 +173,41 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions Setters.Insert(0, new UnsetValueSetter(types, original.DeclaringType, field)); } - abstract class AvaloniaPropertyCustomSetter : IXamlIlPropertySetter + abstract class AvaloniaPropertyCustomSetter : IXamlPropertySetter, IXamlEmitablePropertySetter { protected AvaloniaXamlIlWellKnownTypes Types; - protected IXamlIlField AvaloniaProperty; + protected IXamlField AvaloniaProperty; public AvaloniaPropertyCustomSetter(AvaloniaXamlIlWellKnownTypes types, - IXamlIlType declaringType, - IXamlIlField avaloniaProperty) + IXamlType declaringType, + IXamlField avaloniaProperty) { Types = types; AvaloniaProperty = avaloniaProperty; TargetType = declaringType; } - public IXamlIlType TargetType { get; } + public IXamlType TargetType { get; } public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters { AllowXNull = false }; - public IReadOnlyList Parameters { get; set; } - public abstract void Emit(IXamlIlEmitter codegen); + public IReadOnlyList Parameters { get; set; } + public abstract void Emit(IXamlILEmitter codegen); } class BindingSetter : AvaloniaPropertyCustomSetter { public BindingSetter(AvaloniaXamlIlWellKnownTypes types, - IXamlIlType declaringType, - IXamlIlField avaloniaProperty) : base(types, declaringType, avaloniaProperty) + IXamlType declaringType, + IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty) { Parameters = new[] {types.IBinding}; } - public override void Emit(IXamlIlEmitter emitter) + public override void Emit(IXamlILEmitter emitter) { using (var bloc = emitter.LocalsPool.GetLocal(Types.IBinding)) emitter @@ -217,13 +222,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions class UnsetValueSetter : AvaloniaPropertyCustomSetter { - public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlIlType declaringType, IXamlIlField avaloniaProperty) + public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty) { Parameters = new[] {types.UnsetValueType}; } - public override void Emit(IXamlIlEmitter codegen) + public override void Emit(IXamlILEmitter codegen) { var unsetValue = Types.AvaloniaProperty.Fields.First(f => f.Name == "UnsetValue"); codegen diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github index 0681622454..32702e32fa 160000 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github @@ -1 +1 @@ -Subproject commit 068162245473ec39ee36da12150e928072b96403 +Subproject commit 32702e32fabf2ddda28a740d8e17937678d57344 From 5ed9f0f42038e5f1e786afb12ce811b20c2c2682 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jul 2020 15:09:06 -0300 Subject: [PATCH 79/98] fix some nits --- src/Avalonia.Controls/Window.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 14b2568222..3b36cad649 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -72,8 +72,9 @@ namespace Avalonia.Controls { private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>(); private TitleBar _managedTitleBar; - private bool _isExtendedIntoWindowDecorations; + private Thickness _windowDecorationMargins; + private Thickness _offScreenMargin; /// /// Defines the property. @@ -318,17 +319,13 @@ namespace Avalonia.Controls { get => _isExtendedIntoWindowDecorations; private set => SetAndRaise(IsExtendedIntoWindowDecorationsProperty, ref _isExtendedIntoWindowDecorations, value); - } - - private Thickness _windowDecorationMargins; + } public Thickness WindowDecorationMargins { get => _windowDecorationMargins; private set => SetAndRaise(WindowDecorationMarginsProperty, ref _windowDecorationMargins, value); - } - - private Thickness _offScreenMargin; + } public Thickness OffScreenMargin { @@ -542,7 +539,7 @@ namespace Avalonia.Controls OffScreenMargin = PlatformImpl.OffScreenMargin; - if(PlatformImpl.NeedsManagedDecorations) + if (PlatformImpl.NeedsManagedDecorations) { if (_managedTitleBar == null) { From 9f64463060bb6a6214b48faffcda5f86f88de0e4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jul 2020 15:17:10 -0300 Subject: [PATCH 80/98] fix nits. --- .../Chrome/CaptionButtons.cs | 10 ++-- src/Avalonia.Controls/Chrome/TitleBar.cs | 32 +++++----- src/Avalonia.Controls/Platform/IWindowImpl.cs | 60 +++++++++---------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs index 58f5b09c0d..cc49b8b643 100644 --- a/src/Avalonia.Controls/Chrome/CaptionButtons.cs +++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs @@ -38,7 +38,7 @@ namespace Avalonia.Controls.Chrome { var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - layer.Children.Remove(this); + layer?.Children.Remove(this); _disposables.Dispose(); _disposables = null; @@ -49,10 +49,10 @@ namespace Avalonia.Controls.Chrome { base.OnApplyTemplate(e); - var closeButton = e.NameScope.Find("PART_CloseButton"); - var restoreButton = e.NameScope.Find("PART_RestoreButton"); - var minimiseButton = e.NameScope.Find("PART_MinimiseButton"); - var fullScreenButton = e.NameScope.Find("PART_FullScreenButton"); + var closeButton = e.NameScope.Get("PART_CloseButton"); + var restoreButton = e.NameScope.Get("PART_RestoreButton"); + var minimiseButton = e.NameScope.Get("PART_MinimiseButton"); + var fullScreenButton = e.NameScope.Get("PART_FullScreenButton"); closeButton.PointerReleased += (sender, e) => _hostWindow.Close(); restoreButton.PointerReleased += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index 8e8010d3d4..70ab172cc6 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -26,36 +26,36 @@ namespace Avalonia.Controls.Chrome { var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - layer.Children.Add(this); + layer?.Children.Add(this); _disposables = new CompositeDisposable { _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) - .Subscribe(x => InvalidateSize()), + .Subscribe(x => UpdateSize()), _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) - .Subscribe(x => InvalidateSize()), + .Subscribe(x => UpdateSize()), _hostWindow.GetObservable(Window.OffScreenMarginProperty) - .Subscribe(x => InvalidateSize()), + .Subscribe(x => UpdateSize()), _hostWindow.GetObservable(Window.WindowStateProperty) - .Subscribe(x => - { - PseudoClasses.Set(":minimized", x == WindowState.Minimized); - PseudoClasses.Set(":normal", x == WindowState.Normal); - PseudoClasses.Set(":maximized", x == WindowState.Maximized); - PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); - }) + .Subscribe(x => + { + PseudoClasses.Set(":minimized", x == WindowState.Minimized); + PseudoClasses.Set(":normal", x == WindowState.Normal); + PseudoClasses.Set(":maximized", x == WindowState.Maximized); + PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); + }) }; _captionButtons?.Attach(_hostWindow); - InvalidateSize(); + UpdateSize(); } } - void InvalidateSize() + void UpdateSize() { Margin = new Thickness( _hostWindow.OffScreenMargin.Left, @@ -80,7 +80,7 @@ namespace Avalonia.Controls.Chrome { var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - layer.Children.Remove(this); + layer?.Children.Remove(this); _disposables.Dispose(); _disposables = null; @@ -93,11 +93,11 @@ namespace Avalonia.Controls.Chrome { base.OnApplyTemplate(e); - _captionButtons = e.NameScope.Find("PART_CaptionButtons"); + _captionButtons = e.NameScope.Get("PART_CaptionButtons"); _captionButtons.Attach(_hostWindow); - InvalidateSize(); + UpdateSize(); } } } diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 43647dc7d0..8a1554d344 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -68,6 +68,34 @@ namespace Avalonia.Platform /// Func Closing { get; set; } + /// + /// Gets a value to indicate if the platform was able to extend client area to non-client area. + /// + bool IsClientAreaExtendedToDecorations { get; } + + /// + /// Gets or Sets an action that is called whenever one of the extend client area properties changed. + /// + Action ExtendClientAreaToDecorationsChanged { get; set; } + + /// + /// Gets a flag that indicates if Managed decorations i.e. caption buttons are required. + /// This property is used when is set. + /// + bool NeedsManagedDecorations { get; } + + /// + /// Gets a thickness that describes the amount each side of the non-client area extends into the client area. + /// It includes the titlebar. + /// + Thickness ExtendedMargins { get; } + + /// + /// Gets a thickness that describes the margin around the window that is offscreen. + /// This may happen when a window is maximized and is set. + /// + Thickness OffScreenMargin { get; } + /// /// Starts moving a window with left button being held. Should be called from left mouse button press event handler. /// @@ -99,12 +127,7 @@ namespace Avalonia.Platform /// Sets if the ClientArea is extended into the non-client area. /// /// true to enable, false to disable - void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint); - - /// - /// Gets a value to indicate if the platform was able to extend client area to non-client area. - /// - bool IsClientAreaExtendedToDecorations { get; } + void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint); /// /// Sets hints that configure how the client area extends. @@ -116,29 +139,6 @@ namespace Avalonia.Platform /// Sets how big the non-client titlebar area should be. /// /// -1 for platform default, otherwise the height in DIPs. - void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight); - - /// - /// Gets or Sets an action that is called whenever one of the extend client area properties changed. - /// - Action ExtendClientAreaToDecorationsChanged { get; set; } - - /// - /// Gets a flag that indicates if Managed decorations i.e. caption buttons are required. - /// This property is used when is set. - /// - bool NeedsManagedDecorations { get; } - - /// - /// Gets a thickness that describes the amount each side of the non-client area extends into the client area. - /// It includes the titlebar. - /// - Thickness ExtendedMargins { get; } - - /// - /// Gets a thickness that describes the margin around the window that is offscreen. - /// This may happen when a window is maximized and is set. - /// - Thickness OffScreenMargin { get; } + void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight); } } From d75ca95648c0893954805c763165ef949ea6eece Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jul 2020 15:27:13 -0300 Subject: [PATCH 81/98] add nullable and null checks on titlebar. --- src/Avalonia.Controls/Chrome/TitleBar.cs | 76 +++++++++++++----------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index 70ab172cc6..5e7bd8bebe 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -4,11 +4,13 @@ using Avalonia.Controls.Primitives; namespace Avalonia.Controls.Chrome { +#nullable enable + public class TitleBar : TemplatedControl { - private CompositeDisposable _disposables; - private Window _hostWindow; - private CaptionButtons _captionButtons; + private CompositeDisposable? _disposables; + private Window? _hostWindow; + private CaptionButtons? _captionButtons; public TitleBar(Window hostWindow) { @@ -28,28 +30,31 @@ namespace Avalonia.Controls.Chrome layer?.Children.Add(this); - _disposables = new CompositeDisposable + if (_hostWindow != null) { - _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) - .Subscribe(x => UpdateSize()), - - _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) - .Subscribe(x => UpdateSize()), - - _hostWindow.GetObservable(Window.OffScreenMarginProperty) - .Subscribe(x => UpdateSize()), - - _hostWindow.GetObservable(Window.WindowStateProperty) - .Subscribe(x => - { - PseudoClasses.Set(":minimized", x == WindowState.Minimized); - PseudoClasses.Set(":normal", x == WindowState.Normal); - PseudoClasses.Set(":maximized", x == WindowState.Maximized); - PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); - }) - }; - - _captionButtons?.Attach(_hostWindow); + _disposables = new CompositeDisposable + { + _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) + .Subscribe(x => UpdateSize()), + + _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) + .Subscribe(x => UpdateSize()), + + _hostWindow.GetObservable(Window.OffScreenMarginProperty) + .Subscribe(x => UpdateSize()), + + _hostWindow.GetObservable(Window.WindowStateProperty) + .Subscribe(x => + { + PseudoClasses.Set(":minimized", x == WindowState.Minimized); + PseudoClasses.Set(":normal", x == WindowState.Normal); + PseudoClasses.Set(":maximized", x == WindowState.Maximized); + PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); + }) + }; + + _captionButtons?.Attach(_hostWindow); + } UpdateSize(); } @@ -57,19 +62,22 @@ namespace Avalonia.Controls.Chrome void UpdateSize() { - Margin = new Thickness( - _hostWindow.OffScreenMargin.Left, - _hostWindow.OffScreenMargin.Top, - _hostWindow.OffScreenMargin.Right, - _hostWindow.OffScreenMargin.Bottom); - - if (_hostWindow.WindowState != WindowState.FullScreen) + if (_hostWindow != null) { - Height = _hostWindow.WindowDecorationMargins.Top; + Margin = new Thickness( + _hostWindow.OffScreenMargin.Left, + _hostWindow.OffScreenMargin.Top, + _hostWindow.OffScreenMargin.Right, + _hostWindow.OffScreenMargin.Bottom); - if (_captionButtons != null) + if (_hostWindow.WindowState != WindowState.FullScreen) { - _captionButtons.Height = Height; + Height = _hostWindow.WindowDecorationMargins.Top; + + if (_captionButtons != null) + { + _captionButtons.Height = Height; + } } } } From 0b9a4fc3ab9f11563e4abf05c5778e8062a65809 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jul 2020 15:33:23 -0300 Subject: [PATCH 82/98] nullable and null checks on titlebar / captionbuttons. --- .../Chrome/CaptionButtons.cs | 38 ++++++++++++++----- src/Avalonia.Controls/Chrome/TitleBar.cs | 5 ++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs index cc49b8b643..a66eb853cd 100644 --- a/src/Avalonia.Controls/Chrome/CaptionButtons.cs +++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs @@ -1,16 +1,15 @@ using System; -using System.Collections.Generic; using System.Reactive.Disposables; -using System.Text; using Avalonia.Controls.Primitives; -using Avalonia.VisualTree; namespace Avalonia.Controls.Chrome { +#nullable enable + public class CaptionButtons : TemplatedControl { - private CompositeDisposable _disposables; - private Window _hostWindow; + private CompositeDisposable? _disposables; + private Window? _hostWindow; public void Attach(Window hostWindow) { @@ -54,10 +53,31 @@ namespace Avalonia.Controls.Chrome var minimiseButton = e.NameScope.Get("PART_MinimiseButton"); var fullScreenButton = e.NameScope.Get("PART_FullScreenButton"); - closeButton.PointerReleased += (sender, e) => _hostWindow.Close(); - restoreButton.PointerReleased += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; - minimiseButton.PointerReleased += (sender, e) => _hostWindow.WindowState = WindowState.Minimized; - fullScreenButton.PointerReleased += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen; + closeButton.PointerReleased += (sender, e) => _hostWindow?.Close(); + + restoreButton.PointerReleased += (sender, e) => + { + if (_hostWindow != null) + { + _hostWindow.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; + } + }; + + minimiseButton.PointerReleased += (sender, e) => + { + if (_hostWindow != null) + { + _hostWindow.WindowState = WindowState.Minimized; + } + }; + + fullScreenButton.PointerReleased += (sender, e) => + { + if (_hostWindow != null) + { + _hostWindow.WindowState = _hostWindow.WindowState == WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen; + } + }; } } } diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index 5e7bd8bebe..c3b4dbf3ea 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -103,7 +103,10 @@ namespace Avalonia.Controls.Chrome _captionButtons = e.NameScope.Get("PART_CaptionButtons"); - _captionButtons.Attach(_hostWindow); + if (_hostWindow != null) + { + _captionButtons.Attach(_hostWindow); + } UpdateSize(); } From 928189c8420498bc6c310dc27ee9790a0c3d92ab Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jul 2020 15:42:55 -0300 Subject: [PATCH 83/98] nits --- src/Avalonia.Controls/Chrome/CaptionButtons.cs | 7 +++++-- src/Avalonia.Controls/Chrome/TitleBar.cs | 11 +++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs index a66eb853cd..75d6c366b8 100644 --- a/src/Avalonia.Controls/Chrome/CaptionButtons.cs +++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs @@ -2,10 +2,13 @@ using System.Reactive.Disposables; using Avalonia.Controls.Primitives; -namespace Avalonia.Controls.Chrome -{ #nullable enable +namespace Avalonia.Controls.Chrome +{ + /// + /// Draws window minimize / maximize / close buttons in a when managed client decorations are enabled. + /// public class CaptionButtons : TemplatedControl { private CompositeDisposable? _disposables; diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index c3b4dbf3ea..b044ffc59c 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -2,14 +2,17 @@ using System.Reactive.Disposables; using Avalonia.Controls.Primitives; -namespace Avalonia.Controls.Chrome -{ #nullable enable +namespace Avalonia.Controls.Chrome +{ + /// + /// Draws a titlebar when managed client decorations are enabled. + /// public class TitleBar : TemplatedControl { private CompositeDisposable? _disposables; - private Window? _hostWindow; + private readonly Window? _hostWindow; private CaptionButtons? _captionButtons; public TitleBar(Window hostWindow) @@ -60,7 +63,7 @@ namespace Avalonia.Controls.Chrome } } - void UpdateSize() + private void UpdateSize() { if (_hostWindow != null) { From a8aff643f009af65c295c6f788b6897a5dbe6ea2 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 2 Jul 2020 12:44:03 -0300 Subject: [PATCH 84/98] fix more nits. --- samples/ControlCatalog/MainWindow.xaml | 2 +- samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml | 2 +- src/Avalonia.Controls/Window.cs | 4 ---- src/Avalonia.Native/WindowImpl.cs | 4 ++-- src/Avalonia.Native/WindowImplBase.cs | 2 +- src/Avalonia.Themes.Default/CaptionButtons.xaml | 3 +-- src/Avalonia.Themes.Fluent/CaptionButtons.xaml | 3 +-- src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs | 2 +- 8 files changed, 8 insertions(+), 14 deletions(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 157df05030..121878423a 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -84,7 +84,7 @@ - + diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml index db2a8a465a..b90f43c3b6 100644 --- a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml +++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml @@ -6,7 +6,7 @@ x:Class="ControlCatalog.Pages.WindowCustomizationsPage"> - + diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 3b36cad649..5ef26f1b27 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -104,7 +104,6 @@ namespace Avalonia.Controls public static readonly StyledProperty ExtendClientAreaTitleBarHeightHintProperty = AvaloniaProperty.Register(nameof(ExtendClientAreaTitleBarHeightHint), -1); - /// /// Defines the property. /// @@ -124,7 +123,6 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect(nameof(OffScreenMargin), o => o.OffScreenMargin); - /// /// Defines the property. /// @@ -534,9 +532,7 @@ namespace Avalonia.Controls protected virtual void ExtendClientAreaToDecorationsChanged(bool isExtended) { IsExtendedIntoWindowDecorations = isExtended; - WindowDecorationMargins = PlatformImpl.ExtendedMargins; - OffScreenMargin = PlatformImpl.OffScreenMargin; if (PlatformImpl.NeedsManagedDecorations) diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index ef2bd32bfc..885591495b 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -138,9 +138,9 @@ namespace Avalonia.Native return false; } - private void InvalidateExtendedMargins () + private void InvalidateExtendedMargins() { - if(WindowState == WindowState.FullScreen) + if (WindowState == WindowState.FullScreen) { ExtendedMargins = new Thickness(); } diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index aac4b1a5dd..f19f9e97aa 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -266,7 +266,7 @@ namespace Avalonia.Native return args.Handled; } - protected virtual bool ChromeHitTest (RawPointerEventArgs e) + protected virtual bool ChromeHitTest(RawPointerEventArgs e) { return false; } diff --git a/src/Avalonia.Themes.Default/CaptionButtons.xaml b/src/Avalonia.Themes.Default/CaptionButtons.xaml index 282448bdd5..68249905a1 100644 --- a/src/Avalonia.Themes.Default/CaptionButtons.xaml +++ b/src/Avalonia.Themes.Default/CaptionButtons.xaml @@ -1,7 +1,6 @@ + diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index b044ffc59c..f48ca4e4e8 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -14,28 +14,32 @@ namespace Avalonia.Controls.Chrome private CompositeDisposable? _disposables; private readonly Window? _hostWindow; private CaptionButtons? _captionButtons; + private Panel _underlay; - public TitleBar(Window hostWindow) + public TitleBar(Window hostWindow) : this() { _hostWindow = hostWindow; } public TitleBar() { - + _underlay = new Panel + { + IsHitTestVisible = false, + [~Panel.BackgroundProperty] = this[~BackgroundProperty], + VerticalAlignment = Layout.VerticalAlignment.Top + }; } public void Attach() { - if (_disposables == null) + if (_disposables == null && _hostWindow != null) { - var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + var overlay = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - layer?.Children.Add(this); + overlay?.Children.Add(this); - if (_hostWindow != null) - { - _disposables = new CompositeDisposable + _disposables = new CompositeDisposable { _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) .Subscribe(x => UpdateSize()), @@ -56,11 +60,15 @@ namespace Avalonia.Controls.Chrome }) }; - _captionButtons?.Attach(_hostWindow); - } + _captionButtons?.Attach(_hostWindow); + + var underlay = ChromeUnderlayLayer.GetUnderlayLayer(_hostWindow); + + underlay?.Children.Add(_underlay); UpdateSize(); } + } private void UpdateSize() @@ -76,6 +84,7 @@ namespace Avalonia.Controls.Chrome if (_hostWindow.WindowState != WindowState.FullScreen) { Height = _hostWindow.WindowDecorationMargins.Top; + _underlay.Height = Height; if (_captionButtons != null) { @@ -89,9 +98,14 @@ namespace Avalonia.Controls.Chrome { if (_disposables != null) { - var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + if (_hostWindow != null) + { + var overlay = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + overlay?.Children.Remove(this); - layer?.Children.Remove(this); + var underlay = ChromeUnderlayLayer.GetUnderlayLayer(_hostWindow); + underlay?.Children.Remove(_underlay); + } _disposables.Dispose(); _disposables = null; diff --git a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs index ba0fdfd535..2313222bd3 100644 --- a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs +++ b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs @@ -6,6 +6,27 @@ using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives { + public class ChromeUnderlayLayer : Panel, ICustomSimpleHitTest + { + public static ChromeUnderlayLayer? GetUnderlayLayer(IVisual visual) + { + foreach (var v in visual.GetVisualAncestors()) + if (v is VisualLayerManager vlm) + if (vlm.OverlayLayer != null) + return vlm.ChromeUnderlayLayer; + + if (visual is TopLevel tl) + { + var layers = tl.GetVisualDescendants().OfType().FirstOrDefault(); + return layers?.ChromeUnderlayLayer; + } + + return null; + } + + public bool HitTest(Point point) => Children.HitTestCustom(point); + } + public class ChromeOverlayLayer : Panel, ICustomSimpleHitTest { public static ChromeOverlayLayer? GetOverlayLayer(IVisual visual) diff --git a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs index 3084d7fa72..0213c53c57 100644 --- a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs +++ b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs @@ -8,6 +8,7 @@ namespace Avalonia.Controls.Primitives private const int AdornerZIndex = int.MaxValue - 100; private const int ChromeZIndex = int.MaxValue - 99; private const int OverlayZIndex = int.MaxValue - 98; + private const int UnderlayZIndex = int.MinValue; private ILogicalRoot _logicalRoot; private readonly List _layers = new List(); @@ -26,6 +27,17 @@ namespace Avalonia.Controls.Primitives } } + public ChromeUnderlayLayer ChromeUnderlayLayer + { + get + { + var rv = FindLayer(); + if (rv == null) + AddLayer(rv = new ChromeUnderlayLayer(), UnderlayZIndex); + return rv; + } + } + public ChromeOverlayLayer ChromeOverlayLayer { get diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml index 45798d3fa1..72998583b8 100644 --- a/src/Avalonia.Themes.Fluent/TitleBar.xaml +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -14,7 +14,7 @@ - + diff --git a/src/Avalonia.Themes.Fluent/Window.xaml b/src/Avalonia.Themes.Fluent/Window.xaml index aee15347eb..086b05bb01 100644 --- a/src/Avalonia.Themes.Fluent/Window.xaml +++ b/src/Avalonia.Themes.Fluent/Window.xaml @@ -1,11 +1,11 @@ - diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index f48ca4e4e8..b044ffc59c 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -14,32 +14,28 @@ namespace Avalonia.Controls.Chrome private CompositeDisposable? _disposables; private readonly Window? _hostWindow; private CaptionButtons? _captionButtons; - private Panel _underlay; - public TitleBar(Window hostWindow) : this() + public TitleBar(Window hostWindow) { _hostWindow = hostWindow; } public TitleBar() { - _underlay = new Panel - { - IsHitTestVisible = false, - [~Panel.BackgroundProperty] = this[~BackgroundProperty], - VerticalAlignment = Layout.VerticalAlignment.Top - }; + } public void Attach() { - if (_disposables == null && _hostWindow != null) + if (_disposables == null) { - var overlay = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - overlay?.Children.Add(this); + layer?.Children.Add(this); - _disposables = new CompositeDisposable + if (_hostWindow != null) + { + _disposables = new CompositeDisposable { _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) .Subscribe(x => UpdateSize()), @@ -60,15 +56,11 @@ namespace Avalonia.Controls.Chrome }) }; - _captionButtons?.Attach(_hostWindow); - - var underlay = ChromeUnderlayLayer.GetUnderlayLayer(_hostWindow); - - underlay?.Children.Add(_underlay); + _captionButtons?.Attach(_hostWindow); + } UpdateSize(); } - } private void UpdateSize() @@ -84,7 +76,6 @@ namespace Avalonia.Controls.Chrome if (_hostWindow.WindowState != WindowState.FullScreen) { Height = _hostWindow.WindowDecorationMargins.Top; - _underlay.Height = Height; if (_captionButtons != null) { @@ -98,14 +89,9 @@ namespace Avalonia.Controls.Chrome { if (_disposables != null) { - if (_hostWindow != null) - { - var overlay = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - overlay?.Children.Remove(this); + var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - var underlay = ChromeUnderlayLayer.GetUnderlayLayer(_hostWindow); - underlay?.Children.Remove(_underlay); - } + layer?.Children.Remove(this); _disposables.Dispose(); _disposables = null; diff --git a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs index 2313222bd3..ba0fdfd535 100644 --- a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs +++ b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs @@ -6,27 +6,6 @@ using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives { - public class ChromeUnderlayLayer : Panel, ICustomSimpleHitTest - { - public static ChromeUnderlayLayer? GetUnderlayLayer(IVisual visual) - { - foreach (var v in visual.GetVisualAncestors()) - if (v is VisualLayerManager vlm) - if (vlm.OverlayLayer != null) - return vlm.ChromeUnderlayLayer; - - if (visual is TopLevel tl) - { - var layers = tl.GetVisualDescendants().OfType().FirstOrDefault(); - return layers?.ChromeUnderlayLayer; - } - - return null; - } - - public bool HitTest(Point point) => Children.HitTestCustom(point); - } - public class ChromeOverlayLayer : Panel, ICustomSimpleHitTest { public static ChromeOverlayLayer? GetOverlayLayer(IVisual visual) diff --git a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs index 0213c53c57..3084d7fa72 100644 --- a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs +++ b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs @@ -8,7 +8,6 @@ namespace Avalonia.Controls.Primitives private const int AdornerZIndex = int.MaxValue - 100; private const int ChromeZIndex = int.MaxValue - 99; private const int OverlayZIndex = int.MaxValue - 98; - private const int UnderlayZIndex = int.MinValue; private ILogicalRoot _logicalRoot; private readonly List _layers = new List(); @@ -27,17 +26,6 @@ namespace Avalonia.Controls.Primitives } } - public ChromeUnderlayLayer ChromeUnderlayLayer - { - get - { - var rv = FindLayer(); - if (rv == null) - AddLayer(rv = new ChromeUnderlayLayer(), UnderlayZIndex); - return rv; - } - } - public ChromeOverlayLayer ChromeOverlayLayer { get diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml index 72998583b8..45798d3fa1 100644 --- a/src/Avalonia.Themes.Fluent/TitleBar.xaml +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -14,7 +14,7 @@ - + diff --git a/src/Avalonia.Themes.Fluent/Window.xaml b/src/Avalonia.Themes.Fluent/Window.xaml index 086b05bb01..aee15347eb 100644 --- a/src/Avalonia.Themes.Fluent/Window.xaml +++ b/src/Avalonia.Themes.Fluent/Window.xaml @@ -1,11 +1,11 @@