From 1a16e423789c46b959c7675d70999e31de77af6b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 23 Nov 2018 15:28:30 +0000 Subject: [PATCH] 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)