From 1a16e423789c46b959c7675d70999e31de77af6b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 23 Nov 2018 15:28:30 +0000 Subject: [PATCH 01/42] 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/42] 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/42] 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/42] 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/42] 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/42] 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 f260ec1df43dd227a23ed69fa473833f54100d63 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 26 Nov 2018 23:40:00 +0100 Subject: [PATCH 07/42] Support relative paths for embedded fonts --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 8 +- src/Avalonia.Visuals/Media/FontFamily.cs | 16 +++- .../Media/Fonts/FontFamilyKey.cs | 66 +++++--------- .../Media/Fonts/FontFamilyLoader.cs | 88 +++++++++++++++---- .../Avalonia.Markup.Xaml.csproj | 1 + .../AvaloniaTypeConverters.cs | 9 +- .../Converters/FontFamilyTypeConverter.cs | 28 ++++++ .../Media/Fonts/FontFamilyKeyTests.cs | 4 +- 8 files changed, 148 insertions(+), 72 deletions(-) create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 2c292b1478..67b60568e5 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -44,10 +44,10 @@ res fonts - - - - + + + + diff --git a/src/Avalonia.Visuals/Media/FontFamily.cs b/src/Avalonia.Visuals/Media/FontFamily.cs index 16dba573fd..d32db4ef28 100644 --- a/src/Avalonia.Visuals/Media/FontFamily.cs +++ b/src/Avalonia.Visuals/Media/FontFamily.cs @@ -40,9 +40,10 @@ namespace Avalonia.Media /// /// The name of the . /// The source of font resources. - public FontFamily(string name, Uri source) : this(name) + /// + public FontFamily(string name, Uri source, Uri baseUri = null) : this(name) { - Key = new FontFamilyKey(source); + Key = new FontFamilyKey(source, baseUri); } /// @@ -87,11 +88,12 @@ namespace Avalonia.Media /// Parses a string. /// /// The string. + /// /// /// /// Specified family is not supported. /// - public static FontFamily Parse(string s) + public static FontFamily Parse(string s, Uri baseUri = null) { if (string.IsNullOrEmpty(s)) { @@ -112,7 +114,13 @@ namespace Avalonia.Media case 2: { - return new FontFamily(segments[1], new Uri(segments[0], UriKind.RelativeOrAbsolute)); + var uri = s.StartsWith("/") + ? new Uri(s, UriKind.Relative) + : new Uri(s, UriKind.RelativeOrAbsolute); + + return uri.IsAbsoluteUri + ? new FontFamily(segments[1], uri) + : new FontFamily(segments[1], uri, baseUri); } default: diff --git a/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs b/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs index 90ccac0e46..67b53cf8b4 100644 --- a/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs +++ b/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; -using System.Linq; namespace Avalonia.Media.Fonts { @@ -12,48 +11,26 @@ namespace Avalonia.Media.Fonts public class FontFamilyKey { /// - /// Creates a new instance of and extracts and from given + /// Creates a new instance of /// /// - public FontFamilyKey(Uri source) + /// + public FontFamilyKey(Uri source, Uri baseUri = null) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } + Source = source ?? throw new ArgumentNullException(nameof(source)); - if (source.AbsolutePath.Contains(".ttf")) - { - var filePathWithoutExtension = source.AbsolutePath.Replace(".ttf", string.Empty); - var fileNameWithoutExtension = filePathWithoutExtension.Split('.').Last(); - FileName = fileNameWithoutExtension + ".ttf"; - Location = new Uri(source.OriginalString.Replace("." + FileName, string.Empty), UriKind.RelativeOrAbsolute); - } - else - { - if (source.AbsolutePath.Contains(".otf")) - { - var filePathWithoutExtension = source.AbsolutePath.Replace(".otf", string.Empty); - var fileNameWithoutExtension = filePathWithoutExtension.Split('.').Last(); - FileName = fileNameWithoutExtension + ".otf"; - Location = new Uri(source.OriginalString.Replace("." + FileName, string.Empty), UriKind.RelativeOrAbsolute); - } - else - { - Location = source; - } - } + BaseUri = baseUri; } /// - /// Location of stored font asset that belongs to a + /// Source of stored font asset that belongs to a /// - public Uri Location { get; } + public Uri Source { get; } /// - /// Optional filename for a font asset that belongs to a + /// /// - public string FileName { get; } + public Uri BaseUri { get; } /// /// Returns a hash code for this instance. @@ -67,14 +44,14 @@ namespace Avalonia.Media.Fonts { var hash = (int)2166136261; - if (Location != null) + if (Source != null) { - hash = (hash * 16777619) ^ Location.GetHashCode(); + hash = (hash * 16777619) ^ Source.GetHashCode(); } - if (FileName != null) + if (BaseUri != null) { - hash = (hash * 16777619) ^ FileName.GetHashCode(); + hash = (hash * 16777619) ^ BaseUri.GetHashCode(); } return hash; @@ -95,12 +72,12 @@ namespace Avalonia.Media.Fonts return false; } - if (Location != other.Location) + if (Source != other.Source) { return false; } - if (FileName != other.FileName) + if (BaseUri != other.BaseUri) { return false; } @@ -116,16 +93,17 @@ namespace Avalonia.Media.Fonts /// public override string ToString() { - if (FileName == null) + if (Source.IsAbsoluteUri) { - return Location.PathAndQuery; + return Source.ToString(); } - var builder = new UriBuilder(Location); - - builder.Path += "." + FileName; + if (BaseUri != null) + { + return BaseUri + "/" + Source; + } - return builder.ToString(); + return Source.ToString(); } } } diff --git a/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs b/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs index 166eb4a661..e1eabf7237 100644 --- a/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs +++ b/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using Avalonia.Platform; namespace Avalonia.Media.Fonts @@ -20,21 +19,26 @@ namespace Avalonia.Media.Fonts public static IEnumerable LoadFontAssets(FontFamilyKey fontFamilyKey) { - return fontFamilyKey.FileName != null - ? GetFontAssetsByFileName(fontFamilyKey.Location, fontFamilyKey.FileName) - : GetFontAssetsByLocation(fontFamilyKey.Location); + if (fontFamilyKey.Source.OriginalString.Contains(".ttf") + || fontFamilyKey.Source.OriginalString.Contains(".otf")) + { + return GetFontAssetsByExpression(fontFamilyKey); + } + + return GetFontAssetsBySource(fontFamilyKey); } /// /// Searches for font assets at a given location and returns a quantity of found assets /// - /// + /// /// - private static IEnumerable GetFontAssetsByLocation(Uri location) + private static IEnumerable GetFontAssetsBySource(FontFamilyKey fontFamilyKey) { - var availableAssets = s_assetLoader.GetAssets(location, null); + var availableAssets = s_assetLoader.GetAssets(fontFamilyKey.Source, fontFamilyKey.BaseUri); - var matchingAssets = availableAssets.Where(x => x.AbsolutePath.EndsWith(".ttf") || x.AbsolutePath.EndsWith(".otf")); + var matchingAssets = + availableAssets.Where(x => x.AbsolutePath.EndsWith(".ttf") || x.AbsolutePath.EndsWith(".otf")); return matchingAssets; } @@ -43,20 +47,74 @@ namespace Avalonia.Media.Fonts /// Searches for font assets at a given location and only accepts assets that fit to a given filename expression. /// File names can target multiple files with * wildcard. For example "FontFile*.ttf" /// - /// - /// + /// /// - private static IEnumerable GetFontAssetsByFileName(Uri location, string fileName) + private static IEnumerable GetFontAssetsByExpression(FontFamilyKey fontFamilyKey) { - var availableResources = s_assetLoader.GetAssets(location, null); + var fileName = GetFileName(fontFamilyKey, out var fileExtension, out var location); + + var availableResources = s_assetLoader.GetAssets(location, fontFamilyKey.BaseUri); - var compareTo = location.AbsolutePath + "." + fileName.Split('*').First(); + string compareTo; - var matchingResources = - availableResources.Where(x => x.AbsolutePath.Contains(compareTo) && (x.AbsolutePath.EndsWith(".ttf") || x.AbsolutePath.EndsWith(".otf"))); + if (fontFamilyKey.Source.IsAbsoluteUri) + { + if (fontFamilyKey.Source.Scheme == "resm") + { + compareTo = location.AbsolutePath + "." + fileName.Split('*').First(); + } + else + { + compareTo = location.AbsolutePath + fileName.Split('*').First(); + } + } + else + { + compareTo = location.AbsolutePath + fileName.Split('*').First(); + } + + var matchingResources = availableResources.Where( + x => x.AbsolutePath.Contains(compareTo) + && x.AbsolutePath.EndsWith(fileExtension)); return matchingResources; } + private static string GetFileName(FontFamilyKey fontFamilyKey, out string fileExtension, out Uri location) + { + if (fontFamilyKey.Source.IsAbsoluteUri && fontFamilyKey.Source.Scheme == "resm") + { + fileExtension = "." + fontFamilyKey.Source.AbsolutePath.Split('.').LastOrDefault(); + + var fileName = fontFamilyKey.Source.LocalPath.Replace(fileExtension, string.Empty).Split('.').LastOrDefault(); + + location = new Uri(fontFamilyKey.Source.AbsoluteUri.Replace("." + fileName + fileExtension, string.Empty), UriKind.RelativeOrAbsolute); + + return fileName; + } + + var pathSegments = fontFamilyKey.Source.OriginalString.Split('/'); + + var fileNameWithExtension = pathSegments.Last().Split('#').First(); + + var fileNameSegments = fileNameWithExtension.Split('.'); + + fileExtension = "." + fileNameSegments.Last(); + + if (fontFamilyKey.BaseUri != null) + { + location = new Uri( + fontFamilyKey.BaseUri, + fontFamilyKey.Source.OriginalString.Split('#') + .First() + .Replace(fileNameWithExtension, string.Empty)); + } + else + { + location = new Uri(fontFamilyKey.Source.AbsolutePath.Replace(fileNameWithExtension, string.Empty)); + } + + return fileNameSegments.First(); + } } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index ec73859a0a..bb3883285a 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs index 93db025343..fa9d364fc0 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs @@ -11,6 +11,8 @@ using Avalonia.Controls.Templates; namespace Avalonia.Markup.Xaml { + using Avalonia.Media; + /// /// Maintains a repository of s for XAML parsing on top of those /// maintained by . @@ -37,8 +39,9 @@ namespace Avalonia.Markup.Xaml { typeof(Selector), typeof(SelectorTypeConverter) }, { typeof(TimeSpan), typeof(TimeSpanTypeConverter) }, { typeof(WindowIcon), typeof(IconTypeConverter) }, - { typeof(CultureInfo), typeof(CultureInfoConverter)}, - { typeof(Uri), typeof(AvaloniaUriTypeConverter)} + { typeof(CultureInfo), typeof(CultureInfoConverter) }, + { typeof(Uri), typeof(AvaloniaUriTypeConverter) }, + { typeof(FontFamily), typeof(FontFamilyTypeConverter) } }; /// @@ -84,4 +87,4 @@ namespace Avalonia.Markup.Xaml /// The converter type. Maybe be a non-constructed generic type. public static void Register(Type type, Type converterType) => _converters[type] = converterType; } -} \ No newline at end of file +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs new file mode 100644 index 0000000000..9b0e7a2b6b --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs @@ -0,0 +1,28 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.ComponentModel; +using System.Globalization; + +using Avalonia.Media; + +using Portable.Xaml.ComponentModel; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class FontFamilyTypeConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + var s = (string)value; + + return FontFamily.Parse(s, context.GetBaseUri()); + } + } +} diff --git a/tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyKeyTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyKeyTests.cs index 96464b5784..38ad9e1866 100644 --- a/tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyKeyTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyKeyTests.cs @@ -22,7 +22,7 @@ namespace Avalonia.Visuals.UnitTests.Media.Fonts var fontFamilyKey = new FontFamilyKey(source); - Assert.Equal(new Uri("resm:Avalonia.Visuals.UnitTests"), fontFamilyKey.Location); + Assert.Equal(new Uri("resm:Avalonia.Visuals.UnitTests"), fontFamilyKey.Source); Assert.Null(fontFamilyKey.FileName); } @@ -34,7 +34,7 @@ namespace Avalonia.Visuals.UnitTests.Media.Fonts var fontFamilyKey = new FontFamilyKey(source); - Assert.Equal(new Uri("resm:Avalonia.Visuals.UnitTests"), fontFamilyKey.Location); + Assert.Equal(new Uri("resm:Avalonia.Visuals.UnitTests"), fontFamilyKey.Source); Assert.Equal("MyFont.ttf", fontFamilyKey.FileName); } From 54627eeff114f98cc231d7c788492ed40f0e4f16 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 27 Nov 2018 14:29:10 +0200 Subject: [PATCH 08/42] add failing unittest for immediaterenderer not rendering sometimes controls issue #2141 --- .../Rendering/ImmediateRendererTests.cs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs index 82294246b1..73e4a14539 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs @@ -1,8 +1,11 @@ using System.Collections.Generic; using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Layout; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; +using Avalonia.UnitTests; using Avalonia.VisualTree; using Moq; using Xunit; @@ -94,5 +97,86 @@ namespace Avalonia.Visuals.UnitTests.Rendering //then new position Assert.Equal(new Rect(100, 100, 100, 100), invalidationCalls[2]); } + + [Fact] + public void Should_Render_Child_In_Parent_With_RenderTransform() + { + var targetMock = new Mock() { CallBase = true }; + var target = targetMock.Object; + target.Width = 100; + target.Height = 50; + var child = new Panel() + { + RenderTransform = new RotateTransform() { Angle = 90 }, + Children = + { + new Panel() + { + Children = + { + target + } + } + } + }; + + var visualTarget = targetMock.As(); + int rendered = 0; + visualTarget.Setup(v => v.Render(It.IsAny())).Callback(() => rendered++); + + var root = new TestRoot(child); + root.Renderer = new ImmediateRenderer(root); + + root.LayoutManager.ExecuteInitialLayoutPass(root); + + root.Measure(new Size(50, 100)); + root.Arrange(new Rect(new Size(50, 100))); + + root.Renderer.Paint(root.Bounds); + + Assert.Equal(1, rendered); + } + + [Fact] + public void Should_Render_Child_In_Parent_With_RenderTransform2() + { + var targetMock = new Mock() { CallBase = true }; + var target = targetMock.Object; + + target.Width = 100; + target.Height = 50; + target.HorizontalAlignment = HorizontalAlignment.Center; + target.VerticalAlignment = VerticalAlignment.Center; + + var child = new Panel() + { + RenderTransform = new RotateTransform() { Angle = 90 }, + Children = + { + new Panel() + { + Children = + { + target + } + } + } + }; + + var visualTarget = targetMock.As(); + int rendered = 0; + visualTarget.Setup(v => v.Render(It.IsAny())).Callback(() => rendered++); + + var root = new TestRoot(child); + root.Renderer = new ImmediateRenderer(root); + + root.LayoutManager.ExecuteInitialLayoutPass(root); + + root.Measure(new Size(300, 100)); + root.Arrange(new Rect(new Size(300, 100))); + root.Renderer.Paint(root.Bounds); + + Assert.Equal(1, rendered); + } } } From 55600239a6f64ff2850a3afbc96b00b6750e00f5 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 27 Nov 2018 21:03:00 +0200 Subject: [PATCH 09/42] fix for immediaterenderer not rendering sometimes controls issue #2141 --- src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 08f3803e9b..03ac004fd5 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -266,7 +266,14 @@ namespace Avalonia.Rendering if (clipToBounds) { - clipRect = clipRect.Intersect(new Rect(visual.Bounds.Size)); + if (visual.RenderTransform != null) + { + clipRect = new Rect(visual.Bounds.Size); + } + else + { + clipRect = clipRect.Intersect(new Rect(visual.Bounds.Size)); + } } using (context.PushPostTransform(m)) From 1d19e28e9b839faaa63f6e9bba0748227a168188 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 28 Nov 2018 14:17:50 +0100 Subject: [PATCH 10/42] Full support for relative uris --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 4 ++-- src/Avalonia.Visuals/Media/FontFamily.cs | 6 +++--- src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs | 11 +++-------- .../Media/Fonts/FontFamilyLoader.cs | 13 ++++++------- .../Media/Fonts/FontFamilyKeyTests.cs | 6 +----- 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 67b60568e5..0c0a4d705b 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -44,8 +44,8 @@ res fonts - - + + diff --git a/src/Avalonia.Visuals/Media/FontFamily.cs b/src/Avalonia.Visuals/Media/FontFamily.cs index d32db4ef28..0ba25e6c0d 100644 --- a/src/Avalonia.Visuals/Media/FontFamily.cs +++ b/src/Avalonia.Visuals/Media/FontFamily.cs @@ -114,9 +114,9 @@ namespace Avalonia.Media case 2: { - var uri = s.StartsWith("/") - ? new Uri(s, UriKind.Relative) - : new Uri(s, UriKind.RelativeOrAbsolute); + var uri = segments[0].StartsWith("/") + ? new Uri(segments[0], UriKind.Relative) + : new Uri(segments[0], UriKind.RelativeOrAbsolute); return uri.IsAbsoluteUri ? new FontFamily(segments[1], uri) diff --git a/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs b/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs index 67b53cf8b4..2803b942ad 100644 --- a/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs +++ b/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs @@ -28,7 +28,7 @@ namespace Avalonia.Media.Fonts public Uri Source { get; } /// - /// + /// A base URI to use if is relative /// public Uri BaseUri { get; } @@ -93,14 +93,9 @@ namespace Avalonia.Media.Fonts /// public override string ToString() { - if (Source.IsAbsoluteUri) + if (!Source.IsAbsoluteUri && BaseUri != null) { - return Source.ToString(); - } - - if (BaseUri != null) - { - return BaseUri + "/" + Source; + return string.Empty + BaseUri + Source; } return Source.ToString(); diff --git a/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs b/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs index e1eabf7237..623125164c 100644 --- a/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs +++ b/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs @@ -71,7 +71,7 @@ namespace Avalonia.Media.Fonts else { compareTo = location.AbsolutePath + fileName.Split('*').First(); - } + } var matchingResources = availableResources.Where( x => x.AbsolutePath.Contains(compareTo) @@ -95,7 +95,7 @@ namespace Avalonia.Media.Fonts var pathSegments = fontFamilyKey.Source.OriginalString.Split('/'); - var fileNameWithExtension = pathSegments.Last().Split('#').First(); + var fileNameWithExtension = pathSegments.Last(); var fileNameSegments = fileNameWithExtension.Split('.'); @@ -103,11 +103,10 @@ namespace Avalonia.Media.Fonts if (fontFamilyKey.BaseUri != null) { - location = new Uri( - fontFamilyKey.BaseUri, - fontFamilyKey.Source.OriginalString.Split('#') - .First() - .Replace(fileNameWithExtension, string.Empty)); + var relativePath = fontFamilyKey.Source.OriginalString + .Replace(fileNameWithExtension, string.Empty); + + location = new Uri(fontFamilyKey.BaseUri, relativePath); } else { diff --git a/tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyKeyTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyKeyTests.cs index 38ad9e1866..b57ba781ed 100644 --- a/tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyKeyTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyKeyTests.cs @@ -23,8 +23,6 @@ namespace Avalonia.Visuals.UnitTests.Media.Fonts var fontFamilyKey = new FontFamilyKey(source); Assert.Equal(new Uri("resm:Avalonia.Visuals.UnitTests"), fontFamilyKey.Source); - - Assert.Null(fontFamilyKey.FileName); } [Fact] @@ -34,9 +32,7 @@ namespace Avalonia.Visuals.UnitTests.Media.Fonts var fontFamilyKey = new FontFamilyKey(source); - Assert.Equal(new Uri("resm:Avalonia.Visuals.UnitTests"), fontFamilyKey.Source); - - Assert.Equal("MyFont.ttf", fontFamilyKey.FileName); + Assert.Equal(new Uri("resm:Avalonia.Visuals.UnitTests.MyFont.ttf"), fontFamilyKey.Source); } } } From d6c9ce3277cefa3754b8cc66ec44cb9da5af93aa Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 28 Nov 2018 17:15:40 +0100 Subject: [PATCH 11/42] Make sure only font files are compared --- src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs | 2 +- src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs b/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs index 2803b942ad..76ee2b7aad 100644 --- a/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs +++ b/src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs @@ -95,7 +95,7 @@ namespace Avalonia.Media.Fonts { if (!Source.IsAbsoluteUri && BaseUri != null) { - return string.Empty + BaseUri + Source; + return BaseUri.Authority + Source; } return Source.ToString(); diff --git a/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs b/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs index 623125164c..1e1049d017 100644 --- a/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs +++ b/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs @@ -19,8 +19,10 @@ namespace Avalonia.Media.Fonts public static IEnumerable LoadFontAssets(FontFamilyKey fontFamilyKey) { - if (fontFamilyKey.Source.OriginalString.Contains(".ttf") - || fontFamilyKey.Source.OriginalString.Contains(".otf")) + var sourceWithoutArguments = fontFamilyKey.Source.OriginalString.Split('?').First(); + + if (sourceWithoutArguments.EndsWith(".ttf") + || sourceWithoutArguments.EndsWith(".otf")) { return GetFontAssetsByExpression(fontFamilyKey); } From bd97346b97ad76c00742b7dd6805c3d00105fe57 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 28 Nov 2018 17:18:06 +0100 Subject: [PATCH 12/42] Fix missing comment --- src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs b/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs index 1e1049d017..063fe8f20d 100644 --- a/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs +++ b/src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs @@ -17,6 +17,11 @@ namespace Avalonia.Media.Fonts s_assetLoader = AvaloniaLocator.Current.GetService(); } + /// + /// Loads all font assets that belong to the specified + /// + /// + /// public static IEnumerable LoadFontAssets(FontFamilyKey fontFamilyKey) { var sourceWithoutArguments = fontFamilyKey.Source.OriginalString.Split('?').First(); From c4cc3514a8c35f36230f8902bbddbf7bffaf624f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 28 Nov 2018 16:57:49 +0000 Subject: [PATCH 13/42] 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 14/42] 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 15/42] 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 ea8bde211b57bfdfabfdd0ddf7452f6e3ce52c4c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 29 Nov 2018 11:31:07 +0300 Subject: [PATCH 16/42] Additional `Start` method overload --- samples/ControlCatalog.NetCore/Program.cs | 10 ++++++++-- src/Avalonia.Controls/AppBuilderBase.cs | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs index 1f53dedc14..57c8b700df 100644 --- a/samples/ControlCatalog.NetCore/Program.cs +++ b/samples/ControlCatalog.NetCore/Program.cs @@ -23,6 +23,7 @@ namespace ControlCatalog.NetCore break; } } + if (args.Contains("--fbdev")) AppBuilder.Configure().InitializeWithLinuxFramebuffer(tl => { @@ -30,7 +31,12 @@ namespace ControlCatalog.NetCore System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer()); }); else - BuildAvaloniaApp().Start(); + BuildAvaloniaApp().Start(AppMain, args); + } + + static void AppMain(Application app, string[] args) + { + app.Run(new MainWindow()); } /// @@ -46,4 +52,4 @@ namespace ControlCatalog.NetCore Console.ReadKey(true); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 376714b20b..c5dd072d8a 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -145,6 +145,15 @@ namespace Avalonia.Controls Instance.Run(mainWindow); } + public delegate void AppMainDelegate(Application app, string[] args); + + public void Start(AppMainDelegate main, string[] args) + { + Setup(); + BeforeStartCallback(Self); + main(Instance, args); + } + /// /// Sets up the platform-specific services for the application, but does not run it. /// From 053e6a2be57006efd9be9aea783bd1d311cc40a6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 30 Nov 2018 13:02:40 +0000 Subject: [PATCH 17/42] 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 18/42] [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 19/42] 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 20/42] 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 21/42] 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 22/42] [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 23/42] 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 24/42] 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 f8d3046cb59d09107d112aa801810a6bfffb9893 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 1 Dec 2018 17:54:32 +0300 Subject: [PATCH 25/42] Switched build to Nuke --- .nuke | 0 .travis.yml | 2 +- Avalonia.sln | 6 + appveyor.yml | 2 +- azure-pipelines.yml | 25 ++- build.cake | 312 ---------------------------- build.ps1 | 226 +++++--------------- build.sh | 139 +++++-------- cake.config | 15 -- nukebuild/Build.cs | 278 +++++++++++++++++++++++++ nukebuild/BuildParameters.cs | 186 +++++++++++++++++ nukebuild/Shims.cs | 80 +++++++ nukebuild/_build.csproj | 35 ++++ nukebuild/_build.csproj.DotSettings | 24 +++ 14 files changed, 723 insertions(+), 607 deletions(-) create mode 100644 .nuke delete mode 100644 build.cake delete mode 100644 cake.config create mode 100644 nukebuild/Build.cs create mode 100644 nukebuild/BuildParameters.cs create mode 100644 nukebuild/Shims.cs create mode 100644 nukebuild/_build.csproj create mode 100644 nukebuild/_build.csproj.DotSettings diff --git a/.nuke b/.nuke new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.travis.yml b/.travis.yml index b0c0c807cb..d60323b418 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ dotnet: 2.1.200 script: - sudo apt-get update - sudo apt-get install castxml - - ./build.sh --target "Travis" --configuration "Release" + - ./build.sh --target "CiTravis" --configuration "Release" notifications: email: false webhooks: diff --git a/Avalonia.sln b/Avalonia.sln index df60ff4a75..e006cadb5a 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -191,6 +191,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Desktop", "src\Ava EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Build.Tasks", "src\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj", "{BF28998D-072C-439A-AFBB-2FE5021241E0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "nukebuild\_build.csproj", "{3F00BC43-5095-477F-93D8-E65B08179A00}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 @@ -216,6 +218,10 @@ Global Release|iPhoneSimulator = Release|iPhoneSimulator EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.Build.0 = Release|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU diff --git a/appveyor.yml b/appveyor.yml index 484fb4586f..8694495e66 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,7 +14,7 @@ init: before_build: - git submodule update --init build_script: -- ps: .\build.ps1 -Target "AppVeyor" -Configuration "$env:configuration" +- ps: .\build.ps1 --target "CiAppVeyor" --configuration "$env:configuration" test: off artifacts: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f6929f8dee..dec361affe 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,19 +11,18 @@ jobs: sudo apt-get install castxml - task: CmdLine@2 - displayName: 'Install Cake' + displayName: 'Install Nuke' inputs: script: | - dotnet tool install -g Cake.Tool --version 0.30.0 - + dotnet tool install --global Nuke.GlobalTool --version 0.12.3 - task: CmdLine@2 - displayName: 'Run Cake' + displayName: 'Run Nuke' inputs: script: | export PATH="$PATH:$HOME/.dotnet/tools" dotnet --info printenv - dotnet cake build.cake -target="Azure-Linux" -configuration="Release" + nuke --target="CiAzureLinux" --configuration="Release" - task: PublishTestResults@2 inputs: @@ -55,13 +54,13 @@ jobs: script: brew install castxml - task: CmdLine@2 - displayName: 'Install Cake' + displayName: 'Install Nuke' inputs: script: | - dotnet tool install -g Cake.Tool --version 0.30.0 + dotnet tool install --global Nuke.GlobalTool --version 0.12.3 - task: CmdLine@2 - displayName: 'Run Cake' + displayName: 'Run Nuke' inputs: script: | export COREHOST_TRACE=0 @@ -72,7 +71,7 @@ jobs: export PATH="$PATH:$HOME/.dotnet/tools" dotnet --info printenv - dotnet cake build.cake -target="Azure-OSX" -configuration="Release" + nuke --target="CiAzureOSX" --configuration="Release" - task: PublishTestResults@2 inputs: @@ -97,17 +96,17 @@ jobs: vmImage: 'vs2017-win2016' steps: - task: CmdLine@2 - displayName: 'Install Cake' + displayName: 'Install Nuke' inputs: script: | - dotnet tool install -g Cake.Tool --version 0.30.0 + dotnet tool install --global Nuke.GlobalTool --version 0.12.3 - task: CmdLine@2 - displayName: 'Run Cake' + displayName: 'Run Nuke' inputs: script: | set PATH=%PATH%;%USERPROFILE%\.dotnet\tools - dotnet cake build.cake -target="Azure-Windows" -configuration="Release" + nuke --target="CiAzureWindows" --configuration="Release" - task: PublishTestResults@2 inputs: diff --git a/build.cake b/build.cake deleted file mode 100644 index f10a12c4e6..0000000000 --- a/build.cake +++ /dev/null @@ -1,312 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// TOOLS -/////////////////////////////////////////////////////////////////////////////// - -#tool "nuget:?package=NuGet.CommandLine&version=4.7.1" -#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2018.2.3" -#tool "nuget:?package=xunit.runner.console&version=2.3.1" -#tool "nuget:?package=JetBrains.dotMemoryUnit&version=3.0.20171219.105559" - -/////////////////////////////////////////////////////////////////////////////// -// USINGS -/////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -/////////////////////////////////////////////////////////////////////////////// -// SCRIPTS -/////////////////////////////////////////////////////////////////////////////// - -#load "./parameters.cake" - -/////////////////////////////////////////////////////////////////////////////// -// SETUP -/////////////////////////////////////////////////////////////////////////////// - -Setup(context => -{ - var parameters = new Parameters(context); - - Information("Building version {0} of Avalonia ({1}) using version {2} of Cake.", - parameters.Version, - parameters.Configuration, - typeof(ICakeContext).Assembly.GetName().Version.ToString()); - - if (parameters.IsRunningOnAppVeyor) - { - Information("Repository Name: " + BuildSystem.AppVeyor.Environment.Repository.Name); - Information("Repository Branch: " + BuildSystem.AppVeyor.Environment.Repository.Branch); - } - Information("Target:" + context.TargetTask.Name); - Information("Configuration: " + parameters.Configuration); - Information("IsLocalBuild: " + parameters.IsLocalBuild); - Information("IsRunningOnUnix: " + parameters.IsRunningOnUnix); - Information("IsRunningOnWindows: " + parameters.IsRunningOnWindows); - Information("IsRunningOnAppVeyor: " + parameters.IsRunningOnAppVeyor); - Information("IsRunnongOnAzure:" + parameters.IsRunningOnAzure); - Information("IsPullRequest: " + parameters.IsPullRequest); - Information("IsMainRepo: " + parameters.IsMainRepo); - Information("IsMasterBranch: " + parameters.IsMasterBranch); - Information("IsReleaseBranch: " + parameters.IsReleaseBranch); - Information("IsTagged: " + parameters.IsTagged); - Information("IsReleasable: " + parameters.IsReleasable); - Information("IsMyGetRelease: " + parameters.IsMyGetRelease); - Information("IsNuGetRelease: " + parameters.IsNuGetRelease); - - return parameters; -}); - -/////////////////////////////////////////////////////////////////////////////// -// TEARDOWN -/////////////////////////////////////////////////////////////////////////////// - -Teardown((context, buildContext) => -{ - Information("Finished running tasks."); -}); - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -Task("Clean-Impl") - .Does(data => -{ - CleanDirectories(data.BuildDirs); - CleanDirectory(data.ArtifactsDir); - CleanDirectory(data.NugetRoot); - CleanDirectory(data.ZipRoot); - CleanDirectory(data.TestResultsRoot); -}); - -void DotNetCoreBuild(Parameters parameters) -{ - var settings = new DotNetCoreBuildSettings - { - Configuration = parameters.Configuration, - MSBuildSettings = new DotNetCoreMSBuildSettings - { - Properties = - { - { "PackageVersion", new [] { parameters.Version } } - } - } - }; - - DotNetCoreBuild(parameters.MSBuildSolution, settings); -} - -Task("Build-Impl") - .Does(data => -{ - if(data.IsRunningOnWindows) - { - MSBuild(data.MSBuildSolution, settings => { - settings.SetConfiguration(data.Configuration); - settings.SetVerbosity(Verbosity.Minimal); - settings.WithProperty("iOSRoslynPathHackRequired", "true"); - settings.WithProperty("PackageVersion", data.Version); - settings.UseToolVersion(MSBuildToolVersion.VS2017); - settings.WithRestore(); - }); - } - else - { - DotNetCoreBuild(data); - } -}); - -void RunCoreTest(string project, Parameters parameters, bool coreOnly = false) -{ - if(!project.EndsWith(".csproj")) - project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj"); - Information("Running tests from " + project); - var frameworks = new List(){"netcoreapp2.0"}; - foreach(var fw in frameworks) - { - if(!fw.StartsWith("netcoreapp") && coreOnly) - continue; - Information("Running for " + fw); - - var settings = new DotNetCoreTestSettings { - Configuration = parameters.Configuration, - Framework = fw, - NoBuild = true, - NoRestore = true - }; - - if (parameters.PublishTestResults) - { - settings.Logger = "trx"; - settings.ResultsDirectory = parameters.TestResultsRoot; - } - - DotNetCoreTest(project, settings); - } -} - -Task("Run-Unit-Tests-Impl") - .WithCriteria((context, data) => !data.SkipTests) - .Does(data => -{ - RunCoreTest("./tests/Avalonia.Base.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Controls.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Input.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Layout.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Markup.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Styling.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Visuals.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.Skia.UnitTests", data, false); - RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests", data, false); - if (data.IsRunningOnWindows) - { - RunCoreTest("./tests/Avalonia.Direct2D1.UnitTests", data, false); - } -}); - -Task("Run-Designer-Tests-Impl") - .WithCriteria((context, data) => !data.SkipTests) - .Does(data => -{ - RunCoreTest("./tests/Avalonia.DesignerSupport.Tests", data, false); -}); - -Task("Run-Render-Tests-Impl") - .WithCriteria((context, data) => !data.SkipTests) - .WithCriteria((context, data) => data.IsRunningOnWindows) - .Does(data => -{ - RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", data, true); - RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", data, true); -}); - -Task("Run-Leak-Tests-Impl") - .WithCriteria((context, data) => !data.SkipTests) - .WithCriteria((context, data) => data.IsRunningOnWindows) - .Does(() => -{ - var dotMemoryUnit = Context.Tools.Resolve("dotMemoryUnit.exe"); - var leakTestsExitCode = StartProcess(dotMemoryUnit, new ProcessSettings - { - Arguments = new ProcessArgumentBuilder() - .Append(Context.Tools.Resolve("xunit.console.x86.exe").FullPath) - .Append("--propagate-exit-code") - .Append("--") - .Append("tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll"), - Timeout = 120000 - }); - - if (leakTestsExitCode != 0) - { - throw new Exception("Leak Tests failed"); - } -}); - -Task("Zip-Files-Impl") - .Does(data => -{ - Zip(data.BinRoot, data.ZipCoreArtifacts); - - Zip(data.NugetRoot, data.ZipNuGetArtifacts); - - Zip(data.ZipSourceControlCatalogDesktopDirs, - data.ZipTargetControlCatalogDesktopDirs, - GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") + - GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.config") + - GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.so") + - GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dylib") + - GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe")); -}); - -void DotNetCorePack(Parameters parameters) -{ - var settings = new DotNetCorePackSettings - { - Configuration = parameters.Configuration, - MSBuildSettings = new DotNetCoreMSBuildSettings - { - Properties = - { - { "PackageVersion", new [] { parameters.Version } } - } - } - }; - - DotNetCorePack(parameters.MSBuildSolution, settings); -} - -Task("Create-NuGet-Packages-Impl") - .Does(data => -{ - if(data.IsRunningOnWindows) - { - MSBuild(data.MSBuildSolution, settings => { - settings.SetConfiguration(data.Configuration); - settings.SetVerbosity(Verbosity.Minimal); - settings.WithProperty("iOSRoslynPathHackRequired", "true"); - settings.WithProperty("PackageVersion", data.Version); - settings.UseToolVersion(MSBuildToolVersion.VS2017); - settings.WithRestore(); - settings.WithTarget("Pack"); - }); - } - else - { - DotNetCorePack(data); - } -}); - -/////////////////////////////////////////////////////////////////////////////// -// TARGETS -/////////////////////////////////////////////////////////////////////////////// - -Task("Build") - .IsDependentOn("Clean-Impl") - .IsDependentOn("Build-Impl"); - -Task("Run-Tests") - .IsDependentOn("Build") - .IsDependentOn("Run-Unit-Tests-Impl") - .IsDependentOn("Run-Render-Tests-Impl") - .IsDependentOn("Run-Designer-Tests-Impl") - .IsDependentOn("Run-Leak-Tests-Impl"); - -Task("Package") - .IsDependentOn("Run-Tests") - .IsDependentOn("Create-NuGet-Packages-Impl"); - -Task("AppVeyor") - .IsDependentOn("Package") - .IsDependentOn("Zip-Files-Impl"); - -Task("Travis") - .IsDependentOn("Run-Tests"); - -Task("Azure-Linux") - .IsDependentOn("Run-Tests"); - -Task("Azure-OSX") - .IsDependentOn("Package") - .IsDependentOn("Zip-Files-Impl"); - -Task("Azure-Windows") - .IsDependentOn("Package") - .IsDependentOn("Zip-Files-Impl"); - -/////////////////////////////////////////////////////////////////////////////// -// EXECUTE -/////////////////////////////////////////////////////////////////////////////// - -var target = Context.Argument("target", "Default"); - -if (target == "Default") -{ - target = Context.IsRunningOnWindows() ? "Package" : "Run-Tests"; -} - -RunTarget(target); diff --git a/build.ps1 b/build.ps1 index 46696db2b2..57e2f80075 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,201 +1,69 @@ -########################################################################## -# This is the Cake bootstrapper script for PowerShell. -# This file was downloaded from https://github.com/cake-build/resources -# Feel free to change this file to fit your needs. -########################################################################## - -<# - -.SYNOPSIS -This is a Powershell script to bootstrap a Cake build. - -.DESCRIPTION -This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) -and execute your Cake build script with the parameters you provide. - -.PARAMETER Script -The build script to execute. -.PARAMETER Target -The build script target to run. -.PARAMETER Platform -The build platform to use. -.PARAMETER Configuration -The build configuration to use. -.PARAMETER Verbosity -Specifies the amount of information to be displayed. -.PARAMETER Experimental -Tells Cake to use the latest Roslyn release. -.PARAMETER WhatIf -Performs a dry run of the build script. -No tasks will be executed. -.PARAMETER Mono -Tells Cake to use the Mono scripting engine. -.PARAMETER SkipToolPackageRestore -Skips restoring of packages. -.PARAMETER SkipTests -Skips unit tests -.PARAMETER ScriptArgs -Remaining arguments are added here. - -.LINK -http://cakebuild.net - -#> - [CmdletBinding()] Param( - [string]$Script = "build.cake", - [string]$Target = "Default", - [ValidateSet("Any CPU", "x86", "x64", "NetCoreOnly", "iPhone")] - [string]$Platform = "Any CPU", - [ValidateSet("Release", "Debug")] - [string]$Configuration = "Release", - [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] - [string]$Verbosity = "Verbose", - [switch]$Experimental, - [Alias("DryRun","Noop")] - [switch]$WhatIf, - [switch]$Mono, - [switch]$SkipToolPackageRestore, + #[switch]$CustomParam, [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] - [string[]]$ScriptArgs + [string[]]$BuildArguments ) -[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null -function MD5HashFile([string] $filePath) -{ - if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) - { - return $null - } - - [System.IO.Stream] $file = $null; - [System.Security.Cryptography.MD5] $md5 = $null; - try - { - $md5 = [System.Security.Cryptography.MD5]::Create() - $file = [System.IO.File]::OpenRead($filePath) - return [System.BitConverter]::ToString($md5.ComputeHash($file)) - } - finally - { - if ($file -ne $null) - { - $file.Dispose() - } - } -} - -Write-Host "Preparing to run build script..." - -if(!$PSScriptRoot){ - $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent -} +Write-Output "Windows PowerShell $($Host.Version)" -$TOOLS_DIR = Join-Path $PSScriptRoot "tools" -$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" -$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" -$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" -$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" +Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { exit 1 } +$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent -# Should we use mono? -$UseMono = ""; -if($Mono.IsPresent) { - Write-Verbose -Message "Using the Mono based scripting engine." - $UseMono = "-mono" -} +########################################################################### +# CONFIGURATION +########################################################################### -# Should we use the new Roslyn? -$UseExperimental = ""; -if($Experimental.IsPresent -and !($Mono.IsPresent)) { - Write-Verbose -Message "Using experimental version of Roslyn." - $UseExperimental = "-experimental" -} +$BuildProjectFile = "$PSScriptRoot\nukebuild\_build.csproj" +$TempDirectory = "$PSScriptRoot\\.tmp" -# Is this a dry run? -$UseDryRun = ""; -if($WhatIf.IsPresent) { - $UseDryRun = "-dryrun" -} +$DotNetGlobalFile = "$PSScriptRoot\\global.json" +$DotNetInstallUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1" +$DotNetChannel = "Current" -# Is this a dry run? -$UseSkipTests = ""; -if($SkipTests.IsPresent) { - $UseSkipTests = "-skip-tests" -} +$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1 +$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 +$env:NUGET_XMLDOC_MODE = "skip" -# Make sure tools folder exists -if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { - Write-Verbose -Message "Creating tools directory..." - New-Item -Path $TOOLS_DIR -Type directory | out-null -} +########################################################################### +# EXECUTION +########################################################################### -# Make sure that packages.config exist. -if (!(Test-Path $PACKAGES_CONFIG)) { - Write-Verbose -Message "Downloading packages.config..." - try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { - Throw "Could not download packages.config." - } +function ExecSafe([scriptblock] $cmd) { + & $cmd + if ($LASTEXITCODE) { exit $LASTEXITCODE } } -# Try find NuGet.exe in path if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Trying to find nuget.exe in PATH..." - $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } - $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 - if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { - Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." - $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName +# If global.json exists, load expected version +if (Test-Path $DotNetGlobalFile) { + $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json) + if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) { + $DotNetVersion = $DotNetGlobal.sdk.version } } -# Try download NuGet.exe if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Downloading NuGet.exe..." - try { - (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) - } catch { - Throw "Could not download NuGet.exe." - } +# If dotnet is installed locally, and expected version is not set or installation matches the expected version +if ((Get-Command "dotnet" -ErrorAction SilentlyContinue) -ne $null -and ` + (!(Test-Path variable:DotNetVersion) -or $(& dotnet --version) -eq $DotNetVersion)) { + $env:DOTNET_EXE = (Get-Command "dotnet").Path } - -# Save nuget.exe path to environment to be available to child processed -$ENV:NUGET_EXE = $NUGET_EXE - -# Restore tools from NuGet? -if(-Not $SkipToolPackageRestore.IsPresent) { - Push-Location - Set-Location $TOOLS_DIR - - # Check for changes in packages.config and remove installed tools if true. - [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) - if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or - ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { - Write-Verbose -Message "Missing or changed package.config hash..." - Remove-Item * -Recurse -Exclude packages.config,nuget.exe +else { + $DotNetDirectory = "$TempDirectory\dotnet-win" + $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" + + # Download install script + $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1" + md -force $TempDirectory > $null + (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile) + + # Install by channel or version + if (!(Test-Path variable:DotNetVersion)) { + ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } + } else { + ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } } - - Write-Verbose -Message "Restoring tools from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occured while restoring NuGet tools." - } - else - { - $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" - } - Write-Verbose -Message ($NuGetOutput | out-string) - Pop-Location } -# Make sure that Cake has been installed. -if (!(Test-Path $CAKE_EXE)) { - Throw "Could not find Cake.exe at $CAKE_EXE" -} +Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)" -# Start Cake -Write-Host "Running build script..." -Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -platform=`"$Platform`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseSkipTests $UseMono $UseDryRun $UseExperimental $ScriptArgs" -exit $LASTEXITCODE \ No newline at end of file +ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile -- $BuildArguments } diff --git a/build.sh b/build.sh index 206a55d171..40b1c225a6 100755 --- a/build.sh +++ b/build.sh @@ -1,105 +1,72 @@ #!/usr/bin/env bash -########################################################################## -# This is the Cake bootstrapper script for Linux and OS X. -# This file was downloaded from https://github.com/cake-build/resources -# Feel free to change this file to fit your needs. -########################################################################## +echo $(bash --version 2>&1 | head -n 1) -# Define directories. -SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -TOOLS_DIR=$SCRIPT_DIR/tools -NUGET_EXE=$TOOLS_DIR/nuget.exe -CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe -PACKAGES_CONFIG=$TOOLS_DIR/packages.config -PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum - -# Define md5sum or md5 depending on Linux/OSX -MD5_EXE= -if [[ "$(uname -s)" == "Darwin" ]]; then - MD5_EXE="md5 -r" -else - MD5_EXE="md5sum" -fi - -# Define default arguments. -SCRIPT="build.cake" -TARGET="Default" -CONFIGURATION="Release" -PLATFORM="Any CPU" -VERBOSITY="verbose" -DRYRUN= -SKIP_TESTS= -SHOW_VERSION=false -SCRIPT_ARGUMENTS=() - -# Parse arguments. +#CUSTOMPARAM=0 +BUILD_ARGUMENTS=() for i in "$@"; do - case $1 in - -s|--script) SCRIPT="$2"; shift ;; - -t|--target) TARGET="$2"; shift ;; - -p|--platform) PLATFORM="$2"; shift ;; - -c|--configuration) CONFIGURATION="$2"; shift ;; - --skip-tests) SKIP_TESTS="-skip-tests"; shift ;; - -v|--verbosity) VERBOSITY="$2"; shift ;; - -d|--dryrun) DRYRUN="-dryrun" ;; - --version) SHOW_VERSION=true ;; - --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;; - *) SCRIPT_ARGUMENTS+=("$1") ;; + case $(echo $1 | awk '{print tolower($0)}') in + # -custom-param) CUSTOMPARAM=1;; + *) BUILD_ARGUMENTS+=("$1") ;; esac shift done -# Make sure the tools folder exist. -if [ ! -d "$TOOLS_DIR" ]; then - mkdir "$TOOLS_DIR" -fi +set -eo pipefail +SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) -# Make sure that packages.config exist. -if [ ! -f "$TOOLS_DIR/packages.config" ]; then - echo "Downloading packages.config..." - curl -Lsfo "$TOOLS_DIR/packages.config" http://cakebuild.net/download/bootstrapper/packages - if [ $? -ne 0 ]; then - echo "An error occured while downloading packages.config." - exit 1 - fi -fi +########################################################################### +# CONFIGURATION +########################################################################### -# Download NuGet if it does not exist. -if [ ! -f "$NUGET_EXE" ]; then - echo "Downloading NuGet..." - curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe - if [ $? -ne 0 ]; then - echo "An error occured while downloading nuget.exe." - exit 1 - fi -fi +BUILD_PROJECT_FILE="$SCRIPT_DIR/nukebuild/_build.csproj" +TEMP_DIRECTORY="$SCRIPT_DIR//.tmp" -# Restore tools from NuGet. -pushd "$TOOLS_DIR" >/dev/null -if [ ! -f $PACKAGES_CONFIG_MD5 ] || [ "$( cat $PACKAGES_CONFIG_MD5 | sed 's/\r$//' )" != "$( $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' )" ]; then - find . -type d ! -name . | xargs rm -rf -fi +DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" +DOTNET_INSTALL_URL="https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.sh" +DOTNET_CHANNEL="Current" -mono "$NUGET_EXE" install -ExcludeVersion -if [ $? -ne 0 ]; then - echo "Could not restore NuGet packages." - exit 1 -fi +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 +export NUGET_XMLDOC_MODE="skip" -$MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5 +########################################################################### +# EXECUTION +########################################################################### -popd >/dev/null +function FirstJsonValue { + perl -nle 'print $1 if m{"'$1'": "([^"\-]+)",?}' <<< ${@:2} +} -# Make sure that Cake has been installed. -if [ ! -f "$CAKE_EXE" ]; then - echo "Could not find Cake.exe at '$CAKE_EXE'." - exit 1 +# If global.json exists, load expected version +if [ -f "$DOTNET_GLOBAL_FILE" ]; then + DOTNET_VERSION=$(FirstJsonValue "version" $(cat "$DOTNET_GLOBAL_FILE")) + if [ "$DOTNET_VERSION" == "" ]; then + unset DOTNET_VERSION + fi fi -# Start Cake -if $SHOW_VERSION; then - exec mono "$CAKE_EXE" -version +# If dotnet is installed locally, and expected version is not set or installation matches the expected version +if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") ]]; then + export DOTNET_EXE="$(command -v dotnet)" else - exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -platform="$PLATFORM" -configuration="$CONFIGURATION" -target=$TARGET $DRYRUN $SKIP_TESTS "${SCRIPT_ARGUMENTS[@]}" + DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" + export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" + + # Download install script + DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" + mkdir -p "$TEMP_DIRECTORY" + curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" + chmod +x "$DOTNET_INSTALL_FILE" + + # Install by channel or version + if [ -z ${DOTNET_VERSION+x} ]; then + "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path + else + "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path + fi fi + +echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)" + +"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]} diff --git a/cake.config b/cake.config deleted file mode 100644 index 8089cd4084..0000000000 --- a/cake.config +++ /dev/null @@ -1,15 +0,0 @@ -; This is the default configuration file for Cake. -; This file was downloaded from https://github.com/cake-build/resources - -[Nuget] -Source=https://api.nuget.org/v3/index.json -UseInProcessClient=true -LoadDependencies=false - -[Paths] -Tools=./tools -Addins=./tools/Addins -Modules=./tools/Modules - -[Settings] -SkipVerification=false diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs new file mode 100644 index 0000000000..c937933493 --- /dev/null +++ b/nukebuild/Build.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using Nuke.Common; +using Nuke.Common.Git; +using Nuke.Common.ProjectModel; +using Nuke.Common.Tooling; +using Nuke.Common.Tools.DotNet; +using Nuke.Common.Tools.MSBuild; +using Nuke.Common.Utilities; +using static Nuke.Common.EnvironmentInfo; +using static Nuke.Common.IO.FileSystemTasks; +using static Nuke.Common.IO.PathConstruction; +using static Nuke.Common.Tools.MSBuild.MSBuildTasks; +using static Nuke.Common.Tools.DotNet.DotNetTasks; +using static Nuke.Common.Tools.Xunit.XunitTasks; + + +/* + Before editing this file, install support plugin for your IDE, + running and debugging a particular target (optionally without deps) would be way easier + ReSharper/Rider - https://plugins.jetbrains.com/plugin/10803-nuke-support + VSCode - https://marketplace.visualstudio.com/items?itemName=nuke.support + + */ + +partial class Build : NukeBuild +{ + BuildParameters Parameters { get; set; } + protected override void OnBuildInitialized() + { + Parameters = new BuildParameters(this); + Information("Building version {0} of Avalonia ({1}) using version {2} of Nuke.", + Parameters.Version, + Parameters.Configuration, + typeof(NukeBuild).Assembly.GetName().Version.ToString()); + + if (Parameters.IsLocalBuild) + { + Information("Repository Name: " + Parameters.RepositoryName); + Information("Repository Branch: " + Parameters.RepositoryBranch); + } + Information("Configuration: " + Parameters.Configuration); + Information("IsLocalBuild: " + Parameters.IsLocalBuild); + Information("IsRunningOnUnix: " + Parameters.IsRunningOnUnix); + Information("IsRunningOnWindows: " + Parameters.IsRunningOnWindows); + Information("IsRunningOnAppVeyor: " + Parameters.IsRunningOnAppVeyor); + Information("IsRunnongOnAzure:" + Parameters.IsRunningOnAzure); + Information("IsPullRequest: " + Parameters.IsPullRequest); + Information("IsMainRepo: " + Parameters.IsMainRepo); + Information("IsMasterBranch: " + Parameters.IsMasterBranch); + Information("IsReleaseBranch: " + Parameters.IsReleaseBranch); + Information("IsTagged: " + Parameters.IsTagged); + Information("IsReleasable: " + Parameters.IsReleasable); + Information("IsMyGetRelease: " + Parameters.IsMyGetRelease); + Information("IsNuGetRelease: " + Parameters.IsNuGetRelease); + } + + Target Clean => _ => _.Executes(() => + { + var data = Parameters; + DeleteDirectories(data.BuildDirs); + EnsureCleanDirectories(data.BuildDirs); + EnsureCleanDirectory(data.ArtifactsDir); + EnsureCleanDirectory(data.NugetRoot); + EnsureCleanDirectory(data.ZipRoot); + EnsureCleanDirectory(data.TestResultsRoot); + }); + + + Target Compile => _ => _ + .DependsOn(Clean) + .Executes(() => + { + var data = Parameters; + if (data.IsRunningOnWindows) + MSBuild(data.MSBuildSolution, c => c + .SetConfiguration(data.Configuration) + .SetVerbosity(MSBuildVerbosity.Minimal) + .AddProperty("PackageVersion", Parameters.Version) + .AddProperty("iOSRoslynPathHackRequired", "true") + .SetToolsVersion(MSBuildToolsVersion._15_0) + .AddTargets("Restore", "Build") + ); + + else + DotNetBuild(Parameters.MSBuildSolution, c => c + .AddProperty("PackageVersion", Parameters.Version) + .SetConfiguration(Parameters.Configuration) + ); + }); + + void RunCoreTest(string project, bool coreOnly = false) + { + if(!project.EndsWith(".csproj")) + project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj"); + Information("Running tests from " + project); + var frameworks = new List(){"netcoreapp2.0"}; + foreach(var fw in frameworks) + { + if(!fw.StartsWith("netcoreapp") && coreOnly) + continue; + Information("Running for " + fw); + DotNetTest(c => + { + c = c + .SetProjectFile(project) + .SetConfiguration(Parameters.Configuration) + .SetFramework(fw) + .EnableNoBuild() + .EnableNoRestore(); + // NOTE: I can see that we could maybe add another extension method "Switch" or "If" to make this more convenient + if (Parameters.PublishTestResults) + c = c.SetLogger("trx").SetResultsDirectory(Parameters.TestResultsRoot); + return c; + }); + } + } + + Target RunCoreLibsTests => _ => _ + .OnlyWhen(() => !Parameters.SkipTests) + .DependsOn(Compile) + .Executes(() => + { + + RunCoreTest("./tests/Avalonia.Base.UnitTests", false); + RunCoreTest("./tests/Avalonia.Controls.UnitTests", false); + RunCoreTest("./tests/Avalonia.Input.UnitTests", false); + RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", false); + RunCoreTest("./tests/Avalonia.Layout.UnitTests", false); + RunCoreTest("./tests/Avalonia.Markup.UnitTests", false); + RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", false); + RunCoreTest("./tests/Avalonia.Styling.UnitTests", false); + RunCoreTest("./tests/Avalonia.Visuals.UnitTests", false); + RunCoreTest("./tests/Avalonia.Skia.UnitTests", false); + RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests", false); + + }); + + Target RunRenderTests => _ => _ + .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) + .DependsOn(Compile) + .Executes(() => + { + RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", true); + RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", true); + }); + + Target RunDesignerTests => _ => _ + .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) + .DependsOn(Compile) + .Executes(() => + { + RunCoreTest("./tests/Avalonia.DesignerSupport.Tests", false); + }); + + [PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit; + + Target RunLeakTests => _ => _ + .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows) + .DependsOn(Compile) + .Executes(() => + { + + var dotMemoryUnitPath = + ToolPathResolver.GetPackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe"); + var xunitRunnerPath = + ToolPathResolver.GetPackageExecutable("xunit.runner.console", "xunit.console.x86.exe"); + var args = new[] + { + Path.GetFullPath(xunitRunnerPath), + "--propagate-exit-code", + "--", + "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll" + }; + var cargs = string.Join(" ", args.Select(a => '"' + a + '"')); + + var proc = Process.Start(new ProcessStartInfo(dotMemoryUnitPath, cargs) + { + UseShellExecute = false + }); + + if (!proc.WaitForExit(120000)) + { + proc.Kill(); + throw new Exception("Leak tests timed out"); + } + + var leakTestsExitCode = proc.ExitCode; + + if (leakTestsExitCode != 0) + { + throw new Exception("Leak Tests failed"); + } + + + var testAssembly = "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll"; + DotMemoryUnit( + $"{XunitPath.DoubleQuoteIfNeeded()} --propagate-exit-code -- {testAssembly}", + timeout: 120_000); + }); + + Target ZipFiles => _ => _ + .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package) + .Executes(() => + { + var data = Parameters; + Zip(data.ZipCoreArtifacts, data.BinRoot); + + Zip(data.ZipNuGetArtifacts, data.NugetRoot); + + Zip(data.ZipTargetControlCatalogDesktopDir, + GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dll").Concat( + GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.config")).Concat( + GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.so")).Concat( + GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dylib")).Concat( + GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.exe"))); + }); + + Target CreateNugetPackages => _ => _ + .DependsOn(Compile) + .After(RunTests) + .Executes(() => + { + if (Parameters.IsRunningOnWindows) + + MSBuild(Parameters.MSBuildSolution, c => c + .SetConfiguration(Parameters.Configuration) + .SetVerbosity(MSBuildVerbosity.Minimal) + .AddProperty("PackageVersion", Parameters.Version) + .AddProperty("iOSRoslynPathHackRequired", "true") + .SetToolsVersion(MSBuildToolsVersion._15_0) + .AddTargets("Restore", "Pack")); + else + DotNetPack(Parameters.MSBuildSolution, c => + c.SetConfiguration(Parameters.Configuration) + .AddProperty("PackageVersion", Parameters.Version)); + }); + + Target RunTests => _ => _ + .DependsOn(RunCoreLibsTests) + .DependsOn(RunRenderTests) + .DependsOn(RunDesignerTests) + .DependsOn(RunLeakTests); + + Target Package => _ => _ + .DependsOn(RunTests) + .DependsOn(CreateNugetPackages); + + Target CiAppVeyor => _ => _ + .DependsOn(Package) + .DependsOn(ZipFiles); + + Target CiTravis => _ => _ + .DependsOn(RunTests); + + Target CiAsuzeLinux => _ => _ + .DependsOn(RunTests); + + Target CiAsuzeOSX => _ => _ + .DependsOn(Package) + .DependsOn(ZipFiles); + + Target CiAsuzeWindows => _ => _ + .DependsOn(Package) + .DependsOn(ZipFiles); + + + public static int Main() => + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? Execute(x => x.Package) + : Execute(x => x.RunTests); + +} diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs new file mode 100644 index 0000000000..322871e5db --- /dev/null +++ b/nukebuild/BuildParameters.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Xml.Linq; +using Nuke.Common; +using Nuke.Common.BuildServers; +using Nuke.Common.Execution; +using Nuke.Common.IO; +using static Nuke.Common.IO.FileSystemTasks; +using static Nuke.Common.IO.PathConstruction; +using static Nuke.Common.Tools.MSBuild.MSBuildTasks; + +public partial class Build +{ + [Parameter("configuration")] + public string NukeArgConfiguration { get; set; } + + [Parameter("skip-tests")] + public bool NukeArgSkipTests { get; set; } + + [Parameter("force-nuget-version")] + public string NukeArgForceNugetVersion { get; set; } + + public class BuildParameters + { + public string Configuration { get; } + public bool SkipTests { get; } + public string MainRepo { get; } + public string MasterBranch { get; } + public string RepositoryName { get; } + public string RepositoryBranch { get; } + public string ReleaseConfiguration { get; } + public string ReleaseBranchPrefix { get; } + public string MSBuildSolution { get; } + public bool IsLocalBuild { get; } + public bool IsRunningOnUnix { get; } + public bool IsRunningOnWindows { get; } + public bool IsRunningOnAppVeyor { get; } + public bool IsRunningOnAzure { get; } + public bool IsPullRequest { get; } + public bool IsMainRepo { get; } + public bool IsMasterBranch { get; } + public bool IsReleaseBranch { get; } + public bool IsTagged { get; } + public bool IsReleasable { get; } + public bool IsMyGetRelease { get; } + public bool IsNuGetRelease { get; } + public bool PublishTestResults { get; } + public string Version { get; } + public AbsolutePath ArtifactsDir { get; } + public AbsolutePath NugetRoot { get; } + public AbsolutePath ZipRoot { get; } + public AbsolutePath BinRoot { get; } + public AbsolutePath TestResultsRoot { get; } + public string DirSuffix { get; } + public List BuildDirs { get; } + public string FileZipSuffix { get; } + public AbsolutePath ZipCoreArtifacts { get; } + public AbsolutePath ZipNuGetArtifacts { get; } + public AbsolutePath ZipSourceControlCatalogDesktopDir { get; } + public AbsolutePath ZipTargetControlCatalogDesktopDir { get; } + + + public BuildParameters(Build b) + { + var buildSystem = Host; + + + // ARGUMENTS + Configuration = b.NukeArgConfiguration ?? "Release"; + SkipTests = b.NukeArgSkipTests; + + // CONFIGURATION + MainRepo = "https://github.com/AvaloniaUI/Avalonia"; + MasterBranch = "refs/heads/master"; + ReleaseBranchPrefix = "refs/heads/release/"; + ReleaseConfiguration = "Release"; + MSBuildSolution = RootDirectory / "dirs.proj"; + + // PARAMETERS + IsLocalBuild = buildSystem == HostType.Console; + IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || + Environment.OSVersion.Platform == PlatformID.MacOSX; + IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + IsRunningOnAppVeyor = buildSystem == HostType.AppVeyor; + IsRunningOnAzure = buildSystem == HostType.TeamServices || + Environment.GetEnvironmentVariable("LOGNAME") == "vsts"; + + string tagName = null; + if (IsRunningOnAppVeyor) + { + IsPullRequest = AppVeyor.Instance.PullRequestNumber != 0; + RepositoryName = Environment.GetEnvironmentVariable("BUILD_REPOSITORY_URI"); + RepositoryBranch = Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH"); + + IsReleaseBranch = + (Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH") ?? "").StartsWith(ReleaseBranchPrefix, + StringComparison.OrdinalIgnoreCase); + IsTagged = AppVeyor.Instance.RepositoryTag + && !string.IsNullOrWhiteSpace(AppVeyor.Instance.RepositoryTagName); + + tagName = AppVeyor.Instance.RepositoryTagName; + } + else if (IsRunningOnAzure) + { + RepositoryName = TeamServices.Instance.RepositoryUri; + RepositoryBranch = TeamServices.Instance.SourceBranch; + IsPullRequest = TeamServices.Instance.PullRequestId.HasValue; + IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, TeamServices.Instance.RepositoryUri); + + // TODO??? + IsTagged = false; + tagName = null; + } + IsMainRepo = + StringComparer.OrdinalIgnoreCase.Equals(MainRepo, + RepositoryName); + IsMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch, + RepositoryBranch); + + + IsReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, Configuration); + IsMyGetRelease = !IsTagged && IsReleasable; + IsNuGetRelease = IsMainRepo && IsReleasable && IsReleaseBranch; + + // VERSION + Version = b.NukeArgForceNugetVersion ?? GetVersion(); + + if (IsRunningOnAppVeyor) + { + string tagVersion = null; + if (IsTagged) + { + var tag = tagName; + var nugetReleasePrefix = "nuget-release-"; + IsNuGetRelease = IsTagged && IsReleasable && tag.StartsWith(nugetReleasePrefix); + if (IsNuGetRelease) + tagVersion = tag.Substring(nugetReleasePrefix.Length); + } + + if (tagVersion != null) + { + Version = tagVersion; + } + else + { + // Use AssemblyVersion with Build as version + Version += "-build" + Environment.GetEnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-beta"; + } + } + else if (IsRunningOnAzure) + { + if (!IsNuGetRelease) + { + // Use AssemblyVersion with Build as version + Version += "-build" + Environment.GetEnvironmentVariable("BUILD_BUILDID") + "-beta"; + } + + PublishTestResults = true; + } + + // DIRECTORIES + ArtifactsDir = RootDirectory / "artifacts"; + NugetRoot = ArtifactsDir / "nuget"; + ZipRoot = ArtifactsDir / "zip"; + BinRoot = ArtifactsDir / "bin"; + TestResultsRoot = ArtifactsDir / "test-results"; + BuildDirs = GlobDirectories(RootDirectory, "**bin").Concat(GlobDirectories(RootDirectory, "**obj")).ToList(); + DirSuffix = Configuration; + FileZipSuffix = Version + ".zip"; + ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix); + ZipNuGetArtifacts = ZipRoot / ("Avalonia-NuGet-" + FileZipSuffix); + ZipSourceControlCatalogDesktopDir = + RootDirectory / ("samples/ControlCatalog.Desktop/bin/" + DirSuffix + "/net461"); + ZipTargetControlCatalogDesktopDir = ZipRoot / ("ControlCatalog.Desktop-" + FileZipSuffix); + } + + private static string GetVersion() + { + var xdoc = XDocument.Load("./build/SharedVersion.props"); + return xdoc.Descendants().First(x => x.Name.LocalName == "Version").Value; + } + } + +} diff --git a/nukebuild/Shims.cs b/nukebuild/Shims.cs new file mode 100644 index 0000000000..7f26490493 --- /dev/null +++ b/nukebuild/Shims.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using Nuke.Common; +using Nuke.Common.IO; + +public partial class Build +{ + static void Information(string info) + { + Logger.Info(info); + } + + static void Information(string info, params object[] args) + { + Logger.Info(info, args); + } + + private void Zip(PathConstruction.AbsolutePath target, params string[] paths) => Zip(target, paths.AsEnumerable()); + + private void Zip(PathConstruction.AbsolutePath target, IEnumerable paths) + { + var targetPath = target.ToString(); + bool finished = false, atLeastOneFileAdded = false; + try + { + using (var targetStream = File.Create(targetPath)) + using(var archive = new System.IO.Compression.ZipArchive(targetStream, ZipArchiveMode.Create)) + { + void AddFile(string path, string relativePath) + { + var e = archive.CreateEntry(relativePath.Replace("\\", "/"), CompressionLevel.Optimal); + using (var entryStream = e.Open()) + using (var fileStream = File.OpenRead(path)) + fileStream.CopyTo(entryStream); + atLeastOneFileAdded = true; + } + + foreach (var path in paths) + { + + if (Directory.Exists(path)) + { + var dirInfo = new DirectoryInfo(path); + var rootPath = Path.GetDirectoryName(dirInfo.FullName); + foreach(var fsEntry in dirInfo.EnumerateFileSystemInfos("*", SearchOption.AllDirectories)) + { + if (fsEntry is FileInfo) + { + var relPath = Path.GetRelativePath(rootPath, fsEntry.FullName); + AddFile(fsEntry.FullName, relPath); + } + } + } + else if(File.Exists(path)) + { + var name = Path.GetFileName(path); + AddFile(path, name); + } + } + } + + finished = true; + } + finally + { + try + { + if (!finished || !atLeastOneFileAdded) + File.Delete(targetPath); + } + catch + { + //Ignore + } + } + } +} diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj new file mode 100644 index 0000000000..ed94116a93 --- /dev/null +++ b/nukebuild/_build.csproj @@ -0,0 +1,35 @@ + + + + Exe + netcoreapp2.0 + false + + False + CS0649;CS0169 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nukebuild/_build.csproj.DotSettings b/nukebuild/_build.csproj.DotSettings new file mode 100644 index 0000000000..9aac7d8e8d --- /dev/null +++ b/nukebuild/_build.csproj.DotSettings @@ -0,0 +1,24 @@ + + False + Implicit + Implicit + ExpressionBody + 0 + NEXT_LINE + True + False + 120 + IF_OWNER_IS_SINGLE_LINE + WRAP_IF_LONG + False + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True + True + True + True + True + True + True + True + True From 07475d12f9d973c307de4584e291def4ec009d4a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 14:56:07 +0000 Subject: [PATCH 26/42] 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 27/42] [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 28/42] 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 29/42] 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 30/42] 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 31/42] 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 32/42] 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 33/42] 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 34/42] [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 35/42] 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 36/42] 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; From 422d798108339e7c8a13f90e261654fa318278c2 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Dec 2018 20:56:10 +0000 Subject: [PATCH 37/42] fix non-client WM_Activate. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 4f97f9a472..0b9d16daa0 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -606,13 +606,19 @@ namespace Avalonia.Win32 break; case WindowsMessage.WM_NCPAINT: - case WindowsMessage.WM_NCACTIVATE: if (!_decorated) { return IntPtr.Zero; } break; + case WindowsMessage.WM_NCACTIVATE: + if (!_decorated) + { + return new IntPtr(1); + } + break; + case UnmanagedMethods.WindowsMessage.WM_PAINT: UnmanagedMethods.PAINTSTRUCT ps; if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero) From 3c5ac8f0cc862694fc9932cc3a5f05fca9ad9da6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 2 Dec 2018 00:45:51 +0000 Subject: [PATCH 38/42] allow menu borders to be overridden. --- src/Avalonia.Themes.Default/MenuItem.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml index 07faf7a632..f2940227e1 100644 --- a/src/Avalonia.Themes.Default/MenuItem.xaml +++ b/src/Avalonia.Themes.Default/MenuItem.xaml @@ -49,7 +49,7 @@ ObeyScreenEdges="True"> + BorderThickness="{TemplateBinding BorderThickness}"> + BorderThickness="{TemplateBinding BorderThickness}"> Date: Sun, 2 Dec 2018 10:51:35 +0300 Subject: [PATCH 39/42] Fixed review comments --- .travis.yml | 24 ---------- appveyor.yml | 23 --------- azure-pipelines.yml | 6 +-- nukebuild/Build.cs | 90 +++++++++++------------------------- nukebuild/BuildParameters.cs | 60 +++--------------------- nukebuild/Shims.cs | 1 - 6 files changed, 36 insertions(+), 168 deletions(-) delete mode 100644 .travis.yml delete mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d60323b418..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: csharp -os: - - linux -dist: trusty -osx_image: xcode8.3 -env: - global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - - DOTNET_CLI_TELEMETRY_OPTOUT=1 -mono: - - 5.2.0 -dotnet: 2.1.200 -script: - - sudo apt-get update - - sudo apt-get install castxml - - ./build.sh --target "CiTravis" --configuration "Release" -notifications: - email: false - webhooks: - urls: - - https://webhooks.gitter.im/e/98f653320ef2b7506c05 - on_success: change - on_failure: always - on_start: never diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 8694495e66..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,23 +0,0 @@ -os: Visual Studio 2017 -skip_branch_with_pr: true -configuration: -- Release -environment: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - NUGET_API_URL: https://www.nuget.org/api/v2/package - MYGET_API_KEY: - secure: OtVfyN3ErqQrDTnWH2HDfJDlCiu/i4/X4wFmK3ZXXP7HmCiXYPSbTjMPwwdOxRaK - MYGET_API_URL: https://www.myget.org/F/avalonia-ci/api/v2/package -init: -- ps: if (Test-Path env:nuget_address) {[System.IO.File]::AppendAllText("C:\Windows\System32\drivers\etc\hosts", "`n$($env:nuget_address)`tapi.nuget.org")} -before_build: -- git submodule update --init -build_script: -- ps: .\build.ps1 --target "CiAppVeyor" --configuration "$env:configuration" - -test: off -artifacts: - - path: artifacts\nuget\*.nupkg - - path: artifacts\zip\*.zip - - path: artifacts\inspectcode.xml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index dec361affe..8c5380e65e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ jobs: export PATH="$PATH:$HOME/.dotnet/tools" dotnet --info printenv - nuke --target="CiAzureLinux" --configuration="Release" + nuke --target CiAzureLinux --configuration=Release - task: PublishTestResults@2 inputs: @@ -71,7 +71,7 @@ jobs: export PATH="$PATH:$HOME/.dotnet/tools" dotnet --info printenv - nuke --target="CiAzureOSX" --configuration="Release" + nuke --target CiAzureOSX --configuration Release - task: PublishTestResults@2 inputs: @@ -106,7 +106,7 @@ jobs: inputs: script: | set PATH=%PATH%;%USERPROFILE%\.dotnet\tools - nuke --target="CiAzureWindows" --configuration="Release" + nuke --target CiAzureWindows --configuration Release - task: PublishTestResults@2 inputs: diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index c937933493..63e889ae30 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -48,13 +48,11 @@ partial class Build : NukeBuild Information("IsLocalBuild: " + Parameters.IsLocalBuild); Information("IsRunningOnUnix: " + Parameters.IsRunningOnUnix); Information("IsRunningOnWindows: " + Parameters.IsRunningOnWindows); - Information("IsRunningOnAppVeyor: " + Parameters.IsRunningOnAppVeyor); - Information("IsRunnongOnAzure:" + Parameters.IsRunningOnAzure); + Information("IsRunningOnAzure:" + Parameters.IsRunningOnAzure); Information("IsPullRequest: " + Parameters.IsPullRequest); Information("IsMainRepo: " + Parameters.IsMainRepo); Information("IsMasterBranch: " + Parameters.IsMasterBranch); Information("IsReleaseBranch: " + Parameters.IsReleaseBranch); - Information("IsTagged: " + Parameters.IsTagged); Information("IsReleasable: " + Parameters.IsReleasable); Information("IsMyGetRelease: " + Parameters.IsMyGetRelease); Information("IsNuGetRelease: " + Parameters.IsNuGetRelease); @@ -62,29 +60,37 @@ partial class Build : NukeBuild Target Clean => _ => _.Executes(() => { - var data = Parameters; - DeleteDirectories(data.BuildDirs); - EnsureCleanDirectories(data.BuildDirs); - EnsureCleanDirectory(data.ArtifactsDir); - EnsureCleanDirectory(data.NugetRoot); - EnsureCleanDirectory(data.ZipRoot); - EnsureCleanDirectory(data.TestResultsRoot); + DeleteDirectories(Parameters.BuildDirs); + EnsureCleanDirectories(Parameters.BuildDirs); + EnsureCleanDirectory(Parameters.ArtifactsDir); + EnsureCleanDirectory(Parameters.NugetRoot); + EnsureCleanDirectory(Parameters.ZipRoot); + EnsureCleanDirectory(Parameters.TestResultsRoot); }); - + [Serializable] + class MsBuildSettingsWithRestore : MSBuildSettings + { + protected override Arguments ConfigureArguments(Arguments arguments) + { + arguments.Add("/restore"); + return base.ConfigureArguments(arguments); + } + } + Target Compile => _ => _ .DependsOn(Clean) .Executes(() => { - var data = Parameters; - if (data.IsRunningOnWindows) - MSBuild(data.MSBuildSolution, c => c - .SetConfiguration(data.Configuration) + + if (Parameters.IsRunningOnWindows) + MSBuild(Parameters.MSBuildSolution, c => new MsBuildSettingsWithRestore() + .SetConfiguration(Parameters.Configuration) .SetVerbosity(MSBuildVerbosity.Minimal) .AddProperty("PackageVersion", Parameters.Version) .AddProperty("iOSRoslynPathHackRequired", "true") .SetToolsVersion(MSBuildToolsVersion._15_0) - .AddTargets("Restore", "Build") + .AddTargets("Build") ); else @@ -126,7 +132,6 @@ partial class Build : NukeBuild .DependsOn(Compile) .Executes(() => { - RunCoreTest("./tests/Avalonia.Base.UnitTests", false); RunCoreTest("./tests/Avalonia.Controls.UnitTests", false); RunCoreTest("./tests/Avalonia.Input.UnitTests", false); @@ -138,7 +143,6 @@ partial class Build : NukeBuild RunCoreTest("./tests/Avalonia.Visuals.UnitTests", false); RunCoreTest("./tests/Avalonia.Skia.UnitTests", false); RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests", false); - }); Target RunRenderTests => _ => _ @@ -165,39 +169,6 @@ partial class Build : NukeBuild .DependsOn(Compile) .Executes(() => { - - var dotMemoryUnitPath = - ToolPathResolver.GetPackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe"); - var xunitRunnerPath = - ToolPathResolver.GetPackageExecutable("xunit.runner.console", "xunit.console.x86.exe"); - var args = new[] - { - Path.GetFullPath(xunitRunnerPath), - "--propagate-exit-code", - "--", - "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll" - }; - var cargs = string.Join(" ", args.Select(a => '"' + a + '"')); - - var proc = Process.Start(new ProcessStartInfo(dotMemoryUnitPath, cargs) - { - UseShellExecute = false - }); - - if (!proc.WaitForExit(120000)) - { - proc.Kill(); - throw new Exception("Leak tests timed out"); - } - - var leakTestsExitCode = proc.ExitCode; - - if (leakTestsExitCode != 0) - { - throw new Exception("Leak Tests failed"); - } - - var testAssembly = "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll"; DotMemoryUnit( $"{XunitPath.DoubleQuoteIfNeeded()} --propagate-exit-code -- {testAssembly}", @@ -210,9 +181,7 @@ partial class Build : NukeBuild { var data = Parameters; Zip(data.ZipCoreArtifacts, data.BinRoot); - Zip(data.ZipNuGetArtifacts, data.NugetRoot); - Zip(data.ZipTargetControlCatalogDesktopDir, GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dll").Concat( GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.config")).Concat( @@ -234,7 +203,7 @@ partial class Build : NukeBuild .AddProperty("PackageVersion", Parameters.Version) .AddProperty("iOSRoslynPathHackRequired", "true") .SetToolsVersion(MSBuildToolsVersion._15_0) - .AddTargets("Restore", "Pack")); + .AddTargets("Pack")); else DotNetPack(Parameters.MSBuildSolution, c => c.SetConfiguration(Parameters.Configuration) @@ -251,21 +220,14 @@ partial class Build : NukeBuild .DependsOn(RunTests) .DependsOn(CreateNugetPackages); - Target CiAppVeyor => _ => _ - .DependsOn(Package) - .DependsOn(ZipFiles); - - Target CiTravis => _ => _ - .DependsOn(RunTests); - - Target CiAsuzeLinux => _ => _ + Target CiAzureLinux => _ => _ .DependsOn(RunTests); - Target CiAsuzeOSX => _ => _ + Target CiAzureOSX => _ => _ .DependsOn(Package) .DependsOn(ZipFiles); - Target CiAsuzeWindows => _ => _ + Target CiAzureWindows => _ => _ .DependsOn(Package) .DependsOn(ZipFiles); diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs index 322871e5db..9029aef60d 100644 --- a/nukebuild/BuildParameters.cs +++ b/nukebuild/BuildParameters.cs @@ -36,13 +36,11 @@ public partial class Build public bool IsLocalBuild { get; } public bool IsRunningOnUnix { get; } public bool IsRunningOnWindows { get; } - public bool IsRunningOnAppVeyor { get; } public bool IsRunningOnAzure { get; } public bool IsPullRequest { get; } public bool IsMainRepo { get; } public bool IsMasterBranch { get; } public bool IsReleaseBranch { get; } - public bool IsTagged { get; } public bool IsReleasable { get; } public bool IsMyGetRelease { get; } public bool IsNuGetRelease { get; } @@ -64,9 +62,6 @@ public partial class Build public BuildParameters(Build b) { - var buildSystem = Host; - - // ARGUMENTS Configuration = b.NukeArgConfiguration ?? "Release"; SkipTests = b.NukeArgSkipTests; @@ -79,77 +74,36 @@ public partial class Build MSBuildSolution = RootDirectory / "dirs.proj"; // PARAMETERS - IsLocalBuild = buildSystem == HostType.Console; + IsLocalBuild = Host == HostType.Console; IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - IsRunningOnAppVeyor = buildSystem == HostType.AppVeyor; - IsRunningOnAzure = buildSystem == HostType.TeamServices || + IsRunningOnAzure = Host == HostType.TeamServices || Environment.GetEnvironmentVariable("LOGNAME") == "vsts"; - string tagName = null; - if (IsRunningOnAppVeyor) - { - IsPullRequest = AppVeyor.Instance.PullRequestNumber != 0; - RepositoryName = Environment.GetEnvironmentVariable("BUILD_REPOSITORY_URI"); - RepositoryBranch = Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH"); - - IsReleaseBranch = - (Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH") ?? "").StartsWith(ReleaseBranchPrefix, - StringComparison.OrdinalIgnoreCase); - IsTagged = AppVeyor.Instance.RepositoryTag - && !string.IsNullOrWhiteSpace(AppVeyor.Instance.RepositoryTagName); - - tagName = AppVeyor.Instance.RepositoryTagName; - } - else if (IsRunningOnAzure) + if (IsRunningOnAzure) { RepositoryName = TeamServices.Instance.RepositoryUri; RepositoryBranch = TeamServices.Instance.SourceBranch; IsPullRequest = TeamServices.Instance.PullRequestId.HasValue; IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, TeamServices.Instance.RepositoryUri); - - // TODO??? - IsTagged = false; - tagName = null; } IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, RepositoryName); IsMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch, RepositoryBranch); + IsReleaseBranch = RepositoryBranch?.StartsWith(ReleaseBranchPrefix, StringComparison.OrdinalIgnoreCase) == + true; - IsReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, Configuration); - IsMyGetRelease = !IsTagged && IsReleasable; + IsMyGetRelease = IsReleasable; IsNuGetRelease = IsMainRepo && IsReleasable && IsReleaseBranch; // VERSION Version = b.NukeArgForceNugetVersion ?? GetVersion(); - if (IsRunningOnAppVeyor) - { - string tagVersion = null; - if (IsTagged) - { - var tag = tagName; - var nugetReleasePrefix = "nuget-release-"; - IsNuGetRelease = IsTagged && IsReleasable && tag.StartsWith(nugetReleasePrefix); - if (IsNuGetRelease) - tagVersion = tag.Substring(nugetReleasePrefix.Length); - } - - if (tagVersion != null) - { - Version = tagVersion; - } - else - { - // Use AssemblyVersion with Build as version - Version += "-build" + Environment.GetEnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-beta"; - } - } - else if (IsRunningOnAzure) + if (IsRunningOnAzure) { if (!IsNuGetRelease) { diff --git a/nukebuild/Shims.cs b/nukebuild/Shims.cs index 7f26490493..1ba72494d7 100644 --- a/nukebuild/Shims.cs +++ b/nukebuild/Shims.cs @@ -40,7 +40,6 @@ public partial class Build foreach (var path in paths) { - if (Directory.Exists(path)) { var dirInfo = new DirectoryInfo(path); From 076b811f2aa5ab0a3805f47aa2570d1d7850e2fa Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 2 Dec 2018 10:27:25 +0000 Subject: [PATCH 40/42] enable drop shadow on win32 popups. --- .../Interop/UnmanagedMethods.cs | 27 +++++++++++++++++-- src/Windows/Avalonia.Win32/PopupImpl.cs | 10 ++++++- src/Windows/Avalonia.Win32/WindowImpl.cs | 2 +- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 60b56ea580..7d6e8fc8ce 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -909,8 +909,17 @@ namespace Avalonia.Win32.Interop public enum ClassLongIndex : int { - GCL_HCURSOR = -12, - GCL_HICON = -14 + GCLP_MENUNAME = -8, + GCLP_HBRBACKGROUND = -10, + GCLP_HCURSOR = -12, + GCLP_HICON = -14, + GCLP_HMODULE = -16, + GCL_CBWNDEXTRA = -18, + GCL_CBCLSEXTRA = -20, + GCLP_WNDPROC = -24, + GCL_STYLE = -26, + GCLP_HICONSM = -34, + GCW_ATOM = -32 } [DllImport("user32.dll", EntryPoint = "SetClassLongPtr")] @@ -929,6 +938,20 @@ namespace Avalonia.Win32.Interop return SetClassLong64(hWnd, nIndex, dwNewLong); } + public static IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size > 4) + return GetClassLongPtr64(hWnd, nIndex); + else + return new IntPtr(GetClassLongPtr32(hWnd, nIndex)); + } + + [DllImport("user32.dll", EntryPoint = "GetClassLong")] + public static extern uint GetClassLongPtr32(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")] + public static extern IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex); + [DllImport("user32.dll", EntryPoint = "SetCursor")] internal static extern IntPtr SetCursor(IntPtr hCursor); diff --git a/src/Windows/Avalonia.Win32/PopupImpl.cs b/src/Windows/Avalonia.Win32/PopupImpl.cs index 7849bd6a9d..39f1a95466 100644 --- a/src/Windows/Avalonia.Win32/PopupImpl.cs +++ b/src/Windows/Avalonia.Win32/PopupImpl.cs @@ -24,7 +24,7 @@ namespace Avalonia.Win32 UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW | UnmanagedMethods.WindowStyles.WS_EX_TOPMOST; - return UnmanagedMethods.CreateWindowEx( + var result = UnmanagedMethods.CreateWindowEx( (int)exStyle, atom, null, @@ -37,6 +37,14 @@ namespace Avalonia.Win32 IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + + var classes = (int)UnmanagedMethods.GetClassLongPtr(result, (int)UnmanagedMethods.ClassLongIndex.GCL_STYLE); + + classes |= (int)UnmanagedMethods.ClassStyles.CS_DROPSHADOW; + + UnmanagedMethods.SetClassLong(result, UnmanagedMethods.ClassLongIndex.GCL_STYLE, new IntPtr(classes)); + + return result; } protected override IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 0b9d16daa0..56bb7347ec 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -384,7 +384,7 @@ namespace Avalonia.Win32 public void SetCursor(IPlatformHandle cursor) { var hCursor = cursor?.Handle ?? DefaultCursor; - UnmanagedMethods.SetClassLong(_hwnd, UnmanagedMethods.ClassLongIndex.GCL_HCURSOR, hCursor); + UnmanagedMethods.SetClassLong(_hwnd, UnmanagedMethods.ClassLongIndex.GCLP_HCURSOR, hCursor); if (_owner.IsPointerOver) UnmanagedMethods.SetCursor(hCursor); From 9bd4f35dad3ed4499f77279197e9b94f6b24bb86 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 2 Dec 2018 15:12:21 +0300 Subject: [PATCH 41/42] Removed MsBuildSettingsWithRestore hackery --- nukebuild/Build.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index 63e889ae30..1014aa1b47 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -68,23 +68,14 @@ partial class Build : NukeBuild EnsureCleanDirectory(Parameters.TestResultsRoot); }); - [Serializable] - class MsBuildSettingsWithRestore : MSBuildSettings - { - protected override Arguments ConfigureArguments(Arguments arguments) - { - arguments.Add("/restore"); - return base.ConfigureArguments(arguments); - } - } - Target Compile => _ => _ .DependsOn(Clean) .Executes(() => { if (Parameters.IsRunningOnWindows) - MSBuild(Parameters.MSBuildSolution, c => new MsBuildSettingsWithRestore() + MSBuild(Parameters.MSBuildSolution, c => c + .SetArgumentConfigurator(a => a.Add("/r")) .SetConfiguration(Parameters.Configuration) .SetVerbosity(MSBuildVerbosity.Minimal) .AddProperty("PackageVersion", Parameters.Version) From f678b4c31d692f9aa9bc4a987e312ac4c07a4ce2 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 4 Dec 2018 10:25:23 +0300 Subject: [PATCH 42/42] Removed appveyor badge --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 9d113cf2ef..9280125323 100644 --- a/readme.md +++ b/readme.md @@ -2,9 +2,9 @@ # Avalonia -| Gitter Chat | Build Status (Win, Linux, OSX) | Appveyor Build Status | Open Collective | -|---|---|---|---| -| [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | +| Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective | +|---|---|---| +| [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | ## About