| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083 |
- // Copyright (c) The Avalonia Project. All rights reserved.
- // Licensed under the MIT license. See licence.md file in the project root for full license information.
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Diagnostics.CodeAnalysis;
- using System.Runtime.InteropServices;
- using Avalonia.Controls;
- 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
- {
- public class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
- {
- private static readonly List<WindowImpl> s_instances = new List<WindowImpl>();
- private static readonly IntPtr DefaultCursor = UnmanagedMethods.LoadCursor(
- IntPtr.Zero, new IntPtr((int)UnmanagedMethods.Cursor.IDC_ARROW));
- private UnmanagedMethods.WndProc _wndProcDelegate;
- private string _className;
- private IntPtr _hwnd;
- private bool _multitouch;
- private TouchDevice _touchDevice = new TouchDevice();
- private MouseDevice _mouseDevice = new WindowsMouseDevice();
- private IInputRoot _owner;
- private ManagedDeferredRendererLock _rendererLock = new ManagedDeferredRendererLock();
- private bool _trackingMouse;
- 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;
- private FramebufferManager _framebuffer;
- private IGlPlatformSurface _gl;
- private OleDropTarget _dropTarget;
- private Size _minSize;
- private Size _maxSize;
- private WindowImpl _parent;
- private readonly List<WindowImpl> _disabledBy = new List<WindowImpl>();
- #if USE_MANAGED_DRAG
- private readonly ManagedWindowResizeDragHelper _managedDrag;
- #endif
- public WindowImpl()
- {
- #if USE_MANAGED_DRAG
- _managedDrag = new ManagedWindowResizeDragHelper(this, capture =>
- {
- if (capture)
- UnmanagedMethods.SetCapture(Handle.Handle);
- else
- UnmanagedMethods.ReleaseCapture();
- });
- #endif
- CreateWindow();
- _framebuffer = new FramebufferManager(_hwnd);
- if (Win32GlManager.EglFeature != null)
- _gl = new EglGlPlatformSurface((EglDisplay)Win32GlManager.EglFeature.Display,
- Win32GlManager.EglFeature.DeferredContext, 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 Thickness BorderThickness
- {
- get
- {
- if (_decorated)
- {
- 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
- {
- return new Thickness();
- }
- }
- }
- public Size ClientSize
- {
- get
- {
- UnmanagedMethods.RECT rect;
- UnmanagedMethods.GetClientRect(_hwnd, out rect);
- return new Size(rect.right, rect.bottom) / Scaling;
- }
- }
- public void Move(PixelPoint point) => Position = point;
- public void SetMinMaxSize(Size minSize, Size maxSize)
- {
- _minSize = minSize;
- _maxSize = maxSize;
- }
- public IScreenImpl Screen
- {
- get;
- } = new ScreenImpl();
- 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 * Scaling);
- int requestedClientHeight = (int)(value.Height * Scaling);
- UnmanagedMethods.RECT clientRect;
- UnmanagedMethods.GetClientRect(_hwnd, out clientRect);
-
- // do comparison after scaling to avoid rounding issues
- if (requestedClientWidth != clientRect.Width || requestedClientHeight != clientRect.Height)
- {
- UnmanagedMethods.RECT windowRect;
- UnmanagedMethods.GetWindowRect(_hwnd, out windowRect);
- UnmanagedMethods.SetWindowPos(
- _hwnd,
- IntPtr.Zero,
- 0,
- 0,
- requestedClientWidth + (windowRect.Width - clientRect.Width),
- requestedClientHeight + (windowRect.Height - clientRect.Height),
- UnmanagedMethods.SetWindowPosFlags.SWP_RESIZE);
- }
- }
- public double Scaling => _scaling;
- public IPlatformHandle Handle
- {
- get;
- private set;
- }
- void UpdateEnabled()
- {
- EnableWindow(_hwnd, _disabledBy.Count == 0);
- }
- public Size MaxClientSize
- {
- get
- {
- return (new Size(
- UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXMAXTRACK),
- UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYMAXTRACK))
- - BorderThickness) / Scaling;
- }
- }
- public IMouseDevice MouseDevice => _mouseDevice;
- public WindowState WindowState
- {
- get
- {
- var placement = default(UnmanagedMethods.WINDOWPLACEMENT);
- UnmanagedMethods.GetWindowPlacement(_hwnd, ref placement);
- switch (placement.ShowCmd)
- {
- case UnmanagedMethods.ShowWindowCommand.Maximize:
- return WindowState.Maximized;
- case UnmanagedMethods.ShowWindowCommand.Minimize:
- return WindowState.Minimized;
- default:
- return WindowState.Normal;
- }
- }
- set
- {
- if (UnmanagedMethods.IsWindowVisible(_hwnd))
- {
- ShowWindow(value);
- }
- else
- {
- _showWindowState = value;
- }
- }
- }
- public IEnumerable<object> Surfaces => new object[]
- {
- Handle, _gl, _framebuffer
- };
- public void Activate()
- {
- UnmanagedMethods.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)
- {
- UnmanagedMethods.DestroyWindow(_hwnd);
- _hwnd = IntPtr.Zero;
- }
- if (_className != null)
- {
- UnmanagedMethods.UnregisterClass(_className, UnmanagedMethods.GetModuleHandle(null));
- _className = null;
- }
- }
- public void Hide()
- {
- if (_parent != null)
- {
- _parent._disabledBy.Remove(this);
- _parent.UpdateEnabled();
- _parent = null;
- }
- UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Hide);
- }
- public void SetSystemDecorations(bool value)
- {
- if (value == _decorated)
- {
- return;
- }
- UpdateWMStyles(()=> _decorated = value);
- }
- public void Invalidate(Rect rect)
- {
- var f = Scaling;
- var r = new UnmanagedMethods.RECT
- {
- left = (int)Math.Floor(rect.X * f),
- top = (int)Math.Floor(rect.Y * f),
- right = (int)Math.Ceiling(rect.Right * f),
- bottom = (int)Math.Ceiling(rect.Bottom * f),
- };
- UnmanagedMethods.InvalidateRect(_hwnd, ref r, false);
- }
- public Point PointToClient(PixelPoint 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) / Scaling;
- }
- public PixelPoint PointToScreen(Point point)
- {
- point *= Scaling;
- var p = new UnmanagedMethods.POINT { X = (int)point.X, Y = (int)point.Y };
- UnmanagedMethods.ClientToScreen(_hwnd, ref p);
- return new PixelPoint(p.X, p.Y);
- }
- public void SetInputRoot(IInputRoot inputRoot)
- {
- _owner = inputRoot;
- CreateDropTarget();
- }
- public void SetTitle(string title)
- {
- UnmanagedMethods.SetWindowText(_hwnd, title);
- }
- public virtual void Show()
- {
- SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, IntPtr.Zero);
- ShowWindow(_showWindowState);
- }
- public void BeginMoveDrag(PointerPressedEventArgs e)
- {
- _mouseDevice.Capture(null);
- UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
- new IntPtr((int)UnmanagedMethods.HitTestValues.HTCAPTION), IntPtr.Zero);
- e.Pointer.Capture(null);
- }
- static readonly Dictionary<WindowEdge, UnmanagedMethods.HitTestValues> EdgeDic = new Dictionary<WindowEdge, UnmanagedMethods.HitTestValues>
- {
- {WindowEdge.East, UnmanagedMethods.HitTestValues.HTRIGHT},
- {WindowEdge.North, UnmanagedMethods.HitTestValues.HTTOP },
- {WindowEdge.NorthEast, UnmanagedMethods.HitTestValues.HTTOPRIGHT },
- {WindowEdge.NorthWest, UnmanagedMethods.HitTestValues.HTTOPLEFT },
- {WindowEdge.South, UnmanagedMethods.HitTestValues.HTBOTTOM },
- {WindowEdge.SouthEast, UnmanagedMethods.HitTestValues.HTBOTTOMRIGHT },
- {WindowEdge.SouthWest, UnmanagedMethods.HitTestValues.HTBOTTOMLEFT },
- {WindowEdge.West, UnmanagedMethods.HitTestValues.HTLEFT}
- };
- public void BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e)
- {
- #if USE_MANAGED_DRAG
- _managedDrag.BeginResizeDrag(edge, ScreenToClient(MouseDevice.Position));
- #else
- _mouseDevice.Capture(null);
- UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
- new IntPtr((int)EdgeDic[edge]), IntPtr.Zero);
- #endif
- }
- public PixelPoint Position
- {
- get
- {
- UnmanagedMethods.RECT rc;
- UnmanagedMethods.GetWindowRect(_hwnd, out rc);
- return new PixelPoint(rc.left, rc.top);
- }
- set
- {
- UnmanagedMethods.SetWindowPos(
- Handle.Handle,
- IntPtr.Zero,
- value.X,
- value.Y,
- 0,
- 0,
- UnmanagedMethods.SetWindowPosFlags.SWP_NOSIZE | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE);
- }
- }
- public void ShowDialog(IWindowImpl parent)
- {
- _parent = (WindowImpl)parent;
- _parent._disabledBy.Add(this);
- _parent.UpdateEnabled();
- SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, ((WindowImpl)parent)._hwnd);
- ShowWindow(_showWindowState);
- }
- public void SetCursor(IPlatformHandle cursor)
- {
- var hCursor = cursor?.Handle ?? DefaultCursor;
- UnmanagedMethods.SetClassLong(_hwnd, UnmanagedMethods.ClassLongIndex.GCLP_HCURSOR, hCursor);
- if (_owner.IsPointerOver)
- UnmanagedMethods.SetCursor(hCursor);
- }
- protected virtual IntPtr CreateWindowOverride(ushort atom)
- {
- return UnmanagedMethods.CreateWindowEx(
- 0,
- atom,
- null,
- (int)UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW,
- UnmanagedMethods.CW_USEDEFAULT,
- UnmanagedMethods.CW_USEDEFAULT,
- UnmanagedMethods.CW_USEDEFAULT,
- UnmanagedMethods.CW_USEDEFAULT,
- IntPtr.Zero,
- IntPtr.Zero,
- IntPtr.Zero,
- IntPtr.Zero);
- }
- bool ShouldIgnoreTouchEmulatedMessage()
- {
- if (!_multitouch)
- return false;
- var marker = 0xFF515700L;
- var info = GetMessageExtraInfo().ToInt64();
- return (info & marker) == marker;
- }
-
- [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)
- {
- bool unicode = UnmanagedMethods.IsWindowUnicode(hWnd);
- const double wheelDelta = 120.0;
- uint timestamp = unchecked((uint)UnmanagedMethods.GetMessageTime());
- RawInputEventArgs e = null;
-
- switch ((UnmanagedMethods.WindowsMessage)msg)
- {
- case UnmanagedMethods.WindowsMessage.WM_ACTIVATE:
- var wa = (UnmanagedMethods.WindowActivate)(ToInt32(wParam) & 0xffff);
- switch (wa)
- {
- case UnmanagedMethods.WindowActivate.WA_ACTIVE:
- case UnmanagedMethods.WindowActivate.WA_CLICKACTIVE:
- Activated?.Invoke();
- break;
- case UnmanagedMethods.WindowActivate.WA_INACTIVE:
- Deactivated?.Invoke();
- break;
- }
- 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)
- {
- return IntPtr.Zero;
- }
- break;
- case UnmanagedMethods.WindowsMessage.WM_DESTROY:
- //Window doesn't exist anymore
- _hwnd = IntPtr.Zero;
- //Remove root reference to this class, so unmanaged delegate can be collected
- s_instances.Remove(this);
- Closed?.Invoke();
- if (_parent != null)
- {
- _parent._disabledBy.Remove(this);
- _parent.UpdateEnabled();
- }
- _mouseDevice.Dispose();
- _touchDevice?.Dispose();
- //Free other resources
- Dispose();
- return IntPtr.Zero;
- case UnmanagedMethods.WindowsMessage.WM_DPICHANGED:
- var dpi = ToInt32(wParam) & 0xffff;
- var newDisplayRect = Marshal.PtrToStructure<UnmanagedMethods.RECT>(lParam);
- _scaling = dpi / 96.0;
- ScalingChanged?.Invoke(_scaling);
- SetWindowPos(hWnd,
- IntPtr.Zero,
- newDisplayRect.left,
- newDisplayRect.top,
- newDisplayRect.right - newDisplayRect.left,
- newDisplayRect.bottom - newDisplayRect.top,
- SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE);
- return IntPtr.Zero;
- case UnmanagedMethods.WindowsMessage.WM_KEYDOWN:
- case UnmanagedMethods.WindowsMessage.WM_SYSKEYDOWN:
- e = new RawKeyEventArgs(
- WindowsKeyboardDevice.Instance,
- timestamp,
- _owner,
- RawKeyEventType.KeyDown,
- KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)), WindowsKeyboardDevice.Instance.Modifiers);
- break;
- case UnmanagedMethods.WindowsMessage.WM_MENUCHAR:
- // mute the system beep
- return (IntPtr)((Int32)UnmanagedMethods.MenuCharParam.MNC_CLOSE << 16);
- case UnmanagedMethods.WindowsMessage.WM_KEYUP:
- case UnmanagedMethods.WindowsMessage.WM_SYSKEYUP:
- e = new RawKeyEventArgs(
- WindowsKeyboardDevice.Instance,
- timestamp,
- _owner,
- RawKeyEventType.KeyUp,
- KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)), WindowsKeyboardDevice.Instance.Modifiers);
- break;
- case UnmanagedMethods.WindowsMessage.WM_CHAR:
- // Ignore control chars
- if (ToInt32(wParam) >= 32)
- {
- e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _owner,
- new string((char)ToInt32(wParam), 1));
- }
- break;
- case UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN:
- case UnmanagedMethods.WindowsMessage.WM_RBUTTONDOWN:
- case UnmanagedMethods.WindowsMessage.WM_MBUTTONDOWN:
- case UnmanagedMethods.WindowsMessage.WM_XBUTTONDOWN:
- if (ShouldIgnoreTouchEmulatedMessage())
- break;
- e = new RawPointerEventArgs(
- _mouseDevice,
- timestamp,
- _owner,
- (UnmanagedMethods.WindowsMessage)msg switch
- {
- UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN => RawPointerEventType.LeftButtonDown,
- UnmanagedMethods.WindowsMessage.WM_RBUTTONDOWN => RawPointerEventType.RightButtonDown,
- UnmanagedMethods.WindowsMessage.WM_MBUTTONDOWN => RawPointerEventType.MiddleButtonDown,
- UnmanagedMethods.WindowsMessage.WM_XBUTTONDOWN =>
- HighWord(ToInt32(wParam)) == 1 ? RawPointerEventType.XButton1Down : RawPointerEventType.XButton2Down
- },
- DipFromLParam(lParam), GetMouseModifiers(wParam));
- break;
- case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP:
- case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP:
- case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP:
- case UnmanagedMethods.WindowsMessage.WM_XBUTTONUP:
- if (ShouldIgnoreTouchEmulatedMessage())
- break;
- e = new RawPointerEventArgs(
- _mouseDevice,
- timestamp,
- _owner,
- (UnmanagedMethods.WindowsMessage)msg switch
- {
- UnmanagedMethods.WindowsMessage.WM_LBUTTONUP => RawPointerEventType.LeftButtonUp,
- UnmanagedMethods.WindowsMessage.WM_RBUTTONUP => RawPointerEventType.RightButtonUp,
- UnmanagedMethods.WindowsMessage.WM_MBUTTONUP => RawPointerEventType.MiddleButtonUp,
- UnmanagedMethods.WindowsMessage.WM_XBUTTONUP =>
- HighWord(ToInt32(wParam)) == 1 ? RawPointerEventType.XButton1Up : RawPointerEventType.XButton2Up,
- },
- DipFromLParam(lParam), GetMouseModifiers(wParam));
- break;
- case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
- if(ShouldIgnoreTouchEmulatedMessage())
- break;
- if (!_trackingMouse)
- {
- var tm = new UnmanagedMethods.TRACKMOUSEEVENT
- {
- cbSize = Marshal.SizeOf<UnmanagedMethods.TRACKMOUSEEVENT>(),
- dwFlags = 2,
- hwndTrack = _hwnd,
- dwHoverTime = 0,
- };
- UnmanagedMethods.TrackMouseEvent(ref tm);
- }
- e = new RawPointerEventArgs(
- _mouseDevice,
- timestamp,
- _owner,
- RawPointerEventType.Move,
- DipFromLParam(lParam), GetMouseModifiers(wParam));
- break;
- case UnmanagedMethods.WindowsMessage.WM_MOUSEWHEEL:
- e = new RawMouseWheelEventArgs(
- _mouseDevice,
- timestamp,
- _owner,
- PointToClient(PointFromLParam(lParam)),
- new Vector(0, (ToInt32(wParam) >> 16) / wheelDelta), GetMouseModifiers(wParam));
- break;
- case UnmanagedMethods.WindowsMessage.WM_MOUSEHWHEEL:
- e = new RawMouseWheelEventArgs(
- _mouseDevice,
- timestamp,
- _owner,
- PointToClient(PointFromLParam(lParam)),
- new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0), GetMouseModifiers(wParam));
- break;
- case UnmanagedMethods.WindowsMessage.WM_MOUSELEAVE:
- _trackingMouse = false;
- e = new RawPointerEventArgs(
- _mouseDevice,
- timestamp,
- _owner,
- RawPointerEventType.LeaveWindow,
- new Point(-1,-1), WindowsKeyboardDevice.Instance.Modifiers);
- break;
- case UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN:
- case UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN:
- case UnmanagedMethods.WindowsMessage.WM_NCMBUTTONDOWN:
- case UnmanagedMethods.WindowsMessage.WM_NCXBUTTONDOWN:
- e = new RawPointerEventArgs(
- _mouseDevice,
- timestamp,
- _owner,
- (UnmanagedMethods.WindowsMessage)msg switch
- {
- UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN => RawPointerEventType.NonClientLeftButtonDown,
- UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN => RawPointerEventType.RightButtonDown,
- UnmanagedMethods.WindowsMessage.WM_NCMBUTTONDOWN => RawPointerEventType.MiddleButtonDown,
- UnmanagedMethods.WindowsMessage.WM_NCXBUTTONDOWN =>
- HighWord(ToInt32(wParam)) == 1 ? RawPointerEventType.XButton1Down : RawPointerEventType.XButton2Down,
- },
- PointToClient(PointFromLParam(lParam)), GetMouseModifiers(wParam));
- break;
- case WindowsMessage.WM_TOUCH:
- var touchInputCount = wParam.ToInt32();
- var pTouchInputs = stackalloc TOUCHINPUT[touchInputCount];
- var touchInputs = new Span<TOUCHINPUT>(pTouchInputs, touchInputCount);
- if (GetTouchInputInfo(lParam, (uint)touchInputCount, pTouchInputs, Marshal.SizeOf<TOUCHINPUT>()))
- {
- foreach (var touchInput in touchInputs)
- {
- Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time,
- _owner,
- touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_UP) ?
- RawPointerEventType.TouchEnd :
- touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_DOWN) ?
- RawPointerEventType.TouchBegin :
- RawPointerEventType.TouchUpdate,
- PointToClient(new PixelPoint(touchInput.X / 100, touchInput.Y / 100)),
- WindowsKeyboardDevice.Instance.Modifiers,
- touchInput.Id));
- }
- CloseTouchInputHandle(lParam);
- return IntPtr.Zero;
- }
-
- break;
- case WindowsMessage.WM_NCPAINT:
- if (!_decorated)
- {
- return IntPtr.Zero;
- }
- break;
- case WindowsMessage.WM_NCACTIVATE:
- if (!_decorated)
- {
- return new IntPtr(1);
- }
- break;
- case UnmanagedMethods.WindowsMessage.WM_PAINT:
- using (_rendererLock.Lock())
- {
- UnmanagedMethods.PAINTSTRUCT ps;
- if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero)
- {
- var f = Scaling;
- var r = ps.rcPaint;
- Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f,
- (r.bottom - r.top) / f));
- UnmanagedMethods.EndPaint(_hwnd, ref ps);
- }
- }
- return IntPtr.Zero;
- case UnmanagedMethods.WindowsMessage.WM_SIZE:
- using (_rendererLock.Lock())
- {
- // Do nothing here, just block until the pending frame render is completed on the render thread
- }
- var size = (UnmanagedMethods.SizeCommand)wParam;
- if (Resized != null &&
- (size == UnmanagedMethods.SizeCommand.Restored ||
- size == UnmanagedMethods.SizeCommand.Maximized))
- {
- var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16);
- Resized(clientSize / Scaling);
- }
- var windowState = size == SizeCommand.Maximized ? WindowState.Maximized
- : (size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal);
- if (windowState != _lastWindowState)
- {
- _lastWindowState = windowState;
- WindowStateChanged?.Invoke(windowState);
- }
- return IntPtr.Zero;
- case UnmanagedMethods.WindowsMessage.WM_MOVE:
- PositionChanged?.Invoke(new PixelPoint((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)));
- return IntPtr.Zero;
- case UnmanagedMethods.WindowsMessage.WM_GETMINMAXINFO:
- MINMAXINFO mmi = Marshal.PtrToStructure<UnmanagedMethods.MINMAXINFO>(lParam);
- if (_minSize.Width > 0)
- mmi.ptMinTrackSize.X = (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right);
- if (_minSize.Height > 0)
- mmi.ptMinTrackSize.Y = (int)((_minSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom);
- if (!Double.IsInfinity(_maxSize.Width) && _maxSize.Width > 0)
- mmi.ptMaxTrackSize.X = (int)((_maxSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right);
- if (!Double.IsInfinity(_maxSize.Height) && _maxSize.Height > 0)
- mmi.ptMaxTrackSize.Y = (int)((_maxSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom);
- Marshal.StructureToPtr(mmi, lParam, true);
- return IntPtr.Zero;
- case UnmanagedMethods.WindowsMessage.WM_DISPLAYCHANGE:
- (Screen as ScreenImpl)?.InvalidateScreensCache();
- return IntPtr.Zero;
- }
- #if USE_MANAGED_DRAG
- if (_managedDrag.PreprocessInputEvent(ref e))
- return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
- #endif
- if (e != null && Input != null)
- {
- Input(e);
- if (e.Handled)
- {
- return IntPtr.Zero;
- }
- }
- using (_rendererLock.Lock())
- return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
- }
- static RawInputModifiers GetMouseModifiers(IntPtr wParam)
- {
- var keys = (UnmanagedMethods.ModifierKeys)ToInt32(wParam);
- var modifiers = WindowsKeyboardDevice.Instance.Modifiers;
- if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_LBUTTON))
- modifiers |= RawInputModifiers.LeftMouseButton;
- if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
- modifiers |= RawInputModifiers.RightMouseButton;
- if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
- modifiers |= RawInputModifiers.MiddleMouseButton;
- if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_XBUTTON1))
- modifiers |= RawInputModifiers.XButton1MouseButton;
- if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_XBUTTON2))
- modifiers |= RawInputModifiers.XButton2MouseButton;
- return modifiers;
- }
- private void CreateWindow()
- {
- // Ensure that the delegate doesn't get garbage collected by storing it as a field.
- _wndProcDelegate = new UnmanagedMethods.WndProc(WndProc);
- _className = $"Avalonia-{Guid.NewGuid().ToString()}";
- UnmanagedMethods.WNDCLASSEX wndClassEx = new UnmanagedMethods.WNDCLASSEX
- {
- cbSize = Marshal.SizeOf<UnmanagedMethods.WNDCLASSEX>(),
- style = (int)(ClassStyles.CS_OWNDC | ClassStyles.CS_HREDRAW | ClassStyles.CS_VREDRAW), // Unique DC helps with performance when using Gpu based rendering
- lpfnWndProc = _wndProcDelegate,
- hInstance = UnmanagedMethods.GetModuleHandle(null),
- hCursor = DefaultCursor,
- hbrBackground = IntPtr.Zero,
- lpszClassName = _className
- };
- ushort atom = UnmanagedMethods.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 ?? false;
- if (_multitouch)
- RegisterTouchWindow(_hwnd, 0);
-
- if (UnmanagedMethods.ShCoreAvailable)
- {
- uint dpix, dpiy;
- var monitor = UnmanagedMethods.MonitorFromWindow(
- _hwnd,
- UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST);
- if (UnmanagedMethods.GetDpiForMonitor(
- monitor,
- UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI,
- out dpix,
- out dpiy) == 0)
- {
- _scaling = dpix / 96.0;
- }
- }
- }
- private void CreateDropTarget()
- {
- OleDropTarget odt = new OleDropTarget(this, _owner);
- if (OleContext.Current?.RegisterDragDrop(Handle, odt) ?? false)
- _dropTarget = odt;
- }
- private Point DipFromLParam(IntPtr lParam)
- {
- return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / Scaling;
- }
- private PixelPoint PointFromLParam(IntPtr lParam)
- {
- return new PixelPoint((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16));
- }
- 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);
- }
- private void ShowWindow(WindowState state)
- {
- UnmanagedMethods.ShowWindowCommand command;
- switch (state)
- {
- case WindowState.Minimized:
- command = ShowWindowCommand.Minimize;
- break;
- case WindowState.Maximized:
- command = ShowWindowCommand.Maximize;
- break;
- case WindowState.Normal:
- command = ShowWindowCommand.Restore;
- break;
- default:
- throw new ArgumentException("Invalid WindowState.");
- }
- UnmanagedMethods.ShowWindow(_hwnd, command);
- if (state == WindowState.Maximized)
- {
- MaximizeWithoutCoveringTaskbar();
- }
- if (!Design.IsDesignMode)
- {
- SetFocus(_hwnd);
- }
- }
- private void MaximizeWithoutCoveringTaskbar()
- {
- IntPtr monitor = MonitorFromWindow(_hwnd, MONITOR.MONITOR_DEFAULTTONEAREST);
- if (monitor != IntPtr.Zero)
- {
- MONITORINFO monitorInfo = MONITORINFO.Create();
- if (GetMonitorInfo(monitor, ref monitorInfo))
- {
- RECT rcMonitorArea = monitorInfo.rcMonitor;
- 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);
- }
- }
- }
- public void SetIcon(IWindowIconImpl icon)
- {
- var impl = (IconImpl)icon;
- var hIcon = impl?.HIcon ?? IntPtr.Zero;
- UnmanagedMethods.PostMessage(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_SETICON,
- new IntPtr((int)UnmanagedMethods.Icons.ICON_BIG), hIcon);
- }
- private static int ToInt32(IntPtr ptr)
- {
- if (IntPtr.Size == 4) return ptr.ToInt32();
- 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
- style &= ~(UnmanagedMethods.WindowStyles.WS_EX_APPWINDOW);
- WINDOWPLACEMENT windowPlacement = UnmanagedMethods.WINDOWPLACEMENT.Default;
- if (UnmanagedMethods.GetWindowPlacement(_hwnd, ref windowPlacement))
- {
- //Toggle to make the styles stick
- UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide);
- UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE, (uint)style);
- UnmanagedMethods.ShowWindow(_hwnd, windowPlacement.ShowCmd);
- }
- }
- private void UpdateWMStyles(Action change)
- {
- 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)
- {
- style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU);
- }
- if (!_resizable)
- {
- style ^= (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;
- }
- 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;
- }
- UpdateWMStyles(()=> _resizable = value);
- }
- public void SetTopmost(bool value)
- {
- if (value == _topmost)
- {
- return;
- }
- IntPtr hWndInsertAfter = value ? WindowPosZOrder.HWND_TOPMOST : WindowPosZOrder.HWND_NOTOPMOST;
- UnmanagedMethods.SetWindowPos(_hwnd,
- hWndInsertAfter,
- 0, 0, 0, 0,
- SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
- _topmost = value;
- }
- PixelSize EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Size
- {
- get
- {
- RECT rect;
- GetClientRect(_hwnd, out rect);
- return new PixelSize(
- Math.Max(1, rect.right - rect.left),
- Math.Max(1, rect.bottom - rect.top));
- }
- }
- IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle;
- private static int HighWord(int param) => param >> 16;
- }
- }
|