|
|
|
@ -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; |
|
|
|
@ -94,17 +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); |
|
|
|
var padding = new UnmanagedMethods.RECT(); |
|
|
|
|
|
|
|
if (UnmanagedMethods.AdjustWindowRectEx(ref padding, style, false, exStyle)) |
|
|
|
if (_decorated) |
|
|
|
{ |
|
|
|
return new Thickness(-padding.left, -padding.top, padding.right, padding.bottom); |
|
|
|
var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); |
|
|
|
var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); |
|
|
|
|
|
|
|
var padding = new RECT(); |
|
|
|
|
|
|
|
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(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -147,8 +156,7 @@ namespace Avalonia.Win32 |
|
|
|
if (value != ClientSize) |
|
|
|
{ |
|
|
|
value *= Scaling; |
|
|
|
value += BorderThickness; |
|
|
|
|
|
|
|
|
|
|
|
UnmanagedMethods.SetWindowPos( |
|
|
|
_hwnd, |
|
|
|
IntPtr.Zero, |
|
|
|
@ -265,63 +273,7 @@ namespace Avalonia.Win32 |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); |
|
|
|
|
|
|
|
style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; |
|
|
|
|
|
|
|
if (!value) |
|
|
|
{ |
|
|
|
style ^= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; |
|
|
|
} |
|
|
|
|
|
|
|
UnmanagedMethods.RECT windowRect; |
|
|
|
|
|
|
|
UnmanagedMethods.GetWindowRect(_hwnd, out windowRect); |
|
|
|
|
|
|
|
Rect newRect; |
|
|
|
var oldThickness = BorderThickness; |
|
|
|
|
|
|
|
UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
_decorated = value; |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
UpdateWMStyles(()=> _decorated = value); |
|
|
|
} |
|
|
|
|
|
|
|
public void Invalidate(Rect rect) |
|
|
|
@ -486,6 +438,13 @@ namespace Avalonia.Win32 |
|
|
|
|
|
|
|
return IntPtr.Zero; |
|
|
|
|
|
|
|
case WindowsMessage.WM_NCCALCSIZE: |
|
|
|
if (ToInt32(wParam) == 1 && !_decorated) |
|
|
|
{ |
|
|
|
return IntPtr.Zero; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case UnmanagedMethods.WindowsMessage.WM_CLOSE: |
|
|
|
bool? preventClosing = Closing?.Invoke(); |
|
|
|
if (preventClosing == true) |
|
|
|
@ -646,6 +605,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) |
|
|
|
@ -688,7 +655,7 @@ namespace Avalonia.Win32 |
|
|
|
|
|
|
|
MINMAXINFO mmi = Marshal.PtrToStructure<UnmanagedMethods.MINMAXINFO>(lParam); |
|
|
|
|
|
|
|
if (_minSize.Width > 0) |
|
|
|
if (_minSize.Width > 0) |
|
|
|
mmi.ptMinTrackSize.X = (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); |
|
|
|
|
|
|
|
if (_minSize.Height > 0) |
|
|
|
@ -859,7 +826,7 @@ namespace Avalonia.Win32 |
|
|
|
{ |
|
|
|
MONITORINFO monitorInfo = MONITORINFO.Create(); |
|
|
|
|
|
|
|
if (GetMonitorInfo(monitor,ref monitorInfo)) |
|
|
|
if (GetMonitorInfo(monitor, ref monitorInfo)) |
|
|
|
{ |
|
|
|
RECT rcMonitorArea = monitorInfo.rcMonitor; |
|
|
|
|
|
|
|
@ -888,13 +855,22 @@ 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 |
|
|
|
@ -910,26 +886,68 @@ namespace Avalonia.Win32 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void CanResize(bool value) |
|
|
|
private void UpdateWMStyles(Action change) |
|
|
|
{ |
|
|
|
if (value == _resizable) |
|
|
|
var oldDecorated = _decorated; |
|
|
|
|
|
|
|
var oldThickness = BorderThickness; |
|
|
|
|
|
|
|
change(); |
|
|
|
|
|
|
|
var style = (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE); |
|
|
|
|
|
|
|
const WindowStyles controlledFlags = WindowStyles.WS_OVERLAPPEDWINDOW; |
|
|
|
|
|
|
|
style = style | controlledFlags ^ controlledFlags; |
|
|
|
|
|
|
|
style |= WindowStyles.WS_OVERLAPPEDWINDOW; |
|
|
|
|
|
|
|
if (!_decorated) |
|
|
|
{ |
|
|
|
return; |
|
|
|
style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU); |
|
|
|
} |
|
|
|
|
|
|
|
if (_decorated) |
|
|
|
if (!_resizable) |
|
|
|
{ |
|
|
|
var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); |
|
|
|
style ^= (WindowStyles.WS_SIZEFRAME); |
|
|
|
} |
|
|
|
|
|
|
|
if (value) |
|
|
|
style |= UnmanagedMethods.WindowStyles.WS_SIZEFRAME; |
|
|
|
else |
|
|
|
style &= ~(UnmanagedMethods.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); |
|
|
|
bool frameUpdated = false; |
|
|
|
if (oldDecorated != _decorated) |
|
|
|
{ |
|
|
|
var newRect = oldClientRect; |
|
|
|
if (_decorated) |
|
|
|
AdjustWindowRectEx(ref newRect, (uint)style, false, |
|
|
|
GetWindowLong(_hwnd, (int)WindowLongParam.GWL_EXSTYLE)); |
|
|
|
SetWindowPos(_hwnd, IntPtr.Zero, newRect.left, newRect.top, newRect.Width, newRect.Height, |
|
|
|
SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); |
|
|
|
frameUpdated = true; |
|
|
|
} |
|
|
|
|
|
|
|
UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); |
|
|
|
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) |
|
|
|
{ |
|
|
|
if (value == _resizable) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
_resizable = value; |
|
|
|
UpdateWMStyles(()=> _resizable = value); |
|
|
|
} |
|
|
|
|
|
|
|
public void SetTopmost(bool value) |
|
|
|
|