diff --git a/src/KappaDuck.Quack/Interop/SDL/Primitives/SDL_Locale.cs b/src/KappaDuck.Quack/Interop/SDL/Primitives/SDL_Locale.cs new file mode 100644 index 0000000..d3f320a --- /dev/null +++ b/src/KappaDuck.Quack/Interop/SDL/Primitives/SDL_Locale.cs @@ -0,0 +1,12 @@ +// Copyright (c) KappaDuck. +// Licensed under the MIT license. + +namespace KappaDuck.Quack.Interop.SDL.Primitives; + +[StructLayout(LayoutKind.Sequential)] +internal readonly struct SDL_Locale +{ + public byte* Language { get; } + + public byte* Country { get; } +} diff --git a/src/KappaDuck.Quack/Interop/SDL/SDL3.System.cs b/src/KappaDuck.Quack/Interop/SDL/SDL3.System.cs index 09fd391..46021ce 100644 --- a/src/KappaDuck.Quack/Interop/SDL/SDL3.System.cs +++ b/src/KappaDuck.Quack/Interop/SDL/SDL3.System.cs @@ -1,6 +1,7 @@ // Copyright (c) KappaDuck. // Licensed under the MIT license. +using KappaDuck.Quack.Interop.SDL.Primitives; using KappaDuck.Quack.System; namespace KappaDuck.Quack.Interop.SDL; @@ -21,6 +22,14 @@ internal static partial class SDL3 [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] internal static partial PowerState GetPowerInfo(out int seconds, out int percent); + [LibraryImport(nameof(SDL3), EntryPoint = "SDL_GetPreferredLocales")] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + internal static partial SDL_Locale** GetPreferredLocales(out int count); + + [LibraryImport(nameof(SDL3), EntryPoint = "SDL_GetSystemRAM")] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + internal static partial int GetSystemRAM(); + [LibraryImport(nameof(SDL3), EntryPoint = "SDL_GetSystemTheme")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] internal static partial Theme GetSystemTheme(); diff --git a/src/KappaDuck.Quack/System/DeviceInfo.cs b/src/KappaDuck.Quack/System/DeviceInfo.cs new file mode 100644 index 0000000..7e63afa --- /dev/null +++ b/src/KappaDuck.Quack/System/DeviceInfo.cs @@ -0,0 +1,115 @@ +// Copyright (c) KappaDuck. +// Licensed under the MIT license. + +using KappaDuck.Quack.Interop.SDL.Marshalling; +using KappaDuck.Quack.Interop.SDL.Primitives; +using System.Globalization; + +namespace KappaDuck.Quack.System; + +/// +/// Represents the device on which is currently running. +/// +public static class DeviceInfo +{ + /// + /// Gets the operating system's process architecture, e.g. or . + /// + public static Architecture Architecture { get; } = RuntimeInformation.OSArchitecture; + + /// + /// Gets the user's preferred cultures. + /// + /// + /// This might be a "slow" call that has to query the operating system. It's best to ask for this once and save + /// the results. However, this list can change, usually because the user has changed a system preference outside + /// of your application; Quack! will send an event so you can update by calling this method again. + /// + public static IReadOnlyList Cultures + { + get + { + SDL_Locale** locales = SDL3.GetPreferredLocales(out int count); + + if (locales is null || count == 0) + return []; + + List cultures = [with(count)]; + + unsafe + { + for (int i = 0; i < count; i++) + { + SDL_Locale* locale = locales[i]; + + string language = SDLStringMarshaller.ConvertToManaged(locale->Language)!; + string? country = SDLStringMarshaller.ConvertToManaged(locale->Country); + + if (TryGetCulture(language, country, out CultureInfo? culture)) + cultures.Add(culture); + } + } + + SDL3.Free(locales); + + return cultures; + } + } + + /// + /// Gets the platform name + /// + public static string Platform { get; } = RuntimeInformation.OSDescription; + + /// + /// Gets a snapshot of the current power supply. + /// + /// + /// + /// You should never take the power status for granted. Batteries (especially failing ones) can + /// report incorrect values, and the values reported here are best estimates based on what the + /// hardware reports. It's not uncommon for older batteries to lose stored power much faster than + /// reported, or completely drain when reporting it has 20% left, etc. + /// + /// + /// Battery status can change at any time, so if your application depends on accurate power status, + /// refresh the values by reading this property again, and perhaps ignore changes until they seem + /// stable for a few seconds. A platform may only report battery percentage or time left, not both. + /// + /// + /// On some platforms retrieving power details can be expensive; for continuous display, read it + /// about once a minute rather than every frame. + /// + /// + public static PowerInfo Power => PowerInfo.Capture(); + + /// + /// Gets the number of processors available to the current process. + /// + public static int ProcessorCount => Environment.ProcessorCount; + + /// + /// Gets the amount of RAM configured in the system in MiB. + /// + public static long RAM { get; } = SDL3.GetSystemRAM(); + + /// + /// Gets the current system theme. + /// + public static Theme Theme => SDL3.GetSystemTheme(); + + private static bool TryGetCulture(string language, string? country, [NotNullWhen(true)] out CultureInfo? culture) + { + string name = string.IsNullOrEmpty(country) ? language : $"{language}-{country}"; + try + { + culture = CultureInfo.GetCultureInfo(name); + return true; + } + catch (CultureNotFoundException) + { + culture = null; + return false; + } + } +} diff --git a/src/KappaDuck.Quack/System/PowerInfo.cs b/src/KappaDuck.Quack/System/PowerInfo.cs index b72a811..cdaa521 100644 --- a/src/KappaDuck.Quack/System/PowerInfo.cs +++ b/src/KappaDuck.Quack/System/PowerInfo.cs @@ -15,39 +15,6 @@ private PowerInfo(PowerState state, int? percentage, TimeSpan? remaining) Remaining = remaining; } - /// - /// Gets a snapshot of the current power supply. - /// - /// - /// - /// You should never take the power status for granted. Batteries (especially failing ones) can - /// report incorrect values, and the values reported here are best estimates based on what the - /// hardware reports. It's not uncommon for older batteries to lose stored power much faster than - /// reported, or completely drain when reporting it has 20% left, etc. - /// - /// - /// Battery status can change at any time, so if your application depends on accurate power status, - /// refresh the values by reading this property again, and perhaps ignore changes until they seem - /// stable for a few seconds. A platform may only report battery percentage or time left, not both. - /// - /// - /// On some platforms retrieving power details can be expensive; for continuous display, read it - /// about once a minute rather than every frame. - /// - /// - public static PowerInfo Current - { - get - { - PowerState state = SDL3.GetPowerInfo(out int seconds, out int percent); - - int? percentage = percent < 0 ? null : percent; - TimeSpan? remaining = seconds < 0 ? null : TimeSpan.FromSeconds(seconds); - - return new PowerInfo(state, percentage, remaining); - } - } - /// /// Gets the power state of the system. /// @@ -83,4 +50,13 @@ public static PowerInfo Current /// public bool HasBattery => State is PowerState.OnBattery or PowerState.Charging or PowerState.Charged; + internal static PowerInfo Capture() + { + PowerState state = SDL3.GetPowerInfo(out int seconds, out int percent); + + int? percentage = percent < 0 ? null : percent; + TimeSpan? remaining = seconds < 0 ? null : TimeSpan.FromSeconds(seconds); + + return new PowerInfo(state, percentage, remaining); + } } diff --git a/src/KappaDuck.Quack/System/SystemPreferences.cs b/src/KappaDuck.Quack/System/ScreenSaver.cs similarity index 78% rename from src/KappaDuck.Quack/System/SystemPreferences.cs rename to src/KappaDuck.Quack/System/ScreenSaver.cs index b382bd9..122b83a 100644 --- a/src/KappaDuck.Quack/System/SystemPreferences.cs +++ b/src/KappaDuck.Quack/System/ScreenSaver.cs @@ -6,9 +6,9 @@ namespace KappaDuck.Quack.System; /// -/// Provides access to system preferences. +/// Controls whether the system screen saver may activate while the application runs. /// -public static class SystemPreferences +public static class ScreenSaver { /// /// Gets or sets a value indicating whether the screen saver is enabled. @@ -18,7 +18,7 @@ public static class SystemPreferences /// The screen saver is disabled by default. /// /// Thrown if enabling or disabling the screen saver fails. - public static bool ScreenSaverEnabled + public static bool Enabled { get; set @@ -26,7 +26,6 @@ public static bool ScreenSaverEnabled if (value) { SDLThrowHelper.ThrowIfFailed(SDL3.EnableScreenSaver()); - field = true; return; } @@ -35,9 +34,4 @@ public static bool ScreenSaverEnabled field = false; } } - - /// - /// Gets the current system theme. - /// - public static Theme Theme => SDL3.GetSystemTheme(); } diff --git a/src/KappaDuck.Quack/Interop/Handles/WaylandHandle.cs b/src/KappaDuck.Quack/Windows/Handles/WaylandHandle.cs similarity index 92% rename from src/KappaDuck.Quack/Interop/Handles/WaylandHandle.cs rename to src/KappaDuck.Quack/Windows/Handles/WaylandHandle.cs index f42ba95..c05dd63 100644 --- a/src/KappaDuck.Quack/Interop/Handles/WaylandHandle.cs +++ b/src/KappaDuck.Quack/Windows/Handles/WaylandHandle.cs @@ -1,7 +1,7 @@ // Copyright (c) KappaDuck. // Licensed under the MIT license. -namespace KappaDuck.Quack.Interop.Handles; +namespace KappaDuck.Quack.Windows.Handles; /// /// Represents a Wayland handle. diff --git a/src/KappaDuck.Quack/Interop/Handles/Win32Handle.cs b/src/KappaDuck.Quack/Windows/Handles/Win32Handle.cs similarity index 88% rename from src/KappaDuck.Quack/Interop/Handles/Win32Handle.cs rename to src/KappaDuck.Quack/Windows/Handles/Win32Handle.cs index 13cc846..baa5a9d 100644 --- a/src/KappaDuck.Quack/Interop/Handles/Win32Handle.cs +++ b/src/KappaDuck.Quack/Windows/Handles/Win32Handle.cs @@ -1,7 +1,7 @@ // Copyright (c) KappaDuck. // Licensed under the MIT license. -namespace KappaDuck.Quack.Interop.Handles; +namespace KappaDuck.Quack.Windows.Handles; /// /// Represents a Win32 handle diff --git a/src/KappaDuck.Quack/Interop/Handles/WindowHandle.cs b/src/KappaDuck.Quack/Windows/Handles/WindowHandle.cs similarity index 83% rename from src/KappaDuck.Quack/Interop/Handles/WindowHandle.cs rename to src/KappaDuck.Quack/Windows/Handles/WindowHandle.cs index 6f6c5f5..3cfa219 100644 --- a/src/KappaDuck.Quack/Interop/Handles/WindowHandle.cs +++ b/src/KappaDuck.Quack/Windows/Handles/WindowHandle.cs @@ -1,7 +1,7 @@ // Copyright (c) KappaDuck. // Licensed under the MIT license. -namespace KappaDuck.Quack.Interop.Handles; +namespace KappaDuck.Quack.Windows.Handles; /// /// Represents the specific platform window handle. diff --git a/src/KappaDuck.Quack/Interop/Handles/X11Handle.cs b/src/KappaDuck.Quack/Windows/Handles/X11Handle.cs similarity index 92% rename from src/KappaDuck.Quack/Interop/Handles/X11Handle.cs rename to src/KappaDuck.Quack/Windows/Handles/X11Handle.cs index d7465d2..c5cd93e 100644 --- a/src/KappaDuck.Quack/Interop/Handles/X11Handle.cs +++ b/src/KappaDuck.Quack/Windows/Handles/X11Handle.cs @@ -1,7 +1,7 @@ // Copyright (c) KappaDuck. // Licensed under the MIT license. -namespace KappaDuck.Quack.Interop.Handles; +namespace KappaDuck.Quack.Windows.Handles; /// /// Represents a X11 handle.