feat(hle/am): implement applet and home menu management

- Add home menu popup event and request handling

- Implement various self controller functions for applet lifecycle

- Add applet common functions with event support

- Implement application accessor and debug function stubs

- Add window system hooks for QLaunch integration
This commit is contained in:
Zephyron
2026-01-28 16:41:40 +10:00
parent 53fc6bf107
commit 37863fcb09
15 changed files with 225 additions and 8 deletions

View File

@@ -335,4 +335,11 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
applet->process->Run();
}
void AppletManager::SetHomeMenuRequestCallback(std::function<void()> callback) {
std::unique_lock lk{m_lock};
if (m_window_system) {
m_window_system->SetHomeMenuRequestCallback(std::move(callback));
}
}
} // namespace Service::AM

View File

@@ -4,6 +4,7 @@
#pragma once
#include <condition_variable>
#include <functional>
#include <mutex>
#include "core/hle/service/am/am_types.h"
@@ -46,6 +47,7 @@ public:
public:
void SetWindowSystem(WindowSystem* window_system);
void SetHomeMenuRequestCallback(std::function<void()> callback);
private:
Core::System& m_system;

View File

@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/cmif_serialization.h"
@@ -28,10 +30,24 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
{70, D<&IAppletCommonFunctions::SetCpuBoostRequestPriority>, "SetCpuBoostRequestPriority"},
{80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
{81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
{82, nullptr, "SetBlockingCaptureButtonInEntireSystem"},
{90, nullptr, "OpenNamedChannelAsParent"},
{91, nullptr, "OpenNamedChannelAsChild"},
{100, nullptr, "SetApplicationCoreUsageMode"},
{160, nullptr, "GetNotificationReceiverService"},
{161, nullptr, "GetNotificationSenderService"},
{300, D<&IAppletCommonFunctions::GetCurrentApplicationId>, "GetCurrentApplicationId"},
{310, D<&IAppletCommonFunctions::IsSystemAppletHomeMenu>, "IsSystemAppletHomeMenu"},
{311, D<&IAppletCommonFunctions::Cmd311>, "Cmd311"},
{320, D<&IAppletCommonFunctions::SetGpuTimeSliceBoost>, "SetGpuTimeSliceBoost"},
{321, D<&IAppletCommonFunctions::SetGpuTimeSliceBoostDueToApplication>, "SetGpuTimeSliceBoostDueToApplication"},
{322, D<&IAppletCommonFunctions::Cmd322>, "Cmd322"},
{330, D<&IAppletCommonFunctions::Cmd330>, "Cmd330"},
{340, D<&IAppletCommonFunctions::Cmd340>, "Cmd340"},
{341, D<&IAppletCommonFunctions::Cmd341>, "Cmd341"},
{342, D<&IAppletCommonFunctions::Cmd342>, "Cmd342"},
{350, D<&IAppletCommonFunctions::Cmd350>, "Cmd350"},
{360, D<&IAppletCommonFunctions::Cmd360>, "Cmd360"},
};
// clang-format on
@@ -67,4 +83,60 @@ Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_
R_SUCCEED();
}
Result IAppletCommonFunctions::IsSystemAppletHomeMenu(Out<bool> out_is_home_menu) {
LOG_WARNING(Service_AM, "(STUBBED) called [19.0.0+]");
*out_is_home_menu = applet->applet_id == AppletId::QLaunch;
R_SUCCEED();
}
Result IAppletCommonFunctions::Cmd311() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IAppletCommonFunctions::SetGpuTimeSliceBoost(u64 boost) {
LOG_WARNING(Service_AM, "(STUBBED) called, boost={} [19.0.0+]", boost);
R_SUCCEED();
}
Result IAppletCommonFunctions::SetGpuTimeSliceBoostDueToApplication(u64 boost) {
LOG_WARNING(Service_AM, "(STUBBED) called, boost={} [19.0.0+]", boost);
R_SUCCEED();
}
Result IAppletCommonFunctions::Cmd322() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IAppletCommonFunctions::Cmd330() {
LOG_WARNING(Service_AM, "(STUBBED) called [19.0.0+]");
R_SUCCEED();
}
Result IAppletCommonFunctions::Cmd340() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IAppletCommonFunctions::Cmd341() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IAppletCommonFunctions::Cmd342() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IAppletCommonFunctions::Cmd350() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IAppletCommonFunctions::Cmd360() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
} // namespace Service::AM

View File

@@ -20,6 +20,17 @@ private:
Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
Result SetCpuBoostRequestPriority(s32 priority);
Result GetCurrentApplicationId(Out<u64> out_application_id);
Result IsSystemAppletHomeMenu(Out<bool> out_is_home_menu);
Result Cmd311();
Result SetGpuTimeSliceBoost(u64 boost);
Result SetGpuTimeSliceBoostDueToApplication(u64 boost);
Result Cmd322();
Result Cmd330();
Result Cmd340();
Result Cmd341();
Result Cmd342();
Result Cmd350();
Result Cmd360();
const std::shared_ptr<Applet> applet;
};

View File

@@ -47,6 +47,8 @@ IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_pt
{190, nullptr, "PushToNotificationStorageChannel"},
{200, nullptr, "RequestApplicationSoftReset"},
{201, nullptr, "RestartApplicationTimer"},
{300, D<&IApplicationAccessor::Cmd300>, "Cmd300"},
{301, D<&IApplicationAccessor::Cmd301>, "Cmd301"},
};
// clang-format on
@@ -156,4 +158,14 @@ Result IApplicationAccessor::ReportApplicationExitTimeout() {
R_SUCCEED();
}
Result IApplicationAccessor::Cmd300() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IApplicationAccessor::Cmd301() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
} // namespace Service::AM

View File

@@ -35,6 +35,8 @@ private:
Result CheckRightsEnvironmentAvailable(Out<bool> out_is_available);
Result GetNsRightsEnvironmentHandle(Out<u64> out_handle);
Result ReportApplicationExitTimeout();
Result Cmd300();
Result Cmd301();
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;

View File

@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
@@ -69,6 +69,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
{102, D<&IApplicationFunctions::SetApplicationCopyrightVisibility>, "SetApplicationCopyrightVisibility"},
{110, D<&IApplicationFunctions::QueryApplicationPlayStatistics>, "QueryApplicationPlayStatistics"},
{111, D<&IApplicationFunctions::QueryApplicationPlayStatisticsByUid>, "QueryApplicationPlayStatisticsByUid"},
{112, D<&IApplicationFunctions::Cmd112>, "Cmd112"},
{113, D<&IApplicationFunctions::Cmd113>, "Cmd113"},
{120, D<&IApplicationFunctions::ExecuteProgram>, "ExecuteProgram"},
{121, D<&IApplicationFunctions::ClearUserChannel>, "ClearUserChannel"},
{122, D<&IApplicationFunctions::UnpopToUserChannel>, "UnpopToUserChannel"},
@@ -88,7 +90,10 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
{200, nullptr, "GetLastApplicationExitReason"},
{210, D<&IApplicationFunctions::GetLaunchRequiredVersionUpgrade>, "GetLaunchRequiredVersionUpgrade"},
{211, nullptr, "GetLaunchRequiredVersionUpgradeStatus"},
{220, D<&IApplicationFunctions::Cmd220>, "Cmd220"},
{300, nullptr, "RequestToLaunchApplication"},
{310, D<&IApplicationFunctions::Cmd310>, "Cmd310"},
{320, D<&IApplicationFunctions::Cmd320>, "Cmd320"},
{301, nullptr, "RequestToLaunchApplicationWithUserAndArguments"},
{310, nullptr, "RequestToLaunchApplicationWithArgumentsAndUserSelectionAndError"},
{330, D<&IApplicationFunctions::Unknown330>, "Unknown330"}, // [20.2.0+]
@@ -532,4 +537,29 @@ Result IApplicationFunctions::Unknown330() {
R_SUCCEED();
}
Result IApplicationFunctions::Cmd112() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IApplicationFunctions::Cmd113() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IApplicationFunctions::Cmd220() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IApplicationFunctions::Cmd310() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result IApplicationFunctions::Cmd320() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
} // namespace Service::AM

View File

@@ -79,6 +79,11 @@ private:
Result PrepareForJit();
Result GetLaunchRequiredVersionUpgrade(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result Unknown330(); // [20.2.0+]
Result Cmd112();
Result Cmd113();
Result Cmd220();
Result Cmd310();
Result Cmd320();
const std::shared_ptr<Applet> m_applet;
};

View File

@@ -31,7 +31,13 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
{140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
{200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
{300, nullptr, "TerminateAllRunningApplicationsForDebug"},
{410, nullptr, "CreateGeneralStorageForDebug"},
{411, nullptr, "ReadGeneralStorageForDebug"},
{412, nullptr, "WriteGeneralStorageForDebug"},
{430, nullptr, "Cmd430"},
{431, nullptr, "Cmd431"},
{900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
{910, nullptr, "Cmd910"},
};
// clang-format on

View File

@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/result.h"
@@ -31,6 +31,8 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Ap
{41, D<&IHomeMenuFunctions::IsRebootEnabled>, "IsRebootEnabled"},
{50, D<&IHomeMenuFunctions::LaunchSystemApplet>, "LaunchSystemApplet"},
{51, D<&IHomeMenuFunctions::LaunchStarter>, "LaunchStarter"},
{60, D<&IHomeMenuFunctions::Cmd60>, "Cmd60"},
{61, D<&IHomeMenuFunctions::Cmd61>, "Cmd61"},
{100, D<&IHomeMenuFunctions::PopRequestLaunchApplicationForDebug>, "PopRequestLaunchApplicationForDebug"},
{110, D<&IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug>, "IsForceTerminateApplicationDisabledForDebug"},
{200, D<&IHomeMenuFunctions::LaunchDevMenu>, "LaunchDevMenu"},
@@ -149,4 +151,14 @@ Result IHomeMenuFunctions::SetLastApplicationExitReason(s32 exit_reason) {
R_SUCCEED();
}
Result IHomeMenuFunctions::Cmd60() {
LOG_WARNING(Service_AM, "(STUBBED) called [19.0.0+]");
R_SUCCEED();
}
Result IHomeMenuFunctions::Cmd61() {
LOG_WARNING(Service_AM, "(STUBBED) called [19.0.0+]");
R_SUCCEED();
}
} // namespace Service::AM

View File

@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -39,6 +39,8 @@ private:
Out<bool> out_is_force_terminate_application_disabled_for_debug);
Result LaunchDevMenu();
Result SetLastApplicationExitReason(s32 exit_reason);
Result Cmd60();
Result Cmd61();
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;

View File

@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
@@ -74,9 +74,12 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
{160, nullptr, "SetCpuBoostRequestPriority"},
{170, nullptr, "GetCurrentPerformanceConfiguration"},
{180, nullptr, "GetOperationModeSystemInfo"},
{200, nullptr, "GetSettingsPlatformRegion"},
{210, nullptr, "ActivateMigrationService"},
{211, nullptr, "DeactivateMigrationService"},
{200, D<&ISelfController::Cmd200>, "Cmd200"},
{210, D<&ISelfController::Cmd210>, "Cmd210"},
{211, D<&ISelfController::Cmd211>, "Cmd211"},
{220, D<&ISelfController::Cmd220>, "Cmd220"},
{221, D<&ISelfController::Cmd221>, "Cmd221"},
{230, D<&ISelfController::Cmd230>, "Cmd230"},
{300, nullptr, "SendMessage"},
{301, nullptr, "ReceiveMessage"},
{400, nullptr, "CreateAlbumAccessorApplicationAlbumEntry"},
@@ -424,4 +427,34 @@ Result ISelfController::SetRecordVolumeMuted(bool muted) {
R_SUCCEED();
}
Result ISelfController::Cmd200() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result ISelfController::Cmd210() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result ISelfController::Cmd211() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result ISelfController::Cmd220() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result ISelfController::Cmd221() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
Result ISelfController::Cmd230() {
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
R_SUCCEED();
}
} // namespace Service::AM

View File

@@ -63,6 +63,12 @@ private:
Result SetAlbumImageTakenNotificationEnabled(bool enabled);
Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
Result SetRecordVolumeMuted(bool muted);
Result Cmd200();
Result Cmd210();
Result Cmd211();
Result Cmd220();
Result Cmd221();
Result Cmd230();
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;

View File

@@ -139,8 +139,11 @@ void WindowSystem::OnExitRequested() {
void WindowSystem::OnHomeButtonPressed(ButtonPressDuration type) {
std::scoped_lock lk{m_lock};
// If we don't have a home menu, nothing to do.
// If we don't have a home menu, request frontend to launch QLaunch.
if (!m_home_menu) {
if (m_home_menu_request_callback && type == ButtonPressDuration::ShortPressing) {
m_home_menu_request_callback();
}
return;
}
@@ -312,4 +315,9 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground) {
}
}
void WindowSystem::SetHomeMenuRequestCallback(HomeMenuRequestCallback callback) {
std::scoped_lock lk{m_lock};
m_home_menu_request_callback = std::move(callback);
}
} // namespace Service::AM

View File

@@ -3,6 +3,7 @@
#pragma once
#include <functional>
#include <map>
#include <memory>
#include <mutex>
@@ -24,6 +25,8 @@ enum class ButtonPressDuration {
LongPressing,
};
using HomeMenuRequestCallback = std::function<void()>;
class WindowSystem {
public:
explicit WindowSystem(Core::System& system);
@@ -52,6 +55,9 @@ public:
void OnCaptureButtonPressed(ButtonPressDuration type) {}
void OnPowerButtonPressed(ButtonPressDuration type) {}
public:
void SetHomeMenuRequestCallback(HomeMenuRequestCallback callback);
private:
void PruneTerminatedAppletsLocked();
bool LockHomeMenuIntoForegroundLocked();
@@ -78,6 +84,9 @@ private:
// Applet map by aruid.
std::map<u64, std::shared_ptr<Applet>> m_applets{};
// Callback for requesting home menu launch from frontend.
HomeMenuRequestCallback m_home_menu_request_callback{};
};
} // namespace Service::AM