[gui] Add Avalonia desktop frontend (#35)

* [gui] Add Avalonia desktop frontend

Adds SharpEmu.GUI, a dark-themed desktop frontend that drives the
SharpEmu CLI as a child process:

- Game library with folder scanning for eboot.bin, search, and
  persisted settings (%APPDATA%/SharpEmu/gui-settings.json)
- Launch options mapped to CLI flags (log level, strict dynlib
  resolution, import trace limit)
- Live console with severity color-coding, bounded buffer, and
  crash-safe deferred auto-scroll
- EmulatorProcess launches the CLI via CreateProcessW with the same
  CET/CFG mitigation opt-outs the CLI applies to its own relaunched
  child (suppressed via SHARPEMU_DISABLE_MITIGATION_RELAUNCH so
  output is not lost to a detached console), inheritable pipes for
  stdout/stderr capture, a kill-on-close job object, and a fallback
  to an unmitigated launch on Windows builds that reject the policy
  bits

Also pins Tmds.DBus.Protocol 0.21.3 (transitive of Avalonia.Desktop)
to fix GHSA-xrw6-gwf8-vvr9.


* [gui] Integrate GUI into the SharpEmu executable

Per review feedback, the GUI is no longer a separate application.
SharpEmu.exe now opens the desktop frontend when started without
arguments and behaves exactly as the existing CLI when given any
argument:

- SharpEmu.GUI becomes a class library exposing GuiLauncher.Run(),
  hosted by SharpEmu.CLI
- The console window is hidden in GUI mode only when the process is
  its sole owner (double-click launch), never a terminal the user
  launched from
- In GUI mode the frontend spawns this same executable (with
  arguments) as the emulator child process, so the existing launch,
  piping, and mitigation machinery is unchanged


* [gui] Address review feedback: no console, single-file, param.json, portable settings

- Switch SharpEmu.exe to the GUI subsystem so no console window appears
  at startup. CLI mode attaches to the parent terminal console (or
  allocates one when started with arguments but no terminal) and
  rebinds missing std handles to CONOUT$; piped/redirected output is
  used as-is, so scripted and GUI-spawned runs are unaffected.
- Publish as a true single file: native libraries are embedded and
  self-extracted, with glfw kept as the only loose DLL next to the
  executable.
- The game library reads sce_sys/param.json and shows the game title
  with the title id beneath it, falling back to the folder name.
- GUI settings and the crash log now live next to the executable,
  matching the emulator convention, instead of %APPDATA%.


* [build] Add win-x64 sections to package lock files

Generated by dotnet publish -r win-x64 with locked restore enabled.


* [build] Regenerate lock files from project configuration

dotnet restore --force-evaluate; removes the win-x64 runtime sections
that a local RID-specific publish had written into projects that do
not declare a runtime identifier, which broke locked-mode restore in
CI. Verified with dotnet restore -p:RestoreLockedMode=true.


---------
This commit is contained in:
Brando
2026-07-10 12:21:24 -04:00
committed by GitHub
parent 41d61bde41
commit 42f0fa0e83
16 changed files with 2365 additions and 4 deletions
+102 -1
View File
@@ -3,6 +3,7 @@
using SharpEmu.Core.Runtime;
using SharpEmu.Core.Cpu;
using SharpEmu.GUI;
using SharpEmu.HLE;
using SharpEmu.Logging;
using System.Runtime.InteropServices;
@@ -24,12 +25,32 @@ internal static partial class Program
private const ulong PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_ALWAYS_OFF = 0x00000002UL << 28;
private const ulong PROCESS_CREATION_MITIGATION_POLICY2_USER_CET_SET_CONTEXT_IP_VALIDATION_ALWAYS_OFF = 0x00000002UL << 32;
private const ulong PROCESS_CREATION_MITIGATION_POLICY2_XTENDED_CONTROL_FLOW_GUARD_ALWAYS_OFF = 0x00000002UL << 40;
private const int ATTACH_PARENT_PROCESS = -1;
private const int STD_OUTPUT_HANDLE = -11;
private const int STD_ERROR_HANDLE = -12;
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint FILE_SHARE_READ = 0x00000001;
private const uint FILE_SHARE_WRITE = 0x00000002;
private const uint OPEN_EXISTING = 3;
[STAThread]
private static int Main(string[] args)
{
args = NormalizeInternalArguments(args, out var isMitigatedChild);
if (args.Length == 0 && !isMitigatedChild)
{
// No arguments: open the desktop frontend. Any argument selects
// the classic CLI behavior below.
return GuiLauncher.Run();
}
// The executable uses the GUI subsystem, so CLI mode has to connect
// itself to a console before the first write.
EnsureCliConsole();
Console.Error.WriteLine($"[DEBUG] SharpEmu starting with {args.Length} args");
args = NormalizeInternalArguments(args, out var isMitigatedChild);
if (!isMitigatedChild && TryRunMitigatedChild(args, out var childExitCode))
{
return childExitCode;
@@ -101,6 +122,58 @@ internal static partial class Program
return result == OrbisGen2Result.ORBIS_GEN2_OK ? 0 : 4;
}
private static void EnsureCliConsole()
{
if (!OperatingSystem.IsWindows())
{
return;
}
// Standard handles already provided (pipes or file redirection, e.g.
// when the GUI or a script launches us): use them as-is.
if (IsHandleValid(GetStdHandle(STD_OUTPUT_HANDLE)) && IsHandleValid(GetStdHandle(STD_ERROR_HANDLE)))
{
return;
}
// Prefer the console of the parent process (interactive terminal);
// create one only when started with arguments but no terminal at all
// (e.g. a shortcut), so usage and errors remain visible.
if (!AttachConsole(ATTACH_PARENT_PROCESS) && GetConsoleWindow() == 0)
{
_ = AllocConsole();
}
RebindStdHandleToConsole(STD_OUTPUT_HANDLE);
RebindStdHandleToConsole(STD_ERROR_HANDLE);
}
private static void RebindStdHandleToConsole(int stdHandle)
{
if (IsHandleValid(GetStdHandle(stdHandle)) || GetConsoleWindow() == 0)
{
return;
}
var conOut = CreateFileW(
"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
0,
0);
if (IsHandleValid(conOut))
{
_ = SetStdHandle(stdHandle, conOut);
}
}
private static bool IsHandleValid(nint handle)
{
return handle != 0 && handle != -1;
}
private static string[] NormalizeInternalArguments(string[] args, out bool isMitigatedChild)
{
isMitigatedChild = false;
@@ -670,4 +743,32 @@ internal static partial class Program
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(nint handle);
[DllImport("kernel32.dll")]
private static extern nint GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AttachConsole(int processId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern nint GetStdHandle(int stdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetStdHandle(int stdHandle, nint handle);
[DllImport("kernel32.dll", EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern nint CreateFileW(
string fileName,
uint desiredAccess,
uint shareMode,
nint securityAttributes,
uint creationDisposition,
uint flagsAndAttributes,
nint templateFile);
}
+18 -2
View File
@@ -7,16 +7,19 @@ SPDX-License-Identifier: GPL-2.0-or-later
<ItemGroup>
<ProjectReference Include="..\SharpEmu.Core\SharpEmu.Core.csproj" />
<ProjectReference Include="..\SharpEmu.GUI\SharpEmu.GUI.csproj" />
<ProjectReference Include="..\SharpEmu.Logging\SharpEmu.Logging.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<!-- GUI subsystem so starting without arguments opens the frontend with no
console window; CLI mode re-attaches to the parent terminal's console. -->
<OutputType>WinExe</OutputType>
<AssemblyName>SharpEmu</AssemblyName>
<RuntimeIdentifiers>win-x64;linux-x64;osx-arm64</RuntimeIdentifiers>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<!-- <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract> -->
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -43,4 +46,17 @@ SPDX-License-Identifier: GPL-2.0-or-later
</Content>
</ItemGroup>
<!-- Keep glfw as a loose file next to the executable; every other native
library is embedded into the single-file bundle. -->
<Target Name="KeepGlfwOutsideSingleFile" AfterTargets="ComputeResolvedFilesToPublishList">
<ItemGroup>
<_GlfwPublishFiles Include="@(ResolvedFileToPublish)"
Condition="$([System.String]::Copy('%(ResolvedFileToPublish.Filename)').StartsWith('glfw'))" />
<ResolvedFileToPublish Remove="@(_GlfwPublishFiles)" />
<ResolvedFileToPublish Include="@(_GlfwPublishFiles)">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>
+327
View File
@@ -8,6 +8,105 @@
"resolved": "10.0.3",
"contentHash": "0B6nZyCHWXnvmlB559oduOspVdNOnpNXPjhpWVMovLPAsDVG7A4jJR9rzECf67JUzxP8/ee/wA8clwIzJcWNFA=="
},
"Avalonia.Angle.Windows.Natives": {
"type": "Transitive",
"resolved": "2.1.25547.20250602",
"contentHash": "ZL0VLc4s9rvNNFt19Pxm5UNAkmKNylugAwJPX9ulXZ6JWs/l6XZihPWWTyezaoNOVyEPU8YbURtW7XMAtqXH5A=="
},
"Avalonia.BuildServices": {
"type": "Transitive",
"resolved": "11.3.2",
"contentHash": "qHDToxto1e3hci5YqbG9n0Ty8mlp3zBUN5wT66wKqaDVzXyQ0do3EnRILd4Ke9jpvsktaPpgE0YjEk7hornryQ=="
},
"Avalonia.FreeDesktop": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "aUwv8BNruRUOaUfMu4U3uibIUS60/rSHgGOhd8zBkLkpxY3JFJvgRbeq5ZzHIyKXCuKi18PO00YHAgCarp3wdw==",
"dependencies": {
"Avalonia": "11.3.18",
"Tmds.DBus.Protocol": "0.21.3"
}
},
"Avalonia.Native": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "8g53DROFW6wVJAnTsE1Iu5bdZO5r0oqxbdbMQODs1QDYCK2IU/y/x/vQVKCYOvqxl4tXkzU9tExv8XqSGPWthQ==",
"dependencies": {
"Avalonia": "11.3.18"
}
},
"Avalonia.Remote.Protocol": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "vw+6ZfgTuu72dA9aVWn6u56t2nrBd5MoMU0wo/qI9XJAl/c0oYYphIvwLvJP1JorubQY4UE3d0ac8ULBhrGBiA=="
},
"Avalonia.Skia": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "/B4aXmNRNjG8I5U/a1xJI+bIi0XO6DDzS3mBrIKlVnJRY2CyZiUeESRQXLnIU77Z9TvqkUROs+D47s085YjFtA==",
"dependencies": {
"Avalonia": "11.3.18",
"HarfBuzzSharp": "8.3.1.1",
"HarfBuzzSharp.NativeAssets.Linux": "8.3.1.1",
"HarfBuzzSharp.NativeAssets.WebAssembly": "8.3.1.1",
"SkiaSharp": "2.88.9",
"SkiaSharp.NativeAssets.Linux": "2.88.9",
"SkiaSharp.NativeAssets.WebAssembly": "2.88.9"
}
},
"Avalonia.Win32": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "eioUHkM2PeLPETd1aEks3rvb9plbba6buIrNdrqCpwE/qgHKUjvRNBd5mUQfAbGgTLiAes524gB8uUMDhrsJVQ==",
"dependencies": {
"Avalonia": "11.3.18",
"Avalonia.Angle.Windows.Natives": "2.1.25547.20250602"
}
},
"Avalonia.X11": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "m4Ki/G5Dovnq+6QzfS0iGbK8V77Q6oTjToMLOB0CxPCCrl3Oxywh6kIjuGJDPaN6kopMmjxlNShyQf+vPYL+JA==",
"dependencies": {
"Avalonia": "11.3.18",
"Avalonia.FreeDesktop": "11.3.18",
"Avalonia.Skia": "11.3.18"
}
},
"HarfBuzzSharp": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "tLZN66oe/uiRPTZfrCU4i8ScVGwqHNh5MHrXj0yVf4l7Mz0FhTGnQ71RGySROTmdognAs0JtluHkL41pIabWuQ==",
"dependencies": {
"HarfBuzzSharp.NativeAssets.Win32": "8.3.1.1",
"HarfBuzzSharp.NativeAssets.macOS": "8.3.1.1"
}
},
"HarfBuzzSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "3EZ1mpIiKWRLL5hUYA82ZHteeDIVaEA/Z0rA/wU6tjx6crcAkJnBPwDXZugBSfo8+J3EznvRJf49uMsqYfKrHg=="
},
"HarfBuzzSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "jbtCsgftcaFLCA13tVKo5iWdElJScrulLTKJre36O4YQTIlwDtPPqhRZNk+Y0vv4D1gxbscasGRucUDfS44ofQ=="
},
"HarfBuzzSharp.NativeAssets.WebAssembly": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "loJweK2u/mH/3C2zBa0ggJlITIszOkK64HLAZB7FUT670dTg965whLFYHDQo69NmC4+d9UN0icLC9VHidXaVCA=="
},
"HarfBuzzSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "UsJtQsfAJoFDZrXc4hCUfRPMqccfKZ0iumJ/upcUjz/cmsTgVFGNEL5yaJWmkqsuFYdMWbj/En5/kS4PFl9hBA=="
},
"MicroCom.Runtime": {
"type": "Transitive",
"resolved": "0.11.0",
"contentHash": "MEnrZ3UIiH40hjzMDsxrTyi8dtqB5ziv3iBeeU4bXsL/7NLSal9F1lZKpK+tfBRnUoDSdtcW3KufE4yhATOMCA=="
},
"Microsoft.DotNet.PlatformAbstractions": {
"type": "Transitive",
"resolved": "3.1.6",
@@ -59,6 +158,38 @@
"Silk.NET.Windowing.Common": "2.23.0"
}
},
"SkiaSharp": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "3MD5VHjXXieSHCleRLuaTXmL2pD0mB7CcOB1x2kA1I4bhptf4e3R27iM93264ZYuAq6mkUyX5XbcxnZvMJYc1Q==",
"dependencies": {
"SkiaSharp.NativeAssets.Win32": "2.88.9",
"SkiaSharp.NativeAssets.macOS": "2.88.9"
}
},
"SkiaSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "cWSaJKVPWAaT/WIn9c8T5uT/l4ETwHxNJTkEOtNKjphNo8AW6TF9O32aRkxqw3l8GUdUo66Bu7EiqtFh/XG0Zg==",
"dependencies": {
"SkiaSharp": "2.88.9"
}
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "Nv5spmKc4505Ep7oUoJ5vp3KweFpeNqxpyGDWyeEPTX2uR6S6syXIm3gj75dM0YJz7NPvcix48mR5laqs8dPuA=="
},
"SkiaSharp.NativeAssets.WebAssembly": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "kt06RccBHSnAs2wDYdBSfsjIDbY3EpsOVqnlDgKdgvyuRA8ZFDaHRdWNx1VHjGgYzmnFCGiTJBnXFl5BqGwGnA=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "wb2kYgU7iy84nQLYZwMeJXixvK++GoIuECjU4ECaUKNuflyRlJKyiRhN1MAHswvlvzuvkrjRWlK0Za6+kYQK7w=="
},
"Ultz.Native.GLFW": {
"type": "Transitive",
"resolved": "3.4.0",
@@ -73,6 +204,16 @@
"SharpEmu.Logging": "[1.0.0, )"
}
},
"sharpemu.gui": {
"type": "Project",
"dependencies": {
"Avalonia": "[11.3.18, )",
"Avalonia.Desktop": "[11.3.18, )",
"Avalonia.Fonts.Inter": "[11.3.18, )",
"Avalonia.Themes.Fluent": "[11.3.18, )",
"Tmds.DBus.Protocol": "[0.21.3, )"
}
},
"sharpemu.hle": {
"type": "Project"
},
@@ -89,6 +230,48 @@
"sharpemu.logging": {
"type": "Project"
},
"Avalonia": {
"type": "CentralTransitive",
"requested": "[11.3.18, )",
"resolved": "11.3.18",
"contentHash": "2C4UxhWUObWGgYKWic1x5BMMWGJP6SElb91WeOxs+X/iR26rtkqpxFFwwo50FXS9AyYnHfk8QKXDEfe7oT/kZA==",
"dependencies": {
"Avalonia.BuildServices": "11.3.2",
"Avalonia.Remote.Protocol": "11.3.18",
"MicroCom.Runtime": "0.11.0"
}
},
"Avalonia.Desktop": {
"type": "CentralTransitive",
"requested": "[11.3.18, )",
"resolved": "11.3.18",
"contentHash": "bilMPa5vYiis6fbNovb6esKytBnOCEGojBa1XFegLCRHCP6g6PvZwS0XF/YOAGkENRlHG8dI7lohOpQ9bIkq1g==",
"dependencies": {
"Avalonia": "11.3.18",
"Avalonia.Native": "11.3.18",
"Avalonia.Skia": "11.3.18",
"Avalonia.Win32": "11.3.18",
"Avalonia.X11": "11.3.18"
}
},
"Avalonia.Fonts.Inter": {
"type": "CentralTransitive",
"requested": "[11.3.18, )",
"resolved": "11.3.18",
"contentHash": "27u6hB3Y2Ue586yjfeVakberY73VNQXtuKwe/P927XG1QPlhsfmOyifLHDDpSHG85Zl1x/Xv9IZ3+tk9FnjcZQ==",
"dependencies": {
"Avalonia": "11.3.18"
}
},
"Avalonia.Themes.Fluent": {
"type": "CentralTransitive",
"requested": "[11.3.18, )",
"resolved": "11.3.18",
"contentHash": "+Q/TJoynD0zNuu5w2gD+xcTl7GNKJFxlPYAndRLs/mTDrNbbsvv/271WyIysbMPsXSjCyBDp7RCZzQkpD6x5Bg==",
"dependencies": {
"Avalonia": "11.3.18"
}
},
"Iced": {
"type": "CentralTransitive",
"requested": "[1.21.0, )",
@@ -133,9 +316,61 @@
"Silk.NET.Windowing.Common": "2.23.0",
"Silk.NET.Windowing.Glfw": "2.23.0"
}
},
"Tmds.DBus.Protocol": {
"type": "CentralTransitive",
"requested": "[0.21.3, )",
"resolved": "0.21.3",
"contentHash": "hDwB8WsQoyALQKqIbwzS68UKdlnafDm4T/DkO/JrA/YIneP/rKv96SxYPVXeh3FP4i/SXfShrYftKLtciJAIlw=="
}
},
"net10.0/linux-x64": {
"Avalonia.Angle.Windows.Natives": {
"type": "Transitive",
"resolved": "2.1.25547.20250602",
"contentHash": "ZL0VLc4s9rvNNFt19Pxm5UNAkmKNylugAwJPX9ulXZ6JWs/l6XZihPWWTyezaoNOVyEPU8YbURtW7XMAtqXH5A=="
},
"Avalonia.Native": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "8g53DROFW6wVJAnTsE1Iu5bdZO5r0oqxbdbMQODs1QDYCK2IU/y/x/vQVKCYOvqxl4tXkzU9tExv8XqSGPWthQ==",
"dependencies": {
"Avalonia": "11.3.18"
}
},
"HarfBuzzSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "3EZ1mpIiKWRLL5hUYA82ZHteeDIVaEA/Z0rA/wU6tjx6crcAkJnBPwDXZugBSfo8+J3EznvRJf49uMsqYfKrHg=="
},
"HarfBuzzSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "jbtCsgftcaFLCA13tVKo5iWdElJScrulLTKJre36O4YQTIlwDtPPqhRZNk+Y0vv4D1gxbscasGRucUDfS44ofQ=="
},
"HarfBuzzSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "UsJtQsfAJoFDZrXc4hCUfRPMqccfKZ0iumJ/upcUjz/cmsTgVFGNEL5yaJWmkqsuFYdMWbj/En5/kS4PFl9hBA=="
},
"SkiaSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "cWSaJKVPWAaT/WIn9c8T5uT/l4ETwHxNJTkEOtNKjphNo8AW6TF9O32aRkxqw3l8GUdUo66Bu7EiqtFh/XG0Zg==",
"dependencies": {
"SkiaSharp": "2.88.9"
}
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "Nv5spmKc4505Ep7oUoJ5vp3KweFpeNqxpyGDWyeEPTX2uR6S6syXIm3gj75dM0YJz7NPvcix48mR5laqs8dPuA=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "wb2kYgU7iy84nQLYZwMeJXixvK++GoIuECjU4ECaUKNuflyRlJKyiRhN1MAHswvlvzuvkrjRWlK0Za6+kYQK7w=="
},
"Ultz.Native.GLFW": {
"type": "Transitive",
"resolved": "3.4.0",
@@ -143,6 +378,52 @@
}
},
"net10.0/osx-arm64": {
"Avalonia.Angle.Windows.Natives": {
"type": "Transitive",
"resolved": "2.1.25547.20250602",
"contentHash": "ZL0VLc4s9rvNNFt19Pxm5UNAkmKNylugAwJPX9ulXZ6JWs/l6XZihPWWTyezaoNOVyEPU8YbURtW7XMAtqXH5A=="
},
"Avalonia.Native": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "8g53DROFW6wVJAnTsE1Iu5bdZO5r0oqxbdbMQODs1QDYCK2IU/y/x/vQVKCYOvqxl4tXkzU9tExv8XqSGPWthQ==",
"dependencies": {
"Avalonia": "11.3.18"
}
},
"HarfBuzzSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "3EZ1mpIiKWRLL5hUYA82ZHteeDIVaEA/Z0rA/wU6tjx6crcAkJnBPwDXZugBSfo8+J3EznvRJf49uMsqYfKrHg=="
},
"HarfBuzzSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "jbtCsgftcaFLCA13tVKo5iWdElJScrulLTKJre36O4YQTIlwDtPPqhRZNk+Y0vv4D1gxbscasGRucUDfS44ofQ=="
},
"HarfBuzzSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "UsJtQsfAJoFDZrXc4hCUfRPMqccfKZ0iumJ/upcUjz/cmsTgVFGNEL5yaJWmkqsuFYdMWbj/En5/kS4PFl9hBA=="
},
"SkiaSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "cWSaJKVPWAaT/WIn9c8T5uT/l4ETwHxNJTkEOtNKjphNo8AW6TF9O32aRkxqw3l8GUdUo66Bu7EiqtFh/XG0Zg==",
"dependencies": {
"SkiaSharp": "2.88.9"
}
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "Nv5spmKc4505Ep7oUoJ5vp3KweFpeNqxpyGDWyeEPTX2uR6S6syXIm3gj75dM0YJz7NPvcix48mR5laqs8dPuA=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "wb2kYgU7iy84nQLYZwMeJXixvK++GoIuECjU4ECaUKNuflyRlJKyiRhN1MAHswvlvzuvkrjRWlK0Za6+kYQK7w=="
},
"Ultz.Native.GLFW": {
"type": "Transitive",
"resolved": "3.4.0",
@@ -150,6 +431,52 @@
}
},
"net10.0/win-x64": {
"Avalonia.Angle.Windows.Natives": {
"type": "Transitive",
"resolved": "2.1.25547.20250602",
"contentHash": "ZL0VLc4s9rvNNFt19Pxm5UNAkmKNylugAwJPX9ulXZ6JWs/l6XZihPWWTyezaoNOVyEPU8YbURtW7XMAtqXH5A=="
},
"Avalonia.Native": {
"type": "Transitive",
"resolved": "11.3.18",
"contentHash": "8g53DROFW6wVJAnTsE1Iu5bdZO5r0oqxbdbMQODs1QDYCK2IU/y/x/vQVKCYOvqxl4tXkzU9tExv8XqSGPWthQ==",
"dependencies": {
"Avalonia": "11.3.18"
}
},
"HarfBuzzSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "3EZ1mpIiKWRLL5hUYA82ZHteeDIVaEA/Z0rA/wU6tjx6crcAkJnBPwDXZugBSfo8+J3EznvRJf49uMsqYfKrHg=="
},
"HarfBuzzSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "jbtCsgftcaFLCA13tVKo5iWdElJScrulLTKJre36O4YQTIlwDtPPqhRZNk+Y0vv4D1gxbscasGRucUDfS44ofQ=="
},
"HarfBuzzSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "8.3.1.1",
"contentHash": "UsJtQsfAJoFDZrXc4hCUfRPMqccfKZ0iumJ/upcUjz/cmsTgVFGNEL5yaJWmkqsuFYdMWbj/En5/kS4PFl9hBA=="
},
"SkiaSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "cWSaJKVPWAaT/WIn9c8T5uT/l4ETwHxNJTkEOtNKjphNo8AW6TF9O32aRkxqw3l8GUdUo66Bu7EiqtFh/XG0Zg==",
"dependencies": {
"SkiaSharp": "2.88.9"
}
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "Nv5spmKc4505Ep7oUoJ5vp3KweFpeNqxpyGDWyeEPTX2uR6S6syXIm3gj75dM0YJz7NPvcix48mR5laqs8dPuA=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "2.88.9",
"contentHash": "wb2kYgU7iy84nQLYZwMeJXixvK++GoIuECjU4ECaUKNuflyRlJKyiRhN1MAHswvlvzuvkrjRWlK0Za6+kYQK7w=="
},
"Ultz.Native.GLFW": {
"type": "Transitive",
"resolved": "3.4.0",