/ src / modules / peek / Peek.UI / Extensions / WindowExtensions.cs
WindowExtensions.cs
 1  // Copyright (c) Microsoft Corporation
 2  // The Microsoft Corporation licenses this file to you under the MIT license.
 3  // See the LICENSE file in the project root for more information.
 4  
 5  using System.Runtime.InteropServices;
 6  
 7  using ManagedCommon;
 8  using Microsoft.UI.Xaml;
 9  using Windows.Win32;
10  using Windows.Win32.Foundation;
11  using Windows.Win32.Graphics.Gdi;
12  using Windows.Win32.UI.WindowsAndMessaging;
13  using WinUIEx;
14  
15  namespace Peek.UI.Extensions
16  {
17      public static class WindowExtensions
18      {
19          public static double GetMonitorScale(this Window window)
20          {
21              var hwnd = new HWND(window.GetWindowHandle());
22              return hwnd.GetMonitorScale();
23          }
24  
25          internal static void CenterOnMonitor(this Window window, HWND hwndDesktop, double? width = null, double? height = null)
26          {
27              var hwndToCenter = new HWND(window.GetWindowHandle());
28  
29              // If the window is maximized, restore to normal state before change its size
30              var placement = default(WINDOWPLACEMENT);
31              if (PInvoke_PeekUI.GetWindowPlacement(hwndToCenter, ref placement))
32              {
33                  if (placement.showCmd == SHOW_WINDOW_CMD.SW_MAXIMIZE)
34                  {
35                      placement.showCmd = SHOW_WINDOW_CMD.SW_SHOWNORMAL;
36                      if (!PInvoke_PeekUI.SetWindowPlacement(hwndToCenter, in placement))
37                      {
38                          Logger.LogError($"SetWindowPlacement failed with error {Marshal.GetLastWin32Error()}");
39                      }
40                  }
41              }
42              else
43              {
44                  Logger.LogError($"GetWindowPlacement failed with error {Marshal.GetLastWin32Error()}");
45              }
46  
47              var monitor = PInvoke_PeekUI.MonitorFromWindow(hwndDesktop, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
48              MONITORINFO info = default(MONITORINFO);
49              info.cbSize = 40;
50              PInvoke_PeekUI.GetMonitorInfo(monitor, ref info);
51              var dpi = PInvoke_PeekUI.GetDpiForWindow(new HWND((nint)hwndDesktop));
52              PInvoke_PeekUI.GetWindowRect(hwndToCenter, out RECT windowRect);
53              var scalingFactor = dpi / 96d;
54              var w = width.HasValue ? (int)(width * scalingFactor) : windowRect.right - windowRect.left;
55              var h = height.HasValue ? (int)(height * scalingFactor) : windowRect.bottom - windowRect.top;
56              var cx = (info.rcMonitor.left + info.rcMonitor.right) / 2;
57              var cy = (info.rcMonitor.bottom + info.rcMonitor.top) / 2;
58              var left = cx - (w / 2);
59              var top = cy - (h / 2);
60  
61              SetWindowPosOrThrow(hwndToCenter, default(HWND), left, top, w, h, SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE);
62          }
63  
64          private static void SetWindowPosOrThrow(HWND hWnd, HWND hWndInsertAfter, int x, int y, int cx, int cy, SET_WINDOW_POS_FLAGS uFlags)
65          {
66              bool result = PInvoke_PeekUI.SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags);
67              if (!result)
68              {
69                  Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
70              }
71          }
72      }
73  }