aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAc_K <Acoustik666@gmail.com>2021-06-28 20:54:45 +0200
committerGitHub <noreply@github.com>2021-06-28 20:54:45 +0200
commita79b39b91347816ea14677b58af738b70df03e9c (patch)
tree824a7e056bcd18aced7679df5adb7f5b1d4f6405
parentfefd4619a5347b4ef86314a4e17e1d6e63ced297 (diff)
no name: Mii Editor applet support (#2419)
* no name: Mii Editor applet support * addresses gdkchan feedback * Fix comment * Bypass MountCounter of MiiDatabaseManager * Fix GetSettingsPlatformRegion * Disable Applet Menu for unsupported firmwares
-rw-r--r--Ryujinx.Common/Logging/LogClass.cs1
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs36
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ILibraryAppletProxy.cs105
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/AppletStandalone.cs16
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs78
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/IProcessWindingController.cs24
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IAppletCommonFunctions.cs7
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs101
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs13
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/AppletIdentityInfo.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/AppletProcessLaunchReason.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/LibraryAppletInfo.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/LibraryAppletMode.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/ResultCode.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Mii/Helper.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Mii/IImageDatabaseService.cs35
-rw-r--r--Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs15
-rw-r--r--Ryujinx.HLE/HOS/Services/Settings/Types/PlatformRegion.cs8
-rw-r--r--Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs8
-rw-r--r--Ryujinx/Ui/MainWindow.cs47
-rw-r--r--Ryujinx/Ui/MainWindow.glade30
27 files changed, 591 insertions, 33 deletions
diff --git a/Ryujinx.Common/Logging/LogClass.cs b/Ryujinx.Common/Logging/LogClass.cs
index c2d2f55e..30e3409d 100644
--- a/Ryujinx.Common/Logging/LogClass.cs
+++ b/Ryujinx.Common/Logging/LogClass.cs
@@ -37,6 +37,7 @@ namespace Ryujinx.Common.Logging
ServiceLdn,
ServiceLdr,
ServiceLm,
+ ServiceMii,
ServiceMm,
ServiceNfc,
ServiceNfp,
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 3034d107..a4ed7c37 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -45,10 +45,11 @@ namespace Ryujinx.HLE.HOS
public class Horizon : IDisposable
{
- internal const int HidSize = 0x40000;
- internal const int FontSize = 0x1100000;
- internal const int IirsSize = 0x8000;
- internal const int TimeSize = 0x1000;
+ internal const int HidSize = 0x40000;
+ internal const int FontSize = 0x1100000;
+ internal const int IirsSize = 0x8000;
+ internal const int TimeSize = 0x1000;
+ internal const int AppletCaptureBufferSize = 0x384000;
internal KernelContext KernelContext { get; }
@@ -82,6 +83,9 @@ namespace Ryujinx.HLE.HOS
internal KSharedMemory HidSharedMem { get; private set; }
internal KSharedMemory FontSharedMem { get; private set; }
internal KSharedMemory IirsSharedMem { get; private set; }
+
+ internal KTransferMemory AppletCaptureBufferTransfer { get; private set; }
+
internal SharedFontManager Font { get; private set; }
internal AccountManager AccountManager { get; private set; }
@@ -129,25 +133,29 @@ namespace Ryujinx.HLE.HOS
// region used that is used is Application, so we can use the other ones for anything.
KMemoryRegionManager region = KernelContext.MemoryManager.MemoryRegions[(int)MemoryRegion.NvServices];
- ulong hidPa = region.Address;
- ulong fontPa = region.Address + HidSize;
- ulong iirsPa = region.Address + HidSize + FontSize;
- ulong timePa = region.Address + HidSize + FontSize + IirsSize;
+ ulong hidPa = region.Address;
+ ulong fontPa = region.Address + HidSize;
+ ulong iirsPa = region.Address + HidSize + FontSize;
+ ulong timePa = region.Address + HidSize + FontSize + IirsSize;
+ ulong appletCaptureBufferPa = region.Address + HidSize + FontSize + IirsSize + TimeSize;
- KPageList hidPageList = new KPageList();
- KPageList fontPageList = new KPageList();
- KPageList iirsPageList = new KPageList();
- KPageList timePageList = new KPageList();
+ KPageList hidPageList = new KPageList();
+ KPageList fontPageList = new KPageList();
+ KPageList iirsPageList = new KPageList();
+ KPageList timePageList = new KPageList();
+ KPageList appletCaptureBufferPageList = new KPageList();
- hidPageList.AddRange(hidPa, HidSize / KPageTableBase.PageSize);
+ hidPageList.AddRange(hidPa, HidSize / KPageTableBase.PageSize);
fontPageList.AddRange(fontPa, FontSize / KPageTableBase.PageSize);
iirsPageList.AddRange(iirsPa, IirsSize / KPageTableBase.PageSize);
timePageList.AddRange(timePa, TimeSize / KPageTableBase.PageSize);
+ appletCaptureBufferPageList.AddRange(appletCaptureBufferPa, AppletCaptureBufferSize / KPageTableBase.PageSize);
var hidStorage = new SharedMemoryStorage(KernelContext, hidPageList);
var fontStorage = new SharedMemoryStorage(KernelContext, fontPageList);
var iirsStorage = new SharedMemoryStorage(KernelContext, iirsPageList);
var timeStorage = new SharedMemoryStorage(KernelContext, timePageList);
+ var appletCaptureBufferStorage = new SharedMemoryStorage(KernelContext, appletCaptureBufferPageList);
HidStorage = hidStorage;
@@ -159,6 +167,8 @@ namespace Ryujinx.HLE.HOS
TimeServiceManager.Instance.Initialize(device, this, timeSharedMemory, timeStorage, TimeSize);
+ AppletCaptureBufferTransfer = new KTransferMemory(KernelContext, appletCaptureBufferStorage);
+
AppletState = new AppletStateMgr(this);
AppletState.SetFocus(true);
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ILibraryAppletProxy.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ILibraryAppletProxy.cs
new file mode 100644
index 00000000..b85a39e5
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ILibraryAppletProxy.cs
@@ -0,0 +1,105 @@
+using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy;
+using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy;
+
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
+{
+ class ILibraryAppletProxy : IpcService
+ {
+ private readonly long _pid;
+
+ public ILibraryAppletProxy(long pid)
+ {
+ _pid = pid;
+ }
+
+ [CommandHipc(0)]
+ // GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
+ public ResultCode GetCommonStateGetter(ServiceCtx context)
+ {
+ MakeObject(context, new ICommonStateGetter(context));
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(1)]
+ // GetSelfController() -> object<nn::am::service::ISelfController>
+ public ResultCode GetSelfController(ServiceCtx context)
+ {
+ MakeObject(context, new ISelfController(context, _pid));
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(2)]
+ // GetWindowController() -> object<nn::am::service::IWindowController>
+ public ResultCode GetWindowController(ServiceCtx context)
+ {
+ MakeObject(context, new IWindowController(_pid));
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(3)]
+ // GetAudioController() -> object<nn::am::service::IAudioController>
+ public ResultCode GetAudioController(ServiceCtx context)
+ {
+ MakeObject(context, new IAudioController());
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(4)]
+ // GetDisplayController() -> object<nn::am::service::IDisplayController>
+ public ResultCode GetDisplayController(ServiceCtx context)
+ {
+ MakeObject(context, new IDisplayController(context));
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(10)]
+ // GetProcessWindingController() -> object<nn::am::service::IProcessWindingController>
+ public ResultCode GetProcessWindingController(ServiceCtx context)
+ {
+ MakeObject(context, new IProcessWindingController());
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(11)]
+ // GetLibraryAppletCreator() -> object<nn::am::service::ILibraryAppletCreator>
+ public ResultCode GetLibraryAppletCreator(ServiceCtx context)
+ {
+ MakeObject(context, new ILibraryAppletCreator());
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(20)]
+ // OpenLibraryAppletSelfAccessor() -> object<nn::am::service::ILibraryAppletSelfAccessor>
+ public ResultCode OpenLibraryAppletSelfAccessor(ServiceCtx context)
+ {
+ MakeObject(context, new ILibraryAppletSelfAccessor(context));
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(21)]
+ // GetAppletCommonFunctions() -> object<nn::am::service::IAppletCommonFunctions>
+ public ResultCode GetAppletCommonFunctions(ServiceCtx context)
+ {
+ MakeObject(context, new IAppletCommonFunctions());
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(1000)]
+ // GetDebugFunctions() -> object<nn::am::service::IDebugFunctions>
+ public ResultCode GetDebugFunctions(ServiceCtx context)
+ {
+ MakeObject(context, new IDebugFunctions());
+
+ return ResultCode.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs
index 7017488d..4c94f9b6 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs
@@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
// GetSelfController() -> object<nn::am::service::ISelfController>
public ResultCode GetSelfController(ServiceCtx context)
{
- MakeObject(context, new ISelfController(context.Device.System, _pid));
+ MakeObject(context, new ISelfController(context, _pid));
return ResultCode.Success;
}
@@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
// GetDisplayController() -> object<nn::am::service::IDisplayController>
public ResultCode GetDisplayController(ServiceCtx context)
{
- MakeObject(context, new IDisplayController());
+ MakeObject(context, new IDisplayController(context));
return ResultCode.Success;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/AppletStandalone.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/AppletStandalone.cs
new file mode 100644
index 00000000..69967c56
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/AppletStandalone.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
+{
+ class AppletStandalone
+ {
+ public AppletId AppletId;
+ public LibraryAppletMode LibraryAppletMode;
+ public Queue<byte[]> InputData;
+
+ public AppletStandalone()
+ {
+ InputData = new Queue<byte[]>();
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs
new file mode 100644
index 00000000..00081e1b
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs
@@ -0,0 +1,78 @@
+using Ryujinx.Common;
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
+{
+ class ILibraryAppletSelfAccessor : IpcService
+ {
+ private AppletStandalone _appletStandalone = new AppletStandalone();
+
+ public ILibraryAppletSelfAccessor(ServiceCtx context)
+ {
+ if (context.Device.Application.TitleId == 0x0100000000001009)
+ {
+ // Create MiiEdit data.
+ _appletStandalone = new AppletStandalone()
+ {
+ AppletId = AppletId.MiiEdit,
+ LibraryAppletMode = LibraryAppletMode.AllForeground
+ };
+
+ byte[] miiEditInputData = new byte[0x100];
+ miiEditInputData[0] = 0x03; // Hardcoded unknown value.
+
+ _appletStandalone.InputData.Enqueue(miiEditInputData);
+ }
+ else
+ {
+ throw new NotImplementedException($"{context.Device.Application.TitleId} applet is not implemented.");
+ }
+ }
+
+ [CommandHipc(0)]
+ // PopInData() -> object<nn::am::service::IStorage>
+ public ResultCode PopInData(ServiceCtx context)
+ {
+ byte[] appletData = _appletStandalone.InputData.Dequeue();
+
+ if (appletData.Length == 0)
+ {
+ return ResultCode.NotAvailable;
+ }
+
+ MakeObject(context, new IStorage(appletData));
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(11)]
+ // GetLibraryAppletInfo() -> nn::am::service::LibraryAppletInfo
+ public ResultCode GetLibraryAppletInfo(ServiceCtx context)
+ {
+ LibraryAppletInfo libraryAppletInfo = new LibraryAppletInfo()
+ {
+ AppletId = _appletStandalone.AppletId,
+ LibraryAppletMode = _appletStandalone.LibraryAppletMode
+ };
+
+ context.ResponseData.WriteStruct(libraryAppletInfo);
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(14)]
+ // GetCallerAppletIdentityInfo() -> nn::am::service::AppletIdentityInfo
+ public ResultCode GetCallerAppletIdentityInfo(ServiceCtx context)
+ {
+ AppletIdentifyInfo appletIdentifyInfo = new AppletIdentifyInfo()
+ {
+ AppletId = AppletId.QLaunch,
+ TitleId = 0x0100000000001000
+ };
+
+ context.ResponseData.WriteStruct(appletIdentifyInfo);
+
+ return ResultCode.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/IProcessWindingController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/IProcessWindingController.cs
new file mode 100644
index 00000000..e6c16734
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/IProcessWindingController.cs
@@ -0,0 +1,24 @@
+using Ryujinx.Common;
+
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
+{
+ class IProcessWindingController : IpcService
+ {
+ public IProcessWindingController() { }
+
+ [CommandHipc(0)]
+ // GetLaunchReason() -> nn::am::service::AppletProcessLaunchReason
+ public ResultCode GetLaunchReason(ServiceCtx context)
+ {
+ // NOTE: Flag is set by using an internal field.
+ AppletProcessLaunchReason appletProcessLaunchReason = new AppletProcessLaunchReason()
+ {
+ Flag = 0
+ };
+
+ context.ResponseData.WriteStruct(appletProcessLaunchReason);
+
+ return ResultCode.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IAppletCommonFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IAppletCommonFunctions.cs
new file mode 100644
index 00000000..c42202b8
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IAppletCommonFunctions.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
+{
+ class IAppletCommonFunctions : IpcService
+ {
+ public IAppletCommonFunctions() { }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
index 9e47f05b..4c862dd6 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
@@ -2,6 +2,8 @@ using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Settings.Types;
+using Ryujinx.HLE.HOS.SystemState;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -241,6 +243,18 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return (ResultCode)_apmSystemManagerServer.GetCurrentPerformanceConfiguration(context);
}
+ [CommandHipc(300)] // 9.0.0+
+ // GetSettingsPlatformRegion() -> u8
+ public ResultCode GetSettingsPlatformRegion(ServiceCtx context)
+ {
+ PlatformRegion platformRegion = context.Device.System.State.DesiredRegionCode == (uint)RegionCode.China ? PlatformRegion.China : PlatformRegion.Global;
+
+ // FIXME: Call set:sys GetPlatformRegion
+ context.ResponseData.Write((byte)platformRegion);
+
+ return ResultCode.Success;
+ }
+
[CommandHipc(900)] // 11.0.0+
// SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled()
public ResultCode SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(ServiceCtx context)
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
index 2b04dbb5..d7816de9 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
@@ -1,7 +1,106 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Memory;
+using System;
+
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IDisplayController : IpcService
{
- public IDisplayController() { }
+ private KTransferMemory _transferMem;
+ private bool _lastApplicationCaptureBufferAcquired;
+ private bool _callerAppletCaptureBufferAcquired;
+
+ public IDisplayController(ServiceCtx context)
+ {
+ _transferMem = context.Device.System.AppletCaptureBufferTransfer;
+ }
+
+ [CommandHipc(8)] // 2.0.0+
+ // TakeScreenShotOfOwnLayer(b8, s32)
+ public ResultCode TakeScreenShotOfOwnLayer(ServiceCtx context)
+ {
+ bool unknown1 = context.RequestData.ReadBoolean();
+ int unknown2 = context.RequestData.ReadInt32();
+
+ Logger.Stub?.PrintStub(LogClass.ServiceAm, new { unknown1, unknown2 });
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(11)]
+ // ReleaseLastApplicationCaptureBuffer()
+ public ResultCode ReleaseLastApplicationCaptureBuffer(ServiceCtx context)
+ {
+ if (!_lastApplicationCaptureBufferAcquired)
+ {
+ return ResultCode.BufferNotAcquired;
+ }
+
+ _lastApplicationCaptureBufferAcquired = false;
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(15)]
+ // ReleaseCallerAppletCaptureBuffer()
+ public ResultCode ReleaseCallerAppletCaptureBuffer(ServiceCtx context)
+ {
+ if (!_callerAppletCaptureBufferAcquired)
+ {
+ return ResultCode.BufferNotAcquired;
+ }
+
+ _callerAppletCaptureBufferAcquired = false;
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(16)]
+ // AcquireLastApplicationCaptureBufferEx() -> (b8, handle<copy>)
+ public ResultCode AcquireLastApplicationCaptureBufferEx(ServiceCtx context)
+ {
+ if (_lastApplicationCaptureBufferAcquired)
+ {
+ return ResultCode.BufferAlreadyAcquired;
+ }
+
+ if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != KernelResult.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+
+ _lastApplicationCaptureBufferAcquired = true;
+
+ context.ResponseData.Write(_lastApplicationCaptureBufferAcquired);
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(18)]
+ // AcquireCallerAppletCaptureBufferEx() -> (b8, handle<copy>)
+ public ResultCode AcquireCallerAppletCaptureBufferEx(ServiceCtx context)
+ {
+ if (_callerAppletCaptureBufferAcquired)
+ {
+ return ResultCode.BufferAlreadyAcquired;
+ }
+
+ if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != KernelResult.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+
+ _callerAppletCaptureBufferAcquired = true;
+
+ context.ResponseData.Write(_callerAppletCaptureBufferAcquired);
+
+ return ResultCode.Success;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
index e9af55a0..0ecbd4a0 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
@@ -35,9 +35,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
private uint _screenShotImageOrientation = 0;
private uint _idleTimeDetectionExtension = 0;
- public ISelfController(Horizon system, long pid)
+ public ISelfController(ServiceCtx context, long pid)
{
- _libraryAppletLaunchableEvent = new KEvent(system.KernelContext);
+ _libraryAppletLaunchableEvent = new KEvent(context.Device.System.KernelContext);
_pid = pid;
}
@@ -225,6 +225,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.Success;
}
+ [CommandHipc(41)] // 4.0.0+
+ // IsSystemBufferSharingEnabled()
+ public ResultCode IsSystemBufferSharingEnabled(ServiceCtx context)
+ {
+ // NOTE: Service checks a private field and return an error if the SystemBufferSharing is disabled.
+
+ return ResultCode.NotImplemented;
+ }
+
[CommandHipc(44)] // 10.0.0+
// CreateManagedDisplaySeparableLayer() -> (u64, u64)
public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context)
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs
index 2f5e86ba..926234f5 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs
@@ -15,5 +15,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
return ResultCode.Success;
}
+
+ [CommandHipc(200)]
+ [CommandHipc(201)] // 3.0.0+
+ // OpenLibraryAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ILibraryAppletProxy>
+ public ResultCode OpenLibraryAppletProxy(ServiceCtx context)
+ {
+ MakeObject(context, new ILibraryAppletProxy(context.Request.HandleDesc.PId));
+
+ return ResultCode.Success;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/AppletIdentityInfo.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/AppletIdentityInfo.cs
new file mode 100644
index 00000000..17a485ab
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/AppletIdentityInfo.cs
@@ -0,0 +1,12 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
+{
+ [StructLayout(LayoutKind.Sequential, Size = 0x10)]
+ struct AppletIdentifyInfo
+ {
+ public AppletId AppletId;
+ public uint Padding;
+ public ulong TitleId;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/AppletProcessLaunchReason.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/AppletProcessLaunchReason.cs
new file mode 100644
index 00000000..6c528337
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/AppletProcessLaunchReason.cs
@@ -0,0 +1,12 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
+{
+ [StructLayout(LayoutKind.Sequential, Size = 0x4)]
+ struct AppletProcessLaunchReason
+ {
+ public byte Flag;
+ public ushort Unknown1;
+ public byte Unknown2;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/LibraryAppletInfo.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/LibraryAppletInfo.cs
new file mode 100644
index 00000000..fc1c11e4
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/LibraryAppletInfo.cs
@@ -0,0 +1,11 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
+{
+ [StructLayout(LayoutKind.Sequential, Size = 0x8)]
+ struct LibraryAppletInfo
+ {
+ public AppletId AppletId;
+ public LibraryAppletMode LibraryAppletMode;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/LibraryAppletMode.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/LibraryAppletMode.cs
new file mode 100644
index 00000000..6b9a2284
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Types/LibraryAppletMode.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
+{
+ [Flags]
+ enum LibraryAppletMode : uint
+ {
+ AllForeground,
+ PartialForeground,
+ NoUi,
+ PartialForegroundWithIndirectDisplay,
+ AllForegroundInitiallyHidden
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs
index 8b67cece..44477922 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs
@@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
// GetSelfController() -> object<nn::am::service::ISelfController>
public ResultCode GetSelfController(ServiceCtx context)
{
- MakeObject(context, new ISelfController(context.Device.System, _pid));
+ MakeObject(context, new ISelfController(context, _pid));
return ResultCode.Success;
}
@@ -52,7 +52,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
// GetDisplayController() -> object<nn::am::service::IDisplayController>
public ResultCode GetDisplayController(ServiceCtx context)
{
- MakeObject(context, new IDisplayController());
+ MakeObject(context, new IDisplayController(context));
return ResultCode.Success;
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Am/ResultCode.cs
index 422462e9..5cafff67 100644
--- a/Ryujinx.HLE/HOS/Services/Am/ResultCode.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/ResultCode.cs
@@ -14,6 +14,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
ObjectInvalid = (500 << ErrorCodeShift) | ModuleId,
IStorageInUse = (502 << ErrorCodeShift) | ModuleId,
OutOfBounds = (503 << ErrorCodeShift) | ModuleId,
+ BufferNotAcquired = (504 << ErrorCodeShift) | ModuleId,
+ BufferAlreadyAcquired = (505 << ErrorCodeShift) | ModuleId,
InvalidParameters = (506 << ErrorCodeShift) | ModuleId,
OpenedAsWrongType = (511 << ErrorCodeShift) | ModuleId,
UnbalancedFatalSection = (512 << ErrorCodeShift) | ModuleId,
diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
index fd8844c7..bd07c103 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
@@ -499,6 +499,15 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return (ResultCode)result.Value;
}
+ [CommandHipc(1003)]
+ // DisableAutoSaveDataCreation()
+ public ResultCode DisableAutoSaveDataCreation(ServiceCtx context)
+ {
+ // NOTE: This call does nothing in original service.
+
+ return ResultCode.Success;
+ }
+
[CommandHipc(1004)]
// SetGlobalAccessLogMode(u32 mode)
public ResultCode SetGlobalAccessLogMode(ServiceCtx context)
diff --git a/Ryujinx.HLE/HOS/Services/Mii/Helper.cs b/Ryujinx.HLE/HOS/Services/Mii/Helper.cs
index d5fa98ea..47debd59 100644
--- a/Ryujinx.HLE/HOS/Services/Mii/Helper.cs
+++ b/Ryujinx.HLE/HOS/Services/Mii/Helper.cs
@@ -36,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii
public static UInt128 GetDeviceId()
{
// FIXME: call set:sys GetMiiAuthorId
- return new UInt128(0, 1);
+ return new UInt128("5279754d69694e780000000000000000"); // RyuMiiNx
}
public static ReadOnlySpan<byte> Ver3FacelineColorTable => new byte[] { 0, 1, 2, 3, 4, 5 };
diff --git a/Ryujinx.HLE/HOS/Services/Mii/IImageDatabaseService.cs b/Ryujinx.HLE/HOS/Services/Mii/IImageDatabaseService.cs
index a9f76902..1792bbb7 100644
--- a/Ryujinx.HLE/HOS/Services/Mii/IImageDatabaseService.cs
+++ b/Ryujinx.HLE/HOS/Services/Mii/IImageDatabaseService.cs
@@ -1,8 +1,41 @@
-namespace Ryujinx.HLE.HOS.Services.Mii
+using Ryujinx.Common.Logging;
+
+namespace Ryujinx.HLE.HOS.Services.Mii
{
[Service("miiimg")] // 5.0.0+
class IImageDatabaseService : IpcService
{
+ private uint _imageCount;
+ private bool _isDirty;
+
public IImageDatabaseService(ServiceCtx context) { }
+
+ [CommandHipc(0)]
+ // Initialize(b8) -> b8
+ public ResultCode Initialize(ServiceCtx context)
+ {
+ // TODO: Service uses MiiImage:/database.dat if true, seems to use hardcoded data if false.
+ bool useHardcodedData = context.RequestData.ReadBoolean();
+
+ _imageCount = 0;
+ _isDirty = false;
+
+ context.ResponseData.Write(_isDirty);
+
+ Logger.Stub?.PrintStub(LogClass.ServiceMii, new { useHardcodedData });
+
+ return ResultCode.Success;
+ }
+
+ [CommandHipc(11)]
+ // GetCount() -> u32
+ public ResultCode GetCount(ServiceCtx context)
+ {
+ context.ResponseData.Write(_imageCount);
+
+ Logger.Stub?.PrintStub(LogClass.ServiceMii);
+
+ return ResultCode.Success;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs b/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs
index 4491f2c8..0bf15a7f 100644
--- a/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs
@@ -101,6 +101,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii
// Ensure we have valid data in the database
_database.Format();
+ // TODO: Unmount is currently not implemented properly at dispose, implement that and decrement MountCounter.
+ MountCounter = 0;
+
MountSave();
}
@@ -151,8 +154,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii
}
}
-
-
return result;
}
@@ -183,6 +184,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii
if (result.IsSuccess())
{
result = _filesystemClient.GetFileSize(out long fileSize, handle);
+
if (result.IsSuccess())
{
if (fileSize == Unsafe.SizeOf<NintendoFigurineDatabase>())
diff --git a/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs b/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs
index 66b768ee..1a437289 100644
--- a/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs
@@ -7,6 +7,7 @@ using LibHac.FsSystem.NcaUtils;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.SystemState;
+using Ryujinx.HLE.Utilities;
using System;
using System.IO;
using System.Text;
@@ -271,6 +272,20 @@ namespace Ryujinx.HLE.HOS.Services.Settings
return ResultCode.Success;
}
+ [CommandHipc(90)]
+ // GetMiiAuthorId() -> nn::util::Uuid
+ public ResultCode GetMiiAuthorId(ServiceCtx context)
+ {
+ // NOTE: If miiAuthorId is null ResultCode.NullMiiAuthorIdBuffer is returned.
+ // Doesn't occur in our case.
+
+ UInt128 miiAuthorId = Mii.Helper.GetDeviceId();
+
+ miiAuthorId.Write(context.ResponseData);
+
+ return ResultCode.Success;
+ }
+
public byte[] GetFirmwareData(Switch device)
{
const ulong SystemVersionTitleId = 0x0100000000000809;
diff --git a/Ryujinx.HLE/HOS/Services/Settings/Types/PlatformRegion.cs b/Ryujinx.HLE/HOS/Services/Settings/Types/PlatformRegion.cs
new file mode 100644
index 00000000..b8ef8e8e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Settings/Types/PlatformRegion.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Settings.Types
+{
+ enum PlatformRegion
+ {
+ Global = 1,
+ China = 2
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs
index 2a6f327b..f0b95f55 100644
--- a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs
+++ b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs
@@ -55,11 +55,11 @@ namespace Ryujinx.HLE.HOS.SystemState
DesiredTitleLanguage = language switch
{
- SystemLanguage.Taiwanese or
- SystemLanguage.TraditionalChinese => TitleLanguage.Taiwanese,
+ SystemLanguage.Taiwanese => TitleLanguage.Taiwanese,
+ SystemLanguage.TraditionalChinese or
SystemLanguage.Chinese or
- SystemLanguage.SimplifiedChinese => TitleLanguage.Chinese,
- _ => Enum.Parse<TitleLanguage>(Enum.GetName(typeof(SystemLanguage), language)),
+ SystemLanguage.SimplifiedChinese => TitleLanguage.Chinese,
+ _ => Enum.Parse<TitleLanguage>(Enum.GetName(typeof(SystemLanguage), language)),
};
}
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index 9eb6f303..113ac639 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -3,6 +3,7 @@ using ARMeilleure.Translation.PTC;
using Gtk;
using LibHac.Common;
using LibHac.FsSystem;
+using LibHac.FsSystem.NcaUtils;
using LibHac.Ns;
using Ryujinx.Audio.Backends.Dummy;
using Ryujinx.Audio.Backends.OpenAL;
@@ -87,6 +88,10 @@ namespace Ryujinx.Ui
[GUI] Box _statusBar;
[GUI] MenuItem _optionMenu;
[GUI] MenuItem _manageUserProfiles;
+ [GUI] MenuItem _fileMenu;
+ [GUI] MenuItem _loadApplicationFile;
+ [GUI] MenuItem _loadApplicationFolder;
+ [GUI] MenuItem _appletMenu;
[GUI] MenuItem _actionMenu;
[GUI] MenuItem _stopEmulation;
[GUI] MenuItem _simulateWakeUpMessage;
@@ -165,6 +170,7 @@ namespace Ryujinx.Ui
_applicationLibrary.ApplicationAdded += Application_Added;
_applicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
+ _fileMenu.StateChanged += FileMenu_StateChanged;
_actionMenu.StateChanged += ActionMenu_StateChanged;
_optionMenu.StateChanged += OptionMenu_StateChanged;
@@ -575,7 +581,15 @@ namespace Ryujinx.Ui
SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion();
- bool isDirectory = Directory.Exists(path);
+ bool isDirectory = Directory.Exists(path);
+ bool isFirmwareTitle = false;
+
+ if (path.StartsWith("@SystemContent"))
+ {
+ path = _virtualFileSystem.SwitchPathToSystemPath(path);
+
+ isFirmwareTitle = true;
+ }
if (!SetupValidator.CanStartApplication(_contentManager, path, out UserError userError))
{
@@ -636,7 +650,13 @@ namespace Ryujinx.Ui
Logger.Notice.Print(LogClass.Application, $"Using Firmware Version: {firmwareVersion?.VersionString}");
- if (Directory.Exists(path))
+ if (isFirmwareTitle)
+ {
+ Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA).");
+
+ _emulationContext.LoadNca(path);
+ }
+ else if (Directory.Exists(path))
{
string[] romFsFiles = Directory.GetFiles(path, "*.istorage");
@@ -1100,6 +1120,20 @@ namespace Ryujinx.Ui
}
}
+ private void FileMenu_StateChanged(object o, StateChangedArgs args)
+ {
+ _appletMenu.Sensitive = _emulationContext == null && _contentManager.GetCurrentFirmwareVersion() != null && _contentManager.GetCurrentFirmwareVersion().Major > 3;
+ _loadApplicationFile.Sensitive = _emulationContext == null;
+ _loadApplicationFolder.Sensitive = _emulationContext == null;
+ }
+
+ private void Load_Mii_Edit_Applet(object sender, EventArgs args)
+ {
+ string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.NandSystem, NcaContentType.Program);
+
+ LoadApplication(contentPath);
+ }
+
private void Open_Ryu_Folder(object sender, EventArgs args)
{
OpenHelper.OpenFolder(AppDataManager.BaseDirPath);
@@ -1217,6 +1251,15 @@ namespace Ryujinx.Ui
GtkDialog.CreateInfoDialog(dialogTitle, message);
Logger.Info?.Print(LogClass.Application, message);
+
+ // Purge Applet Cache.
+
+ DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
+
+ if (miiEditorCacheFolder.Exists)
+ {
+ miiEditorCacheFolder.Delete(true);
+ }
});
}
catch (Exception ex)
diff --git a/Ryujinx/Ui/MainWindow.glade b/Ryujinx/Ui/MainWindow.glade
index 129b768e..e974d878 100644
--- a/Ryujinx/Ui/MainWindow.glade
+++ b/Ryujinx/Ui/MainWindow.glade
@@ -19,7 +19,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkMenuItem" id="FileMenu">
+ <object class="GtkMenuItem" id="_fileMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">File</property>
@@ -29,7 +29,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkMenuItem" id="LoadApplicationFile">
+ <object class="GtkMenuItem" id="_loadApplicationFile">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Open a file chooser to chose a switch compatible file to load</property>
@@ -39,7 +39,7 @@
</object>
</child>
<child>
- <object class="GtkMenuItem" id="LoadApplicationFolder">
+ <object class="GtkMenuItem" id="_loadApplicationFolder">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Open a file chooser to chose a switch compatible, unpacked application to load</property>
@@ -49,6 +49,30 @@
</object>
</child>
<child>
+ <object class="GtkMenuItem" id="_appletMenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Load Applet</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="LoadMiiEditApplet">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Open Mii Editor Applet in Standalone mode</property>
+ <property name="label" translatable="yes">Mii Editor</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="Load_Mii_Edit_Applet" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>