mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-27 18:10:04 +02:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e6e4076bf | ||
|
|
ab7176e6fc | ||
|
|
20868546b0 |
@@ -38,7 +38,7 @@
|
|||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.4-build6" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.4-build6" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.3-ryujinx.1" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.3-ryujinx.1" />
|
||||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
||||||
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.918.0" />
|
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.707.0" />
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
|
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
|
||||||
|
|||||||
@@ -166,15 +166,13 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
|
|
||||||
string[] buttons = GetButtonsText(module, description, "DlgBtn");
|
string[] buttons = GetButtonsText(module, description, "DlgBtn");
|
||||||
|
|
||||||
(uint Module, uint Description) errorCodeTuple = (module, uint.Parse(description.ToString("0000")));
|
bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons);
|
||||||
|
|
||||||
bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons, errorCodeTuple);
|
|
||||||
if (showDetails)
|
if (showDetails)
|
||||||
{
|
{
|
||||||
message = GetMessageText(module, description, "FlvMsg");
|
message = GetMessageText(module, description, "FlvMsg");
|
||||||
buttons = GetButtonsText(module, description, "FlvBtn");
|
buttons = GetButtonsText(module, description, "FlvBtn");
|
||||||
|
|
||||||
_horizon.Device.UIHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons, errorCodeTuple);
|
_horizon.Device.UIHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,19 +27,9 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
_normalSession = normalSession;
|
_normalSession = normalSession;
|
||||||
_interactiveSession = interactiveSession;
|
_interactiveSession = interactiveSession;
|
||||||
|
|
||||||
UserProfile selected = _system.Device.UIHandler.ShowPlayerSelectDialog();
|
// TODO(jduncanator): Parse PlayerSelectConfig from input data
|
||||||
if (selected == null)
|
|
||||||
{
|
|
||||||
_normalSession.Push(BuildResponse());
|
_normalSession.Push(BuildResponse());
|
||||||
}
|
|
||||||
else if (selected.UserId == new UserId("00000000000000000000000000000080"))
|
|
||||||
{
|
|
||||||
_normalSession.Push(BuildGuestResponse());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_normalSession.Push(BuildResponse(selected));
|
|
||||||
}
|
|
||||||
AppletStateChanged?.Invoke(this, null);
|
AppletStateChanged?.Invoke(this, null);
|
||||||
|
|
||||||
_system.ReturnFocus();
|
_system.ReturnFocus();
|
||||||
@@ -47,34 +37,16 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] BuildResponse(UserProfile selectedUser)
|
private byte[] BuildResponse()
|
||||||
{
|
{
|
||||||
|
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
||||||
|
|
||||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
using BinaryWriter writer = new(stream);
|
using BinaryWriter writer = new(stream);
|
||||||
|
|
||||||
writer.Write((ulong)PlayerSelectResult.Success);
|
writer.Write((ulong)PlayerSelectResult.Success);
|
||||||
|
|
||||||
selectedUser.UserId.Write(writer);
|
currentUser.UserId.Write(writer);
|
||||||
|
|
||||||
return stream.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] BuildGuestResponse()
|
|
||||||
{
|
|
||||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
|
||||||
using BinaryWriter writer = new(stream);
|
|
||||||
|
|
||||||
writer.Write(new byte());
|
|
||||||
|
|
||||||
return stream.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] BuildResponse()
|
|
||||||
{
|
|
||||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
|
||||||
using BinaryWriter writer = new(stream);
|
|
||||||
|
|
||||||
writer.Write((ulong)PlayerSelectResult.Failure);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
|||||||
{
|
{
|
||||||
MemoryArrange.MemoryArrange4GiB or
|
MemoryArrange.MemoryArrange4GiB or
|
||||||
MemoryArrange.MemoryArrange4GiBSystemDev or
|
MemoryArrange.MemoryArrange4GiBSystemDev or
|
||||||
MemoryArrange.MemoryArrange6GiBAppletDev => 3236 * MiB,
|
MemoryArrange.MemoryArrange6GiBAppletDev => 3173 * MiB,
|
||||||
MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB,
|
MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB,
|
||||||
MemoryArrange.MemoryArrange6GiB => 4867 * MiB,
|
MemoryArrange.MemoryArrange6GiB => 4804 * MiB,
|
||||||
MemoryArrange.MemoryArrange8GiB => 6915 * MiB,
|
MemoryArrange.MemoryArrange8GiB => 6852 * MiB,
|
||||||
MemoryArrange.MemoryArrange10GiB => 8963 * MiB,
|
MemoryArrange.MemoryArrange10GiB => 8900 * MiB,
|
||||||
MemoryArrange.MemoryArrange12GiB => 11011 * MiB,
|
MemoryArrange.MemoryArrange12GiB => 10948 * MiB,
|
||||||
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
|
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,9 +203,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
heapRegion.Size = memConfig switch {
|
heapRegion.Size = memConfig switch {
|
||||||
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
|
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
|
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration10GiB => 0x200000000u,
|
|
||||||
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
|
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration12GiB => 0x200000000u,
|
|
||||||
_ => 0x180000000u
|
_ => 0x180000000u
|
||||||
};
|
};
|
||||||
stackRegion.Size = 0;
|
stackRegion.Size = 0;
|
||||||
@@ -240,9 +238,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
heapRegion.Size = memConfig switch {
|
heapRegion.Size = memConfig switch {
|
||||||
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
|
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
|
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration10GiB => 0x200000000u,
|
|
||||||
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
|
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration12GiB => 0x200000000u,
|
|
||||||
_ => 0x180000000u
|
_ => 0x180000000u
|
||||||
};
|
};
|
||||||
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
|
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
|
||||||
@@ -261,9 +257,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
heapRegion.Size = memConfig switch {
|
heapRegion.Size = memConfig switch {
|
||||||
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
|
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
|
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration10GiB => 0x200000000u,
|
|
||||||
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
|
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
|
||||||
MemoryConfiguration.MemoryConfiguration12GiB => 0x200000000u,
|
|
||||||
_ => 0x180000000u
|
_ => 0x180000000u
|
||||||
};
|
};
|
||||||
stackRegion.Size = 0x80000000;
|
stackRegion.Size = 0x80000000;
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.8 KiB |
-15
@@ -21,21 +21,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandCmif(3)] // 20.0.0+
|
|
||||||
// CreateLibraryAppletEx(u32, u32, u64) -> object<nn::am::service::ILibraryAppletAccessor>
|
|
||||||
public ResultCode CreateLibraryAppletEx(ServiceCtx context)
|
|
||||||
{
|
|
||||||
AppletId appletId = (AppletId)context.RequestData.ReadInt32();
|
|
||||||
|
|
||||||
_ = context.RequestData.ReadInt32(); // libraryAppletMode
|
|
||||||
|
|
||||||
_ = context.RequestData.ReadUInt64(); // threadId
|
|
||||||
|
|
||||||
MakeObject(context, new ILibraryAppletAccessor(appletId, context.Device.System));
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandCmif(10)]
|
[CommandCmif(10)]
|
||||||
// CreateStorage(u64) -> object<nn::am::service::IStorage>
|
// CreateStorage(u64) -> object<nn::am::service::IStorage>
|
||||||
public ResultCode CreateStorage(ServiceCtx context)
|
public ResultCode CreateStorage(ServiceCtx context)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using LibHac.Tools.Fs;
|
|||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.Gpu;
|
|
||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@@ -24,62 +23,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
private ulong _latestPid;
|
private ulong _latestPid;
|
||||||
|
|
||||||
private readonly object _pidLock = new();
|
public ProcessResult ActiveApplication => _processesByPid[_latestPid];
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
public ProcessResult? ActiveApplication
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_pidLock)
|
|
||||||
{
|
|
||||||
// Check if _latestPid is still valid
|
|
||||||
if (_latestPid == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify process still exists in kernel (authoritative source)
|
|
||||||
if (!_device.System.KernelContext.Processes.TryGetValue(_latestPid, out HOS.Kernel.Process.KProcess? kernelProcess))
|
|
||||||
{
|
|
||||||
// Process no longer exists in kernel, clear stale state
|
|
||||||
Logger.Warning?.Print(LogClass.Loader,
|
|
||||||
$"ActiveApplication PID {_latestPid} no longer exists in kernel, clearing stale state");
|
|
||||||
|
|
||||||
_processesByPid.TryRemove(_latestPid, out _);
|
|
||||||
_latestPid = 0;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify process still exists in ProcessLoader's dictionary
|
|
||||||
if (_processesByPid.TryGetValue(_latestPid, out ProcessResult? processResult))
|
|
||||||
{
|
|
||||||
// Additional check: verify process state
|
|
||||||
if (kernelProcess.State == HOS.Kernel.Process.ProcessState.Exited ||
|
|
||||||
kernelProcess.State == HOS.Kernel.Process.ProcessState.Exiting)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Loader,
|
|
||||||
$"ActiveApplication PID {_latestPid} is in state {kernelProcess.State}, clearing");
|
|
||||||
|
|
||||||
_processesByPid.TryRemove(_latestPid, out _);
|
|
||||||
_latestPid = 0;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return processResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: clear stale PID if not in our dictionary
|
|
||||||
Logger.Warning?.Print(LogClass.Loader,
|
|
||||||
$"ActiveApplication PID {_latestPid} not in ProcessLoader dictionary, clearing");
|
|
||||||
_latestPid = 0;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
public ProcessLoader(Switch device)
|
public ProcessLoader(Switch device)
|
||||||
{
|
{
|
||||||
@@ -282,7 +226,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Explicitly null TitleId to disable the shader cache.
|
// Explicitly null TitleId to disable the shader cache.
|
||||||
GraphicsConfig.TitleId = null;
|
Graphics.Gpu.GraphicsConfig.TitleId = null;
|
||||||
_device.Gpu.HostInitalized.Set();
|
_device.Gpu.HostInitalized.Set();
|
||||||
|
|
||||||
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
|
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
|
||||||
@@ -321,37 +265,5 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clears a specific process from the ProcessLoader's tracking.
|
|
||||||
/// This should be called when a process exits or is terminated.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pid">The process ID to clear</param>
|
|
||||||
public void ClearProcess(ulong pid)
|
|
||||||
{
|
|
||||||
lock (_pidLock)
|
|
||||||
{
|
|
||||||
if (_processesByPid.TryRemove(pid, out _))
|
|
||||||
{
|
|
||||||
if (_latestPid == pid)
|
|
||||||
{
|
|
||||||
_latestPid = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clears all processes from the ProcessLoader's tracking.
|
|
||||||
/// This should be called during system shutdown.
|
|
||||||
/// </summary>
|
|
||||||
public void ClearAllProcesses()
|
|
||||||
{
|
|
||||||
lock (_pidLock)
|
|
||||||
{
|
|
||||||
_processesByPid.Clear();
|
|
||||||
_latestPid = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@
|
|||||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_BtnB.png" />
|
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_BtnB.png" />
|
||||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_KeyF6.png" />
|
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_KeyF6.png" />
|
||||||
<EmbeddedResource Include="HOS\Services\Account\Acc\DefaultUserImage.jpg" />
|
<EmbeddedResource Include="HOS\Services\Account\Acc\DefaultUserImage.jpg" />
|
||||||
<EmbeddedResource Include="HOS\Services\Account\Acc\GuestUserImage.jpg" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -208,7 +208,6 @@ namespace Ryujinx.HLE
|
|||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
Processes.ClearAllProcesses();
|
|
||||||
System.Dispose();
|
System.Dispose();
|
||||||
AudioDeviceDriver.Dispose();
|
AudioDeviceDriver.Dispose();
|
||||||
FileSystem.Dispose();
|
FileSystem.Dispose();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.UI
|
namespace Ryujinx.HLE.UI
|
||||||
@@ -49,8 +48,7 @@ namespace Ryujinx.HLE.UI
|
|||||||
/// Displays a Message Dialog box specific to Error Applet and blocks until it is closed.
|
/// Displays a Message Dialog box specific to Error Applet and blocks until it is closed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>False when OK is pressed, True when another button (Details) is pressed.</returns>
|
/// <returns>False when OK is pressed, True when another button (Details) is pressed.</returns>
|
||||||
// ReSharper disable once UnusedParameter.Global
|
bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText);
|
||||||
bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText, (uint Module, uint Description)? errorCode = null);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a handler to process keyboard inputs into text strings.
|
/// Creates a handler to process keyboard inputs into text strings.
|
||||||
@@ -67,10 +65,5 @@ namespace Ryujinx.HLE.UI
|
|||||||
/// Takes a screenshot from the current renderer and saves it in the screenshots folder.
|
/// Takes a screenshot from the current renderer and saves it in the screenshots folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void TakeScreenshot();
|
void TakeScreenshot();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Displays the player select dialog and returns the selected profile.
|
|
||||||
/// </summary>
|
|
||||||
UserProfile ShowPlayerSelectDialog();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using Ryujinx.Graphics.GAL.Multithreading;
|
|||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
using Ryujinx.Graphics.OpenGL;
|
||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
using Ryujinx.HLE.Loaders.Processes;
|
using Ryujinx.HLE.Loaders.Processes;
|
||||||
using Ryujinx.HLE.UI;
|
using Ryujinx.HLE.UI;
|
||||||
@@ -29,7 +28,6 @@ using static SDL.SDL3;
|
|||||||
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||||
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
||||||
using Switch = Ryujinx.HLE.Switch;
|
using Switch = Ryujinx.HLE.Switch;
|
||||||
using UserProfile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless
|
||||||
{
|
{
|
||||||
@@ -533,7 +531,7 @@ namespace Ryujinx.Headless
|
|||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText, (uint Module, uint Description)? errorCode = null)
|
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText)
|
||||||
{
|
{
|
||||||
SDL_MessageBoxButtonData[] buttons = new SDL_MessageBoxButtonData[buttonsText.Length];
|
SDL_MessageBoxButtonData[] buttons = new SDL_MessageBoxButtonData[buttonsText.Length];
|
||||||
|
|
||||||
@@ -592,10 +590,5 @@ namespace Ryujinx.Headless
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserProfile ShowPlayerSelectDialog()
|
|
||||||
{
|
|
||||||
return AccountSaveDataManager.GetLastUsedUser();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,10 +169,4 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<TrimmerRootDescriptor Include="TrimmerRootDescriptor.xml" />
|
<TrimmerRootDescriptor Include="TrimmerRootDescriptor.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Compile Update="UI\Applet\UserSelectorDialog.axaml.cs">
|
|
||||||
<DependentUpon>UserSelectorDialog.axaml</DependentUpon>
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Gommon;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Controls;
|
using Ryujinx.Ava.UI.Controls;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
using Ryujinx.HLE.UI;
|
using Ryujinx.HLE.UI;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Applet
|
namespace Ryujinx.Ava.UI.Applet
|
||||||
@@ -221,7 +215,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
_parent.ViewModel.AppHost?.Stop();
|
_parent.ViewModel.AppHost?.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons, (uint Module, uint Description)? errorCode = null)
|
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
|
||||||
{
|
{
|
||||||
ManualResetEvent dialogCloseEvent = new(false);
|
ManualResetEvent dialogCloseEvent = new(false);
|
||||||
|
|
||||||
@@ -262,59 +256,9 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
return showDetails;
|
return showDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDynamicTextInputHandler CreateDynamicTextInputHandler() => new AvaloniaDynamicTextInputHandler(_parent);
|
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
|
||||||
|
|
||||||
public UserProfile ShowPlayerSelectDialog()
|
|
||||||
{
|
{
|
||||||
UserId selected = UserId.Null;
|
return new AvaloniaDynamicTextInputHandler(_parent);
|
||||||
byte[] defaultGuestImage = EmbeddedResources.Read("Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg");
|
|
||||||
UserProfile guest = new UserProfile(new UserId("00000000000000000000000000000080"), "Guest", defaultGuestImage);
|
|
||||||
|
|
||||||
ManualResetEvent dialogCloseEvent = new(false);
|
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
|
||||||
{
|
|
||||||
ObservableCollection<BaseModel> profiles = [];
|
|
||||||
NavigationDialogHost nav = new();
|
|
||||||
|
|
||||||
_parent.AccountManager.GetAllUsers()
|
|
||||||
.OrderBy(x => x.Name)
|
|
||||||
.ForEach(profile => profiles.Add(new Models.UserProfile(profile, nav)));
|
|
||||||
|
|
||||||
profiles.Add(new Models.UserProfile(guest, nav));
|
|
||||||
ProfileSelectorDialogViewModel viewModel = new()
|
|
||||||
{
|
|
||||||
Profiles = profiles,
|
|
||||||
SelectedUserId = _parent.AccountManager.LastOpenedUser.UserId
|
|
||||||
};
|
|
||||||
(selected, _) = await ProfileSelectorDialog.ShowInputDialog(viewModel);
|
|
||||||
|
|
||||||
dialogCloseEvent.Set();
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogCloseEvent.WaitOne();
|
|
||||||
|
|
||||||
UserProfile profile = _parent.AccountManager.LastOpenedUser;
|
|
||||||
if (selected == guest.UserId)
|
|
||||||
{
|
|
||||||
profile = guest;
|
|
||||||
}
|
|
||||||
else if (selected == UserId.Null)
|
|
||||||
{
|
|
||||||
profile = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (UserProfile p in _parent.AccountManager.GetAllUsers())
|
|
||||||
{
|
|
||||||
if (p.UserId == selected)
|
|
||||||
{
|
|
||||||
profile = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return profile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TakeScreenshot()
|
public void TakeScreenshot()
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
<UserControl
|
|
||||||
x:Class="Ryujinx.Ava.UI.Applet.ProfileSelectorDialog"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
|
||||||
xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
|
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
|
||||||
d:DesignHeight="450"
|
|
||||||
MinWidth="500"
|
|
||||||
d:DesignWidth="800"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Focusable="True"
|
|
||||||
x:DataType="viewModels:ProfileSelectorDialogViewModel">
|
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<Design.DataContext>
|
|
||||||
<viewModels:ProfileSelectorDialogViewModel />
|
|
||||||
</Design.DataContext>
|
|
||||||
|
|
||||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Border
|
|
||||||
CornerRadius="5"
|
|
||||||
BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
|
|
||||||
BorderThickness="1">
|
|
||||||
|
|
||||||
<ListBox
|
|
||||||
MaxHeight="300"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Background="Transparent"
|
|
||||||
ItemsSource="{Binding Profiles}"
|
|
||||||
SelectionChanged="ProfilesList_SelectionChanged">
|
|
||||||
|
|
||||||
<ListBox.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<WrapPanel
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ListBox.ItemsPanel>
|
|
||||||
|
|
||||||
<ListBox.Styles>
|
|
||||||
<Style Selector="ListBoxItem">
|
|
||||||
<Setter Property="Margin" Value="5 5 0 5" />
|
|
||||||
<Setter Property="CornerRadius" Value="5" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="Rectangle#SelectionIndicator">
|
|
||||||
<Setter Property="Opacity" Value="0" />
|
|
||||||
</Style>
|
|
||||||
</ListBox.Styles>
|
|
||||||
|
|
||||||
<ListBox.DataTemplates>
|
|
||||||
<DataTemplate
|
|
||||||
DataType="models:UserProfile">
|
|
||||||
<Grid
|
|
||||||
PointerEntered="Grid_PointerEntered"
|
|
||||||
PointerExited="Grid_OnPointerExited">
|
|
||||||
<Border
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
ClipToBounds="True"
|
|
||||||
CornerRadius="5"
|
|
||||||
Background="{Binding BackgroundColor}">
|
|
||||||
<StackPanel
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch">
|
|
||||||
<Image
|
|
||||||
Width="96"
|
|
||||||
Height="96"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
|
|
||||||
<TextBlock
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
MaxWidth="90"
|
|
||||||
Text="{Binding Name}"
|
|
||||||
TextAlignment="Center"
|
|
||||||
TextWrapping="Wrap"
|
|
||||||
TextTrimming="CharacterEllipsis"
|
|
||||||
MaxLines="2"
|
|
||||||
Margin="5" />
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
|
||||||
<DataTemplate
|
|
||||||
DataType="viewModels:BaseModel">
|
|
||||||
<Panel
|
|
||||||
Height="118"
|
|
||||||
Width="96">
|
|
||||||
<Panel.Styles>
|
|
||||||
<Style Selector="Panel">
|
|
||||||
<Setter Property="Background" Value="{DynamicResource ListBoxBackground}" />
|
|
||||||
</Style>
|
|
||||||
</Panel.Styles>
|
|
||||||
</Panel>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListBox.DataTemplates>
|
|
||||||
</ListBox>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<StackPanel
|
|
||||||
Grid.Row="1"
|
|
||||||
Margin="0 24 0 0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Spacing="10">
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Input;
|
|
||||||
using FluentAvalonia.UI.Controls;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
|
||||||
using Ryujinx.Ava.UI.Controls;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.UI.Common.Configuration;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
|
|
||||||
using UserProfileSft = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Applet
|
|
||||||
{
|
|
||||||
public partial class ProfileSelectorDialog : UserControl
|
|
||||||
{
|
|
||||||
public ProfileSelectorDialogViewModel ViewModel { get; set; }
|
|
||||||
|
|
||||||
public ProfileSelectorDialog(ProfileSelectorDialogViewModel viewModel)
|
|
||||||
{
|
|
||||||
DataContext = ViewModel = viewModel;
|
|
||||||
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Grid_PointerEntered(object sender, PointerEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is Grid { DataContext: UserProfile profile })
|
|
||||||
{
|
|
||||||
profile.IsPointerOver = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Grid_OnPointerExited(object sender, PointerEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is Grid { DataContext: UserProfile profile })
|
|
||||||
{
|
|
||||||
profile.IsPointerOver = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProfilesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is ListBox listBox)
|
|
||||||
{
|
|
||||||
int selectedIndex = listBox.SelectedIndex;
|
|
||||||
|
|
||||||
if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
|
|
||||||
{
|
|
||||||
if (ViewModel.Profiles[selectedIndex] is UserProfile userProfile)
|
|
||||||
{
|
|
||||||
ViewModel.SelectedUserId = userProfile.UserId;
|
|
||||||
Logger.Info?.Print(LogClass.UI, $"Selected: {userProfile.UserId}", "ProfileSelector");
|
|
||||||
|
|
||||||
ObservableCollection<BaseModel> newProfiles = [];
|
|
||||||
|
|
||||||
foreach (BaseModel item in ViewModel.Profiles)
|
|
||||||
{
|
|
||||||
if (item is UserProfile originalItem)
|
|
||||||
{
|
|
||||||
UserProfileSft profile = new(originalItem.UserId, originalItem.Name, originalItem.Image);
|
|
||||||
|
|
||||||
if (profile.UserId == ViewModel.SelectedUserId)
|
|
||||||
{
|
|
||||||
profile.AccountState = AccountState.Open;
|
|
||||||
}
|
|
||||||
|
|
||||||
newProfiles.Add(new UserProfile(profile, new NavigationDialogHost()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewModel.Profiles = newProfiles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<(UserId Id, bool Result)> ShowInputDialog(ProfileSelectorDialogViewModel viewModel)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (ConfigurationState.Instance.System.SkipUserProfilesManager)
|
|
||||||
{
|
|
||||||
UserId defaultId = viewModel.SelectedUserId;
|
|
||||||
return (defaultId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
FAContentDialog contentDialog = new()
|
|
||||||
{
|
|
||||||
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
|
|
||||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.Continue],
|
|
||||||
SecondaryButtonText = string.Empty,
|
|
||||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.Cancel],
|
|
||||||
Content = new ProfileSelectorDialog(viewModel),
|
|
||||||
Padding = new Thickness(0)
|
|
||||||
};
|
|
||||||
|
|
||||||
UserId result = UserId.Null;
|
|
||||||
bool input = false;
|
|
||||||
|
|
||||||
contentDialog.Closed += Handler;
|
|
||||||
|
|
||||||
await ContentDialogHelper.ShowAsync(contentDialog);
|
|
||||||
|
|
||||||
return (result, input);
|
|
||||||
|
|
||||||
void Handler(FAContentDialog sender, FAContentDialogClosedEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (eventArgs.Result == FAContentDialogResult.Primary)
|
|
||||||
{
|
|
||||||
result = viewModel.SelectedUserId;
|
|
||||||
input = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = UserId.Null;
|
|
||||||
input = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
|
||||||
{
|
|
||||||
public partial class ProfileSelectorDialogViewModel : BaseModel
|
|
||||||
{
|
|
||||||
|
|
||||||
[ObservableProperty] private UserId _selectedUserId;
|
|
||||||
|
|
||||||
[ObservableProperty] private ObservableCollection<BaseModel> _profiles = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user