33using System . Runtime . InteropServices ;
44using System . Runtime . Versioning ;
55using System . Text . RegularExpressions ;
6+ using SixLabors . ImageSharp ;
67#if WINDOWS
78using SnapX . Core . Utils . Native ;
89using Windows . Win32 . System . SystemInformation ;
@@ -16,25 +17,26 @@ namespace SnapX.Core.Utils;
1617
1718public static partial class OsInfo
1819{
20+ #if WINDOWS
1921 public record WindowsGpuInfo ( string Description , string DriverVersion ) ;
20- public record WindowsMonitorInfo ( string Name , string Position , string Resolution ) ;
22+ public record WindowsMonitorInfo ( string Name , Point Position , string Resolution ) ;
2123 public record WindowsGraphicsInfo ( List < WindowsGpuInfo > Gpus , List < WindowsMonitorInfo > Monitors ) ;
22-
24+ #endif
2325 public record LinuxGpuInfo ( string Description , string Vendor , string DriverVersion ) ;
24- public record LinuxMonitorInfo ( string Name , string Resolution , string Coordinates ) ;
26+ public record LinuxMonitorInfo ( string Name , string Resolution , Point Coordinates ) ;
2527 public record LinuxGraphicsInfo ( List < LinuxGpuInfo > ? Gpus , List < LinuxMonitorInfo > Monitors ) ;
2628
2729 public record MacOSGraphicsInfo ( string GpuChipset , string GpuDriverVersion , string MonitorResolution ) ;
2830 public record GenericGpuInfo ( string Description , string DriverVersion , string ? Vendor = null ) ;
29- public record GenericMonitorInfo ( string Name , string Resolution , string ? Position = null )
31+ public record GenericMonitorInfo ( string Name , string Resolution , Point ? Position = null )
3032 {
3133 public override string ToString ( ) =>
3234 Position is not null
3335 ? $ "{ Name } [{ Resolution } @ { Position } ]"
3436 : $ "{ Name } [{ Resolution } ]";
3537 }
3638 public record GenericGraphicsInfo ( List < GenericGpuInfo > ? Gpus , List < GenericMonitorInfo > ? Monitors , string OperatingSystemName , string ? ErrorMessage = null ) ;
37-
39+ #if WINDOWS
3840 private static readonly Dictionary < string , string > BuildToFriendlyName = new ( )
3941 {
4042 // Windows 11
@@ -61,6 +63,7 @@ public record GenericGraphicsInfo(List<GenericGpuInfo>? Gpus, List<GenericMonito
6163 { "19044" , "21H2" } ,
6264 { "19045" , "22H2" }
6365 } ;
66+ #endif
6467 public static string GetFancyOSNameAndVersion ( )
6568 {
6669 if ( OperatingSystem . IsWindows ( ) ) return GetWindowsVersion ( ) ;
@@ -218,7 +221,7 @@ private static string GetProcessorNameLinux()
218221 foreach ( var line in lines )
219222 {
220223 if ( ! line . StartsWith ( "model name" ) ) continue ;
221- var processorName = line [ ( line . IndexOf ( ":" ) + 2 ) ..] . Trim ( ) ;
224+ var processorName = line [ ( line . IndexOf ( ':' ) + 2 ) ..] . Trim ( ) ;
222225 return processorName ;
223226 }
224227 }
@@ -294,10 +297,10 @@ public static (long totalMemory, long usedMemory) GetMemoryInfo()
294297
295298 return ( 0 , 0 ) ;
296299 }
300+ #if WINDOWS
297301 [ SupportedOSPlatform ( "windows5.1.2600" ) ]
298302 private static ( long totalMemory , long usedMemory ) GetMemoryInfoWindows ( )
299303 {
300- #if WINDOWS
301304 try
302305 {
303306 var status = new MEMORYSTATUSEX
@@ -320,13 +323,11 @@ private static (long totalMemory, long usedMemory) GetMemoryInfoWindows()
320323 {
321324 DebugHelper . WriteException ( "Error reading memory info on Windows: " + ex . Message ) ;
322325 }
323- #endif
324326 return ( 0 , 0 ) ;
325327 }
326328 [ SupportedOSPlatform ( "windows5.1.2600" ) ]
327329 private static long GetAvailableMemoryWindows ( )
328330 {
329- #if WINDOWS
330331 var status = new MEMORYSTATUSEX
331332 {
332333 dwLength = ( uint ) Marshal . SizeOf ( typeof ( MEMORYSTATUSEX ) )
@@ -337,9 +338,9 @@ private static long GetAvailableMemoryWindows()
337338 return ( long ) status . ullAvailPhys ;
338339 }
339340 DebugHelper . WriteException ( new Exception ( "Unable to retrieve memory information." ) ) ;
340- #endif
341341 return - 1 ;
342342 }
343+ #endif
343344 [ SupportedOSPlatform ( "linux" ) ]
344345 private static ( long totalMemory , long usedMemory ) GetMemoryInfoLinux ( )
345346 {
@@ -501,13 +502,17 @@ public static GenericGraphicsInfo GetGenericGraphicsInfo()
501502 {
502503 if ( OperatingSystem . IsWindows ( ) )
503504 {
505+ #if WINDOWS
504506 var windowsInfo = GetGraphicsInfoWindows ( ) ;
505507 if ( windowsInfo == null )
506508 return new GenericGraphicsInfo ( [ ] , [ ] , "Windows" ,
507509 "Error retrieving Windows graphics info." ) ;
508510 var genericGpus = windowsInfo . Gpus . Select ( g => new GenericGpuInfo ( g . Description , g . DriverVersion ) ) . ToList ( ) ;
509511 var genericMonitors = windowsInfo . Monitors . Select ( m => new GenericMonitorInfo ( m . Name , m . Resolution , m . Position ) ) . ToList ( ) ;
510512 return new GenericGraphicsInfo ( genericGpus , genericMonitors , "Windows" ) ;
513+ #else
514+ return new GenericGraphicsInfo ( [ ] , [ ] , "Windows" , "Compilation error for Windows specific code not being included??" ) ;
515+ #endif
511516 }
512517 else
513518 {
@@ -546,10 +551,10 @@ public static GenericGraphicsInfo GetGenericGraphicsInfo()
546551 return new GenericGraphicsInfo ( genericGpusmacOS , genericMonitors , "macOS" ) ;
547552 }
548553 }
554+ #if WINDOWS
549555 [ SupportedOSPlatform ( "windows" ) ]
550556 public static WindowsGraphicsInfo ? GetGraphicsInfoWindows ( )
551557 {
552- #if WINDOWS
553558 try
554559 {
555560 const string gpuCommand = """
@@ -610,22 +615,63 @@ public static GenericGraphicsInfo GetGenericGraphicsInfo()
610615 {
611616 return null ;
612617 }
613- #else
614- return null ;
615- #endif
616618 }
617619 private static List < WindowsGpuInfo > ParseWindowsGpuInfo ( string rawOutput )
618620 {
619621 var lines = rawOutput . Trim ( ) . Split ( Environment . NewLine , StringSplitOptions . RemoveEmptyEntries ) ;
620622 var regex = WindowsGPUInfoRegex ( ) ;
621623 return ( from line in lines select line . Trim ( ) into trimmedLine select regex . Match ( trimmedLine ) into match where match . Success let name = match . Groups [ 1 ] . Value . Trim ( ) let driver = match . Groups [ 2 ] . Value . Trim ( ) select new WindowsGpuInfo ( name , driver ) ) . ToList ( ) ;
622624 }
623-
624625 private static List < WindowsMonitorInfo > ParseWindowsMonitorInfo ( string rawOutput )
625626 {
626627 var lines = rawOutput . Split ( Environment . NewLine , StringSplitOptions . RemoveEmptyEntries ) ;
627- return ( from line in lines where line . StartsWith ( "Monitor:" ) select line [ "Monitor: " . Length ..] . Split ( [ ", Position: " , ", Resolution: " ] , StringSplitOptions . RemoveEmptyEntries ) into parts where parts . Length == 3 let name = parts [ 0 ] let positionPart = parts [ 1 ] let resolutionPart = parts [ 2 ] select new WindowsMonitorInfo ( name , positionPart , resolutionPart ) ) . ToList ( ) ;
628+ return ( from line in lines where line . StartsWith ( "Monitor:" ) select line [ "Monitor: " . Length ..] . Split ( [ ", Position: " , ", Resolution: " ] , StringSplitOptions . RemoveEmptyEntries ) into parts where parts . Length == 3 let name = parts [ 0 ] let positionPart = parts [ 1 ] let resolutionPart = parts [ 2 ] select new WindowsMonitorInfo ( name , ParsePosition ( positionPart ) , resolutionPart ) ) . ToList ( ) ;
629+ }
630+ public static Point ParsePosition ( string position )
631+ {
632+ if ( string . IsNullOrWhiteSpace ( position ) )
633+ return new Point ( 0 , 0 ) ;
634+
635+ try
636+ {
637+ // Remove surrounding parentheses if present
638+ position = position . Trim ( ) ;
639+ if ( position . StartsWith ( "(" ) && position . EndsWith ( ")" ) )
640+ {
641+ position = position . Substring ( 1 , position . Length - 2 ) . Trim ( ) ;
642+ }
643+
644+ // Expected format after trimming: "X: 0, Y: 0"
645+ var parts = position . Split ( ',' ) ;
646+ int x = 0 , y = 0 ;
647+
648+ foreach ( var part in parts )
649+ {
650+ var kv = part . Split ( ':' ) ;
651+ if ( kv . Length != 2 ) continue ;
652+
653+ var key = kv [ 0 ] . Trim ( ) . ToUpperInvariant ( ) ;
654+ var value = int . Parse ( kv [ 1 ] . Trim ( ) ) ;
655+
656+ switch ( key )
657+ {
658+ case "X" :
659+ x = value ;
660+ break ;
661+ case "Y" :
662+ y = value ;
663+ break ;
664+ }
665+ }
666+
667+ return new Point ( x , y ) ;
668+ }
669+ catch
670+ {
671+ return new Point ( 0 , 0 ) ; // fallback if parsing fails
672+ }
628673 }
674+ #endif
629675 public static LinuxGraphicsInfo ? GetGraphicsInfoLinux ( )
630676 {
631677 try
@@ -658,9 +704,9 @@ private static List<WindowsMonitorInfo> ParseWindowsMonitorInfo(string rawOutput
658704 var glxLines = glxInfo . Split ( Environment . NewLine , StringSplitOptions . RemoveEmptyEntries ) ;
659705 if ( string . IsNullOrWhiteSpace ( driverVersion ) )
660706 {
661- driverVersion = glxLines . FirstOrDefault ( line => line . Contains ( "OpenGL version" ) ) ? . Split ( ':' ) [ 1 ] ? . Trim ( ) ;
707+ driverVersion = glxLines . FirstOrDefault ( glxLine => glxLine . Contains ( "OpenGL version" ) ) ? . Split ( ':' ) [ 1 ] ? . Trim ( ) ;
662708 var mesaRegex = MesaRegex ( ) ;
663- var versionLine = glxLines . FirstOrDefault ( line => line . Contains ( "OpenGL version" ) ) ;
709+ var versionLine = glxLines . FirstOrDefault ( glxLine => glxLine . Contains ( "OpenGL version" ) ) ;
664710 var mesaMatch = mesaRegex . Match ( versionLine ?? string . Empty ) ;
665711 if ( mesaMatch . Success )
666712 driverVersion = mesaMatch . Value ;
@@ -669,6 +715,10 @@ private static List<WindowsMonitorInfo> ParseWindowsMonitorInfo(string rawOutput
669715 {
670716 driverVersion = $ "Kernel { kernelVersion } { driverVersion } ";
671717 }
718+ else if ( driverVersion ? . Contains ( "NVIDIA" , StringComparison . InvariantCultureIgnoreCase ) ?? false )
719+ {
720+ driverVersion = driverVersion ? . Split ( ' ' ) . Last ( ) ;
721+ }
672722 }
673723 var vendor = glxLines . FirstOrDefault ( line => line . Contains ( "OpenGL vendor string" ) ) ? . Split ( ':' ) [ 1 ] ? . Trim ( ) ;
674724 gpuInfoList . Add ( new LinuxGpuInfo ( gpu , vendor , driverVersion ) ) ;
@@ -700,11 +750,10 @@ private static List<WindowsMonitorInfo> ParseWindowsMonitorInfo(string rawOutput
700750 }
701751
702752 var coordinateParts = resolutionAndCoords . Split ( '+' ) ;
703- var x = coordinateParts . Length > 1 ? coordinateParts [ 1 ] : string . Empty ;
704- var y = coordinateParts . Length > 2 ? coordinateParts [ 2 ] : string . Empty ;
705- var coordinates = $ "({ x } , { y } )";
753+ var x = int . Parse ( coordinateParts . Length > 1 ? coordinateParts [ 1 ] : string . Empty ) ;
754+ var y = int . Parse ( coordinateParts . Length > 2 ? coordinateParts [ 2 ] : string . Empty ) ;
706755
707- monitors . Add ( new LinuxMonitorInfo ( monitorName , resolution , coordinates ) ) ;
756+ monitors . Add ( new LinuxMonitorInfo ( monitorName , resolution , new Point ( x , y ) ) ) ;
708757 }
709758 }
710759 catch ( Exception ex )
@@ -779,7 +828,6 @@ public static bool IsHdrSupported()
779828 // If they're on Linux, they should know they're using things like HDR.
780829 }
781830
782- [ SupportedOSPlatform ( "linux" ) ]
783831 public static bool IsWSL ( )
784832 {
785833 if ( ! OperatingSystem . IsLinux ( ) ) return false ;
@@ -793,18 +841,15 @@ public static bool IsWSL()
793841 return false ;
794842 }
795843 }
844+ #if WINDOWS
796845 [ SupportedOSPlatform ( "windows5.0" ) ]
797846 private static bool CheckWindowsHdr ( )
798847 {
799- #if WINDOWS
800848 var hdc = PInvoke . GetDC ( new HWND ( IntPtr . Zero ) ) ;
801849 var bpp = PInvoke . GetDeviceCaps ( hdc , GET_DEVICE_CAPS_INDEX . BITSPIXEL ) ;
802850 return bpp >= 30 ;
803- #else
804- return false ;
805- #endif
806851 }
807-
852+ #endif
808853 private static bool CheckMacOSHdr ( )
809854 {
810855 var displayInfo = GetMacOSDisplayInfo ( ) ;
0 commit comments