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 }