0
0
Fork 0

hle: Some cleanup (#3210)

* hle: Some cleanup

This PR cleaned up a bit the HLE folder and the VirtualFileSystem one, since we use LibHac, we can use some class of it directly instead of duplicate things. The "Content" of VFS folder is removed since it should be handled in the NCM service directly.
A larger cleanup should be done later since there is still be duplicated code here and there.

* Fix Headless.SDL2

* Addresses gdkchan feedback
This commit is contained in:
Ac_K 2022-03-22 20:46:16 +01:00 committed by GitHub
parent ba0171d054
commit e3b36db71c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 192 additions and 373 deletions

View file

@ -1,19 +0,0 @@
namespace Ryujinx.HLE.FileSystem.Content
{
static class ContentPath
{
public const string SystemContent = "@SystemContent";
public const string UserContent = "@UserContent";
public const string SdCardContent = "@SdCardContent";
public const string SdCard = "@SdCard";
public const string CalibFile = "@CalibFile";
public const string Safe = "@Safe";
public const string User = "@User";
public const string System = "@System";
public const string Host = "@Host";
public const string GamecardApp = "@GcApp";
public const string GamecardContents = "@GcS00000001";
public const string GamecardUpdate = "@upp";
public const string RegisteredUpdate = "@RegUpdate";
}
}

View file

@ -1,91 +0,0 @@
using System;
using System.IO;
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
namespace Ryujinx.HLE.FileSystem.Content
{
internal static class LocationHelper
{
public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath)
{
string basePath = fileSystem.GetBasePath();
switch (switchContentPath)
{
case ContentPath.SystemContent:
return Path.Combine(basePath, SystemNandPath, "Contents");
case ContentPath.UserContent:
return Path.Combine(basePath, UserNandPath, "Contents");
case ContentPath.SdCardContent:
return Path.Combine(fileSystem.GetSdCardPath(), "Nintendo", "Contents");
case ContentPath.System:
return Path.Combine(basePath, SystemNandPath);
case ContentPath.User:
return Path.Combine(basePath, UserNandPath);
default:
throw new NotSupportedException($"Content Path `{switchContentPath}` is not supported.");
}
}
public static string GetContentPath(ContentStorageId contentStorageId)
{
switch (contentStorageId)
{
case ContentStorageId.NandSystem:
return ContentPath.SystemContent;
case ContentStorageId.NandUser:
return ContentPath.UserContent;
case ContentStorageId.SdCard:
return ContentPath.SdCardContent;
default:
throw new NotSupportedException($"Content Storage `{contentStorageId}` is not supported.");
}
}
public static string GetContentRoot(StorageId storageId)
{
switch (storageId)
{
case StorageId.NandSystem:
return ContentPath.SystemContent;
case StorageId.NandUser:
return ContentPath.UserContent;
case StorageId.SdCard:
return ContentPath.SdCardContent;
default:
throw new NotSupportedException($"Storage Id `{storageId}` is not supported.");
}
}
public static StorageId GetStorageId(string contentPathString)
{
string cleanedPath = contentPathString.Split(':')[0];
switch (cleanedPath)
{
case ContentPath.SystemContent:
case ContentPath.System:
return StorageId.NandSystem;
case ContentPath.UserContent:
case ContentPath.User:
return StorageId.NandUser;
case ContentPath.SdCardContent:
return StorageId.SdCard;
case ContentPath.Host:
return StorageId.Host;
case ContentPath.GamecardApp:
case ContentPath.GamecardContents:
case ContentPath.GamecardUpdate:
return StorageId.GameCard;
default:
return StorageId.None;
}
}
}
}

View file

@ -1,9 +0,0 @@
namespace Ryujinx.HLE.FileSystem.Content
{
public enum ContentStorageId
{
NandSystem,
NandUser,
SdCard
}
}

View file

@ -1,15 +0,0 @@
namespace Ryujinx.HLE.FileSystem.Content
{
enum TitleType
{
SystemPrograms = 0x01,
SystemDataArchive = 0x02,
SystemUpdate = 0x03,
FirmwarePackageA = 0x04,
FirmwarePackageB = 0x05,
RegularApplication = 0x80,
Update = 0x81,
AddOnContent = 0x82,
DeltaTitle = 0x83
}
}

View file

@ -20,7 +20,7 @@ using System.IO.Compression;
using System.Linq; using System.Linq;
using Path = System.IO.Path; using Path = System.IO.Path;
namespace Ryujinx.HLE.FileSystem.Content namespace Ryujinx.HLE.FileSystem
{ {
public class ContentManager public class ContentManager
{ {
@ -110,8 +110,8 @@ namespace Ryujinx.HLE.FileSystem.Content
try try
{ {
contentPathString = LocationHelper.GetContentRoot(storageId); contentPathString = ContentPath.GetContentPath(storageId);
contentDirectory = LocationHelper.GetRealPath(_virtualFileSystem, contentPathString); contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString);
registeredDirectory = Path.Combine(contentDirectory, "registered"); registeredDirectory = Path.Combine(contentDirectory, "registered");
} }
catch (NotSupportedException) catch (NotSupportedException)
@ -367,8 +367,7 @@ namespace Ryujinx.HLE.FileSystem.Content
{ {
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
return locationEntry.ContentPath != null ? return locationEntry.ContentPath != null ? ContentPath.GetStorageId(locationEntry.ContentPath) : StorageId.None;
LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None;
} }
} }
@ -493,8 +492,8 @@ namespace Ryujinx.HLE.FileSystem.Content
public void InstallFirmware(string firmwareSource) public void InstallFirmware(string firmwareSource)
{ {
string contentPathString = LocationHelper.GetContentRoot(StorageId.NandSystem); string contentPathString = ContentPath.GetContentPath(StorageId.BuiltInSystem);
string contentDirectory = LocationHelper.GetRealPath(_virtualFileSystem, contentPathString); string contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString);
string registeredDirectory = Path.Combine(contentDirectory, "registered"); string registeredDirectory = Path.Combine(contentDirectory, "registered");
string temporaryDirectory = Path.Combine(contentDirectory, "temp"); string temporaryDirectory = Path.Combine(contentDirectory, "temp");
@ -998,9 +997,9 @@ namespace Ryujinx.HLE.FileSystem.Content
foreach (var entry in updateNcas) foreach (var entry in updateNcas)
{ {
foreach (var nca in entry.Value) foreach (var (type, path) in entry.Value)
{ {
extraNcas += nca.path + Environment.NewLine; extraNcas += path + Environment.NewLine;
} }
} }
@ -1019,7 +1018,7 @@ namespace Ryujinx.HLE.FileSystem.Content
lock (_lock) lock (_lock)
{ {
var locationEnties = _locationEntries[StorageId.NandSystem]; var locationEnties = _locationEntries[StorageId.BuiltInSystem];
foreach (var entry in locationEnties) foreach (var entry in locationEnties)
{ {

View file

@ -0,0 +1,82 @@
using LibHac.Fs;
using LibHac.Ncm;
using Ryujinx.Common.Configuration;
using System;
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
using Path = System.IO.Path;
namespace Ryujinx.HLE.FileSystem
{
internal static class ContentPath
{
public const string SystemContent = "@SystemContent";
public const string UserContent = "@UserContent";
public const string SdCardContent = "@SdCardContent";
public const string SdCard = "@Sdcard";
public const string CalibFile = "@CalibFile";
public const string Safe = "@Safe";
public const string User = "@User";
public const string System = "@System";
public const string Host = "@Host";
public const string GamecardApp = "@GcApp";
public const string GamecardContents = "@GcS00000001";
public const string GamecardUpdate = "@upp";
public const string RegisteredUpdate = "@RegUpdate";
public const string Nintendo = "Nintendo";
public const string Contents = "Contents";
public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath)
{
return switchContentPath switch
{
SystemContent => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath, Contents),
UserContent => Path.Combine(AppDataManager.BaseDirPath, UserNandPath, Contents),
SdCardContent => Path.Combine(fileSystem.GetSdCardPath(), Nintendo, Contents),
System => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath),
User => Path.Combine(AppDataManager.BaseDirPath, UserNandPath),
_ => throw new NotSupportedException($"Content Path \"`{switchContentPath}`\" is not supported.")
};
}
public static string GetContentPath(ContentStorageId contentStorageId)
{
return contentStorageId switch
{
ContentStorageId.System => SystemContent,
ContentStorageId.User => UserContent,
ContentStorageId.SdCard => SdCardContent,
_ => throw new NotSupportedException($"Content Storage Id \"`{contentStorageId}`\" is not supported.")
};
}
public static string GetContentPath(StorageId storageId)
{
return storageId switch
{
StorageId.BuiltInSystem => SystemContent,
StorageId.BuiltInUser => UserContent,
StorageId.SdCard => SdCardContent,
_ => throw new NotSupportedException($"Storage Id \"`{storageId}`\" is not supported.")
};
}
public static StorageId GetStorageId(string contentPathString)
{
return contentPathString.Split(':')[0] switch
{
SystemContent or
System => StorageId.BuiltInSystem,
UserContent or
User => StorageId.BuiltInUser,
SdCardContent => StorageId.SdCard,
Host => StorageId.Host,
GamecardApp or
GamecardContents or
GamecardUpdate => StorageId.GameCard,
_ => StorageId.None
};
}
}
}

View file

@ -8,7 +8,6 @@ namespace Ryujinx.HLE.FileSystem
{ {
public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator
{ {
public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem,
ref SharedRef<IFileSystem> baseFileSystem, IEncryptedFileSystemCreator.KeyId idIndex, ref SharedRef<IFileSystem> baseFileSystem, IEncryptedFileSystemCreator.KeyId idIndex,
in EncryptionSeed encryptionSeed) in EncryptionSeed encryptionSeed)
@ -18,10 +17,10 @@ namespace Ryujinx.HLE.FileSystem
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
} }
// Todo: Reenable when AesXtsFileSystem is fixed // TODO: Reenable when AesXtsFileSystem is fixed.
outEncryptedFileSystem = SharedRef<IFileSystem>.CreateMove(ref baseFileSystem); outEncryptedFileSystem = SharedRef<IFileSystem>.CreateMove(ref baseFileSystem);
return Result.Success; return Result.Success;
} }
} }
} }

View file

@ -1,6 +1,6 @@
using LibHac.FsSystem; using LibHac.FsSystem;
namespace Ryujinx.HLE.FileSystem.Content namespace Ryujinx.HLE.FileSystem
{ {
public struct LocationEntry public struct LocationEntry
{ {

View file

@ -1,12 +0,0 @@
namespace Ryujinx.HLE.FileSystem
{
enum SaveDataType : byte
{
SystemSaveData,
SaveData,
BcatDeliveryCacheStorage,
DeviceSaveData,
TemporaryStorage,
CacheStorage
}
}

View file

@ -1,27 +0,0 @@
using Ryujinx.HLE.HOS.Services.Account.Acc;
namespace Ryujinx.HLE.FileSystem
{
struct SaveInfo
{
public ulong TitleId { get; private set; }
public long SaveId { get; private set; }
public SaveDataType SaveDataType { get; private set; }
public SaveSpaceId SaveSpaceId { get; private set; }
public UserId UserId { get; private set; }
public SaveInfo(
ulong titleId,
long saveId,
SaveDataType saveDataType,
SaveSpaceId saveSpaceId,
UserId userId = new UserId())
{
TitleId = titleId;
SaveId = saveId;
SaveDataType = saveDataType;
SaveSpaceId = saveSpaceId;
UserId = userId;
}
}
}

View file

@ -1,10 +0,0 @@
namespace Ryujinx.HLE.FileSystem
{
enum SaveSpaceId
{
NandSystem,
NandUser,
SdCard,
TemporaryStorage
}
}

View file

@ -1,12 +0,0 @@
namespace Ryujinx.HLE.FileSystem
{
public enum StorageId
{
None,
Host,
GameCard,
NandSystem,
NandUser,
SdCard
}
}

View file

@ -1,8 +1,7 @@
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System.IO; using System.IO;
using System.Text;
namespace Ryujinx.HLE.FileSystem.Content namespace Ryujinx.HLE.FileSystem
{ {
public class SystemVersion public class SystemVersion
{ {

View file

@ -13,7 +13,6 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using System; using System;
using System.Buffers.Text; using System.Buffers.Text;
@ -28,20 +27,29 @@ namespace Ryujinx.HLE.FileSystem
{ {
public class VirtualFileSystem : IDisposable public class VirtualFileSystem : IDisposable
{ {
public const string NandPath = AppDataManager.DefaultNandDir; public static string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe");
public const string SdCardPath = AppDataManager.DefaultSdcardDir; public static string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system");
public static string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user");
public static string SafeNandPath = Path.Combine(NandPath, "safe"); public KeySet KeySet { get; private set; }
public static string SystemNandPath = Path.Combine(NandPath, "system"); public EmulatedGameCard GameCard { get; private set; }
public static string UserNandPath = Path.Combine(NandPath, "user"); public EmulatedSdCard SdCard { get; private set; }
public ModLoader ModLoader { get; private set; }
public Stream RomFs { get; private set; }
private static bool _isInitialized = false; private static bool _isInitialized = false;
public KeySet KeySet { get; private set; } public static VirtualFileSystem CreateInstance()
public EmulatedGameCard GameCard { get; private set; } {
public EmulatedSdCard SdCard { get; private set; } if (_isInitialized)
{
throw new InvalidOperationException("VirtualFileSystem can only be instantiated once!");
}
public ModLoader ModLoader { get; private set; } _isInitialized = true;
return new VirtualFileSystem();
}
private VirtualFileSystem() private VirtualFileSystem()
{ {
@ -49,8 +57,6 @@ namespace Ryujinx.HLE.FileSystem
ModLoader = new ModLoader(); // Should only be created once ModLoader = new ModLoader(); // Should only be created once
} }
public Stream RomFs { get; private set; }
public void LoadRomFs(string fileName) public void LoadRomFs(string fileName)
{ {
RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read); RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
@ -79,7 +85,7 @@ namespace Ryujinx.HLE.FileSystem
string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName)); string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName));
if (!fullPath.StartsWith(GetBasePath())) if (!fullPath.StartsWith(AppDataManager.BaseDirPath))
{ {
return null; return null;
} }
@ -87,14 +93,8 @@ namespace Ryujinx.HLE.FileSystem
return fullPath; return fullPath;
} }
internal string GetBasePath() => AppDataManager.BaseDirPath; internal string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir);
internal string GetSdCardPath() => MakeFullPath(SdCardPath); public string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir);
public string GetNandPath() => MakeFullPath(NandPath);
public string GetFullPartitionPath(string partitionPath)
{
return MakeFullPath(partitionPath);
}
public string SwitchPathToSystemPath(string switchPath) public string SwitchPathToSystemPath(string switchPath)
{ {
@ -110,7 +110,7 @@ namespace Ryujinx.HLE.FileSystem
public string SystemPathToSwitchPath(string systemPath) public string SystemPathToSwitchPath(string systemPath)
{ {
string baseSystemPath = GetBasePath() + Path.DirectorySeparatorChar; string baseSystemPath = AppDataManager.BaseDirPath + Path.DirectorySeparatorChar;
if (systemPath.StartsWith(baseSystemPath)) if (systemPath.StartsWith(baseSystemPath))
{ {
@ -136,8 +136,7 @@ namespace Ryujinx.HLE.FileSystem
switch (path) switch (path)
{ {
case ContentPath.SdCard: case ContentPath.SdCard:
case "@Sdcard": path = AppDataManager.DefaultSdcardDir;
path = SdCardPath;
break; break;
case ContentPath.User: case ContentPath.User:
path = UserNandPath; path = UserNandPath;
@ -146,7 +145,7 @@ namespace Ryujinx.HLE.FileSystem
path = SystemNandPath; path = SystemNandPath;
break; break;
case ContentPath.SdCardContent: case ContentPath.SdCardContent:
path = Path.Combine(SdCardPath, "Nintendo", "Contents"); path = Path.Combine(AppDataManager.DefaultSdcardDir, "Nintendo", "Contents");
break; break;
case ContentPath.UserContent: case ContentPath.UserContent:
path = Path.Combine(UserNandPath, "Contents"); path = Path.Combine(UserNandPath, "Contents");
@ -156,27 +155,19 @@ namespace Ryujinx.HLE.FileSystem
break; break;
} }
string fullPath = Path.Combine(GetBasePath(), path); string fullPath = Path.Combine(AppDataManager.BaseDirPath, path);
if (isDirectory) if (isDirectory && !Directory.Exists(fullPath))
{ {
if (!Directory.Exists(fullPath)) Directory.CreateDirectory(fullPath);
{
Directory.CreateDirectory(fullPath);
}
} }
return fullPath; return fullPath;
} }
public DriveInfo GetDrive()
{
return new DriveInfo(Path.GetPathRoot(GetBasePath()));
}
public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient) public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient)
{ {
LocalFileSystem serverBaseFs = new LocalFileSystem(GetBasePath()); LocalFileSystem serverBaseFs = new LocalFileSystem(AppDataManager.BaseDirPath);
fsServerClient = horizon.CreatePrivilegedHorizonClient(); fsServerClient = horizon.CreatePrivilegedHorizonClient();
var fsServer = new FileSystemServer(fsServerClient); var fsServer = new FileSystemServer(fsServerClient);
@ -505,7 +496,7 @@ namespace Ryujinx.HLE.FileSystem
bool canFixBySaveDataId = extraData.Attribute.StaticSaveDataId == 0 && info.StaticSaveDataId != 0; bool canFixBySaveDataId = extraData.Attribute.StaticSaveDataId == 0 && info.StaticSaveDataId != 0;
bool hasEmptyOwnerId = extraData.OwnerId == 0 && info.Type != LibHac.Fs.SaveDataType.System; bool hasEmptyOwnerId = extraData.OwnerId == 0 && info.Type != SaveDataType.System;
if (!canFixByProgramId && !canFixBySaveDataId && !hasEmptyOwnerId) if (!canFixByProgramId && !canFixBySaveDataId && !hasEmptyOwnerId)
{ {
@ -523,7 +514,7 @@ namespace Ryujinx.HLE.FileSystem
// The rest of the extra data can't be created from the save data info. // The rest of the extra data can't be created from the save data info.
// On user saves the owner ID will almost certainly be the same as the program ID. // On user saves the owner ID will almost certainly be the same as the program ID.
if (info.Type != LibHac.Fs.SaveDataType.System) if (info.Type != SaveDataType.System)
{ {
extraData.OwnerId = info.ProgramId.Value; extraData.OwnerId = info.ProgramId.Value;
} }
@ -580,11 +571,6 @@ namespace Ryujinx.HLE.FileSystem
} }
}; };
public void Unload()
{
RomFs?.Dispose();
}
public void Dispose() public void Dispose()
{ {
Dispose(true); Dispose(true);
@ -594,20 +580,8 @@ namespace Ryujinx.HLE.FileSystem
{ {
if (disposing) if (disposing)
{ {
Unload(); RomFs?.Dispose();
} }
} }
public static VirtualFileSystem CreateInstance()
{
if (_isInitialized)
{
throw new InvalidOperationException("VirtualFileSystem can only be instantiated once!");
}
_isInitialized = true;
return new VirtualFileSystem();
}
} }
} }

View file

@ -3,7 +3,6 @@ using Ryujinx.Audio.Integration;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;

View file

@ -2,10 +2,10 @@
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
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.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Am.AppletAE; using Ryujinx.HLE.HOS.Services.Am.AppletAE;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using System; using System;
@ -106,7 +106,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
private string GetMessageText(uint module, uint description, string key) private string GetMessageText(uint module, uint description, string key)
{ {
string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.NandSystem, NcaContentType.Data); string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
using (LibHac.Fs.IStorage ncaFileStream = new LocalStorage(_horizon.Device.FileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open)) using (LibHac.Fs.IStorage ncaFileStream = new LocalStorage(_horizon.Device.FileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open))
{ {

View file

@ -10,7 +10,7 @@ using Ryujinx.Audio.Integration;
using Ryujinx.Audio.Output; using Ryujinx.Audio.Output;
using Ryujinx.Audio.Renderer.Device; using Ryujinx.Audio.Renderer.Device;
using Ryujinx.Audio.Renderer.Server; using Ryujinx.Audio.Renderer.Server;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
@ -238,6 +238,7 @@ namespace Ryujinx.HLE.HOS
SurfaceFlinger = new SurfaceFlinger(device); SurfaceFlinger = new SurfaceFlinger(device);
InitializeAudioRenderer(); InitializeAudioRenderer();
InitializeServices();
} }
private void InitializeAudioRenderer() private void InitializeAudioRenderer()
@ -288,7 +289,7 @@ namespace Ryujinx.HLE.HOS
AudioManager.Start(); AudioManager.Start();
} }
public void InitializeServices() private void InitializeServices()
{ {
SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext)); SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext));

View file

@ -1,4 +1,4 @@
using Ryujinx.HLE.FileSystem; using LibHac.Ncm;
namespace Ryujinx.HLE.HOS.Services.Arp namespace Ryujinx.HLE.HOS.Services.Arp
{ {
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp
{ {
TitleId = 0x00, TitleId = 0x00,
Version = 0x00, Version = 0x00,
BaseGameStorageId = (byte)StorageId.NandSystem, BaseGameStorageId = (byte)StorageId.BuiltInSystem,
UpdateGameStorageId = (byte)StorageId.None UpdateGameStorageId = (byte)StorageId.None
}; };
} }
@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp
{ {
TitleId = context.Device.Application.TitleId, TitleId = context.Device.Application.TitleId,
Version = 0x00, Version = 0x00,
BaseGameStorageId = (byte)StorageId.NandSystem, BaseGameStorageId = (byte)StorageId.BuiltInSystem,
UpdateGameStorageId = (byte)StorageId.None UpdateGameStorageId = (byte)StorageId.None
}; };
} }

View file

@ -2,7 +2,6 @@ using LibHac;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Shim; using LibHac.Fs.Shim;
using LibHac.FsSrv;
using LibHac.FsSrv.Impl; using LibHac.FsSrv.Impl;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm; using LibHac.Ncm;
@ -19,7 +18,6 @@ using static Ryujinx.HLE.Utilities.StringUtils;
using IFileSystem = LibHac.FsSrv.Sf.IFileSystem; using IFileSystem = LibHac.FsSrv.Sf.IFileSystem;
using IStorage = LibHac.FsSrv.Sf.IStorage; using IStorage = LibHac.FsSrv.Sf.IStorage;
using RightsId = LibHac.Fs.RightsId; using RightsId = LibHac.Fs.RightsId;
using StorageId = Ryujinx.HLE.FileSystem.StorageId;
namespace Ryujinx.HLE.HOS.Services.Fs namespace Ryujinx.HLE.HOS.Services.Fs
{ {

View file

@ -55,9 +55,11 @@ namespace Ryujinx.HLE.HOS.Services.Hid
_storage = storage; _storage = storage;
SharedMemory = SharedMemory.Create(); SharedMemory = SharedMemory.Create();
InitDevices();
} }
public void InitDevices() private void InitDevices()
{ {
DebugPad = new DebugPadDevice(_device, true); DebugPad = new DebugPadDevice(_device, true);
Touchscreen = new TouchDevice(_device, true); Touchscreen = new TouchDevice(_device, true);

View file

@ -1,4 +1,4 @@
using Ryujinx.HLE.FileSystem; using LibHac.Ncm;
using Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager; using Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager;
namespace Ryujinx.HLE.HOS.Services.Ncm.Lr namespace Ryujinx.HLE.HOS.Services.Ncm.Lr

View file

@ -1,6 +1,6 @@
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using System.Text; using System.Text;
using static Ryujinx.HLE.Utilities.StringUtils; using static Ryujinx.HLE.Utilities.StringUtils;

View file

@ -1,5 +1,5 @@
using Ryujinx.Common.Logging; using LibHac.Ncm;
using Ryujinx.HLE.FileSystem; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Arp; using Ryujinx.HLE.HOS.Services.Arp;
using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface; using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface;

View file

@ -2,11 +2,11 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Services.Sdb.Pl.Types; using Ryujinx.HLE.HOS.Services.Sdb.Pl.Types;
using System; using System;
@ -63,7 +63,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
{ {
if (contentManager.TryGetFontTitle(name, out ulong fontTitle) && contentManager.TryGetFontFilename(name, out string fontFilename)) if (contentManager.TryGetFontTitle(name, out ulong fontTitle) && contentManager.TryGetFontFilename(name, out string fontFilename))
{ {
string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, NcaContentType.Data); string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.BuiltInSystem, NcaContentType.Data);
string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath); string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(fontPath)) if (!string.IsNullOrWhiteSpace(fontPath))

View file

@ -3,9 +3,9 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System; using System;
@ -290,7 +290,7 @@ namespace Ryujinx.HLE.HOS.Services.Settings
{ {
const ulong SystemVersionTitleId = 0x0100000000000809; const ulong SystemVersionTitleId = 0x0100000000000809;
string contentPath = device.System.ContentManager.GetInstalledContentPath(SystemVersionTitleId, StorageId.NandSystem, NcaContentType.Data); string contentPath = device.System.ContentManager.GetInstalledContentPath(SystemVersionTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
if (string.IsNullOrWhiteSpace(contentPath)) if (string.IsNullOrWhiteSpace(contentPath))
{ {

View file

@ -1,5 +1,4 @@
using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Spl.Types; using Ryujinx.HLE.HOS.Services.Spl.Types;

View file

@ -3,13 +3,13 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Services.Ssl.Types; using Ryujinx.HLE.HOS.Services.Ssl.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -82,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
public string GetCertStoreTitleContentPath() public string GetCertStoreTitleContentPath()
{ {
return _contentManager.GetInstalledContentPath(CertStoreTitleId, StorageId.NandSystem, NcaContentType.Data); return _contentManager.GetInstalledContentPath(CertStoreTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
} }
public bool HasCertStoreTitle() public bool HasCertStoreTitle()

View file

@ -3,12 +3,12 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
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.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Services.Time.Clock; using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System; using System;
@ -241,7 +241,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
public string GetTimeZoneBinaryTitleContentPath() public string GetTimeZoneBinaryTitleContentPath()
{ {
return _contentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.NandSystem, NcaContentType.Data); return _contentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
} }
public bool HasTimeZoneBinaryTitle() public bool HasTimeZoneBinaryTitle()

View file

@ -13,27 +13,17 @@ namespace Ryujinx.HLE
{ {
public class Switch : IDisposable public class Switch : IDisposable
{ {
public HLEConfiguration Configuration { get; } public HLEConfiguration Configuration { get; }
public IHardwareDeviceDriver AudioDeviceDriver { get; } public IHardwareDeviceDriver AudioDeviceDriver { get; }
public MemoryBlock Memory { get; }
internal MemoryBlock Memory { get; } public GpuContext Gpu { get; }
public VirtualFileSystem FileSystem { get; }
public GpuContext Gpu { get; } public Horizon System { get; }
public ApplicationLoader Application { get; }
public VirtualFileSystem FileSystem => Configuration.VirtualFileSystem; public PerformanceStatistics Statistics { get; }
public Hid Hid { get; }
public Horizon System { get; } public TamperMachine TamperMachine { get; }
public IHostUiHandler UiHandler { get; }
public ApplicationLoader Application { get; }
public PerformanceStatistics Statistics { get; }
public Hid Hid { get; }
public TamperMachine TamperMachine { get; }
public IHostUiHandler UiHandler { get; }
public bool EnableDeviceVsync { get; set; } = true; public bool EnableDeviceVsync { get; set; } = true;
@ -55,47 +45,27 @@ namespace Ryujinx.HLE
} }
Configuration = configuration; Configuration = configuration;
FileSystem = Configuration.VirtualFileSystem;
UiHandler = Configuration.HostUiHandler;
UiHandler = configuration.HostUiHandler; AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), MemoryAllocationFlags.Reserve);
Gpu = new GpuContext(Configuration.GpuRenderer);
System = new Horizon(this);
Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidStorage);
Application = new ApplicationLoader(this);
TamperMachine = new TamperMachine();
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(configuration.AudioDeviceDriver);
Memory = new MemoryBlock(configuration.MemoryConfiguration.ToDramSize(), MemoryAllocationFlags.Reserve);
Gpu = new GpuContext(configuration.GpuRenderer);
System = new Horizon(this);
System.InitializeServices();
Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidStorage);
Hid.InitDevices();
Application = new ApplicationLoader(this);
TamperMachine = new TamperMachine();
Initialize();
}
private void Initialize()
{
System.State.SetLanguage(Configuration.SystemLanguage); System.State.SetLanguage(Configuration.SystemLanguage);
System.State.SetRegion(Configuration.Region); System.State.SetRegion(Configuration.Region);
EnableDeviceVsync = Configuration.EnableVsync; EnableDeviceVsync = Configuration.EnableVsync;
System.State.DockedMode = Configuration.EnableDockedMode;
System.State.DockedMode = Configuration.EnableDockedMode;
System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default; System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
System.EnablePtc = Configuration.EnablePtc;
System.EnablePtc = Configuration.EnablePtc; System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
} }
public void LoadCart(string exeFsDir, string romFsFile = null) public void LoadCart(string exeFsDir, string romFsFile = null)
@ -132,7 +102,6 @@ namespace Ryujinx.HLE
{ {
Gpu.ProcessShaderCacheQueue(); Gpu.ProcessShaderCacheQueue();
Gpu.Renderer.PreFrame(); Gpu.Renderer.PreFrame();
Gpu.GPFifo.DispatchCalls(); Gpu.GPFifo.DispatchCalls();
} }
@ -182,9 +151,9 @@ namespace Ryujinx.HLE
{ {
System.Dispose(); System.Dispose();
AudioDeviceDriver.Dispose(); AudioDeviceDriver.Dispose();
FileSystem.Unload(); FileSystem.Dispose();
Memory.Dispose(); Memory.Dispose();
} }
} }
} }
} }

View file

@ -20,7 +20,6 @@ using Ryujinx.Graphics.OpenGL;
using Ryujinx.Headless.SDL2.OpenGL; using Ryujinx.Headless.SDL2.OpenGL;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Input; using Ryujinx.Input;
@ -29,7 +28,6 @@ using Ryujinx.Input.SDL2;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;

View file

@ -1,5 +1,5 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem;
using Ryujinx.Ui.Widgets; using Ryujinx.Ui.Widgets;
using System; using System;
using System.IO; using System.IO;

View file

@ -1,18 +1,10 @@
using System; using ARMeilleure.Translation;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using ARMeilleure.Translation;
using ARMeilleure.Translation.PTC; using ARMeilleure.Translation.PTC;
using Gtk; using Gtk;
using LibHac.Common; using LibHac.Common;
using LibHac.Common.Keys; using LibHac.Common.Keys;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Ns; using LibHac.Ns;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.Dummy; using Ryujinx.Audio.Backends.Dummy;
@ -29,7 +21,6 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.OpenGL; using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
@ -42,9 +33,14 @@ using Ryujinx.Ui.Applet;
using Ryujinx.Ui.Helper; using Ryujinx.Ui.Helper;
using Ryujinx.Ui.Widgets; using Ryujinx.Ui.Widgets;
using Ryujinx.Ui.Windows; using Ryujinx.Ui.Windows;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using GUI = Gtk.Builder.ObjectAttribute; using GUI = Gtk.Builder.ObjectAttribute;
using PtcLoadingState = ARMeilleure.Translation.PTC.PtcLoadingState; using PtcLoadingState = ARMeilleure.Translation.PTC.PtcLoadingState;
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
@ -1283,7 +1279,7 @@ namespace Ryujinx.Ui
private void Load_Mii_Edit_Applet(object sender, EventArgs args) private void Load_Mii_Edit_Applet(object sender, EventArgs args)
{ {
string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.NandSystem, NcaContentType.Program); string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program);
LoadApplication(contentPath); LoadApplication(contentPath);
} }

View file

@ -3,10 +3,10 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -115,7 +115,7 @@ namespace Ryujinx.Ui.Windows
return; return;
} }
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.NandSystem, NcaContentType.Data); string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath); string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(avatarPath)) if (!string.IsNullOrWhiteSpace(avatarPath))

View file

@ -105,9 +105,9 @@ namespace Ryujinx.Ui.Windows
#pragma warning restore CS0649, IDE0044 #pragma warning restore CS0649, IDE0044
public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : this(parent, new Builder("Ryujinx.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { } public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this(parent, new Builder("Ryujinx.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { }
private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle) private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle)
{ {
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png"); Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png");

View file

@ -1,6 +1,5 @@
using Gtk; using Gtk;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Ui.Widgets; using Ryujinx.Ui.Widgets;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
@ -12,7 +11,7 @@ using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Image = SixLabors.ImageSharp.Image; using Image = SixLabors.ImageSharp.Image;
using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId; using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
namespace Ryujinx.Ui.Windows namespace Ryujinx.Ui.Windows