From 1a16e423789c46b959c7675d70999e31de77af6b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 23 Nov 2018 15:28:30 +0000 Subject: [PATCH 01/28] prototype, allowing to draw in non-client area. without breaking win32 frame functionality. --- samples/ControlCatalog/MainWindow.xaml | 8 +- src/Avalonia.Visuals/Rect.cs | 7 ++ .../Interop/UnmanagedMethods.cs | 12 +++ src/Windows/Avalonia.Win32/WindowImpl.cs | 96 +++++++++++++++++++ 4 files changed, 120 insertions(+), 3 deletions(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 7029273a84..4be11f13b3 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -1,6 +1,8 @@  - - \ No newline at end of file + xmlns:local="clr-namespace:ControlCatalog" Background="Transparent"> + + + + diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index 63d34b474b..37c320ab39 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -120,6 +120,8 @@ namespace Avalonia /// public Size Size => new Size(_width, _height); + public double Left => _x; + /// /// Gets the right position of the rectangle. /// @@ -130,6 +132,11 @@ namespace Avalonia /// public double Bottom => _y + _height; + /// + /// Gets the top position of the rectangle. + /// + public double Top => _y; + /// /// Gets the top left point of the rectangle. /// diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 9e8ff20e44..98eb6f1e30 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -907,6 +907,18 @@ namespace Avalonia.Win32.Interop [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SetWindowTextW")] public static extern bool SetWindowText(IntPtr hwnd, string lpString); + [StructLayout(LayoutKind.Sequential)] + public struct MARGINS + { + public int leftWidth; + public int rightWidth; + public int topHeight; + public int bottomHeight; + } + + [DllImport("dwmapi.dll")] + public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); + public enum ClassLongIndex : int { GCL_HCURSOR = -12, diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 18f0696cd8..395ea43999 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -455,6 +455,54 @@ namespace Avalonia.Win32 IntPtr.Zero); } + + protected int BorderTop { get; private set; } + protected int BorderLeft { get; private set; } + protected int BorderRight { get; private set; } + protected int BorderBottom { get; private set; } + + private HitTestValues NCHitText(uint m, IntPtr LParam, IntPtr wParam) + { + int lParam = (int)LParam; + Point pt = new Point(lParam & 0xffff, lParam >> 16); + + var rc = new Rect(Position, ClientSize); + + int row = 1; + int col = 1; + bool onResizeBorder = false; + + // Determine if we are on the top or bottom border + if (pt.Y >= rc.Top && pt.Y < rc.Top + BorderTop) + { + onResizeBorder = pt.Y < (rc.Top + BorderBottom); + row = 0; + } + else if (pt.Y < rc.Bottom && pt.Y > rc.Bottom - BorderBottom) + { + row = 2; + } + + // Determine if we are on the left border or the right border + if (pt.X >= rc.Left && pt.X < rc.Left + BorderLeft) + { + col = 0; + } + else if (pt.X < rc.Right && pt.X >= rc.Right - BorderRight) + { + col = 2; + } + + HitTestValues[,] hitTests = new HitTestValues[,] + { + {HitTestValues.HTTOPLEFT, onResizeBorder ? HitTestValues.HTTOP : HitTestValues.HTCAPTION, HitTestValues.HTTOPRIGHT}, + {HitTestValues.HTLEFT, HitTestValues.HTNOWHERE, HitTestValues.HTRIGHT}, + {HitTestValues.HTBOTTOMLEFT, HitTestValues.HTBOTTOM, HitTestValues.HTBOTTOMRIGHT} + }; + + return hitTests[row, col]; + } + [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")] protected virtual IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { @@ -465,6 +513,8 @@ namespace Avalonia.Win32 RawInputEventArgs e = null; + bool callDWP = false; + WindowsMouseDevice.Instance.CurrentWindow = this; switch ((UnmanagedMethods.WindowsMessage)msg) @@ -484,8 +534,54 @@ namespace Avalonia.Win32 break; } + MARGINS margins = new MARGINS(); + + margins.leftWidth = Math.Abs(BorderLeft); + margins.rightWidth = Math.Abs(BorderRight); + margins.bottomHeight = Math.Abs(BorderBottom); + margins.topHeight = Math.Abs(BorderTop); + + // int hr = UnmanagedMethods.DwmExtendFrameIntoClientArea(hWnd, ref margins); + return IntPtr.Zero; + case WindowsMessage.WM_NCCALCSIZE: + return IntPtr.Zero; + //break; + + case WindowsMessage.WM_CREATE: + RECT rcClient; + UnmanagedMethods.GetWindowRect(hWnd, out rcClient); + + + RECT rc = new RECT(); + uint style = UnmanagedMethods.GetWindowLong(hWnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + uint styleEx = UnmanagedMethods.GetWindowLong(hWnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); + UnmanagedMethods.AdjustWindowRectEx(ref rc, style, false, styleEx); + + BorderTop = Math.Abs(rc.top); + BorderLeft = Math.Abs(0); + BorderRight = Math.Abs(0); + BorderBottom = Math.Abs(0); + break; + + case WindowsMessage.WM_NCHITTEST: + var ht = NCHitText(msg, lParam, wParam); + + + callDWP = (ht == HitTestValues.HTNOWHERE); + + if (callDWP) + { + + } + else + { + return new IntPtr((int)ht); + } + break; + + case UnmanagedMethods.WindowsMessage.WM_CLOSE: bool? preventClosing = Closing?.Invoke(); if (preventClosing == true) From 6f540cf2609931004b92080fb1208600584972a0 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 23 Nov 2018 15:43:27 +0000 Subject: [PATCH 02/28] fix removing decorations --- samples/ControlCatalog/MainWindow.xaml | 6 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 131 +++-------------------- 2 files changed, 19 insertions(+), 118 deletions(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 4be11f13b3..e722206fd0 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -2,7 +2,5 @@ Title="Avalonia Control Gallery" Icon="resm:ControlCatalog.Assets.test_icon.ico?assembly=ControlCatalog" xmlns:local="clr-namespace:ControlCatalog" Background="Transparent"> - - - - + + diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 395ea43999..17b72955bc 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -269,11 +269,6 @@ namespace Avalonia.Win32 style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; - if (!value) - { - style ^= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; - } - UnmanagedMethods.RECT windowRect; UnmanagedMethods.GetWindowRect(_hwnd, out windowRect); @@ -282,32 +277,29 @@ namespace Avalonia.Win32 var oldThickness = BorderThickness; UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); + + var thickness = BorderThickness; + + _decorated = value; - if (value) - { - var thickness = BorderThickness; + newRect = new Rect( + windowRect.left - thickness.Left, + windowRect.top - thickness.Top, + (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), + (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - newRect = new Rect( - windowRect.left - thickness.Left, - windowRect.top - thickness.Top, - (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), - (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - } - else + if(!value) { - newRect = new Rect( - windowRect.left + oldThickness.Left, - windowRect.top + oldThickness.Top, - (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), - (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); + RECT rc = new RECT(); + uint style1 = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + uint styleEx1 = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); + UnmanagedMethods.AdjustWindowRectEx(ref rc, style1, false, styleEx1); } UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, (int)newRect.Height, UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE); - _decorated = value; - if(_decorated) { if (_resizable) @@ -455,54 +447,6 @@ namespace Avalonia.Win32 IntPtr.Zero); } - - protected int BorderTop { get; private set; } - protected int BorderLeft { get; private set; } - protected int BorderRight { get; private set; } - protected int BorderBottom { get; private set; } - - private HitTestValues NCHitText(uint m, IntPtr LParam, IntPtr wParam) - { - int lParam = (int)LParam; - Point pt = new Point(lParam & 0xffff, lParam >> 16); - - var rc = new Rect(Position, ClientSize); - - int row = 1; - int col = 1; - bool onResizeBorder = false; - - // Determine if we are on the top or bottom border - if (pt.Y >= rc.Top && pt.Y < rc.Top + BorderTop) - { - onResizeBorder = pt.Y < (rc.Top + BorderBottom); - row = 0; - } - else if (pt.Y < rc.Bottom && pt.Y > rc.Bottom - BorderBottom) - { - row = 2; - } - - // Determine if we are on the left border or the right border - if (pt.X >= rc.Left && pt.X < rc.Left + BorderLeft) - { - col = 0; - } - else if (pt.X < rc.Right && pt.X >= rc.Right - BorderRight) - { - col = 2; - } - - HitTestValues[,] hitTests = new HitTestValues[,] - { - {HitTestValues.HTTOPLEFT, onResizeBorder ? HitTestValues.HTTOP : HitTestValues.HTCAPTION, HitTestValues.HTTOPRIGHT}, - {HitTestValues.HTLEFT, HitTestValues.HTNOWHERE, HitTestValues.HTRIGHT}, - {HitTestValues.HTBOTTOMLEFT, HitTestValues.HTBOTTOM, HitTestValues.HTBOTTOMRIGHT} - }; - - return hitTests[row, col]; - } - [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")] protected virtual IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { @@ -513,8 +457,6 @@ namespace Avalonia.Win32 RawInputEventArgs e = null; - bool callDWP = false; - WindowsMouseDevice.Instance.CurrentWindow = this; switch ((UnmanagedMethods.WindowsMessage)msg) @@ -534,53 +476,14 @@ namespace Avalonia.Win32 break; } - MARGINS margins = new MARGINS(); - - margins.leftWidth = Math.Abs(BorderLeft); - margins.rightWidth = Math.Abs(BorderRight); - margins.bottomHeight = Math.Abs(BorderBottom); - margins.topHeight = Math.Abs(BorderTop); - - // int hr = UnmanagedMethods.DwmExtendFrameIntoClientArea(hWnd, ref margins); - return IntPtr.Zero; case WindowsMessage.WM_NCCALCSIZE: - return IntPtr.Zero; - //break; - - case WindowsMessage.WM_CREATE: - RECT rcClient; - UnmanagedMethods.GetWindowRect(hWnd, out rcClient); - - - RECT rc = new RECT(); - uint style = UnmanagedMethods.GetWindowLong(hWnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); - uint styleEx = UnmanagedMethods.GetWindowLong(hWnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); - UnmanagedMethods.AdjustWindowRectEx(ref rc, style, false, styleEx); - - BorderTop = Math.Abs(rc.top); - BorderLeft = Math.Abs(0); - BorderRight = Math.Abs(0); - BorderBottom = Math.Abs(0); - break; - - case WindowsMessage.WM_NCHITTEST: - var ht = NCHitText(msg, lParam, wParam); - - - callDWP = (ht == HitTestValues.HTNOWHERE); - - if (callDWP) + if (!_decorated) { - - } - else - { - return new IntPtr((int)ht); + return IntPtr.Zero; } - break; - + break; case UnmanagedMethods.WindowsMessage.WM_CLOSE: bool? preventClosing = Closing?.Invoke(); From 7483b1cb4cfd4b30017453ba3b3e5ab6eedfa035 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 23 Nov 2018 15:44:47 +0000 Subject: [PATCH 03/28] revert changes. --- samples/ControlCatalog/MainWindow.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index e722206fd0..4aa16aabfa 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -1,6 +1,6 @@  - + xmlns:local="clr-namespace:ControlCatalog"> + From 6a76c00f3ee5bfb09269cf879d956edaa92d2a0f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 23 Nov 2018 15:46:29 +0000 Subject: [PATCH 04/28] remove unused changes. --- src/Avalonia.Visuals/Rect.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index 37c320ab39..86597627b6 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -120,8 +120,6 @@ namespace Avalonia /// public Size Size => new Size(_width, _height); - public double Left => _x; - /// /// Gets the right position of the rectangle. /// @@ -131,12 +129,7 @@ namespace Avalonia /// Gets the bottom position of the rectangle. /// public double Bottom => _y + _height; - - /// - /// Gets the top position of the rectangle. - /// - public double Top => _y; - + /// /// Gets the top left point of the rectangle. /// From 607703427da97fcdcdbed7cbde93a7aa5666e30e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 23 Nov 2018 15:47:13 +0000 Subject: [PATCH 05/28] whitespace. --- src/Avalonia.Visuals/Rect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index 86597627b6..63d34b474b 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -129,7 +129,7 @@ namespace Avalonia /// Gets the bottom position of the rectangle. /// public double Bottom => _y + _height; - + /// /// Gets the top left point of the rectangle. /// From 9f02b7f7c12449fafa8b97fd2ab0b3fb6c41815c Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 23 Nov 2018 15:48:13 +0000 Subject: [PATCH 06/28] remove unused method. --- .../Avalonia.Win32/Interop/UnmanagedMethods.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 98eb6f1e30..9e8ff20e44 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -907,18 +907,6 @@ namespace Avalonia.Win32.Interop [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SetWindowTextW")] public static extern bool SetWindowText(IntPtr hwnd, string lpString); - [StructLayout(LayoutKind.Sequential)] - public struct MARGINS - { - public int leftWidth; - public int rightWidth; - public int topHeight; - public int bottomHeight; - } - - [DllImport("dwmapi.dll")] - public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); - public enum ClassLongIndex : int { GCL_HCURSOR = -12, From c4cc3514a8c35f36230f8902bbddbf7bffaf624f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 28 Nov 2018 16:57:49 +0000 Subject: [PATCH 07/28] Set win32 WindowStyle flags individually. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 17b72955bc..bdf58e51ee 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -265,13 +265,18 @@ namespace Avalonia.Win32 return; } - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); - style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; - - UnmanagedMethods.RECT windowRect; - - UnmanagedMethods.GetWindowRect(_hwnd, out windowRect); + if (value) + { + style |= (WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU & WindowStyles.WS_SIZEFRAME); + } + else + { + style ^= (WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU & WindowStyles.WS_SIZEFRAME); + } + + UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); Rect newRect; var oldThickness = BorderThickness; @@ -436,7 +441,7 @@ namespace Avalonia.Win32 0, atom, null, - (int)UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW, + (int)(WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU & WindowStyles.WS_SIZEFRAME), UnmanagedMethods.CW_USEDEFAULT, UnmanagedMethods.CW_USEDEFAULT, UnmanagedMethods.CW_USEDEFAULT, From 743e61cfde37e608820e1d6c7e0671a5e22e781e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 28 Nov 2018 16:57:49 +0000 Subject: [PATCH 08/28] Revert "Set win32 WindowStyle flags individually." This reverts commit c4cc3514a8c35f36230f8902bbddbf7bffaf624f. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index bdf58e51ee..17b72955bc 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -265,18 +265,13 @@ namespace Avalonia.Win32 return; } - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); - if (value) - { - style |= (WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU & WindowStyles.WS_SIZEFRAME); - } - else - { - style ^= (WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU & WindowStyles.WS_SIZEFRAME); - } - - UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); + style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; + + UnmanagedMethods.RECT windowRect; + + UnmanagedMethods.GetWindowRect(_hwnd, out windowRect); Rect newRect; var oldThickness = BorderThickness; @@ -441,7 +436,7 @@ namespace Avalonia.Win32 0, atom, null, - (int)(WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU & WindowStyles.WS_SIZEFRAME), + (int)UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW, UnmanagedMethods.CW_USEDEFAULT, UnmanagedMethods.CW_USEDEFAULT, UnmanagedMethods.CW_USEDEFAULT, From c8515ebea094c0798fd59404957dc7611ff34aaf Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 28 Nov 2018 17:17:46 +0000 Subject: [PATCH 09/28] handle window styles so that it obeys can resize. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 26 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 17b72955bc..e8f9f37087 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -269,6 +269,17 @@ namespace Avalonia.Win32 style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; + if (!value) + { + style ^= (WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU); + + if (!_resizable) + { + style ^= (UnmanagedMethods.WindowStyles.WS_SIZEFRAME); + } + } + + UnmanagedMethods.RECT windowRect; UnmanagedMethods.GetWindowRect(_hwnd, out windowRect); @@ -916,17 +927,14 @@ namespace Avalonia.Win32 return; } - if (_decorated) - { - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); - if (value) - style |= UnmanagedMethods.WindowStyles.WS_SIZEFRAME; - else - style &= ~(UnmanagedMethods.WindowStyles.WS_SIZEFRAME); + if (value) + style |= UnmanagedMethods.WindowStyles.WS_SIZEFRAME; + else + style &= ~(UnmanagedMethods.WindowStyles.WS_SIZEFRAME); - UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); - } + UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); _resizable = value; } From 053e6a2be57006efd9be9aea783bd1d311cc40a6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 30 Nov 2018 13:02:40 +0000 Subject: [PATCH 10/28] update wmstyles in single place, and implement nccalc size message. --- .../Interop/UnmanagedMethods.cs | 20 ++++ src/Windows/Avalonia.Win32/WindowImpl.cs | 113 +++++++++--------- 2 files changed, 79 insertions(+), 54 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 9e8ff20e44..adfbf0cb52 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1181,6 +1181,26 @@ namespace Avalonia.Win32.Interop } } + [StructLayout(LayoutKind.Sequential)] + public struct WINDOWPOS + { + public IntPtr hwnd; + public IntPtr hwndInsertAfter; + public int x; + public int y; + public int cx; + public int cy; + public uint flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct NCCALCSIZE_PARAMS + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public RECT[] rgrc; + public WINDOWPOS lppos; + } + public struct TRACKMOUSEEVENT { public int cbSize; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index e8f9f37087..fbd0752a19 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -35,6 +35,7 @@ namespace Avalonia.Win32 private bool _decorated = true; private bool _resizable = true; private bool _topmost = false; + private bool _taskbarIcon = true; private double _scaling = 1; private WindowState _showWindowState; private WindowState _lastWindowState; @@ -96,7 +97,8 @@ namespace Avalonia.Win32 { var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); - var padding = new UnmanagedMethods.RECT(); + + var padding = new RECT(); if (UnmanagedMethods.AdjustWindowRectEx(ref padding, style, false, exStyle)) { @@ -265,66 +267,27 @@ namespace Avalonia.Win32 return; } - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); - - style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; - - if (!value) - { - style ^= (WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU); - - if (!_resizable) - { - style ^= (UnmanagedMethods.WindowStyles.WS_SIZEFRAME); - } - } - - - UnmanagedMethods.RECT windowRect; - - UnmanagedMethods.GetWindowRect(_hwnd, out windowRect); + _decorated = value; - Rect newRect; + UpdateWMStyles(); + + UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); + var oldThickness = BorderThickness; - - UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); var thickness = BorderThickness; _decorated = value; - newRect = new Rect( + var newRect = new Rect( windowRect.left - thickness.Left, windowRect.top - thickness.Top, (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - if(!value) - { - RECT rc = new RECT(); - uint style1 = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); - uint styleEx1 = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); - UnmanagedMethods.AdjustWindowRectEx(ref rc, style1, false, styleEx1); - } - UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, (int)newRect.Height, UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE); - - if(_decorated) - { - if (_resizable) - { - // If we switch decorations back on we need to restore WS_SizeFrame. - _resizable = false; - CanResize(true); - } - else - { - _resizable = true; - CanResize(false); - } - } } public void Invalidate(Rect rect) @@ -490,8 +453,23 @@ namespace Avalonia.Win32 return IntPtr.Zero; case WindowsMessage.WM_NCCALCSIZE: - if (!_decorated) + if (ToInt32(wParam) == 1 && !_decorated) { + + // Calculate new NCCALCSIZE_PARAMS based on custom NCA inset. + var pncsp = Marshal.PtrToStructure(lParam); + + pncsp.rgrc[0].left = pncsp.rgrc[0].left + 0; + pncsp.rgrc[0].top = pncsp.rgrc[0].top + 0; + pncsp.rgrc[0].right = pncsp.rgrc[0].right - 0; + pncsp.rgrc[0].bottom = pncsp.rgrc[0].bottom - 0; + + //lRet = 0; + + // No need to pass the message on to the DefWindowProc. + //fCallDWP = false; + + return IntPtr.Zero; } break; @@ -897,14 +875,23 @@ namespace Avalonia.Win32 return (int)(ptr.ToInt64() & 0xffffffff); } + public void ShowTaskbarIcon(bool value) { + if(_taskbarIcon == value) + { + return; + } + + _taskbarIcon = value; + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE); style |= UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW; + if (value) style |= UnmanagedMethods.WindowStyles.WS_EX_APPWINDOW; else @@ -920,23 +907,41 @@ namespace Avalonia.Win32 } } - public void CanResize(bool value) + private void UpdateWMStyles() { - if (value == _resizable) + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + + style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; + + if (!_decorated) { - return; + style ^= (WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU); } - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); - - if (value) + if (_resizable) + { style |= UnmanagedMethods.WindowStyles.WS_SIZEFRAME; + } else - style &= ~(UnmanagedMethods.WindowStyles.WS_SIZEFRAME); + { + style ^= (UnmanagedMethods.WindowStyles.WS_SIZEFRAME); + } UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); + var thickness = BorderThickness; + } + + public void CanResize(bool value) + { + if (value == _resizable) + { + return; + } + _resizable = value; + + UpdateWMStyles(); } public void SetTopmost(bool value) From 1c871bf423db1d2d777cc5ca53de229e5c5787bb Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 30 Nov 2018 13:42:22 +0000 Subject: [PATCH 11/28] [win32] fix maximize borders and wm window styles for non-decorated windows. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index fbd0752a19..d32d2be1a6 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -455,21 +455,6 @@ namespace Avalonia.Win32 case WindowsMessage.WM_NCCALCSIZE: if (ToInt32(wParam) == 1 && !_decorated) { - - // Calculate new NCCALCSIZE_PARAMS based on custom NCA inset. - var pncsp = Marshal.PtrToStructure(lParam); - - pncsp.rgrc[0].left = pncsp.rgrc[0].left + 0; - pncsp.rgrc[0].top = pncsp.rgrc[0].top + 0; - pncsp.rgrc[0].right = pncsp.rgrc[0].right - 0; - pncsp.rgrc[0].bottom = pncsp.rgrc[0].bottom - 0; - - //lRet = 0; - - // No need to pass the message on to the DefWindowProc. - //fCallDWP = false; - - return IntPtr.Zero; } break; @@ -915,7 +900,7 @@ namespace Avalonia.Win32 if (!_decorated) { - style ^= (WindowStyles.WS_CAPTION & WindowStyles.WS_MINIMIZEBOX & WindowStyles.WS_MAXIMIZEBOX & WindowStyles.WS_SYSMENU); + style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_MAXIMIZEBOX | WindowStyles.WS_SYSMENU); } if (_resizable) From 2572e0d0656cb230472fe1052b20234c5c588edb Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 30 Nov 2018 14:02:41 +0000 Subject: [PATCH 12/28] fix rendering issues when clicking on modal dialogs parent and dialog is non-decorated. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index d32d2be1a6..e49eb5be9f 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -619,6 +619,14 @@ namespace Avalonia.Win32 new Point(0, 0), GetMouseModifiers(wParam)); break; + case WindowsMessage.WM_NCPAINT: + case WindowsMessage.WM_NCACTIVATE: + if (!_decorated) + { + return IntPtr.Zero; + } + break; + case UnmanagedMethods.WindowsMessage.WM_PAINT: UnmanagedMethods.PAINTSTRUCT ps; if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero) From 658ff21d0ff97cac034ff416b4f73d948fc71aff Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 30 Nov 2018 14:03:00 +0000 Subject: [PATCH 13/28] fix border thickness being added to non-decorated windows. --- 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 e49eb5be9f..932cb4a9d0 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -149,7 +149,11 @@ namespace Avalonia.Win32 if (value != ClientSize) { value *= Scaling; - value += BorderThickness; + + if (_decorated) + { + value += BorderThickness; + } UnmanagedMethods.SetWindowPos( _hwnd, From 374d6a5f0d06412e0b194915aefdafea22079375 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 30 Nov 2018 14:15:24 +0000 Subject: [PATCH 14/28] fix smooth toggling between decorated and non-decorated. --- samples/ControlCatalog/DecoratedWindow.xaml | 6 +++- src/Windows/Avalonia.Win32/WindowImpl.cs | 31 +++++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/samples/ControlCatalog/DecoratedWindow.xaml b/samples/ControlCatalog/DecoratedWindow.xaml index 37014255cc..fdb18fcca2 100644 --- a/samples/ControlCatalog/DecoratedWindow.xaml +++ b/samples/ControlCatalog/DecoratedWindow.xaml @@ -3,7 +3,7 @@ x:Class="ControlCatalog.DecoratedWindow" Title="Avalonia Control Gallery" Icon="/Assets/test_icon.ico" - xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False"> + xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False" Name="Window"> @@ -20,7 +20,11 @@ + Hello world! + + Decorated + diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 932cb4a9d0..5fa399e2a9 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -279,23 +279,36 @@ namespace Avalonia.Win32 var oldThickness = BorderThickness; - var thickness = BorderThickness; - _decorated = value; - var newRect = new Rect( - windowRect.left - thickness.Left, - windowRect.top - thickness.Top, - (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), - (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); + Rect newRect; + + if (value) + { + var thickness = BorderThickness; + + newRect = new Rect( + windowRect.left - thickness.Left, + windowRect.top - thickness.Top, + (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), + (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); + } + else + { + newRect = new Rect( + windowRect.left + oldThickness.Left, + windowRect.top + oldThickness.Top, + (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), + (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); + } UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, (int)newRect.Height, - UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE); + UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); } public void Invalidate(Rect rect) - { + { var f = Scaling; var r = new UnmanagedMethods.RECT { From 9050409afcfa20fb00c3b2b26b8c5e588e02dd9c Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 14:28:03 +0000 Subject: [PATCH 15/28] [win32] windowimpl update style calculations done in one place. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 111 ++++++++++++----------- 1 file changed, 58 insertions(+), 53 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 5fa399e2a9..621de88019 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -271,44 +271,11 @@ namespace Avalonia.Win32 return; } - _decorated = value; - - UpdateWMStyles(); - - UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); - - var oldThickness = BorderThickness; - - _decorated = value; - - Rect newRect; - - if (value) - { - var thickness = BorderThickness; - - newRect = new Rect( - windowRect.left - thickness.Left, - windowRect.top - thickness.Top, - (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), - (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - } - else - { - newRect = new Rect( - windowRect.left + oldThickness.Left, - windowRect.top + oldThickness.Top, - (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), - (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); - } - - UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, - (int)newRect.Height, - UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + UpdateWMStyles(() => _decorated = value); } public void Invalidate(Rect rect) - { + { var f = Scaling; var r = new UnmanagedMethods.RECT { @@ -474,7 +441,7 @@ namespace Avalonia.Win32 { return IntPtr.Zero; } - break; + break; case UnmanagedMethods.WindowsMessage.WM_CLOSE: bool? preventClosing = Closing?.Invoke(); @@ -686,7 +653,7 @@ namespace Avalonia.Win32 MINMAXINFO mmi = Marshal.PtrToStructure(lParam); - if (_minSize.Width > 0) + if (_minSize.Width > 0) mmi.ptMinTrackSize.X = (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); if (_minSize.Height > 0) @@ -857,7 +824,7 @@ namespace Avalonia.Win32 { MONITORINFO monitorInfo = MONITORINFO.Create(); - if (GetMonitorInfo(monitor,ref monitorInfo)) + if (GetMonitorInfo(monitor, ref monitorInfo)) { RECT rcMonitorArea = monitorInfo.rcMonitor; @@ -885,17 +852,17 @@ namespace Avalonia.Win32 return (int)(ptr.ToInt64() & 0xffffffff); } - + public void ShowTaskbarIcon(bool value) { - if(_taskbarIcon == value) + if (_taskbarIcon == value) { return; } _taskbarIcon = value; - + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE); @@ -917,29 +884,69 @@ namespace Avalonia.Win32 } } - private void UpdateWMStyles() + private void UpdateWMStyles(Action changer) { - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + var decorated = _decorated; + + var resizable = _resizable; - style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; + changer(); - if (!_decorated) + var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE); + + if (decorated != _decorated) { - style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_MAXIMIZEBOX | WindowStyles.WS_SYSMENU); + style |= WindowStyles.WS_OVERLAPPEDWINDOW; + + if (!_decorated) + { + style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU); + } } if (_resizable) { - style |= UnmanagedMethods.WindowStyles.WS_SIZEFRAME; + style |= WindowStyles.WS_SIZEFRAME; } else { - style ^= (UnmanagedMethods.WindowStyles.WS_SIZEFRAME); + style ^= (WindowStyles.WS_SIZEFRAME); } - UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); + SetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE, (uint)style); + + if (decorated != _decorated) + { + UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); + + var oldThickness = BorderThickness; + + Rect newRect; + + if (_decorated) + { + var thickness = BorderThickness; - var thickness = BorderThickness; + newRect = new Rect( + windowRect.left - thickness.Left, + windowRect.top - thickness.Top, + (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), + (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); + } + else + { + newRect = new Rect( + windowRect.left + oldThickness.Left, + windowRect.top + oldThickness.Top, + (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), + (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); + } + + UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, + (int)newRect.Height, + UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + + } } public void CanResize(bool value) @@ -949,9 +956,7 @@ namespace Avalonia.Win32 return; } - _resizable = value; - - UpdateWMStyles(); + UpdateWMStyles(() => _resizable = value); } public void SetTopmost(bool value) From c9b069ffb74a44536059bf88db1922d637a2ca6f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 14:34:42 +0000 Subject: [PATCH 16/28] simplify style flag calculation. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 621de88019..8343ccbd44 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -892,23 +892,14 @@ namespace Avalonia.Win32 changer(); - var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE); + var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE) | WindowStyles.WS_OVERLAPPEDWINDOW; - if (decorated != _decorated) + if (!_decorated) { - style |= WindowStyles.WS_OVERLAPPEDWINDOW; - - if (!_decorated) - { - style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU); - } + style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU); } - if (_resizable) - { - style |= WindowStyles.WS_SIZEFRAME; - } - else + if (!_resizable) { style ^= (WindowStyles.WS_SIZEFRAME); } From dbacf80511f5dd0ee18cb97b3b81e656fb4fc339 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 14:53:19 +0000 Subject: [PATCH 17/28] tidy decorated window. --- samples/ControlCatalog/DecoratedWindow.xaml | 65 ++++++++++----------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/samples/ControlCatalog/DecoratedWindow.xaml b/samples/ControlCatalog/DecoratedWindow.xaml index fdb18fcca2..9f05cd1f57 100644 --- a/samples/ControlCatalog/DecoratedWindow.xaml +++ b/samples/ControlCatalog/DecoratedWindow.xaml @@ -1,39 +1,38 @@ - - - - - Title - - - - - - - - - - - - Hello world! + + + + Title + + + + + + + + + + + + Hello world! - Decorated - - - - - - - - - - - - + Decorated + + + + + + + + + + + + From 07475d12f9d973c307de4584e291def4ec009d4a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 14:56:07 +0000 Subject: [PATCH 18/28] simplify apply styles --- src/Windows/Avalonia.Win32/WindowImpl.cs | 69 ++++++++++++------------ 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 8343ccbd44..4316166343 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -271,7 +271,9 @@ namespace Avalonia.Win32 return; } - UpdateWMStyles(() => _decorated = value); + _decorated = value; + + UpdateWMStyles(); } public void Invalidate(Rect rect) @@ -884,15 +886,15 @@ namespace Avalonia.Win32 } } - private void UpdateWMStyles(Action changer) + private void UpdateWMStyles() { - var decorated = _decorated; + var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE); - var resizable = _resizable; + const WindowStyles controlledFlags = WindowStyles.WS_OVERLAPPEDWINDOW; - changer(); + style = style | controlledFlags ^ controlledFlags; - var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE) | WindowStyles.WS_OVERLAPPEDWINDOW; + style |= WindowStyles.WS_OVERLAPPEDWINDOW; if (!_decorated) { @@ -904,40 +906,39 @@ namespace Avalonia.Win32 style ^= (WindowStyles.WS_SIZEFRAME); } + UnmanagedMethods.GetWindowRect(_hwnd, out var oldRect); + SetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE, (uint)style); - if (decorated != _decorated) - { - UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); + UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); - var oldThickness = BorderThickness; + var oldThickness = BorderThickness; - Rect newRect; + Rect newRect; - if (_decorated) - { - var thickness = BorderThickness; + if (_decorated) + { + var thickness = BorderThickness; - newRect = new Rect( - windowRect.left - thickness.Left, - windowRect.top - thickness.Top, - (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), - (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - } - else - { - newRect = new Rect( - windowRect.left + oldThickness.Left, - windowRect.top + oldThickness.Top, - (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), - (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); - } + newRect = new Rect( + windowRect.left - thickness.Left, + windowRect.top - thickness.Top, + (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), + (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); + } + else + { + newRect = new Rect( + windowRect.left + oldThickness.Left, + windowRect.top + oldThickness.Top, + (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), + (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); + } - UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, - (int)newRect.Height, - UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, + (int)newRect.Height, + UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); - } } public void CanResize(bool value) @@ -947,7 +948,9 @@ namespace Avalonia.Win32 return; } - UpdateWMStyles(() => _resizable = value); + _resizable = value; + + UpdateWMStyles(); } public void SetTopmost(bool value) From ca59da108ed2a35b1b49e1ab1c1a051bf31db100 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 15:08:29 +0000 Subject: [PATCH 19/28] [win32] smoothly toggle decorations. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 4316166343..1383a81dd6 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -906,14 +906,12 @@ namespace Avalonia.Win32 style ^= (WindowStyles.WS_SIZEFRAME); } - UnmanagedMethods.GetWindowRect(_hwnd, out var oldRect); + var oldThickness = BorderThickness; SetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE, (uint)style); UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); - var oldThickness = BorderThickness; - Rect newRect; if (_decorated) From 333c0ac907d57bda332600283e6ab724d465b346 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 15:13:20 +0000 Subject: [PATCH 20/28] simply applywm styles. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 1383a81dd6..146ab496fa 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -894,16 +894,20 @@ namespace Avalonia.Win32 style = style | controlledFlags ^ controlledFlags; - style |= WindowStyles.WS_OVERLAPPEDWINDOW; + style |= WindowStyles.WS_OVERLAPPED | + WindowStyles.WS_MINIMIZEBOX | + WindowStyles.WS_MAXIMIZEBOX; - if (!_decorated) + if (_decorated) { - style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU); + style |= + WindowStyles.WS_CAPTION | + WindowStyles.WS_SYSMENU; } - if (!_resizable) + if (_resizable) { - style ^= (WindowStyles.WS_SIZEFRAME); + style |= WindowStyles.WS_SIZEFRAME; } var oldThickness = BorderThickness; @@ -936,7 +940,6 @@ namespace Avalonia.Win32 UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, (int)newRect.Height, UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); - } public void CanResize(bool value) From 99a1392febc429eaae2dbc6234ee4893fb375de1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 15:16:04 +0000 Subject: [PATCH 21/28] remove flags from overlapped. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 146ab496fa..1383a81dd6 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -894,20 +894,16 @@ namespace Avalonia.Win32 style = style | controlledFlags ^ controlledFlags; - style |= WindowStyles.WS_OVERLAPPED | - WindowStyles.WS_MINIMIZEBOX | - WindowStyles.WS_MAXIMIZEBOX; + style |= WindowStyles.WS_OVERLAPPEDWINDOW; - if (_decorated) + if (!_decorated) { - style |= - WindowStyles.WS_CAPTION | - WindowStyles.WS_SYSMENU; + style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU); } - if (_resizable) + if (!_resizable) { - style |= WindowStyles.WS_SIZEFRAME; + style ^= (WindowStyles.WS_SIZEFRAME); } var oldThickness = BorderThickness; @@ -940,6 +936,7 @@ namespace Avalonia.Win32 UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, (int)newRect.Height, UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + } public void CanResize(bool value) From 7d1f145f9331ba3b0cc47a3963b4324e20d38f3b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 15:34:19 +0000 Subject: [PATCH 22/28] add CanResize checkbox to decorated window. --- samples/ControlCatalog/DecoratedWindow.xaml | 63 ++++++++++---------- src/Windows/Avalonia.Win32/WindowImpl.cs | 64 +++++++++++---------- 2 files changed, 66 insertions(+), 61 deletions(-) diff --git a/samples/ControlCatalog/DecoratedWindow.xaml b/samples/ControlCatalog/DecoratedWindow.xaml index 9f05cd1f57..b2462cda26 100644 --- a/samples/ControlCatalog/DecoratedWindow.xaml +++ b/samples/ControlCatalog/DecoratedWindow.xaml @@ -3,36 +3,37 @@ x:Class="ControlCatalog.DecoratedWindow" Title="Avalonia Control Gallery" xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False" Name="Window"> - - - - Title - - - - - - - - - - - - Hello world! + + + + Title + + + + + + + + + + + + Hello world! - Decorated - - - - - - - - - - - - + Decorated + CanResize + + + + + + + + + + + + diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 1383a81dd6..22dd6142fc 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -271,9 +271,7 @@ namespace Avalonia.Win32 return; } - _decorated = value; - - UpdateWMStyles(); + UpdateWMStyles(() => _decorated = value); } public void Invalidate(Rect rect) @@ -850,7 +848,8 @@ namespace Avalonia.Win32 private static int ToInt32(IntPtr ptr) { - if (IntPtr.Size == 4) return ptr.ToInt32(); + if (IntPtr.Size == 4) + return ptr.ToInt32(); return (int)(ptr.ToInt64() & 0xffffffff); } @@ -886,8 +885,13 @@ namespace Avalonia.Win32 } } - private void UpdateWMStyles() + private void UpdateWMStyles(Action change) { + var decorated = _decorated; + var resizable = _resizable; + + change(); + var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE); const WindowStyles controlledFlags = WindowStyles.WS_OVERLAPPEDWINDOW; @@ -910,33 +914,35 @@ namespace Avalonia.Win32 SetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE, (uint)style); - UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); - - Rect newRect; - - if (_decorated) + if (decorated != _decorated) { var thickness = BorderThickness; - newRect = new Rect( - windowRect.left - thickness.Left, - windowRect.top - thickness.Top, - (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), - (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - } - else - { - newRect = new Rect( - windowRect.left + oldThickness.Left, - windowRect.top + oldThickness.Top, - (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), - (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); - } + UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); - UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, - (int)newRect.Height, - UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + Rect newRect; + if (_decorated) + { + newRect = new Rect( + windowRect.left - thickness.Left, + windowRect.top - thickness.Top, + (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), + (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); + } + else + { + newRect = new Rect( + windowRect.left + oldThickness.Left, + windowRect.top + oldThickness.Top, + (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), + (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); + } + + UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, + (int)newRect.Height, + UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + } } public void CanResize(bool value) @@ -946,9 +952,7 @@ namespace Avalonia.Win32 return; } - _resizable = value; - - UpdateWMStyles(); + UpdateWMStyles(() => _resizable = value); } public void SetTopmost(bool value) From 5d327abc65ab65da15e45febbfbe4583cd7404d0 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 15:34:19 +0000 Subject: [PATCH 23/28] Revert "add CanResize checkbox to decorated window." This reverts commit 7d1f145f9331ba3b0cc47a3963b4324e20d38f3b. --- samples/ControlCatalog/DecoratedWindow.xaml | 63 ++++++++++---------- src/Windows/Avalonia.Win32/WindowImpl.cs | 64 ++++++++++----------- 2 files changed, 61 insertions(+), 66 deletions(-) diff --git a/samples/ControlCatalog/DecoratedWindow.xaml b/samples/ControlCatalog/DecoratedWindow.xaml index b2462cda26..9f05cd1f57 100644 --- a/samples/ControlCatalog/DecoratedWindow.xaml +++ b/samples/ControlCatalog/DecoratedWindow.xaml @@ -3,37 +3,36 @@ x:Class="ControlCatalog.DecoratedWindow" Title="Avalonia Control Gallery" xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False" Name="Window"> - - - - Title - - - - - - - - - - - - Hello world! + + + + Title + + + + + + + + + + + + Hello world! - Decorated - CanResize - - - - - - - - - - - - + Decorated + + + + + + + + + + + + diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 22dd6142fc..1383a81dd6 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -271,7 +271,9 @@ namespace Avalonia.Win32 return; } - UpdateWMStyles(() => _decorated = value); + _decorated = value; + + UpdateWMStyles(); } public void Invalidate(Rect rect) @@ -848,8 +850,7 @@ namespace Avalonia.Win32 private static int ToInt32(IntPtr ptr) { - if (IntPtr.Size == 4) - return ptr.ToInt32(); + if (IntPtr.Size == 4) return ptr.ToInt32(); return (int)(ptr.ToInt64() & 0xffffffff); } @@ -885,13 +886,8 @@ namespace Avalonia.Win32 } } - private void UpdateWMStyles(Action change) + private void UpdateWMStyles() { - var decorated = _decorated; - var resizable = _resizable; - - change(); - var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE); const WindowStyles controlledFlags = WindowStyles.WS_OVERLAPPEDWINDOW; @@ -914,35 +910,33 @@ namespace Avalonia.Win32 SetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE, (uint)style); - if (decorated != _decorated) + UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); + + Rect newRect; + + if (_decorated) { var thickness = BorderThickness; - UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); - - Rect newRect; + newRect = new Rect( + windowRect.left - thickness.Left, + windowRect.top - thickness.Top, + (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), + (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); + } + else + { + newRect = new Rect( + windowRect.left + oldThickness.Left, + windowRect.top + oldThickness.Top, + (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), + (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); + } - if (_decorated) - { - newRect = new Rect( - windowRect.left - thickness.Left, - windowRect.top - thickness.Top, - (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), - (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - } - else - { - newRect = new Rect( - windowRect.left + oldThickness.Left, - windowRect.top + oldThickness.Top, - (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), - (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); - } + UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, + (int)newRect.Height, + UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); - UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, - (int)newRect.Height, - UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); - } } public void CanResize(bool value) @@ -952,7 +946,9 @@ namespace Avalonia.Win32 return; } - UpdateWMStyles(() => _resizable = value); + _resizable = value; + + UpdateWMStyles(); } public void SetTopmost(bool value) From 3ce39fe7a07eac3d111a7b261a4cde1b1400faaa Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 15:42:56 +0000 Subject: [PATCH 24/28] use Action to set flags and recalculate wmstyles. --- samples/ControlCatalog/DecoratedWindow.xaml | 64 +++++++++++---------- src/Windows/Avalonia.Win32/WindowImpl.cs | 59 ++++++++++--------- 2 files changed, 64 insertions(+), 59 deletions(-) diff --git a/samples/ControlCatalog/DecoratedWindow.xaml b/samples/ControlCatalog/DecoratedWindow.xaml index 9f05cd1f57..cb6016b324 100644 --- a/samples/ControlCatalog/DecoratedWindow.xaml +++ b/samples/ControlCatalog/DecoratedWindow.xaml @@ -3,36 +3,38 @@ x:Class="ControlCatalog.DecoratedWindow" Title="Avalonia Control Gallery" xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False" Name="Window"> - - - - Title - - - - - - - - - - - - Hello world! + + + + Title + + + + + + + + + + + + Hello world! - Decorated - - - - - - - - - - - - + Decorated + + CanResize + + + + + + + + + + + + diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 1383a81dd6..7a1802826d 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -271,9 +271,7 @@ namespace Avalonia.Win32 return; } - _decorated = value; - - UpdateWMStyles(); + UpdateWMStyles(()=> _decorated = value); } public void Invalidate(Rect rect) @@ -886,8 +884,13 @@ namespace Avalonia.Win32 } } - private void UpdateWMStyles() + private void UpdateWMStyles(Action change) { + var decorated = _decorated; + var resizable = _resizable; + + change(); + var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE); const WindowStyles controlledFlags = WindowStyles.WS_OVERLAPPEDWINDOW; @@ -912,31 +915,33 @@ namespace Avalonia.Win32 UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); - Rect newRect; - - if (_decorated) + if (decorated != _decorated) { - var thickness = BorderThickness; + Rect newRect; - newRect = new Rect( - windowRect.left - thickness.Left, - windowRect.top - thickness.Top, - (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), - (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - } - else - { - newRect = new Rect( - windowRect.left + oldThickness.Left, - windowRect.top + oldThickness.Top, - (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), - (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); - } + if (_decorated) + { + var thickness = BorderThickness; - UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, - (int)newRect.Height, - UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + newRect = new Rect( + windowRect.left - thickness.Left, + windowRect.top - thickness.Top, + (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), + (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); + } + else + { + newRect = new Rect( + windowRect.left + oldThickness.Left, + windowRect.top + oldThickness.Top, + (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), + (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); + } + UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, + (int)newRect.Height, + UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + } } public void CanResize(bool value) @@ -946,9 +951,7 @@ namespace Avalonia.Win32 return; } - _resizable = value; - - UpdateWMStyles(); + UpdateWMStyles(()=> _resizable = value); } public void SetTopmost(bool value) From b91233e3dfc0c706042cbe6c5470ae2a5711d0df Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 15:47:37 +0000 Subject: [PATCH 25/28] remove unused var --- src/Windows/Avalonia.Win32/WindowImpl.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 7a1802826d..5b5aeb88ab 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -887,7 +887,6 @@ namespace Avalonia.Win32 private void UpdateWMStyles(Action change) { var decorated = _decorated; - var resizable = _resizable; change(); From f0f7cf44272866ea7adf5962f7bd8caa527d8dcf Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 15:53:50 +0000 Subject: [PATCH 26/28] [win32 window] fix BorderThickness --- src/Windows/Avalonia.Win32/WindowImpl.cs | 32 +++++++++++++----------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 5b5aeb88ab..3eeccb368c 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -95,18 +95,25 @@ namespace Avalonia.Win32 { get { - var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); - var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); + if (_decorated) + { + var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); - var padding = new RECT(); + var padding = new RECT(); - if (UnmanagedMethods.AdjustWindowRectEx(ref padding, style, false, exStyle)) - { - return new Thickness(-padding.left, -padding.top, padding.right, padding.bottom); + if (UnmanagedMethods.AdjustWindowRectEx(ref padding, style, false, exStyle)) + { + return new Thickness(-padding.left, -padding.top, padding.right, padding.bottom); + } + else + { + throw new Win32Exception(); + } } else { - throw new Win32Exception(); + return new Thickness(); } } } @@ -149,12 +156,7 @@ namespace Avalonia.Win32 if (value != ClientSize) { value *= Scaling; - - if (_decorated) - { - value += BorderThickness; - } - + UnmanagedMethods.SetWindowPos( _hwnd, IntPtr.Zero, @@ -888,6 +890,8 @@ namespace Avalonia.Win32 { var decorated = _decorated; + var oldThickness = BorderThickness; + change(); var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE); @@ -908,8 +912,6 @@ namespace Avalonia.Win32 style ^= (WindowStyles.WS_SIZEFRAME); } - var oldThickness = BorderThickness; - SetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE, (uint)style); UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); From a54b85bfa7507e9124f06e31bf1cfe8c00574233 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 1 Dec 2018 20:17:06 +0300 Subject: [PATCH 27/28] A bit more clean method of new window rect calculation --- .../Interop/UnmanagedMethods.cs | 10 ++++ src/Windows/Avalonia.Win32/WindowImpl.cs | 48 +++++++++---------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index adfbf0cb52..60b56ea580 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1172,6 +1172,8 @@ namespace Avalonia.Win32.Interop public int right; public int bottom; + public int Width => right - left; + public int Height => bottom - top; public RECT(Rect rect) { left = (int)rect.X; @@ -1179,6 +1181,14 @@ namespace Avalonia.Win32.Interop right = (int)(rect.X + rect.Width); bottom = (int)(rect.Y + rect.Height); } + + public void Offset(POINT pt) + { + left += pt.X; + right += pt.X; + top += pt.Y; + bottom += pt.Y; + } } [StructLayout(LayoutKind.Sequential)] diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 3eeccb368c..1213be1bf0 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -888,7 +888,7 @@ namespace Avalonia.Win32 private void UpdateWMStyles(Action change) { - var decorated = _decorated; + var oldDecorated = _decorated; var oldThickness = BorderThickness; @@ -912,37 +912,33 @@ namespace Avalonia.Win32 style ^= (WindowStyles.WS_SIZEFRAME); } + GetClientRect(_hwnd, out var oldClientRect); + var oldClientRectOrigin = new UnmanagedMethods.POINT(); + ClientToScreen(_hwnd, ref oldClientRectOrigin); + oldClientRect.Offset(oldClientRectOrigin); + + SetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE, (uint)style); UnmanagedMethods.GetWindowRect(_hwnd, out var windowRect); - - if (decorated != _decorated) + bool frameUpdated = false; + if (oldDecorated != _decorated) { - Rect newRect; - + var newRect = oldClientRect; if (_decorated) - { - var thickness = BorderThickness; - - newRect = new Rect( - windowRect.left - thickness.Left, - windowRect.top - thickness.Top, - (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), - (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); - } - else - { - newRect = new Rect( - windowRect.left + oldThickness.Left, - windowRect.top + oldThickness.Top, - (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), - (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); - } - - UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width, - (int)newRect.Height, - UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + AdjustWindowRectEx(ref newRect, (uint)style, false, + GetWindowLong(_hwnd, (int)WindowLongParam.GWL_EXSTYLE)); + _changingDecorations = true; + SetWindowPos(_hwnd, IntPtr.Zero, newRect.left, newRect.top, newRect.Width, newRect.Height, + SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); + frameUpdated = true; } + + if (!frameUpdated) + SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, + SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOZORDER | + SetWindowPosFlags.SWP_NOACTIVATE + | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); } public void CanResize(bool value) From 6254036fb55a89bfc4dac0f8491c194e7cf0c2e0 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 1 Dec 2018 20:18:21 +0300 Subject: [PATCH 28/28] Opps --- src/Windows/Avalonia.Win32/WindowImpl.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 1213be1bf0..4f97f9a472 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -928,7 +928,6 @@ namespace Avalonia.Win32 if (_decorated) AdjustWindowRectEx(ref newRect, (uint)style, false, GetWindowLong(_hwnd, (int)WindowLongParam.GWL_EXSTYLE)); - _changingDecorations = true; SetWindowPos(_hwnd, IntPtr.Zero, newRect.left, newRect.top, newRect.Width, newRect.Height, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); frameUpdated = true;