using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Media;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32
{
///
/// Window implementation for Win32 platform.
///
public partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
{
private static readonly List s_instances = new List();
private static readonly IntPtr DefaultCursor = LoadCursor(
IntPtr.Zero, new IntPtr((int)UnmanagedMethods.Cursor.IDC_ARROW));
private static readonly Dictionary s_edgeLookup =
new Dictionary
{
{ WindowEdge.East, HitTestValues.HTRIGHT },
{ WindowEdge.North, HitTestValues.HTTOP },
{ WindowEdge.NorthEast, HitTestValues.HTTOPRIGHT },
{ WindowEdge.NorthWest, HitTestValues.HTTOPLEFT },
{ WindowEdge.South, HitTestValues.HTBOTTOM },
{ WindowEdge.SouthEast, HitTestValues.HTBOTTOMRIGHT },
{ WindowEdge.SouthWest, HitTestValues.HTBOTTOMLEFT },
{ WindowEdge.West, HitTestValues.HTLEFT }
};
private SavedWindowInfo _savedWindowInfo;
private bool _isFullScreenActive;
#if USE_MANAGED_DRAG
private readonly ManagedWindowResizeDragHelper _managedDrag;
#endif
private const WindowStyles WindowStateMask = (WindowStyles.WS_MAXIMIZE | WindowStyles.WS_MINIMIZE);
private readonly TouchDevice _touchDevice;
private readonly MouseDevice _mouseDevice;
private readonly ManagedDeferredRendererLock _rendererLock;
private readonly FramebufferManager _framebuffer;
private readonly IGlPlatformSurface _gl;
private WndProc _wndProcDelegate;
private string _className;
private IntPtr _hwnd;
private bool _multitouch;
private IInputRoot _owner;
private WindowProperties _windowProperties;
private bool _trackingMouse;
private bool _topmost;
private double _scaling = 1;
private WindowState _showWindowState;
private WindowState _lastWindowState;
private OleDropTarget _dropTarget;
private Size _minSize;
private Size _maxSize;
private WindowImpl _parent;
public WindowImpl()
{
_touchDevice = new TouchDevice();
_mouseDevice = new WindowsMouseDevice();
#if USE_MANAGED_DRAG
_managedDrag = new ManagedWindowResizeDragHelper(this, capture =>
{
if (capture)
UnmanagedMethods.SetCapture(Handle.Handle);
else
UnmanagedMethods.ReleaseCapture();
});
#endif
_windowProperties = new WindowProperties
{
ShowInTaskbar = false,
IsResizable = true,
Decorations = SystemDecorations.Full
};
_rendererLock = new ManagedDeferredRendererLock();
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
if (Win32GlManager.EglFeature != null)
_gl = new EglGlPlatformSurface(Win32GlManager.EglFeature.DeferredContext, this);
Screen = new ScreenImpl();
s_instances.Add(this);
}
public Action Activated { get; set; }
public Func Closing { get; set; }
public Action Closed { get; set; }
public Action Deactivated { get; set; }
public Action Input { get; set; }
public Action Paint { get; set; }
public Action Resized { get; set; }
public Action ScalingChanged { get; set; }
public Action PositionChanged { get; set; }
public Action WindowStateChanged { get; set; }
public Action TransparencyLevelChanged { get; set; }
public Thickness BorderThickness
{
get
{
if (HasFullDecorations)
{
var style = GetStyle();
var exStyle = GetExtendedStyle();
var padding = new RECT();
if (AdjustWindowRectEx(ref padding, (uint)style, false, (uint)exStyle))
{
return new Thickness(-padding.left, -padding.top, padding.right, padding.bottom);
}
else
{
throw new Win32Exception();
}
}
else
{
return new Thickness();
}
}
}
public double Scaling => _scaling;
public Size ClientSize
{
get
{
GetClientRect(_hwnd, out var rect);
return new Size(rect.right, rect.bottom) / Scaling;
}
}
public IScreenImpl Screen { get; }
public IPlatformHandle Handle { get; private set; }
public Size MaxClientSize
{
get
{
return (new Size(
GetSystemMetrics(SystemMetric.SM_CXMAXTRACK),
GetSystemMetrics(SystemMetric.SM_CYMAXTRACK))
- BorderThickness) / Scaling;
}
}
public IMouseDevice MouseDevice => _mouseDevice;
public WindowState WindowState
{
get
{
var placement = default(WINDOWPLACEMENT);
GetWindowPlacement(_hwnd, ref placement);
return placement.ShowCmd switch
{
ShowWindowCommand.Maximize => WindowState.Maximized,
ShowWindowCommand.Minimize => WindowState.Minimized,
_ => WindowState.Normal
};
}
set
{
if (IsWindowVisible(_hwnd))
{
ShowWindow(value);
}
else
{
_showWindowState = value;
}
}
}
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public void SetTransparencyLevelHint (WindowTransparencyLevel transparencyLevel)
{
TransparencyLevel = EnableBlur(transparencyLevel);
}
private WindowTransparencyLevel EnableBlur(WindowTransparencyLevel transparencyLevel)
{
bool canUseTransparency = false;
bool canUseAcrylic = false;
if (Win32Platform.WindowsVersion.Major >= 10)
{
canUseTransparency = true;
if (Win32Platform.WindowsVersion.Major > 10 || Win32Platform.WindowsVersion.Build >= 19628)
{
canUseAcrylic = true;
}
}
if (!canUseTransparency || DwmIsCompositionEnabled(out var compositionEnabled) != 0 || !compositionEnabled)
{
return WindowTransparencyLevel.None;
}
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
if(transparencyLevel == WindowTransparencyLevel.AcrylicBlur && !canUseAcrylic)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
switch (transparencyLevel)
{
default:
case WindowTransparencyLevel.None:
accent.AccentState = AccentState.ACCENT_DISABLED;
break;
case WindowTransparencyLevel.Transparent:
accent.AccentState = AccentState.ACCENT_ENABLE_TRANSPARENTGRADIENT;
break;
case WindowTransparencyLevel.Blur:
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
break;
case WindowTransparencyLevel.AcrylicBlur:
case (WindowTransparencyLevel.AcrylicBlur + 1): // hack-force acrylic.
accent.AccentState = AccentState.ACCENT_ENABLE_ACRYLIC;
transparencyLevel = WindowTransparencyLevel.AcrylicBlur;
break;
}
accent.AccentFlags = 2;
accent.GradientColor = 0x00FFFFFF;
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var data = new WindowCompositionAttributeData();
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
SetWindowCompositionAttribute(_hwnd, ref data);
Marshal.FreeHGlobal(accentPtr);
return transparencyLevel;
}
public IEnumerable