| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Runtime.InteropServices;
- using Avalonia.Controls;
- using Avalonia.Controls.Platform;
- using Avalonia.Input;
- using Avalonia.Input.Raw;
- 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
- {
- /// <summary>
- /// Window implementation for Win32 platform.
- /// </summary>
- public partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo,
- ITopLevelImplWithNativeControlHost
- {
- private static readonly List<WindowImpl> s_instances = new List<WindowImpl>();
- private static readonly IntPtr DefaultCursor = LoadCursor(
- IntPtr.Zero, new IntPtr((int)UnmanagedMethods.Cursor.IDC_ARROW));
- private static readonly Dictionary<WindowEdge, HitTestValues> s_edgeLookup =
- new Dictionary<WindowEdge, HitTestValues>
- {
- { 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;
- private bool _isClientAreaExtended;
- private Thickness _extendedMargins;
- private Thickness _offScreenMargin;
- private double _extendTitleBarHint = -1;
- #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 Win32NativeControlHost _nativeControlHost;
- 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 POINT _maxTrackSize;
- private WindowImpl _parent;
- private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default;
- 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();
- _nativeControlHost = new Win32NativeControlHost(this);
- s_instances.Add(this);
- }
- public Action Activated { get; set; }
- public Func<bool> Closing { get; set; }
- public Action Closed { get; set; }
- public Action Deactivated { get; set; }
- public Action<RawInputEventArgs> Input { get; set; }
- public Action<Rect> Paint { get; set; }
- public Action<Size> Resized { get; set; }
- public Action<double> ScalingChanged { get; set; }
- public Action<PixelPoint> PositionChanged { get; set; }
- public Action<WindowState> WindowStateChanged { get; set; }
-
- public Action LostFocus { get; set; }
- public Action<WindowTransparencyLevel> 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 RenderScaling => _scaling;
- public double DesktopScaling => RenderScaling;
- public Size ClientSize
- {
- get
- {
- GetClientRect(_hwnd, out var rect);
- return new Size(rect.right, rect.bottom) / RenderScaling;
- }
- }
- public IScreenImpl Screen { get; }
- public IPlatformHandle Handle { get; private set; }
- public virtual Size MaxAutoSizeHint => new Size(_maxTrackSize.X / RenderScaling, _maxTrackSize.Y / RenderScaling);
- public IMouseDevice MouseDevice => _mouseDevice;
- public WindowState WindowState
- {
- get
- {
- if(_isFullScreenActive)
- {
- return WindowState.FullScreen;
- }
- 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; }
- protected IntPtr Hwnd => _hwnd;
- public void SetTransparencyLevelHint (WindowTransparencyLevel transparencyLevel)
- {
- TransparencyLevel = EnableBlur(transparencyLevel);
- }
- private WindowTransparencyLevel EnableBlur(WindowTransparencyLevel transparencyLevel)
- {
- if (Win32Platform.WindowsVersion.Major >= 6)
- {
- if (DwmIsCompositionEnabled(out var compositionEnabled) != 0 || !compositionEnabled)
- {
- return WindowTransparencyLevel.None;
- }
- else if (Win32Platform.WindowsVersion.Major >= 10)
- {
- return Win10EnableBlur(transparencyLevel);
- }
- else if (Win32Platform.WindowsVersion.Minor >= 2)
- {
- return Win8xEnableBlur(transparencyLevel);
- }
- else
- {
- return Win7EnableBlur(transparencyLevel);
- }
- }
- else
- {
- return WindowTransparencyLevel.None;
- }
- }
- private WindowTransparencyLevel Win7EnableBlur(WindowTransparencyLevel transparencyLevel)
- {
- if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur)
- {
- transparencyLevel = WindowTransparencyLevel.Blur;
- }
- var blurInfo = new DWM_BLURBEHIND(false);
-
- if (transparencyLevel == WindowTransparencyLevel.Blur)
- {
- blurInfo = new DWM_BLURBEHIND(true);
- }
-
- DwmEnableBlurBehindWindow(_hwnd, ref blurInfo);
- if (transparencyLevel == WindowTransparencyLevel.Transparent)
- {
- return WindowTransparencyLevel.None;
- }
- else
- {
- return transparencyLevel;
- }
- }
- private WindowTransparencyLevel Win8xEnableBlur(WindowTransparencyLevel transparencyLevel)
- {
- var accent = new AccentPolicy();
- var accentStructSize = Marshal.SizeOf(accent);
- if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur)
- {
- transparencyLevel = WindowTransparencyLevel.Blur;
- }
- if (transparencyLevel == WindowTransparencyLevel.Transparent)
- {
- accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
- }
- else
- {
- accent.AccentState = AccentState.ACCENT_DISABLED;
- }
- 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);
- if (transparencyLevel >= WindowTransparencyLevel.Blur)
- {
- Win7EnableBlur(transparencyLevel);
- }
- return transparencyLevel;
- }
- private WindowTransparencyLevel Win10EnableBlur(WindowTransparencyLevel transparencyLevel)
- {
- bool canUseAcrylic = Win32Platform.WindowsVersion.Major > 10 || Win32Platform.WindowsVersion.Build >= 19628;
- 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 = 0x01000000;
- 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<object> Surfaces => new object[] { Handle, _gl, _framebuffer };
- public PixelPoint Position
- {
- get
- {
- GetWindowRect(_hwnd, out var rc);
- return new PixelPoint(rc.left, rc.top);
- }
- set
- {
- SetWindowPos(
- Handle.Handle,
- IntPtr.Zero,
- value.X,
- value.Y,
- 0,
- 0,
- SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
- }
- }
- private bool HasFullDecorations => _windowProperties.Decorations == SystemDecorations.Full;
- public void Move(PixelPoint point) => Position = point;
- public void SetMinMaxSize(Size minSize, Size maxSize)
- {
- _minSize = minSize;
- _maxSize = maxSize;
- }
- public IRenderer CreateRenderer(IRenderRoot root)
- {
- var loop = AvaloniaLocator.Current.GetService<IRenderLoop>();
- var customRendererFactory = AvaloniaLocator.Current.GetService<IRendererFactory>();
- if (customRendererFactory != null)
- return customRendererFactory.Create(root, loop);
- return Win32Platform.UseDeferredRendering ?
- (IRenderer)new DeferredRenderer(root, loop, rendererLock: _rendererLock) :
- new ImmediateRenderer(root);
- }
- public void Resize(Size value)
- {
- int requestedClientWidth = (int)(value.Width * RenderScaling);
- int requestedClientHeight = (int)(value.Height * RenderScaling);
- GetClientRect(_hwnd, out var clientRect);
- // do comparison after scaling to avoid rounding issues
- if (requestedClientWidth != clientRect.Width || requestedClientHeight != clientRect.Height)
- {
- GetWindowRect(_hwnd, out var windowRect);
- SetWindowPos(
- _hwnd,
- IntPtr.Zero,
- 0,
- 0,
- requestedClientWidth + (windowRect.Width - clientRect.Width),
- requestedClientHeight + (windowRect.Height - clientRect.Height),
- SetWindowPosFlags.SWP_RESIZE);
- }
- }
- public void Activate()
- {
- SetActiveWindow(_hwnd);
- }
- public IPopupImpl CreatePopup() => Win32Platform.UseOverlayPopups ? null : new PopupImpl(this);
- public void Dispose()
- {
- if (_dropTarget != null)
- {
- OleContext.Current?.UnregisterDragDrop(Handle);
- _dropTarget = null;
- }
- if (_hwnd != IntPtr.Zero)
- {
- DestroyWindow(_hwnd);
- _hwnd = IntPtr.Zero;
- }
- if (_className != null)
- {
- UnregisterClass(_className, GetModuleHandle(null));
- _className = null;
- }
- _framebuffer.Dispose();
- }
- public void Invalidate(Rect rect)
- {
- var scaling = RenderScaling;
- var r = new RECT
- {
- left = (int)Math.Floor(rect.X * scaling),
- top = (int)Math.Floor(rect.Y * scaling),
- right = (int)Math.Ceiling(rect.Right * scaling),
- bottom = (int)Math.Ceiling(rect.Bottom * scaling),
- };
- InvalidateRect(_hwnd, ref r, false);
- }
- public Point PointToClient(PixelPoint point)
- {
- var p = new POINT { X = point.X, Y = point.Y };
- UnmanagedMethods.ScreenToClient(_hwnd, ref p);
- return new Point(p.X, p.Y) / RenderScaling;
- }
- public PixelPoint PointToScreen(Point point)
- {
- point *= RenderScaling;
- var p = new POINT { X = (int)point.X, Y = (int)point.Y };
- ClientToScreen(_hwnd, ref p);
- return new PixelPoint(p.X, p.Y);
- }
- public void SetInputRoot(IInputRoot inputRoot)
- {
- _owner = inputRoot;
- CreateDropTarget();
- }
- public void Hide()
- {
- UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide);
- }
- public virtual void Show()
- {
- SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent != null ? _parent._hwnd : IntPtr.Zero);
- ShowWindow(_showWindowState);
- }
- public Action GotInputWhenDisabled { get; set; }
- public void SetParent(IWindowImpl parent)
- {
- _parent = (WindowImpl)parent;
- SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent._hwnd);
- }
- public void SetEnabled(bool enable) => EnableWindow(_hwnd, enable);
- public void BeginMoveDrag(PointerPressedEventArgs e)
- {
- _mouseDevice.Capture(null);
- DefWindowProc(_hwnd, (int)WindowsMessage.WM_NCLBUTTONDOWN,
- new IntPtr((int)HitTestValues.HTCAPTION), IntPtr.Zero);
- e.Pointer.Capture(null);
- }
- public void BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e)
- {
- #if USE_MANAGED_DRAG
- _managedDrag.BeginResizeDrag(edge, ScreenToClient(MouseDevice.Position.ToPoint(_scaling)));
- #else
- _mouseDevice.Capture(null);
- DefWindowProc(_hwnd, (int)WindowsMessage.WM_NCLBUTTONDOWN,
- new IntPtr((int)s_edgeLookup[edge]), IntPtr.Zero);
- #endif
- }
- public void SetTitle(string title)
- {
- SetWindowText(_hwnd, title);
- }
- public void SetCursor(IPlatformHandle cursor)
- {
- var hCursor = cursor?.Handle ?? DefaultCursor;
- SetClassLong(_hwnd, ClassLongIndex.GCLP_HCURSOR, hCursor);
- if (_owner.IsPointerOver)
- {
- UnmanagedMethods.SetCursor(hCursor);
- }
- }
- public void SetIcon(IWindowIconImpl icon)
- {
- var impl = (IconImpl)icon;
- var hIcon = impl?.HIcon ?? IntPtr.Zero;
- PostMessage(_hwnd, (int)WindowsMessage.WM_SETICON,
- new IntPtr((int)Icons.ICON_BIG), hIcon);
- }
- public void ShowTaskbarIcon(bool value)
- {
- var newWindowProperties = _windowProperties;
- newWindowProperties.ShowInTaskbar = value;
- UpdateWindowProperties(newWindowProperties);
- }
- public void CanResize(bool value)
- {
- var newWindowProperties = _windowProperties;
- newWindowProperties.IsResizable = value;
- UpdateWindowProperties(newWindowProperties);
- }
- public void SetSystemDecorations(SystemDecorations value)
- {
- var newWindowProperties = _windowProperties;
- newWindowProperties.Decorations = value;
- UpdateWindowProperties(newWindowProperties);
- }
- public void SetTopmost(bool value)
- {
- if (value == _topmost)
- {
- return;
- }
- IntPtr hWndInsertAfter = value ? WindowPosZOrder.HWND_TOPMOST : WindowPosZOrder.HWND_NOTOPMOST;
- SetWindowPos(_hwnd,
- hWndInsertAfter,
- 0, 0, 0, 0,
- SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
- _topmost = value;
- }
- protected virtual IntPtr CreateWindowOverride(ushort atom)
- {
- return CreateWindowEx(
- 0,
- atom,
- null,
- (int)WindowStyles.WS_OVERLAPPEDWINDOW | (int) WindowStyles.WS_CLIPCHILDREN,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- IntPtr.Zero,
- IntPtr.Zero,
- IntPtr.Zero,
- IntPtr.Zero);
- }
- private void CreateWindow()
- {
- // Ensure that the delegate doesn't get garbage collected by storing it as a field.
- _wndProcDelegate = WndProc;
- _className = $"Avalonia-{Guid.NewGuid().ToString()}";
- // Unique DC helps with performance when using Gpu based rendering
- const ClassStyles windowClassStyle = ClassStyles.CS_OWNDC | ClassStyles.CS_HREDRAW | ClassStyles.CS_VREDRAW;
- var wndClassEx = new WNDCLASSEX
- {
- cbSize = Marshal.SizeOf<WNDCLASSEX>(),
- style = (int)windowClassStyle,
- lpfnWndProc = _wndProcDelegate,
- hInstance = GetModuleHandle(null),
- hCursor = DefaultCursor,
- hbrBackground = IntPtr.Zero,
- lpszClassName = _className
- };
- ushort atom = RegisterClassEx(ref wndClassEx);
- if (atom == 0)
- {
- throw new Win32Exception();
- }
- _hwnd = CreateWindowOverride(atom);
- if (_hwnd == IntPtr.Zero)
- {
- throw new Win32Exception();
- }
- Handle = new PlatformHandle(_hwnd, PlatformConstants.WindowHandleType);
- _multitouch = Win32Platform.Options.EnableMultitouch ?? true;
- if (_multitouch)
- {
- RegisterTouchWindow(_hwnd, 0);
- }
- if (ShCoreAvailable)
- {
- var monitor = MonitorFromWindow(
- _hwnd,
- MONITOR.MONITOR_DEFAULTTONEAREST);
- if (GetDpiForMonitor(
- monitor,
- MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI,
- out var dpix,
- out var dpiy) == 0)
- {
- _scaling = dpix / 96.0;
- }
- }
- }
- private void CreateDropTarget()
- {
- var odt = new OleDropTarget(this, _owner);
- if (OleContext.Current?.RegisterDragDrop(Handle, odt) ?? false)
- {
- _dropTarget = odt;
- }
- }
- /// <summary>
- /// Ported from https://github.com/chromium/chromium/blob/master/ui/views/win/fullscreen_handler.cc
- /// Method must only be called from inside UpdateWindowProperties.
- /// </summary>
- /// <param name="fullscreen"></param>
- private void SetFullScreen(bool fullscreen)
- {
- if (fullscreen)
- {
- GetWindowRect(_hwnd, out var windowRect);
- _savedWindowInfo.WindowRect = windowRect;
- var current = GetStyle();
- var currentEx = GetExtendedStyle();
- _savedWindowInfo.Style = current;
- _savedWindowInfo.ExStyle = currentEx;
- // Set new window style and size.
- SetStyle(current & ~(WindowStyles.WS_CAPTION | WindowStyles.WS_THICKFRAME), false);
- SetExtendedStyle(currentEx & ~(WindowStyles.WS_EX_DLGMODALFRAME | WindowStyles.WS_EX_WINDOWEDGE | WindowStyles.WS_EX_CLIENTEDGE | WindowStyles.WS_EX_STATICEDGE), false);
- // On expand, if we're given a window_rect, grow to it, otherwise do
- // not resize.
- MONITORINFO monitor_info = MONITORINFO.Create();
- GetMonitorInfo(MonitorFromWindow(_hwnd, MONITOR.MONITOR_DEFAULTTONEAREST), ref monitor_info);
- var window_rect = monitor_info.rcMonitor.ToPixelRect();
- SetWindowPos(_hwnd, IntPtr.Zero, window_rect.X, window_rect.Y,
- window_rect.Width, window_rect.Height,
- SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED);
- _isFullScreenActive = true;
- }
- else
- {
- // Reset original window style and size. The multiple window size/moves
- // here are ugly, but if SetWindowPos() doesn't redraw, the taskbar won't be
- // repainted. Better-looking methods welcome.
- _isFullScreenActive = false;
- var windowStates = GetWindowStateStyles();
- SetStyle((_savedWindowInfo.Style & ~WindowStateMask) | windowStates, false);
- SetExtendedStyle(_savedWindowInfo.ExStyle, false);
- // On restore, resize to the previous saved rect size.
- var new_rect = _savedWindowInfo.WindowRect.ToPixelRect();
- SetWindowPos(_hwnd, IntPtr.Zero, new_rect.X, new_rect.Y, new_rect.Width,
- new_rect.Height,
- SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED);
- UpdateWindowProperties(_windowProperties, true);
- }
- TaskBarList.MarkFullscreen(_hwnd, fullscreen);
-
- ExtendClientArea();
- }
- private MARGINS UpdateExtendMargins()
- {
- RECT borderThickness = new RECT();
- RECT borderCaptionThickness = new RECT();
- AdjustWindowRectEx(ref borderCaptionThickness, (uint)(GetStyle()), false, 0);
- AdjustWindowRectEx(ref borderThickness, (uint)(GetStyle() & ~WindowStyles.WS_CAPTION), false, 0);
- borderThickness.left *= -1;
- borderThickness.top *= -1;
- borderCaptionThickness.left *= -1;
- borderCaptionThickness.top *= -1;
- bool wantsTitleBar = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemChrome) || _extendTitleBarHint == -1;
- if (!wantsTitleBar)
- {
- borderCaptionThickness.top = 1;
- }
- MARGINS margins = new MARGINS();
- margins.cxLeftWidth = 1;
- margins.cxRightWidth = 1;
- margins.cyBottomHeight = 1;
- if (_extendTitleBarHint != -1)
- {
- borderCaptionThickness.top = (int)(_extendTitleBarHint * RenderScaling);
- }
- margins.cyTopHeight = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemChrome) && !_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChrome) ? borderCaptionThickness.top : 1;
- if (WindowState == WindowState.Maximized)
- {
- _extendedMargins = new Thickness(0, (borderCaptionThickness.top - borderThickness.top) / RenderScaling, 0, 0);
- _offScreenMargin = new Thickness(borderThickness.left / RenderScaling, borderThickness.top / RenderScaling, borderThickness.right / RenderScaling, borderThickness.bottom / RenderScaling);
- }
- else
- {
- _extendedMargins = new Thickness(0, (borderCaptionThickness.top) / RenderScaling, 0, 0);
- _offScreenMargin = new Thickness();
- }
- return margins;
- }
- private void ExtendClientArea()
- {
- if (DwmIsCompositionEnabled(out bool compositionEnabled) < 0 || !compositionEnabled)
- {
- _isClientAreaExtended = false;
- return;
- }
- GetWindowRect(_hwnd, out var rcClient);
- // Inform the application of the frame change.
- SetWindowPos(_hwnd,
- IntPtr.Zero,
- rcClient.left, rcClient.top,
- rcClient.Width, rcClient.Height,
- SetWindowPosFlags.SWP_FRAMECHANGED);
- if (_isClientAreaExtended && WindowState != WindowState.FullScreen)
- {
- var margins = UpdateExtendMargins();
- DwmExtendFrameIntoClientArea(_hwnd, ref margins);
- }
- else
- {
- var margins = new MARGINS();
- DwmExtendFrameIntoClientArea(_hwnd, ref margins);
- _offScreenMargin = new Thickness();
- _extendedMargins = new Thickness();
- }
- if(!_isClientAreaExtended || (_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemChrome) &&
- !_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChrome)))
- {
- EnableCloseButton(_hwnd);
- }
- else
- {
- DisableCloseButton(_hwnd);
- }
- ExtendClientAreaToDecorationsChanged?.Invoke(_isClientAreaExtended);
- }
- private void ShowWindow(WindowState state)
- {
- ShowWindowCommand? command;
- var newWindowProperties = _windowProperties;
- switch (state)
- {
- case WindowState.Minimized:
- newWindowProperties.IsFullScreen = false;
- command = ShowWindowCommand.Minimize;
- break;
- case WindowState.Maximized:
- newWindowProperties.IsFullScreen = false;
- command = ShowWindowCommand.Maximize;
- break;
- case WindowState.Normal:
- newWindowProperties.IsFullScreen = false;
- command = ShowWindowCommand.Restore;
- break;
- case WindowState.FullScreen:
- newWindowProperties.IsFullScreen = true;
- command = IsWindowVisible(_hwnd) ? (ShowWindowCommand?)null : ShowWindowCommand.Restore;
- break;
- default:
- throw new ArgumentException("Invalid WindowState.");
- }
- UpdateWindowProperties(newWindowProperties);
- if (command.HasValue)
- {
- UnmanagedMethods.ShowWindow(_hwnd, command.Value);
- }
- if (state == WindowState.Maximized)
- {
- MaximizeWithoutCoveringTaskbar();
- }
- if (!Design.IsDesignMode)
- {
- SetFocus(_hwnd);
- }
- }
- private void MaximizeWithoutCoveringTaskbar()
- {
- IntPtr monitor = MonitorFromWindow(_hwnd, MONITOR.MONITOR_DEFAULTTONEAREST);
- if (monitor != IntPtr.Zero)
- {
- var monitorInfo = MONITORINFO.Create();
- if (GetMonitorInfo(monitor, ref monitorInfo))
- {
- var x = monitorInfo.rcWork.left;
- var y = monitorInfo.rcWork.top;
- var cx = Math.Abs(monitorInfo.rcWork.right - x);
- var cy = Math.Abs(monitorInfo.rcWork.bottom - y);
- SetWindowPos(_hwnd, WindowPosZOrder.HWND_NOTOPMOST, x, y, cx, cy, SetWindowPosFlags.SWP_SHOWWINDOW);
- }
- }
- }
- private WindowStyles GetWindowStateStyles()
- {
- return GetStyle() & WindowStateMask;
- }
- private WindowStyles GetStyle()
- {
- if (_isFullScreenActive)
- {
- return _savedWindowInfo.Style;
- }
- else
- {
- return (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE);
- }
- }
- private WindowStyles GetExtendedStyle()
- {
- if (_isFullScreenActive)
- {
- return _savedWindowInfo.ExStyle;
- }
- else
- {
- return (WindowStyles)GetWindowLong(_hwnd, (int)WindowLongParam.GWL_EXSTYLE);
- }
- }
- private void SetStyle(WindowStyles style, bool save = true)
- {
- if (save)
- {
- _savedWindowInfo.Style = style;
- }
- if (!_isFullScreenActive)
- {
- SetWindowLong(_hwnd, (int)WindowLongParam.GWL_STYLE, (uint)style);
- }
- }
- private void SetExtendedStyle(WindowStyles style, bool save = true)
- {
- if (save)
- {
- _savedWindowInfo.ExStyle = style;
- }
- if (!_isFullScreenActive)
- {
- SetWindowLong(_hwnd, (int)WindowLongParam.GWL_EXSTYLE, (uint)style);
- }
- }
- private void UpdateWindowProperties(WindowProperties newProperties, bool forceChanges = false)
- {
- var oldProperties = _windowProperties;
- // Calling SetWindowPos will cause events to be sent and we need to respond
- // according to the new values already.
- _windowProperties = newProperties;
- if ((oldProperties.ShowInTaskbar != newProperties.ShowInTaskbar) || forceChanges)
- {
- var exStyle = GetExtendedStyle();
- if (newProperties.ShowInTaskbar)
- {
- exStyle |= WindowStyles.WS_EX_APPWINDOW;
- }
- else
- {
- exStyle &= ~WindowStyles.WS_EX_APPWINDOW;
- }
- SetExtendedStyle(exStyle);
- // TODO: To hide non-owned window from taskbar we need to parent it to a hidden window.
- // Otherwise it will still show in the taskbar.
- }
- WindowStyles style;
- if ((oldProperties.IsResizable != newProperties.IsResizable) || forceChanges)
- {
- style = GetStyle();
- if (newProperties.IsResizable)
- {
- style |= WindowStyles.WS_SIZEFRAME;
- style |= WindowStyles.WS_MAXIMIZEBOX;
- }
- else
- {
- style &= ~WindowStyles.WS_SIZEFRAME;
- style &= ~WindowStyles.WS_MAXIMIZEBOX;
- }
- SetStyle(style);
- }
- if (oldProperties.IsFullScreen != newProperties.IsFullScreen)
- {
- SetFullScreen(newProperties.IsFullScreen);
- }
- if ((oldProperties.Decorations != newProperties.Decorations) || forceChanges)
- {
- style = GetStyle();
- const WindowStyles fullDecorationFlags = WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU;
- if (newProperties.Decorations == SystemDecorations.Full)
- {
- style |= fullDecorationFlags;
- }
- else
- {
- style &= ~fullDecorationFlags;
- }
- SetStyle(style);
- if (!_isFullScreenActive)
- {
- var margin = newProperties.Decorations == SystemDecorations.BorderOnly ? 1 : 0;
- var margins = new MARGINS
- {
- cyBottomHeight = margin,
- cxRightWidth = margin,
- cxLeftWidth = margin,
- cyTopHeight = margin
- };
- DwmExtendFrameIntoClientArea(_hwnd, ref margins);
- GetClientRect(_hwnd, out var oldClientRect);
- var oldClientRectOrigin = new POINT();
- ClientToScreen(_hwnd, ref oldClientRectOrigin);
- oldClientRect.Offset(oldClientRectOrigin);
- var newRect = oldClientRect;
- if (newProperties.Decorations == SystemDecorations.Full)
- {
- AdjustWindowRectEx(ref newRect, (uint)style, false, (uint)GetExtendedStyle());
- }
- SetWindowPos(_hwnd, IntPtr.Zero, newRect.left, newRect.top, newRect.Width, newRect.Height,
- SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE |
- SetWindowPosFlags.SWP_FRAMECHANGED);
- }
- }
- }
- private const int MF_BYCOMMAND = 0x0;
- private const int MF_BYPOSITION = 0x400;
- private const int MF_REMOVE = 0x1000;
- private const int MF_ENABLED = 0x0;
- private const int MF_GRAYED = 0x1;
- private const int MF_DISABLED = 0x2;
- private const int SC_CLOSE = 0xF060;
- void DisableCloseButton(IntPtr hwnd)
- {
- EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE,
- MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
- }
- void EnableCloseButton(IntPtr hwnd)
- {
- EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE,
- MF_BYCOMMAND | MF_ENABLED);
- }
- #if USE_MANAGED_DRAG
- private Point ScreenToClient(Point point)
- {
- var p = new UnmanagedMethods.POINT { X = (int)point.X, Y = (int)point.Y };
- UnmanagedMethods.ScreenToClient(_hwnd, ref p);
- return new Point(p.X, p.Y);
- }
- #endif
- PixelSize EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Size
- {
- get
- {
- GetClientRect(_hwnd, out var rect);
- return new PixelSize(
- Math.Max(1, rect.right - rect.left),
- Math.Max(1, rect.bottom - rect.top));
- }
- }
- double EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Scaling => RenderScaling;
- IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle;
- public void SetExtendClientAreaToDecorationsHint(bool hint)
- {
- _isClientAreaExtended = hint;
-
- ExtendClientArea();
- }
- public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints)
- {
- _extendChromeHints = hints;
- ExtendClientArea();
- }
-
- /// <inheritdoc/>
- public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight)
- {
- _extendTitleBarHint = titleBarHeight;
- ExtendClientArea();
- }
- /// <inheritdoc/>
- public bool IsClientAreaExtendedToDecorations => _isClientAreaExtended;
- /// <inheritdoc/>
- public Action<bool> ExtendClientAreaToDecorationsChanged { get; set; }
-
- /// <inheritdoc/>
- public bool NeedsManagedDecorations => _isClientAreaExtended && _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChrome);
- /// <inheritdoc/>
- public Thickness ExtendedMargins => _extendedMargins;
- /// <inheritdoc/>
- public Thickness OffScreenMargin => _offScreenMargin;
- /// <inheritdoc/>
- public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 0.8, 0);
- private struct SavedWindowInfo
- {
- public WindowStyles Style { get; set; }
- public WindowStyles ExStyle { get; set; }
- public RECT WindowRect { get; set; }
- };
- private struct WindowProperties
- {
- public bool ShowInTaskbar;
- public bool IsResizable;
- public SystemDecorations Decorations;
- public bool IsFullScreen;
- }
- }
- }
|