public virtual IntPtr WindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch ((WM)msg) { case WM.WINDOWPOSCHANGING: { WINDOWPOS windowPos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS)); if (Helpers.WindowChanged(windowPos.flags)) { // Get the monitor area that intersect the most with the specified rectangle MonitorArea monitorArea = Helpers.GetMonitorArea(hWnd, new RECT { left = windowPos.x, top = windowPos.y, right = windowPos.x + windowPos.cx, bottom = windowPos.y + windowPos.cy }); UpdateDisplayDevice(monitorArea.Device); } break; } } return(IntPtr.Zero); }
/// <summary> /// Activate or deactivate left/right resize handles given /// the current window position and size /// </summary> /// <remarks> /// Applies to snapped window only /// The maximum window size is limited by the (multi) screen size /// </remarks> /// <param name="window"></param> /// <param name="monitorArea"></param> /// <param name="left"></param> /// <param name="right"></param> private static void UpdateResizeBorder(Window window, MonitorArea monitorArea, double left, double right) { double borderWidth = GetResizeBorderWidth(window as CustomChrome); double virtualLeft = SystemParameters.VirtualScreenLeft; double virtualRight = SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth; double leftBorder = left <= virtualLeft + monitorArea.Offset.x ? 0 : borderWidth; double rightBorder = right >= virtualRight ? 0 : borderWidth; EnableResizeBorder(window, leftBorder, 0, rightBorder, 0); }
private static IntPtr WindowHookProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { CustomChrome window = GetWindow(hWnd) as CustomChrome; switch (msg) { // Toggle the DropShadowEffect when window is snapped or maximized case WM_SIZE: { int resizing = (int)wParam; if (resizing == SIZE_RESTORED) { MonitorArea monitorArea = GetMonitorArea(hWnd); if (monitorArea != null) { // LOWORD int width = ((int)lParam & 0x0000ffff); // HIWORD int height = (int)((int)lParam & 0xffff0000) >> 16; // Detect if window was snapped to screen side of current monitor // or if spanning width on multiple monitors (to avoid unsnapping) if (height == monitorArea.Work.Height || width >= SystemParameters.VirtualScreenWidth) { window.IsSnapped = true; UpdateResizeBorder(window, monitorArea, window.Left, window.Left + width); } else { window.IsSnapped = false; ShowDropShadow(window); EnableResizeBorder(window); } } } else if (resizing == SIZE_MAXIMIZED) { // Required when maximized from dragging window DisableResizeBorder(window); } } break; // To handle proper resizing of the custom window case WM_GETMINMAXINFO: { MonitorArea monitorArea = GetMonitorArea(hWnd); if (monitorArea != null) { MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); mmi.ptMaxPosition.x = monitorArea.Offset.x; mmi.ptMaxPosition.y = monitorArea.Offset.y; mmi.ptMaxSize.x = monitorArea.Work.Width; mmi.ptMaxSize.y = monitorArea.Work.Height; // To support minimum window size mmi.ptMinTrackSize.x = (int)window.MinWidth; mmi.ptMinTrackSize.y = (int)window.MinHeight; Marshal.StructureToPtr(mmi, lParam, true); handled = true; } } break; // To activate/deactivate border resize handles from window position case WM_WINDOWPOSCHANGED: { WINDOWPOS windowPos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS)); // When window is snapped and position changes if ((windowPos.flags & SWP_NOMOVE) != SWP_NOMOVE) { if (window.IsSnapped) { MonitorArea monitorArea = GetMonitorArea(hWnd); if (monitorArea != null) { UpdateResizeBorder(window, monitorArea, windowPos.x, windowPos.x + windowPos.cx); } } } } break; } return(IntPtr.Zero); }
/// <summary> /// Support for custom window drag move and /// restore from maximized window state /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void OnDragControlMouseMove(object sender, MouseEventArgs e) { base.OnMouseMove(e); if (e.LeftButton == MouseButtonState.Pressed && !this.IsMaximizing && !this.SystemMenuShown) { if (this.WindowState == WindowState.Maximized) { // When passing null to GetPosition, we get the mouse position // relative to the containing window (on current screen) // Remarks: Mouse.GetPosition(this), e.GetPosition(null); // and e.MouseDevice.GetPosition(null) seems to get the // same coordinates // Local (within window) and global (screen) coordinates Point local = e.GetPosition(null); Point global = this.PointToScreen(local); IntPtr hwnd = new WindowInteropHelper(this).EnsureHandle(); MonitorArea monitorArea = GetMonitorArea(hwnd); // Coordinates relative to the drag control Point position = e.GetPosition(dragControl); Point relative = this.PointToScreen(position); double dragAreaWidth = dragControl.ActualWidth; double leftMargin = global.X - relative.X; double rightMargin = monitorArea.Work.Width - dragAreaWidth - leftMargin; double restoreDragAreaWidth = this.RestoreBounds.Width - leftMargin - rightMargin; // New X coordinate relative to restored window double x = Math.Round(restoreDragAreaWidth * local.X / dragAreaWidth); // Compensate for the resize border (uniform) width double resizeBorderWidth = GetResizeBorderWidth(this); double left = monitorArea.Work.Left - resizeBorderWidth; double right = monitorArea.Work.Left + monitorArea.Work.Width + resizeBorderWidth; double leftBound = left + this.RestoreBounds.Width - rightMargin; double rightBound = right - this.RestoreBounds.Width + leftMargin; Point offset = new Point(0, resizeBorderWidth); // The restore bounds width is within the left bound region if (global.X < leftBound) { // Align restored window to left of screen this.Left = left; offset.X = resizeBorderWidth; } // The restore bounds width is within the right bound region else if (global.X > rightBound) { // Align restored window to right of screen this.Left = right - this.RestoreBounds.Width; offset.X = -resizeBorderWidth; } // The restore bounds width is shorter than the left / right bound region width else if ((global.X > leftBound) && (global.X < rightBound)) { this.Left = global.X - x - leftMargin - resizeBorderWidth; } this.Top = global.Y - local.Y; // Set and remove the horizontal offset to avoid the restored window's border // to momentarily get outside the current monitor space creating a short flicker. this.Left += offset.X; this.WindowState = WindowState.Normal; this.Left -= offset.X; this.Top -= offset.Y; } this.IsDragging = true; HideDropShadow(this); this.DragMove(); this.IsDragging = false; ShowDropShadow(this); } // Reset special condition guard flags this.IsMaximizing = false; this.SystemMenuShown = false; e.Handled = true; }