ForceDpiAware.cs 3.5 KB

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