/ src / Ryujinx.Common / SystemInterop / ForceDpiAware.cs
ForceDpiAware.cs
 1  using Ryujinx.Common.Logging;
 2  using System;
 3  using System.Globalization;
 4  using System.Runtime.InteropServices;
 5  
 6  namespace Ryujinx.Common.SystemInterop
 7  {
 8      public static partial class ForceDpiAware
 9      {
10          [LibraryImport("user32.dll")]
11          [return: MarshalAs(UnmanagedType.Bool)]
12          private static partial bool SetProcessDPIAware();
13  
14          private const string X11LibraryName = "libX11.so.6";
15  
16          [LibraryImport(X11LibraryName)]
17          private static partial IntPtr XOpenDisplay([MarshalAs(UnmanagedType.LPStr)] string display);
18  
19          [LibraryImport(X11LibraryName)]
20          private static partial IntPtr XGetDefault(IntPtr display, [MarshalAs(UnmanagedType.LPStr)] string program, [MarshalAs(UnmanagedType.LPStr)] string option);
21  
22          [LibraryImport(X11LibraryName)]
23          private static partial int XDisplayWidth(IntPtr display, int screenNumber);
24  
25          [LibraryImport(X11LibraryName)]
26          private static partial int XDisplayWidthMM(IntPtr display, int screenNumber);
27  
28          [LibraryImport(X11LibraryName)]
29          private static partial int XCloseDisplay(IntPtr display);
30  
31          private const double StandardDpiScale = 96.0;
32          private const double MaxScaleFactor = 1.25;
33  
34          /// <summary>
35          /// Marks the application as DPI-Aware when running on the Windows operating system.
36          /// </summary>
37          public static void Windows()
38          {
39              // Make process DPI aware for proper window sizing on high-res screens.
40              if (OperatingSystem.IsWindowsVersionAtLeast(6))
41              {
42                  SetProcessDPIAware();
43              }
44          }
45  
46          public static double GetActualScaleFactor()
47          {
48              double userDpiScale = 96.0;
49  
50              try
51              {
52                  if (OperatingSystem.IsWindows())
53                  {
54                      userDpiScale = GdiPlusHelper.GetDpiX(IntPtr.Zero);
55                  }
56                  else if (OperatingSystem.IsLinux())
57                  {
58                      string xdgSessionType = Environment.GetEnvironmentVariable("XDG_SESSION_TYPE")?.ToLower();
59  
60                      if (xdgSessionType == null || xdgSessionType == "x11")
61                      {
62                          IntPtr display = XOpenDisplay(null);
63                          string dpiString = Marshal.PtrToStringAnsi(XGetDefault(display, "Xft", "dpi"));
64                          if (dpiString == null || !double.TryParse(dpiString, NumberStyles.Any, CultureInfo.InvariantCulture, out userDpiScale))
65                          {
66                              userDpiScale = XDisplayWidth(display, 0) * 25.4 / XDisplayWidthMM(display, 0);
67                          }
68                          _ = XCloseDisplay(display);
69                      }
70                      else if (xdgSessionType == "wayland")
71                      {
72                          // TODO
73                          Logger.Warning?.Print(LogClass.Application, "Couldn't determine monitor DPI: Wayland not yet supported");
74                      }
75                      else
76                      {
77                          Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: Unrecognised XDG_SESSION_TYPE: {xdgSessionType}");
78                      }
79                  }
80              }
81              catch (Exception e)
82              {
83                  Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: {e.Message}");
84              }
85  
86              return userDpiScale;
87          }
88  
89          public static double GetWindowScaleFactor()
90          {
91              double userDpiScale = GetActualScaleFactor();
92  
93              return Math.Min(userDpiScale / StandardDpiScale, MaxScaleFactor);
94          }
95      }
96  }