|
|
|
@ -12,11 +12,164 @@ using static Avalonia.Win32.Interop.UnmanagedMethods; |
|
|
|
|
|
|
|
namespace Avalonia.Win32 |
|
|
|
{ |
|
|
|
public partial class WindowImpl |
|
|
|
{ |
|
|
|
private int LEFTEXTENDWIDTH = 4; |
|
|
|
private int RIGHTEXTENDWIDTH = 4; |
|
|
|
private int BOTTOMEXTENDWIDTH = 4; |
|
|
|
private int TOPEXTENDWIDTH = 100; |
|
|
|
|
|
|
|
// Hit test the frame for resizing and moving.
|
|
|
|
HitTestValues HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam) |
|
|
|
{ |
|
|
|
// Get the point coordinates for the hit test.
|
|
|
|
var ptMouse = PointFromLParam(lParam); |
|
|
|
|
|
|
|
// Get the window rectangle.
|
|
|
|
GetWindowRect(hWnd, out var rcWindow); |
|
|
|
|
|
|
|
// Get the frame rectangle, adjusted for the style without a caption.
|
|
|
|
RECT rcFrame = new RECT(); |
|
|
|
AdjustWindowRectEx(ref rcFrame, (uint)(WindowStyles.WS_OVERLAPPEDWINDOW & ~WindowStyles.WS_CAPTION), false, 0); |
|
|
|
|
|
|
|
// Determine if the hit test is for resizing. Default middle (1,1).
|
|
|
|
ushort uRow = 1; |
|
|
|
ushort uCol = 1; |
|
|
|
bool fOnResizeBorder = false; |
|
|
|
|
|
|
|
// Determine if the point is at the top or bottom of the window.
|
|
|
|
if (ptMouse.Y >= rcWindow.top && ptMouse.Y < rcWindow.top + TOPEXTENDWIDTH) |
|
|
|
{ |
|
|
|
fOnResizeBorder = (ptMouse.Y < (rcWindow.top - rcFrame.top)); |
|
|
|
uRow = 0; |
|
|
|
} |
|
|
|
else if (ptMouse.Y < rcWindow.bottom && ptMouse.Y >= rcWindow.bottom - BOTTOMEXTENDWIDTH) |
|
|
|
{ |
|
|
|
uRow = 2; |
|
|
|
} |
|
|
|
|
|
|
|
// Determine if the point is at the left or right of the window.
|
|
|
|
if (ptMouse.X >= rcWindow.left && ptMouse.X < rcWindow.left + LEFTEXTENDWIDTH) |
|
|
|
{ |
|
|
|
uCol = 0; // left side
|
|
|
|
} |
|
|
|
else if (ptMouse.X < rcWindow.right && ptMouse.X >= rcWindow.right - RIGHTEXTENDWIDTH) |
|
|
|
{ |
|
|
|
uCol = 2; // right side
|
|
|
|
} |
|
|
|
|
|
|
|
// Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT)
|
|
|
|
HitTestValues[][] hitTests = new[] |
|
|
|
{ |
|
|
|
new []{ HitTestValues.HTTOPLEFT, fOnResizeBorder ? HitTestValues.HTTOP : HitTestValues.HTCAPTION, HitTestValues.HTTOPRIGHT }, |
|
|
|
new []{ HitTestValues.HTLEFT, HitTestValues.HTNOWHERE, HitTestValues.HTRIGHT }, |
|
|
|
new []{ HitTestValues.HTBOTTOMLEFT, HitTestValues.HTBOTTOM, HitTestValues.HTBOTTOMRIGHT }, |
|
|
|
}; |
|
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine(hitTests[uRow][uCol]); |
|
|
|
|
|
|
|
return hitTests[uRow][uCol]; |
|
|
|
} |
|
|
|
|
|
|
|
protected virtual unsafe IntPtr CustomCaptionProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref bool callDwp) |
|
|
|
{ |
|
|
|
IntPtr lRet = IntPtr.Zero; |
|
|
|
|
|
|
|
callDwp = !DwmDefWindowProc(hWnd, msg, wParam, lParam, ref lRet); |
|
|
|
|
|
|
|
MARGINS margins = new MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyBottomHeight = 0, cyTopHeight = 100 }; |
|
|
|
RECT border_thickness = new RECT(); |
|
|
|
|
|
|
|
switch ((WindowsMessage)msg) |
|
|
|
{ |
|
|
|
case WindowsMessage.WM_ACTIVATE: |
|
|
|
{ |
|
|
|
if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME)) |
|
|
|
{ |
|
|
|
AdjustWindowRectEx(ref border_thickness, (uint)(GetStyle()), false, 0); |
|
|
|
border_thickness.left *= -1; |
|
|
|
border_thickness.top *= -1; |
|
|
|
} |
|
|
|
else if (GetStyle().HasFlag(WindowStyles.WS_BORDER)) |
|
|
|
{ |
|
|
|
border_thickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 }; |
|
|
|
} |
|
|
|
|
|
|
|
LEFTEXTENDWIDTH = border_thickness.left; |
|
|
|
RIGHTEXTENDWIDTH = border_thickness.right; |
|
|
|
BOTTOMEXTENDWIDTH = border_thickness.bottom; |
|
|
|
|
|
|
|
// Extend the frame into the client area.
|
|
|
|
margins.cxLeftWidth = border_thickness.left; |
|
|
|
margins.cxRightWidth = border_thickness.right; |
|
|
|
margins.cyBottomHeight = border_thickness.bottom; |
|
|
|
margins.cyTopHeight = border_thickness.top; |
|
|
|
|
|
|
|
var hr = DwmExtendFrameIntoClientArea(hWnd, ref margins); |
|
|
|
|
|
|
|
//if (hr < 0)
|
|
|
|
{ |
|
|
|
// Handle the error.
|
|
|
|
} |
|
|
|
|
|
|
|
lRet = IntPtr.Zero; |
|
|
|
callDwp = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case WindowsMessage.WM_NCCALCSIZE: |
|
|
|
{ |
|
|
|
if (ToInt32(wParam) == 1) |
|
|
|
{ |
|
|
|
lRet = IntPtr.Zero; |
|
|
|
callDwp = false; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case WindowsMessage.WM_NCHITTEST: |
|
|
|
if (lRet == IntPtr.Zero) |
|
|
|
{ |
|
|
|
lRet = (IntPtr)HitTestNCA(hWnd, wParam, lParam); |
|
|
|
|
|
|
|
if (((HitTestValues)lRet) != HitTestValues.HTNOWHERE) |
|
|
|
{ |
|
|
|
callDwp = false; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return lRet; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public partial class WindowImpl |
|
|
|
{ |
|
|
|
protected virtual unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) |
|
|
|
{ |
|
|
|
IntPtr lRet = IntPtr.Zero; |
|
|
|
bool callDwp = true; |
|
|
|
|
|
|
|
if (DwmIsCompositionEnabled(out bool enabled) == 0) |
|
|
|
{ |
|
|
|
lRet = CustomCaptionProc(hWnd, msg, wParam, lParam, ref callDwp); |
|
|
|
} |
|
|
|
|
|
|
|
if (callDwp) |
|
|
|
{ |
|
|
|
lRet = AppWndProc(hWnd, msg, wParam, lParam); |
|
|
|
} |
|
|
|
|
|
|
|
return lRet; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public partial class WindowImpl |
|
|
|
{ |
|
|
|
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", |
|
|
|
Justification = "Using Win32 naming for consistency.")] |
|
|
|
protected virtual unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) |
|
|
|
protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) |
|
|
|
{ |
|
|
|
const double wheelDelta = 120.0; |
|
|
|
uint timestamp = unchecked((uint)GetMessageTime()); |
|
|
|
|