mirror of
https://git.citron-emu.org/citron/emulator
synced 2026-02-02 23:53:36 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user