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.