protected IntPtr HandleNCHitTest(IntPtr lParam) { // Because we still have the System Border (which technically extends beyond the actual window // into where the Drop shadows are), we can use DefWindowProc here to handle resizing, except // on the top. We'll handle that below var originalRet = Win32Interop.DefWindowProc(Hwnd, (uint)WM.NCHITTEST, IntPtr.Zero, lParam); if (originalRet != new IntPtr(1)) { return(originalRet); } // At this point, we know that the cursor is inside the client area so it // has to be either the little border at the top of our custom title bar, // the drag bar or something else in the XAML island. But the XAML Island // handles WM_NCHITTEST on its own so actually it cannot be the XAML // Island. Then it must be the drag bar or the little border at the top // which the user can use to move or resize the window. var point = PointToClient(PointFromLParam(lParam)); RECT rcWindow; Win32Interop.GetWindowRect(Hwnd, out rcWindow); // On the Top border, the resize handle overlaps with the Titlebar area, which matches // a typical Win32 window or modern app window var resizeBorderHeight = GetResizeHandleHeight(); bool isOnResizeBorder = point.Y < resizeBorderHeight; // Make sure the caption buttons still get precedence // This is where things get tricky too. On Win11, we still want to suppor the snap // layout feature when hovering over the Maximize button. Unfortunately no API exists // yet to call that manually if using a custom titlebar. But, if we return HT_MAXBUTTON // here, the pointer events no longer enter the window // See https://github.com/dotnet/wpf/issues/4825 for more on this... // To hack our way into making this work, we'll return HT_MAXBUTTON here, but manually // manage the state and handle stuff through the WM_NCLBUTTON... events // This only applies on Windows 11, Windows 10 will work normally b/c no snap layout thing if (_owner !.HitTestCaptionButtons(point)) { if (_isWindows11) { var result = _owner.HitTestMaximizeButton(point); if (result) { _fakingMaximizeButton = true; return(new IntPtr(9)); } } }
private void ViewerPosUpdateHandler(object obj) { if (mainWindowHandle != IntPtr.Zero && dock != DockType.None) { if (Win32Interop.IsWindowVisible(mainWindowHandle)) { if (!Win32Interop.IsZoomed(mainWindowHandle)) { Win32Interop.Rect currentPosition; Win32Interop.GetWindowRect(mainWindowHandle, out currentPosition); if (!currentPosition.IsSame(lastPosition)) { this.SafeInvoke(() => { ViewerPosUpdate(currentPosition); }); lastPosition = currentPosition; } } } } }