mirror of
https://git.suyu.dev/suyu/suyu
synced 2024-12-23 18:02:46 -06:00
Merge pull request #12760 from liamwhite/mp-am
am: rewrite for multiprocess support
This commit is contained in:
commit
7cc7d027f7
132 changed files with 7088 additions and 4714 deletions
|
@ -261,7 +261,7 @@ object NativeLibrary {
|
|||
/**
|
||||
* Begins emulation.
|
||||
*/
|
||||
external fun run(path: String?, programIndex: Int = 0)
|
||||
external fun run(path: String?, programIndex: Int, frontendInitiated: Boolean)
|
||||
|
||||
// Surface Handling
|
||||
external fun surfaceChanged(surf: Surface?)
|
||||
|
|
|
@ -927,7 +927,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
emulationThread.join()
|
||||
emulationThread = Thread({
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.")
|
||||
NativeLibrary.run(gamePath, programIndex)
|
||||
NativeLibrary.run(gamePath, programIndex, false)
|
||||
}, "NativeEmulation")
|
||||
emulationThread.start()
|
||||
}
|
||||
|
@ -981,7 +981,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
State.STOPPED -> {
|
||||
emulationThread = Thread({
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.")
|
||||
NativeLibrary.run(gamePath, programIndex)
|
||||
NativeLibrary.run(gamePath, programIndex, true)
|
||||
}, "NativeEmulation")
|
||||
emulationThread.start()
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobj
|
|||
const jstring string = reinterpret_cast<jstring>(env->GetObjectField(
|
||||
object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;")));
|
||||
return ResultData{GetJString(env, string),
|
||||
static_cast<Service::AM::Applets::SwkbdResult>(env->GetIntField(
|
||||
static_cast<Service::AM::Frontend::SwkbdResult>(env->GetIntField(
|
||||
object, env->GetFieldID(s_keyboard_data_class, "result", "I")))};
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ void AndroidKeyboard::ShowNormalKeyboard() const {
|
|||
}
|
||||
|
||||
void AndroidKeyboard::ShowTextCheckDialog(
|
||||
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||
Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) const {
|
||||
LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog.");
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ void AndroidKeyboard::InlineTextChanged(
|
|||
"\ncursor_position={}",
|
||||
Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
|
||||
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
|
||||
text_parameters.input_text, text_parameters.cursor_position);
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) {
|
|||
|
||||
m_current_text += submitted_text;
|
||||
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
|
||||
m_current_text.size());
|
||||
}
|
||||
|
||||
|
@ -236,12 +236,12 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
|
|||
case KEYCODE_BACK:
|
||||
case KEYCODE_ENTER:
|
||||
m_is_inline_active = false;
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, m_current_text,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, m_current_text,
|
||||
static_cast<s32>(m_current_text.size()));
|
||||
break;
|
||||
case KEYCODE_DEL:
|
||||
m_current_text.pop_back();
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
|
||||
m_current_text.size());
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
|
||||
void ShowNormalKeyboard() const override;
|
||||
|
||||
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||
void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) const override;
|
||||
|
||||
void ShowInlineKeyboard(
|
||||
|
@ -45,7 +45,7 @@ private:
|
|||
static ResultData CreateFromFrontend(jobject object);
|
||||
|
||||
std::string text;
|
||||
Service::AM::Applets::SwkbdResult result{};
|
||||
Service::AM::Frontend::SwkbdResult result{};
|
||||
};
|
||||
|
||||
void SubmitNormalText(const ResultData& result) const;
|
||||
|
|
|
@ -42,14 +42,15 @@
|
|||
#include "core/frontend/applets/cabinet.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
#include "core/frontend/applets/general.h"
|
||||
#include "core/frontend/applets/mii_edit.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "frontend_common/config.h"
|
||||
|
@ -211,8 +212,15 @@ void EmulationSession::InitializeSystem(bool reload) {
|
|||
m_system.GetFileSystemController().CreateFactories(*m_vfs);
|
||||
}
|
||||
|
||||
void EmulationSession::SetAppletId(int applet_id) {
|
||||
m_applet_id = applet_id;
|
||||
m_system.GetFrontendAppletHolder().SetCurrentAppletId(
|
||||
static_cast<Service::AM::AppletId>(m_applet_id));
|
||||
}
|
||||
|
||||
Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath,
|
||||
const std::size_t program_index) {
|
||||
const std::size_t program_index,
|
||||
const bool frontend_initiated) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// Create the render window.
|
||||
|
@ -226,7 +234,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
|
|||
m_system.ApplySettings();
|
||||
Settings::LogSettings();
|
||||
m_system.HIDCore().ReloadInputDevices();
|
||||
m_system.SetAppletFrontendSet({
|
||||
m_system.SetFrontendAppletSet({
|
||||
nullptr, // Amiibo Settings
|
||||
nullptr, // Controller Selector
|
||||
nullptr, // Error Display
|
||||
|
@ -242,8 +250,13 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
|
|||
ConfigureFilesystemProvider(filepath);
|
||||
|
||||
// Load the ROM.
|
||||
m_load_result =
|
||||
m_system.Load(EmulationSession::GetInstance().Window(), filepath, 0, program_index);
|
||||
Service::AM::FrontendAppletParameters params{
|
||||
.applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
|
||||
.launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
|
||||
: Service::AM::LaunchType::ApplicationInitiated,
|
||||
.program_index = static_cast<s32>(program_index),
|
||||
};
|
||||
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
|
||||
if (m_load_result != Core::SystemResultStatus::Success) {
|
||||
return m_load_result;
|
||||
}
|
||||
|
@ -339,6 +352,9 @@ void EmulationSession::RunEmulation() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset current applet ID.
|
||||
m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
|
||||
}
|
||||
|
||||
bool EmulationSession::IsHandheldOnly() {
|
||||
|
@ -434,7 +450,8 @@ u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
|
|||
}
|
||||
|
||||
static Core::SystemResultStatus RunEmulation(const std::string& filepath,
|
||||
const size_t program_index = 0) {
|
||||
const size_t program_index,
|
||||
const bool frontend_initiated) {
|
||||
MicroProfileOnThreadCreate("EmuThread");
|
||||
SCOPE_EXIT({ MicroProfileShutdown(); });
|
||||
|
||||
|
@ -447,7 +464,8 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
|
|||
|
||||
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
|
||||
|
||||
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index);
|
||||
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
|
||||
frontend_initiated);
|
||||
if (result != Core::SystemResultStatus::Success) {
|
||||
return result;
|
||||
}
|
||||
|
@ -744,10 +762,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj
|
|||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
|
||||
jint j_program_index) {
|
||||
jint j_program_index,
|
||||
jboolean j_frontend_initiated) {
|
||||
const std::string path = GetJString(env, j_path);
|
||||
|
||||
const Core::SystemResultStatus result{RunEmulation(path, j_program_index)};
|
||||
const Core::SystemResultStatus result{
|
||||
RunEmulation(path, j_program_index, j_frontend_initiated)};
|
||||
if (result != Core::SystemResultStatus::Success) {
|
||||
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
|
||||
IDCache::GetExitEmulationActivity(), static_cast<int>(result));
|
||||
|
@ -809,13 +829,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j
|
|||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz,
|
||||
jint jappletId) {
|
||||
EmulationSession::GetInstance().System().GetAppletManager().SetCurrentAppletId(
|
||||
static_cast<Service::AM::Applets::AppletId>(jappletId));
|
||||
EmulationSession::GetInstance().SetAppletId(jappletId);
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz,
|
||||
jint jcabinetMode) {
|
||||
EmulationSession::GetInstance().System().GetAppletManager().SetCabinetMode(
|
||||
EmulationSession::GetInstance().System().GetFrontendAppletHolder().SetCabinetMode(
|
||||
static_cast<Service::NFP::CabinetMode>(jcabinetMode));
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,10 @@ public:
|
|||
const Core::PerfStatsResults& PerfStats();
|
||||
void ConfigureFilesystemProvider(const std::string& filepath);
|
||||
void InitializeSystem(bool reload);
|
||||
void SetAppletId(int applet_id);
|
||||
Core::SystemResultStatus InitializeEmulation(const std::string& filepath,
|
||||
const std::size_t program_index = 0);
|
||||
const std::size_t program_index,
|
||||
const bool frontend_initiated);
|
||||
|
||||
bool IsHandheldOnly();
|
||||
void SetDeviceType([[maybe_unused]] int index, int type);
|
||||
|
@ -79,6 +81,7 @@ private:
|
|||
std::atomic<bool> m_is_paused = false;
|
||||
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
|
||||
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
|
||||
int m_applet_id{1};
|
||||
|
||||
// GPU driver parameters
|
||||
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
|
||||
|
|
|
@ -176,8 +176,8 @@ add_library(core STATIC
|
|||
frontend/applets/controller.h
|
||||
frontend/applets/error.cpp
|
||||
frontend/applets/error.h
|
||||
frontend/applets/general_frontend.cpp
|
||||
frontend/applets/general_frontend.h
|
||||
frontend/applets/general.cpp
|
||||
frontend/applets/general.h
|
||||
frontend/applets/mii_edit.cpp
|
||||
frontend/applets/mii_edit.h
|
||||
frontend/applets/profile_select.cpp
|
||||
|
@ -390,39 +390,101 @@ add_library(core STATIC
|
|||
hle/service/acc/errors.h
|
||||
hle/service/acc/profile_manager.cpp
|
||||
hle/service/acc/profile_manager.h
|
||||
hle/service/am/frontend/applet_cabinet.cpp
|
||||
hle/service/am/frontend/applet_cabinet.h
|
||||
hle/service/am/frontend/applet_controller.cpp
|
||||
hle/service/am/frontend/applet_controller.h
|
||||
hle/service/am/frontend/applet_error.cpp
|
||||
hle/service/am/frontend/applet_error.h
|
||||
hle/service/am/frontend/applet_general.cpp
|
||||
hle/service/am/frontend/applet_general.h
|
||||
hle/service/am/frontend/applet_mii_edit.cpp
|
||||
hle/service/am/frontend/applet_mii_edit.h
|
||||
hle/service/am/frontend/applet_mii_edit_types.h
|
||||
hle/service/am/frontend/applet_profile_select.cpp
|
||||
hle/service/am/frontend/applet_profile_select.h
|
||||
hle/service/am/frontend/applet_software_keyboard.cpp
|
||||
hle/service/am/frontend/applet_software_keyboard.h
|
||||
hle/service/am/frontend/applet_software_keyboard_types.h
|
||||
hle/service/am/frontend/applet_web_browser.cpp
|
||||
hle/service/am/frontend/applet_web_browser.h
|
||||
hle/service/am/frontend/applet_web_browser_types.h
|
||||
hle/service/am/frontend/applets.cpp
|
||||
hle/service/am/frontend/applets.h
|
||||
hle/service/am/am.cpp
|
||||
hle/service/am/am.h
|
||||
hle/service/am/am_results.h
|
||||
hle/service/am/am_types.h
|
||||
hle/service/am/applet.cpp
|
||||
hle/service/am/applet.h
|
||||
hle/service/am/applet_ae.cpp
|
||||
hle/service/am/applet_ae.h
|
||||
hle/service/am/applet_manager.cpp
|
||||
hle/service/am/applet_data_broker.cpp
|
||||
hle/service/am/applet_data_broker.h
|
||||
hle/service/am/applet_manager.h
|
||||
hle/service/am/applet_oe.cpp
|
||||
hle/service/am/applet_oe.h
|
||||
hle/service/am/applets/applet_cabinet.cpp
|
||||
hle/service/am/applets/applet_cabinet.h
|
||||
hle/service/am/applets/applet_controller.cpp
|
||||
hle/service/am/applets/applet_controller.h
|
||||
hle/service/am/applets/applet_error.cpp
|
||||
hle/service/am/applets/applet_error.h
|
||||
hle/service/am/applets/applet_general_backend.cpp
|
||||
hle/service/am/applets/applet_general_backend.h
|
||||
hle/service/am/applets/applet_mii_edit.cpp
|
||||
hle/service/am/applets/applet_mii_edit.h
|
||||
hle/service/am/applets/applet_mii_edit_types.h
|
||||
hle/service/am/applets/applet_profile_select.cpp
|
||||
hle/service/am/applets/applet_profile_select.h
|
||||
hle/service/am/applets/applet_software_keyboard.cpp
|
||||
hle/service/am/applets/applet_software_keyboard.h
|
||||
hle/service/am/applets/applet_software_keyboard_types.h
|
||||
hle/service/am/applets/applet_web_browser.cpp
|
||||
hle/service/am/applets/applet_web_browser.h
|
||||
hle/service/am/applets/applet_web_browser_types.h
|
||||
hle/service/am/applets/applets.cpp
|
||||
hle/service/am/applets/applets.h
|
||||
hle/service/am/applet_common_functions.cpp
|
||||
hle/service/am/applet_common_functions.h
|
||||
hle/service/am/applet_message_queue.cpp
|
||||
hle/service/am/applet_message_queue.h
|
||||
hle/service/am/application_creator.cpp
|
||||
hle/service/am/application_creator.h
|
||||
hle/service/am/application_functions.cpp
|
||||
hle/service/am/application_functions.h
|
||||
hle/service/am/application_proxy.cpp
|
||||
hle/service/am/application_proxy.h
|
||||
hle/service/am/audio_controller.cpp
|
||||
hle/service/am/audio_controller.h
|
||||
hle/service/am/common_state_getter.cpp
|
||||
hle/service/am/common_state_getter.h
|
||||
hle/service/am/debug_functions.cpp
|
||||
hle/service/am/debug_functions.h
|
||||
hle/service/am/display_controller.cpp
|
||||
hle/service/am/display_controller.h
|
||||
hle/service/am/global_state_controller.cpp
|
||||
hle/service/am/global_state_controller.h
|
||||
hle/service/am/hid_registration.cpp
|
||||
hle/service/am/hid_registration.h
|
||||
hle/service/am/home_menu_functions.cpp
|
||||
hle/service/am/home_menu_functions.h
|
||||
hle/service/am/idle.cpp
|
||||
hle/service/am/idle.h
|
||||
hle/service/am/library_applet_accessor.cpp
|
||||
hle/service/am/library_applet_accessor.h
|
||||
hle/service/am/library_applet_creator.cpp
|
||||
hle/service/am/library_applet_creator.h
|
||||
hle/service/am/library_applet_proxy.cpp
|
||||
hle/service/am/library_applet_proxy.h
|
||||
hle/service/am/library_applet_self_accessor.cpp
|
||||
hle/service/am/library_applet_self_accessor.h
|
||||
hle/service/am/library_applet_storage.cpp
|
||||
hle/service/am/library_applet_storage.h
|
||||
hle/service/am/lock_accessor.cpp
|
||||
hle/service/am/lock_accessor.h
|
||||
hle/service/am/managed_layer_holder.cpp
|
||||
hle/service/am/managed_layer_holder.h
|
||||
hle/service/am/omm.cpp
|
||||
hle/service/am/omm.h
|
||||
hle/service/am/process_winding_controller.cpp
|
||||
hle/service/am/process_winding_controller.h
|
||||
hle/service/am/process.cpp
|
||||
hle/service/am/process.h
|
||||
hle/service/am/self_controller.cpp
|
||||
hle/service/am/self_controller.h
|
||||
hle/service/am/system_applet_proxy.cpp
|
||||
hle/service/am/system_applet_proxy.h
|
||||
hle/service/am/system_buffer_manager.cpp
|
||||
hle/service/am/system_buffer_manager.h
|
||||
hle/service/am/spsm.cpp
|
||||
hle/service/am/spsm.h
|
||||
hle/service/am/storage_accessor.cpp
|
||||
hle/service/am/storage_accessor.h
|
||||
hle/service/am/storage.cpp
|
||||
hle/service/am/storage.h
|
||||
hle/service/am/window_controller.cpp
|
||||
hle/service/am/window_controller.h
|
||||
hle/service/aoc/aoc_u.cpp
|
||||
hle/service/aoc/aoc_u.h
|
||||
hle/service/apm/apm.cpp
|
||||
|
@ -486,6 +548,8 @@ add_library(core STATIC
|
|||
hle/service/es/es.h
|
||||
hle/service/eupld/eupld.cpp
|
||||
hle/service/eupld/eupld.h
|
||||
hle/service/event.cpp
|
||||
hle/service/event.h
|
||||
hle/service/fatal/fatal.cpp
|
||||
hle/service/fatal/fatal.h
|
||||
hle/service/fatal/fatal_p.cpp
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
|
@ -135,8 +136,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
|||
|
||||
struct System::Impl {
|
||||
explicit Impl(System& system)
|
||||
: kernel{system}, fs_controller{system}, hid_core{}, room_network{},
|
||||
cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {}
|
||||
: kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
|
||||
reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {}
|
||||
|
||||
void Initialize(System& system) {
|
||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||
|
@ -157,7 +158,7 @@ struct System::Impl {
|
|||
}
|
||||
|
||||
// Create default implementations of applets if one is not provided.
|
||||
applet_manager.SetDefaultAppletsIfMissing();
|
||||
frontend_applets.SetDefaultAppletsIfMissing();
|
||||
|
||||
is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
|
||||
|
||||
|
@ -330,16 +331,27 @@ struct System::Impl {
|
|||
}
|
||||
|
||||
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
|
||||
const std::string& filepath, u64 program_id,
|
||||
std::size_t program_index) {
|
||||
const std::string& filepath,
|
||||
Service::AM::FrontendAppletParameters& params) {
|
||||
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
|
||||
program_id, program_index);
|
||||
params.program_id, params.program_index);
|
||||
|
||||
if (!app_loader) {
|
||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||
return SystemResultStatus::ErrorGetLoader;
|
||||
}
|
||||
|
||||
if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to find title id for ROM!");
|
||||
}
|
||||
|
||||
std::string name = "Unknown program";
|
||||
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to read title for ROM!");
|
||||
}
|
||||
|
||||
LOG_INFO(Core, "Loading {} ({})", name, params.program_id);
|
||||
|
||||
InitializeKernel(system);
|
||||
|
||||
// Create the application process.
|
||||
|
@ -373,9 +385,14 @@ struct System::Impl {
|
|||
cheat_engine->Initialize();
|
||||
}
|
||||
|
||||
// Register with applet manager.
|
||||
applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(),
|
||||
params);
|
||||
|
||||
// All threads are started, begin main process execution, now that we're in the clear.
|
||||
main_process->Run(load_parameters->main_thread_priority,
|
||||
load_parameters->main_thread_stack_size);
|
||||
main_process->Close();
|
||||
|
||||
if (Settings::values.gamecard_inserted) {
|
||||
if (Settings::values.gamecard_current_game) {
|
||||
|
@ -386,21 +403,13 @@ struct System::Impl {
|
|||
}
|
||||
}
|
||||
|
||||
if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result);
|
||||
}
|
||||
perf_stats = std::make_unique<PerfStats>(program_id);
|
||||
perf_stats = std::make_unique<PerfStats>(params.program_id);
|
||||
// Reset counters and set time origin to current frame
|
||||
GetAndResetPerfStats();
|
||||
perf_stats->BeginSystemFrame();
|
||||
|
||||
std::string name = "Unknown Game";
|
||||
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);
|
||||
}
|
||||
|
||||
std::string title_version;
|
||||
const FileSys::PatchManager pm(program_id, system.GetFileSystemController(),
|
||||
const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider());
|
||||
const auto metadata = pm.GetControlMetadata();
|
||||
if (metadata.first != nullptr) {
|
||||
|
@ -409,14 +418,15 @@ struct System::Impl {
|
|||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||
Network::GameInfo game_info;
|
||||
game_info.name = name;
|
||||
game_info.id = program_id;
|
||||
game_info.id = params.program_id;
|
||||
game_info.version = title_version;
|
||||
room_member->SendGameInfo(game_info);
|
||||
}
|
||||
|
||||
// Workarounds:
|
||||
// Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK
|
||||
Settings::values.renderer_amdvlk_depth_bias_workaround = program_id == 0x1006A800016E000ULL;
|
||||
Settings::values.renderer_amdvlk_depth_bias_workaround =
|
||||
params.program_id == 0x1006A800016E000ULL;
|
||||
|
||||
status = SystemResultStatus::Success;
|
||||
return status;
|
||||
|
@ -455,6 +465,7 @@ struct System::Impl {
|
|||
}
|
||||
kernel.CloseServices();
|
||||
kernel.ShutdownCores();
|
||||
applet_manager.Reset();
|
||||
services.reset();
|
||||
service_manager.reset();
|
||||
fs_controller.Reset();
|
||||
|
@ -566,8 +577,9 @@ struct System::Impl {
|
|||
|
||||
std::unique_ptr<Tools::RenderdocAPI> renderdoc_api;
|
||||
|
||||
/// Frontend applets
|
||||
Service::AM::Applets::AppletManager applet_manager;
|
||||
/// Applets
|
||||
Service::AM::AppletManager applet_manager;
|
||||
Service::AM::Frontend::FrontendAppletHolder frontend_applets;
|
||||
|
||||
/// APM (Performance) services
|
||||
Service::APM::Controller apm_controller{core_timing};
|
||||
|
@ -680,8 +692,8 @@ void System::InitializeDebugger() {
|
|||
}
|
||||
|
||||
SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||
u64 program_id, std::size_t program_index) {
|
||||
return impl->Load(*this, emu_window, filepath, program_id, program_index);
|
||||
Service::AM::FrontendAppletParameters& params) {
|
||||
return impl->Load(*this, emu_window, filepath, params);
|
||||
}
|
||||
|
||||
bool System::IsPoweredOn() const {
|
||||
|
@ -871,19 +883,19 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
|
|||
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
|
||||
}
|
||||
|
||||
void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) {
|
||||
impl->applet_manager.SetAppletFrontendSet(std::move(set));
|
||||
void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
|
||||
impl->frontend_applets.SetFrontendAppletSet(std::move(set));
|
||||
}
|
||||
|
||||
void System::SetDefaultAppletFrontendSet() {
|
||||
impl->applet_manager.SetDefaultAppletFrontendSet();
|
||||
Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() {
|
||||
return impl->frontend_applets;
|
||||
}
|
||||
|
||||
Service::AM::Applets::AppletManager& System::GetAppletManager() {
|
||||
return impl->applet_manager;
|
||||
const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const {
|
||||
return impl->frontend_applets;
|
||||
}
|
||||
|
||||
const Service::AM::Applets::AppletManager& System::GetAppletManager() const {
|
||||
Service::AM::AppletManager& System::GetAppletManager() {
|
||||
return impl->applet_manager;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,10 +50,15 @@ namespace Account {
|
|||
class ProfileManager;
|
||||
} // namespace Account
|
||||
|
||||
namespace AM::Applets {
|
||||
struct AppletFrontendSet;
|
||||
namespace AM {
|
||||
struct FrontendAppletParameters;
|
||||
class AppletManager;
|
||||
} // namespace AM::Applets
|
||||
} // namespace AM
|
||||
|
||||
namespace AM::Frontend {
|
||||
struct FrontendAppletSet;
|
||||
class FrontendAppletHolder;
|
||||
} // namespace AM::Frontend
|
||||
|
||||
namespace APM {
|
||||
class Controller;
|
||||
|
@ -203,8 +208,8 @@ public:
|
|||
* @returns SystemResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
[[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window,
|
||||
const std::string& filepath, u64 program_id = 0,
|
||||
std::size_t program_index = 0);
|
||||
const std::string& filepath,
|
||||
Service::AM::FrontendAppletParameters& params);
|
||||
|
||||
/**
|
||||
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
|
||||
|
@ -344,11 +349,13 @@ public:
|
|||
const std::array<u8, 0x20>& build_id, u64 main_region_begin,
|
||||
u64 main_region_size);
|
||||
|
||||
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
|
||||
void SetDefaultAppletFrontendSet();
|
||||
void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set);
|
||||
|
||||
[[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager();
|
||||
[[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
|
||||
[[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder();
|
||||
[[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder()
|
||||
const;
|
||||
|
||||
[[nodiscard]] Service::AM::AppletManager& GetAppletManager();
|
||||
|
||||
void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
#include "core/frontend/applets/general.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
|
@ -8,15 +8,15 @@
|
|||
|
||||
#include "common/uuid.h"
|
||||
#include "core/frontend/applets/applet.h"
|
||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||
#include "core/hle/service/am/frontend/applet_profile_select.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
struct ProfileSelectParameters {
|
||||
Service::AM::Applets::UiMode mode;
|
||||
Service::AM::Frontend::UiMode mode;
|
||||
std::array<Common::UUID, 8> invalid_uid_list;
|
||||
Service::AM::Applets::UiSettingsDisplayOptions display_options;
|
||||
Service::AM::Applets::UserSelectionPurpose purpose;
|
||||
Service::AM::Frontend::UiSettingsDisplayOptions display_options;
|
||||
Service::AM::Frontend::UserSelectionPurpose purpose;
|
||||
};
|
||||
|
||||
class ProfileSelectApplet : public Applet {
|
||||
|
|
|
@ -69,7 +69,7 @@ void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
|
|||
}
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
|
||||
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||
Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) const {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_
|
|||
"\ncursor_position={}",
|
||||
Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
|
||||
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
|
||||
text_parameters.input_text, text_parameters.cursor_position);
|
||||
}
|
||||
|
||||
|
@ -127,22 +127,22 @@ void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
|
|||
}
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
|
||||
submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text, true);
|
||||
submit_normal_callback(Service::AM::Frontend::SwkbdResult::Ok, text, true);
|
||||
}
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
|
||||
for (std::size_t index = 0; index < text.size(); ++index) {
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
|
||||
std::u16string(text.data(), text.data() + index + 1),
|
||||
static_cast<s32>(index) + 1);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
}
|
||||
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text),
|
||||
static_cast<s32>(text.size()));
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter,
|
||||
std::u16string(text), static_cast<s32>(text.size()));
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "common/common_types.h"
|
||||
|
||||
#include "core/frontend/applets/applet.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
||||
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
|
@ -23,10 +23,10 @@ struct KeyboardInitializeParameters {
|
|||
u32 max_text_length;
|
||||
u32 min_text_length;
|
||||
s32 initial_cursor_position;
|
||||
Service::AM::Applets::SwkbdType type;
|
||||
Service::AM::Applets::SwkbdPasswordMode password_mode;
|
||||
Service::AM::Applets::SwkbdTextDrawType text_draw_type;
|
||||
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
|
||||
Service::AM::Frontend::SwkbdType type;
|
||||
Service::AM::Frontend::SwkbdPasswordMode password_mode;
|
||||
Service::AM::Frontend::SwkbdTextDrawType text_draw_type;
|
||||
Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
|
||||
bool use_blur_background;
|
||||
bool enable_backspace_button;
|
||||
bool enable_return_button;
|
||||
|
@ -40,8 +40,8 @@ struct InlineAppearParameters {
|
|||
f32 key_top_scale_y;
|
||||
f32 key_top_translate_x;
|
||||
f32 key_top_translate_y;
|
||||
Service::AM::Applets::SwkbdType type;
|
||||
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
|
||||
Service::AM::Frontend::SwkbdType type;
|
||||
Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
|
||||
bool key_top_as_floating;
|
||||
bool enable_backspace_button;
|
||||
bool enable_return_button;
|
||||
|
@ -56,9 +56,9 @@ struct InlineTextParameters {
|
|||
class SoftwareKeyboardApplet : public Applet {
|
||||
public:
|
||||
using SubmitInlineCallback =
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>;
|
||||
std::function<void(Service::AM::Frontend::SwkbdReplyType, std::u16string, s32)>;
|
||||
using SubmitNormalCallback =
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>;
|
||||
std::function<void(Service::AM::Frontend::SwkbdResult, std::u16string, bool)>;
|
||||
|
||||
virtual ~SoftwareKeyboardApplet();
|
||||
|
||||
|
@ -69,7 +69,7 @@ public:
|
|||
|
||||
virtual void ShowNormalKeyboard() const = 0;
|
||||
|
||||
virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||
virtual void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) const = 0;
|
||||
|
||||
virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;
|
||||
|
@ -93,7 +93,7 @@ public:
|
|||
|
||||
void ShowNormalKeyboard() const override;
|
||||
|
||||
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||
void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) const override;
|
||||
|
||||
void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override;
|
||||
|
|
|
@ -18,7 +18,7 @@ void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url,
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
|
||||
local_url);
|
||||
|
||||
callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
|
||||
callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
|
||||
}
|
||||
|
||||
void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url,
|
||||
|
@ -26,7 +26,7 @@ void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_ur
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
|
||||
external_url);
|
||||
|
||||
callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
|
||||
callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <functional>
|
||||
|
||||
#include "core/frontend/applets/applet.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser_types.h"
|
||||
#include "core/hle/service/am/frontend/applet_web_browser_types.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
|
@ -14,7 +14,7 @@ class WebBrowserApplet : public Applet {
|
|||
public:
|
||||
using ExtractROMFSCallback = std::function<void()>;
|
||||
using OpenWebPageCallback =
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)>;
|
||||
std::function<void(Service::AM::Frontend::WebExitReason, std::string)>;
|
||||
|
||||
virtual ~WebBrowserApplet();
|
||||
|
||||
|
|
|
@ -97,8 +97,14 @@ struct KernelCore::Impl {
|
|||
RegisterHostThread(nullptr);
|
||||
}
|
||||
|
||||
void TerminateApplicationProcess() {
|
||||
application_process.load()->Terminate();
|
||||
void TerminateAllProcesses() {
|
||||
std::scoped_lock lk{process_list_lock};
|
||||
for (auto& process : process_list) {
|
||||
process->Terminate();
|
||||
process->Close();
|
||||
process = nullptr;
|
||||
}
|
||||
process_list.clear();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
|
@ -107,18 +113,9 @@ struct KernelCore::Impl {
|
|||
|
||||
CloseServices();
|
||||
|
||||
auto* old_process = application_process.exchange(nullptr);
|
||||
if (old_process) {
|
||||
old_process->Close();
|
||||
}
|
||||
|
||||
{
|
||||
std::scoped_lock lk{process_list_lock};
|
||||
for (auto* const process : process_list) {
|
||||
process->Terminate();
|
||||
process->Close();
|
||||
}
|
||||
process_list.clear();
|
||||
if (application_process) {
|
||||
application_process->Close();
|
||||
application_process = nullptr;
|
||||
}
|
||||
|
||||
next_object_id = 0;
|
||||
|
@ -354,6 +351,7 @@ struct KernelCore::Impl {
|
|||
|
||||
void MakeApplicationProcess(KProcess* process) {
|
||||
application_process = process;
|
||||
application_process->Open();
|
||||
}
|
||||
|
||||
static inline thread_local u8 host_thread_id = UINT8_MAX;
|
||||
|
@ -779,7 +777,7 @@ struct KernelCore::Impl {
|
|||
// Lists all processes that exist in the current session.
|
||||
std::mutex process_list_lock;
|
||||
std::vector<KProcess*> process_list;
|
||||
std::atomic<KProcess*> application_process{};
|
||||
KProcess* application_process{};
|
||||
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
||||
std::unique_ptr<Kernel::KHardwareTimer> hardware_timer;
|
||||
|
||||
|
@ -1243,7 +1241,7 @@ void KernelCore::SuspendApplication(bool suspended) {
|
|||
}
|
||||
|
||||
void KernelCore::ShutdownCores() {
|
||||
impl->TerminateApplicationProcess();
|
||||
impl->TerminateAllProcesses();
|
||||
|
||||
KScopedSchedulerLock lk{*this};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,20 +1,11 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
class KReadableEvent;
|
||||
class KTransferMemory;
|
||||
} // namespace Kernel
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class Nvnflinger;
|
||||
|
@ -22,443 +13,6 @@ class Nvnflinger;
|
|||
|
||||
namespace Service::AM {
|
||||
|
||||
class AppletMessageQueue {
|
||||
public:
|
||||
// This is nn::am::AppletMessage
|
||||
enum class AppletMessage : u32 {
|
||||
None = 0,
|
||||
ChangeIntoForeground = 1,
|
||||
ChangeIntoBackground = 2,
|
||||
Exit = 4,
|
||||
ApplicationExited = 6,
|
||||
FocusStateChanged = 15,
|
||||
Resume = 16,
|
||||
DetectShortPressingHomeButton = 20,
|
||||
DetectLongPressingHomeButton = 21,
|
||||
DetectShortPressingPowerButton = 22,
|
||||
DetectMiddlePressingPowerButton = 23,
|
||||
DetectLongPressingPowerButton = 24,
|
||||
RequestToPrepareSleep = 25,
|
||||
FinishedSleepSequence = 26,
|
||||
SleepRequiredByHighTemperature = 27,
|
||||
SleepRequiredByLowBattery = 28,
|
||||
AutoPowerDown = 29,
|
||||
OperationModeChanged = 30,
|
||||
PerformanceModeChanged = 31,
|
||||
DetectReceivingCecSystemStandby = 32,
|
||||
SdCardRemoved = 33,
|
||||
LaunchApplicationRequested = 50,
|
||||
RequestToDisplay = 51,
|
||||
ShowApplicationLogo = 55,
|
||||
HideApplicationLogo = 56,
|
||||
ForceHideApplicationLogo = 57,
|
||||
FloatingApplicationDetected = 60,
|
||||
DetectShortPressingCaptureButton = 90,
|
||||
AlbumScreenShotTaken = 92,
|
||||
AlbumRecordingSaved = 93,
|
||||
};
|
||||
|
||||
explicit AppletMessageQueue(Core::System& system);
|
||||
~AppletMessageQueue();
|
||||
|
||||
Kernel::KReadableEvent& GetMessageReceiveEvent();
|
||||
Kernel::KReadableEvent& GetOperationModeChangedEvent();
|
||||
void PushMessage(AppletMessage msg);
|
||||
AppletMessage PopMessage();
|
||||
std::size_t GetMessageCount() const;
|
||||
void RequestExit();
|
||||
void RequestResume();
|
||||
void FocusStateChanged();
|
||||
void OperationModeChanged();
|
||||
|
||||
private:
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
Kernel::KEvent* on_new_message;
|
||||
Kernel::KEvent* on_operation_mode_changed;
|
||||
|
||||
std::queue<AppletMessage> messages;
|
||||
};
|
||||
|
||||
class IWindowController final : public ServiceFramework<IWindowController> {
|
||||
public:
|
||||
explicit IWindowController(Core::System& system_);
|
||||
~IWindowController() override;
|
||||
|
||||
private:
|
||||
void GetAppletResourceUserId(HLERequestContext& ctx);
|
||||
void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
|
||||
void AcquireForegroundRights(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class IAudioController final : public ServiceFramework<IAudioController> {
|
||||
public:
|
||||
explicit IAudioController(Core::System& system_);
|
||||
~IAudioController() override;
|
||||
|
||||
private:
|
||||
void SetExpectedMasterVolume(HLERequestContext& ctx);
|
||||
void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
|
||||
void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
|
||||
void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
|
||||
void SetTransparentAudioRate(HLERequestContext& ctx);
|
||||
|
||||
static constexpr float min_allowed_volume = 0.0f;
|
||||
static constexpr float max_allowed_volume = 1.0f;
|
||||
|
||||
float main_applet_volume{0.25f};
|
||||
float library_applet_volume{max_allowed_volume};
|
||||
float transparent_volume_rate{min_allowed_volume};
|
||||
|
||||
// Volume transition fade time in nanoseconds.
|
||||
// e.g. If the main applet volume was 0% and was changed to 50%
|
||||
// with a fade of 50ns, then over the course of 50ns,
|
||||
// the volume will gradually fade up to 50%
|
||||
std::chrono::nanoseconds fade_time_ns{0};
|
||||
};
|
||||
|
||||
class IDisplayController final : public ServiceFramework<IDisplayController> {
|
||||
public:
|
||||
explicit IDisplayController(Core::System& system_);
|
||||
~IDisplayController() override;
|
||||
|
||||
private:
|
||||
void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
|
||||
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
|
||||
void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
|
||||
public:
|
||||
explicit IDebugFunctions(Core::System& system_);
|
||||
~IDebugFunctions() override;
|
||||
};
|
||||
|
||||
class ISelfController final : public ServiceFramework<ISelfController> {
|
||||
public:
|
||||
explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_);
|
||||
~ISelfController() override;
|
||||
|
||||
private:
|
||||
void Exit(HLERequestContext& ctx);
|
||||
void LockExit(HLERequestContext& ctx);
|
||||
void UnlockExit(HLERequestContext& ctx);
|
||||
void EnterFatalSection(HLERequestContext& ctx);
|
||||
void LeaveFatalSection(HLERequestContext& ctx);
|
||||
void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
|
||||
void SetScreenShotPermission(HLERequestContext& ctx);
|
||||
void SetOperationModeChangedNotification(HLERequestContext& ctx);
|
||||
void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
|
||||
void SetFocusHandlingMode(HLERequestContext& ctx);
|
||||
void SetRestartMessageEnabled(HLERequestContext& ctx);
|
||||
void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
|
||||
void SetAlbumImageOrientation(HLERequestContext& ctx);
|
||||
void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
|
||||
void GetSystemSharedBufferHandle(HLERequestContext& ctx);
|
||||
void GetSystemSharedLayerHandle(HLERequestContext& ctx);
|
||||
void CreateManagedDisplayLayer(HLERequestContext& ctx);
|
||||
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
|
||||
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
|
||||
void ApproveToDisplay(HLERequestContext& ctx);
|
||||
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||
void ReportUserIsActive(HLERequestContext& ctx);
|
||||
void SetAutoSleepDisabled(HLERequestContext& ctx);
|
||||
void IsAutoSleepDisabled(HLERequestContext& ctx);
|
||||
void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
|
||||
void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
|
||||
void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
|
||||
void SaveCurrentScreenshot(HLERequestContext& ctx);
|
||||
void SetRecordVolumeMuted(HLERequestContext& ctx);
|
||||
|
||||
Result EnsureBufferSharingEnabled();
|
||||
|
||||
enum class ScreenshotPermission : u32 {
|
||||
Inherit = 0,
|
||||
Enable = 1,
|
||||
Disable = 2,
|
||||
};
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
Kernel::KEvent* launchable_event;
|
||||
Kernel::KEvent* accumulated_suspended_tick_changed_event;
|
||||
|
||||
u32 idle_time_detection_extension = 0;
|
||||
u64 num_fatal_sections_entered = 0;
|
||||
u64 system_shared_buffer_id = 0;
|
||||
u64 system_shared_layer_id = 0;
|
||||
bool is_auto_sleep_disabled = false;
|
||||
bool buffer_sharing_enabled = false;
|
||||
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
|
||||
};
|
||||
|
||||
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
|
||||
public:
|
||||
explicit ILockAccessor(Core::System& system_);
|
||||
~ILockAccessor() override;
|
||||
|
||||
private:
|
||||
void TryLock(HLERequestContext& ctx);
|
||||
void Unlock(HLERequestContext& ctx);
|
||||
void GetEvent(HLERequestContext& ctx);
|
||||
void IsLocked(HLERequestContext& ctx);
|
||||
|
||||
bool is_locked{};
|
||||
|
||||
Kernel::KEvent* lock_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
public:
|
||||
explicit ICommonStateGetter(Core::System& system_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_);
|
||||
~ICommonStateGetter() override;
|
||||
|
||||
private:
|
||||
// This is nn::oe::FocusState
|
||||
enum class FocusState : u8 {
|
||||
InFocus = 1,
|
||||
NotInFocus = 2,
|
||||
Background = 3,
|
||||
};
|
||||
|
||||
// This is nn::oe::OperationMode
|
||||
enum class OperationMode : u8 {
|
||||
Handheld = 0,
|
||||
Docked = 1,
|
||||
};
|
||||
|
||||
// This is nn::am::service::SystemButtonType
|
||||
enum class SystemButtonType {
|
||||
None,
|
||||
HomeButtonShortPressing,
|
||||
HomeButtonLongPressing,
|
||||
PowerButtonShortPressing,
|
||||
PowerButtonLongPressing,
|
||||
ShutdownSystem,
|
||||
CaptureButtonShortPressing,
|
||||
CaptureButtonLongPressing,
|
||||
};
|
||||
|
||||
enum class SysPlatformRegion : s32 {
|
||||
Global = 1,
|
||||
Terra = 2,
|
||||
};
|
||||
|
||||
void GetEventHandle(HLERequestContext& ctx);
|
||||
void ReceiveMessage(HLERequestContext& ctx);
|
||||
void GetCurrentFocusState(HLERequestContext& ctx);
|
||||
void RequestToAcquireSleepLock(HLERequestContext& ctx);
|
||||
void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
|
||||
void GetReaderLockAccessorEx(HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
|
||||
void GetOperationMode(HLERequestContext& ctx);
|
||||
void GetPerformanceMode(HLERequestContext& ctx);
|
||||
void GetBootMode(HLERequestContext& ctx);
|
||||
void IsVrModeEnabled(HLERequestContext& ctx);
|
||||
void SetVrModeEnabled(HLERequestContext& ctx);
|
||||
void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
|
||||
void BeginVrModeEx(HLERequestContext& ctx);
|
||||
void EndVrModeEx(HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolution(HLERequestContext& ctx);
|
||||
void SetCpuBoostMode(HLERequestContext& ctx);
|
||||
void GetBuiltInDisplayType(HLERequestContext& ctx);
|
||||
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
|
||||
void GetSettingsPlatformRegion(HLERequestContext& ctx);
|
||||
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
bool vr_mode_state{};
|
||||
Kernel::KEvent* sleep_lock_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
class IStorageImpl {
|
||||
public:
|
||||
virtual ~IStorageImpl();
|
||||
virtual std::vector<u8>& GetData() = 0;
|
||||
virtual const std::vector<u8>& GetData() const = 0;
|
||||
virtual std::size_t GetSize() const = 0;
|
||||
};
|
||||
|
||||
class IStorage final : public ServiceFramework<IStorage> {
|
||||
public:
|
||||
explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
|
||||
~IStorage() override;
|
||||
|
||||
std::vector<u8>& GetData() {
|
||||
return impl->GetData();
|
||||
}
|
||||
|
||||
const std::vector<u8>& GetData() const {
|
||||
return impl->GetData();
|
||||
}
|
||||
|
||||
std::size_t GetSize() const {
|
||||
return impl->GetSize();
|
||||
}
|
||||
|
||||
private:
|
||||
void Register();
|
||||
void Open(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<IStorageImpl> impl;
|
||||
};
|
||||
|
||||
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
|
||||
public:
|
||||
explicit IStorageAccessor(Core::System& system_, IStorage& backing_);
|
||||
~IStorageAccessor() override;
|
||||
|
||||
private:
|
||||
void GetSize(HLERequestContext& ctx);
|
||||
void Write(HLERequestContext& ctx);
|
||||
void Read(HLERequestContext& ctx);
|
||||
|
||||
IStorage& backing;
|
||||
};
|
||||
|
||||
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
|
||||
public:
|
||||
explicit ILibraryAppletCreator(Core::System& system_);
|
||||
~ILibraryAppletCreator() override;
|
||||
|
||||
private:
|
||||
void CreateLibraryApplet(HLERequestContext& ctx);
|
||||
void CreateStorage(HLERequestContext& ctx);
|
||||
void CreateTransferMemoryStorage(HLERequestContext& ctx);
|
||||
void CreateHandleStorage(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
|
||||
public:
|
||||
explicit ILibraryAppletSelfAccessor(Core::System& system_);
|
||||
~ILibraryAppletSelfAccessor() override;
|
||||
|
||||
private:
|
||||
void PopInData(HLERequestContext& ctx);
|
||||
void PushOutData(HLERequestContext& ctx);
|
||||
void GetLibraryAppletInfo(HLERequestContext& ctx);
|
||||
void GetMainAppletIdentityInfo(HLERequestContext& ctx);
|
||||
void ExitProcessAndReturn(HLERequestContext& ctx);
|
||||
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
||||
void GetDesirableKeyboardLayout(HLERequestContext& ctx);
|
||||
void GetMainAppletAvailableUsers(HLERequestContext& ctx);
|
||||
void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx);
|
||||
|
||||
void PushInShowAlbum();
|
||||
void PushInShowCabinetData();
|
||||
void PushInShowMiiEditData();
|
||||
void PushInShowSoftwareKeyboard();
|
||||
void PushInShowController();
|
||||
|
||||
std::deque<std::vector<u8>> queue_data;
|
||||
};
|
||||
|
||||
class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
|
||||
public:
|
||||
explicit IAppletCommonFunctions(Core::System& system_);
|
||||
~IAppletCommonFunctions() override;
|
||||
|
||||
private:
|
||||
void SetCpuBoostRequestPriority(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
|
||||
public:
|
||||
explicit IApplicationFunctions(Core::System& system_);
|
||||
~IApplicationFunctions() override;
|
||||
|
||||
private:
|
||||
void PopLaunchParameter(HLERequestContext& ctx);
|
||||
void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
|
||||
void EnsureSaveData(HLERequestContext& ctx);
|
||||
void SetTerminateResult(HLERequestContext& ctx);
|
||||
void GetDisplayVersion(HLERequestContext& ctx);
|
||||
void GetDesiredLanguage(HLERequestContext& ctx);
|
||||
void IsGamePlayRecordingSupported(HLERequestContext& ctx);
|
||||
void InitializeGamePlayRecording(HLERequestContext& ctx);
|
||||
void SetGamePlayRecordingState(HLERequestContext& ctx);
|
||||
void NotifyRunning(HLERequestContext& ctx);
|
||||
void GetPseudoDeviceId(HLERequestContext& ctx);
|
||||
void ExtendSaveData(HLERequestContext& ctx);
|
||||
void GetSaveDataSize(HLERequestContext& ctx);
|
||||
void CreateCacheStorage(HLERequestContext& ctx);
|
||||
void GetSaveDataSizeMax(HLERequestContext& ctx);
|
||||
void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
|
||||
void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
|
||||
void BeginBlockingHomeButton(HLERequestContext& ctx);
|
||||
void EndBlockingHomeButton(HLERequestContext& ctx);
|
||||
void EnableApplicationCrashReport(HLERequestContext& ctx);
|
||||
void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
|
||||
void SetApplicationCopyrightImage(HLERequestContext& ctx);
|
||||
void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatistics(HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
|
||||
void ExecuteProgram(HLERequestContext& ctx);
|
||||
void ClearUserChannel(HLERequestContext& ctx);
|
||||
void UnpopToUserChannel(HLERequestContext& ctx);
|
||||
void GetPreviousProgramIndex(HLERequestContext& ctx);
|
||||
void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
|
||||
void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
|
||||
void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
|
||||
void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
|
||||
void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
|
||||
void PrepareForJit(HLERequestContext& ctx);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
bool launch_popped_account_preselect = false;
|
||||
s32 previous_program_index{-1};
|
||||
Kernel::KEvent* gpu_error_detected_event;
|
||||
Kernel::KEvent* friend_invitation_storage_channel_event;
|
||||
Kernel::KEvent* notification_storage_channel_event;
|
||||
Kernel::KEvent* health_warning_disappeared_system_event;
|
||||
};
|
||||
|
||||
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
|
||||
public:
|
||||
explicit IHomeMenuFunctions(Core::System& system_);
|
||||
~IHomeMenuFunctions() override;
|
||||
|
||||
private:
|
||||
void RequestToGetForeground(HLERequestContext& ctx);
|
||||
void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
Kernel::KEvent* pop_from_general_channel_event;
|
||||
};
|
||||
|
||||
class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
|
||||
public:
|
||||
explicit IGlobalStateController(Core::System& system_);
|
||||
~IGlobalStateController() override;
|
||||
};
|
||||
|
||||
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
|
||||
public:
|
||||
explicit IApplicationCreator(Core::System& system_);
|
||||
~IApplicationCreator() override;
|
||||
};
|
||||
|
||||
class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
|
||||
public:
|
||||
explicit IProcessWindingController(Core::System& system_);
|
||||
~IProcessWindingController() override;
|
||||
|
||||
private:
|
||||
void GetLaunchReason(HLERequestContext& ctx);
|
||||
void OpenCallingLibraryApplet(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
|
||||
|
||||
} // namespace Service::AM
|
||||
|
|
16
src/core/hle/service/am/am_results.h
Normal file
16
src/core/hle/service/am/am_results.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
|
||||
constexpr Result ResultNoMessages{ErrorModule::AM, 3};
|
||||
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
|
||||
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
|
||||
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
|
||||
|
||||
} // namespace Service::AM
|
178
src/core/hle/service/am/am_types.h
Normal file
178
src/core/hle/service/am/am_types.h
Normal file
|
@ -0,0 +1,178 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace Frontend {
|
||||
class FrontendApplet;
|
||||
}
|
||||
|
||||
enum class AppletType {
|
||||
Application,
|
||||
LibraryApplet,
|
||||
SystemApplet,
|
||||
};
|
||||
|
||||
enum class GameplayRecordingState : u32 {
|
||||
Disabled,
|
||||
Enabled,
|
||||
};
|
||||
|
||||
// This is nn::oe::FocusState
|
||||
enum class FocusState : u8 {
|
||||
InFocus = 1,
|
||||
NotInFocus = 2,
|
||||
Background = 3,
|
||||
};
|
||||
|
||||
// This is nn::oe::OperationMode
|
||||
enum class OperationMode : u8 {
|
||||
Handheld = 0,
|
||||
Docked = 1,
|
||||
};
|
||||
|
||||
// This is nn::am::service::SystemButtonType
|
||||
enum class SystemButtonType {
|
||||
None,
|
||||
HomeButtonShortPressing,
|
||||
HomeButtonLongPressing,
|
||||
PowerButtonShortPressing,
|
||||
PowerButtonLongPressing,
|
||||
ShutdownSystem,
|
||||
CaptureButtonShortPressing,
|
||||
CaptureButtonLongPressing,
|
||||
};
|
||||
|
||||
enum class SysPlatformRegion : s32 {
|
||||
Global = 1,
|
||||
Terra = 2,
|
||||
};
|
||||
|
||||
struct AppletProcessLaunchReason {
|
||||
u8 flag;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(AppletProcessLaunchReason) == 0x4,
|
||||
"AppletProcessLaunchReason is an invalid size");
|
||||
|
||||
enum class ScreenshotPermission : u32 {
|
||||
Inherit = 0,
|
||||
Enable = 1,
|
||||
Disable = 2,
|
||||
};
|
||||
|
||||
struct FocusHandlingMode {
|
||||
bool unknown0;
|
||||
bool unknown1;
|
||||
bool unknown2;
|
||||
bool unknown3;
|
||||
};
|
||||
|
||||
enum class IdleTimeDetectionExtension : u32 {
|
||||
Disabled = 0,
|
||||
Extended = 1,
|
||||
ExtendedUnsafe = 2,
|
||||
};
|
||||
|
||||
enum class AppletId : u32 {
|
||||
None = 0x00,
|
||||
Application = 0x01,
|
||||
OverlayDisplay = 0x02,
|
||||
QLaunch = 0x03,
|
||||
Starter = 0x04,
|
||||
Auth = 0x0A,
|
||||
Cabinet = 0x0B,
|
||||
Controller = 0x0C,
|
||||
DataErase = 0x0D,
|
||||
Error = 0x0E,
|
||||
NetConnect = 0x0F,
|
||||
ProfileSelect = 0x10,
|
||||
SoftwareKeyboard = 0x11,
|
||||
MiiEdit = 0x12,
|
||||
Web = 0x13,
|
||||
Shop = 0x14,
|
||||
PhotoViewer = 0x15,
|
||||
Settings = 0x16,
|
||||
OfflineWeb = 0x17,
|
||||
LoginShare = 0x18,
|
||||
WebAuth = 0x19,
|
||||
MyPage = 0x1A,
|
||||
};
|
||||
|
||||
enum class AppletProgramId : u64 {
|
||||
QLaunch = 0x0100000000001000ull,
|
||||
Auth = 0x0100000000001001ull,
|
||||
Cabinet = 0x0100000000001002ull,
|
||||
Controller = 0x0100000000001003ull,
|
||||
DataErase = 0x0100000000001004ull,
|
||||
Error = 0x0100000000001005ull,
|
||||
NetConnect = 0x0100000000001006ull,
|
||||
ProfileSelect = 0x0100000000001007ull,
|
||||
SoftwareKeyboard = 0x0100000000001008ull,
|
||||
MiiEdit = 0x0100000000001009ull,
|
||||
Web = 0x010000000000100Aull,
|
||||
Shop = 0x010000000000100Bull,
|
||||
OverlayDisplay = 0x010000000000100Cull,
|
||||
PhotoViewer = 0x010000000000100Dull,
|
||||
Settings = 0x010000000000100Eull,
|
||||
OfflineWeb = 0x010000000000100Full,
|
||||
LoginShare = 0x0100000000001010ull,
|
||||
WebAuth = 0x0100000000001011ull,
|
||||
Starter = 0x0100000000001012ull,
|
||||
MyPage = 0x0100000000001013ull,
|
||||
MaxProgramId = 0x0100000000001FFFull,
|
||||
};
|
||||
|
||||
enum class LibraryAppletMode : u32 {
|
||||
AllForeground = 0,
|
||||
Background = 1,
|
||||
NoUI = 2,
|
||||
BackgroundIndirectDisplay = 3,
|
||||
AllForegroundInitiallyHidden = 4,
|
||||
};
|
||||
|
||||
enum class CommonArgumentVersion : u32 {
|
||||
Version0,
|
||||
Version1,
|
||||
Version2,
|
||||
Version3,
|
||||
};
|
||||
|
||||
enum class CommonArgumentSize : u32 {
|
||||
Version3 = 0x20,
|
||||
};
|
||||
|
||||
enum class ThemeColor : u32 {
|
||||
BasicWhite = 0,
|
||||
BasicBlack = 3,
|
||||
};
|
||||
|
||||
struct CommonArguments {
|
||||
CommonArgumentVersion arguments_version;
|
||||
CommonArgumentSize size;
|
||||
u32 library_version;
|
||||
ThemeColor theme_color;
|
||||
bool play_startup_sound;
|
||||
u64 system_tick;
|
||||
};
|
||||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
||||
|
||||
struct AppletIdentityInfo {
|
||||
AppletId applet_id;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u64 application_id;
|
||||
};
|
||||
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
|
||||
|
||||
using AppletResourceUserId = u64;
|
||||
using ProgramId = u64;
|
||||
|
||||
struct Applet;
|
||||
class AppletDataBroker;
|
||||
|
||||
} // namespace Service::AM
|
27
src/core/hle/service/am/applet.cpp
Normal file
27
src/core/hle/service/am/applet.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
Applet::Applet(Core::System& system, std::unique_ptr<Process> process_)
|
||||
: context(system, "Applet"), message_queue(system), process(std::move(process_)),
|
||||
hid_registration(system, *process), gpu_error_detected_event(context),
|
||||
friend_invitation_storage_channel_event(context), notification_storage_channel_event(context),
|
||||
health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context),
|
||||
pop_from_general_channel_event(context), library_applet_launchable_event(context),
|
||||
accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) {
|
||||
|
||||
aruid = process->GetProcessId();
|
||||
program_id = process->GetProgramId();
|
||||
}
|
||||
|
||||
Applet::~Applet() = default;
|
||||
|
||||
} // namespace Service::AM
|
133
src/core/hle/service/am/applet.h
Normal file
133
src/core/hle/service/am/applet.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
#include "common/math_util.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
#include "core/hle/service/am/applet_message_queue.h"
|
||||
#include "core/hle/service/am/hid_registration.h"
|
||||
#include "core/hle/service/am/managed_layer_holder.h"
|
||||
#include "core/hle/service/am/process.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/am/system_buffer_manager.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet {
|
||||
explicit Applet(Core::System& system, std::unique_ptr<Process> process_);
|
||||
~Applet();
|
||||
|
||||
// Lock
|
||||
std::mutex lock{};
|
||||
|
||||
// Event creation helper
|
||||
KernelHelpers::ServiceContext context;
|
||||
|
||||
// Applet message queue
|
||||
AppletMessageQueue message_queue;
|
||||
|
||||
// Process
|
||||
std::unique_ptr<Process> process;
|
||||
|
||||
// Creation state
|
||||
AppletId applet_id{};
|
||||
AppletResourceUserId aruid{};
|
||||
AppletProcessLaunchReason launch_reason{};
|
||||
AppletType type{};
|
||||
ProgramId program_id{};
|
||||
LibraryAppletMode library_applet_mode{};
|
||||
s32 previous_program_index{-1};
|
||||
ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable};
|
||||
|
||||
// TODO: some fields above can be AppletIdentityInfo
|
||||
AppletIdentityInfo screen_shot_identity;
|
||||
|
||||
// hid state
|
||||
HidRegistration hid_registration;
|
||||
|
||||
// vi state
|
||||
SystemBufferManager system_buffer_manager{};
|
||||
ManagedLayerHolder managed_layer_holder{};
|
||||
|
||||
// Applet common functions
|
||||
Result terminate_result{};
|
||||
s32 display_logical_width{};
|
||||
s32 display_logical_height{};
|
||||
Common::Rectangle<f32> display_magnification{0, 0, 1, 1};
|
||||
bool home_button_double_click_enabled{};
|
||||
bool home_button_short_pressed_blocked{};
|
||||
bool home_button_long_pressed_blocked{};
|
||||
bool vr_mode_curtain_required{};
|
||||
bool sleep_required_by_high_temperature{};
|
||||
bool sleep_required_by_low_battery{};
|
||||
s32 cpu_boost_request_priority{-1};
|
||||
bool handling_capture_button_short_pressed_message_enabled_for_applet{};
|
||||
bool handling_capture_button_long_pressed_message_enabled_for_applet{};
|
||||
u32 application_core_usage_mode{};
|
||||
|
||||
// Application functions
|
||||
bool gameplay_recording_supported{};
|
||||
GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled};
|
||||
bool jit_service_launched{};
|
||||
bool is_running{};
|
||||
bool application_crash_report_enabled{};
|
||||
|
||||
// Common state
|
||||
FocusState focus_state{};
|
||||
bool sleep_lock_enabled{};
|
||||
bool vr_mode_enabled{};
|
||||
bool lcd_backlight_off_enabled{};
|
||||
APM::CpuBoostMode boost_mode{};
|
||||
bool request_exit_to_library_applet_at_execute_next_program_enabled{};
|
||||
|
||||
// Channels
|
||||
std::deque<std::vector<u8>> user_channel_launch_parameter{};
|
||||
std::deque<std::vector<u8>> preselected_user_launch_parameter{};
|
||||
|
||||
// Caller applet
|
||||
std::weak_ptr<Applet> caller_applet{};
|
||||
std::shared_ptr<AppletDataBroker> caller_applet_broker{};
|
||||
|
||||
// Self state
|
||||
bool exit_locked{};
|
||||
s32 fatal_section_count{};
|
||||
bool operation_mode_changed_notification_enabled{true};
|
||||
bool performance_mode_changed_notification_enabled{true};
|
||||
FocusHandlingMode focus_handling_mode{};
|
||||
bool restart_message_enabled{};
|
||||
bool out_of_focus_suspension_enabled{true};
|
||||
Capture::AlbumImageOrientation album_image_orientation{};
|
||||
bool handles_request_to_display{};
|
||||
ScreenshotPermission screenshot_permission{};
|
||||
IdleTimeDetectionExtension idle_time_detection_extension{};
|
||||
bool auto_sleep_disabled{};
|
||||
u64 suspended_ticks{};
|
||||
bool album_image_taken_notification_enabled{};
|
||||
bool record_volume_muted{};
|
||||
|
||||
// Events
|
||||
Event gpu_error_detected_event;
|
||||
Event friend_invitation_storage_channel_event;
|
||||
Event notification_storage_channel_event;
|
||||
Event health_warning_disappeared_system_event;
|
||||
Event acquired_sleep_lock_event;
|
||||
Event pop_from_general_channel_event;
|
||||
Event library_applet_launchable_event;
|
||||
Event accumulated_suspended_tick_changed_event;
|
||||
Event sleep_lock_event;
|
||||
|
||||
// Frontend state
|
||||
std::shared_ptr<Frontend::FrontendApplet> frontend{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
|
@ -1,291 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/library_applet_proxy.h"
|
||||
#include "core/hle/service/am/system_applet_proxy.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
|
||||
public:
|
||||
explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_,
|
||||
Core::System& system_)
|
||||
: ServiceFramework{system_, "ILibraryAppletProxy"},
|
||||
nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
|
||||
{2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"},
|
||||
{3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"},
|
||||
{4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
|
||||
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
|
||||
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
|
||||
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
|
||||
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
|
||||
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
|
||||
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetCommonStateGetter(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
|
||||
}
|
||||
|
||||
void GetSelfController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISelfController>(system, nvnflinger);
|
||||
}
|
||||
|
||||
void GetWindowController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IWindowController>(system);
|
||||
}
|
||||
|
||||
void GetAudioController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAudioController>(system);
|
||||
}
|
||||
|
||||
void GetDisplayController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDisplayController>(system);
|
||||
}
|
||||
|
||||
void GetProcessWindingController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IProcessWindingController>(system);
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>(system);
|
||||
}
|
||||
|
||||
void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system);
|
||||
}
|
||||
|
||||
void GetAppletCommonFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAppletCommonFunctions>(system);
|
||||
}
|
||||
|
||||
void GetHomeMenuFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IHomeMenuFunctions>(system);
|
||||
}
|
||||
|
||||
void GetGlobalStateController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IGlobalStateController>(system);
|
||||
}
|
||||
|
||||
void GetDebugFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDebugFunctions>(system);
|
||||
}
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
|
||||
public:
|
||||
explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_,
|
||||
Core::System& system_)
|
||||
: ServiceFramework{system_, "ISystemAppletProxy"},
|
||||
nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
|
||||
{2, &ISystemAppletProxy::GetWindowController, "GetWindowController"},
|
||||
{3, &ISystemAppletProxy::GetAudioController, "GetAudioController"},
|
||||
{4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"},
|
||||
{10, nullptr, "GetProcessWindingController"},
|
||||
{11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
|
||||
{21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
|
||||
{22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"},
|
||||
{23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
|
||||
{1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetCommonStateGetter(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
|
||||
}
|
||||
|
||||
void GetSelfController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISelfController>(system, nvnflinger);
|
||||
}
|
||||
|
||||
void GetWindowController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IWindowController>(system);
|
||||
}
|
||||
|
||||
void GetAudioController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAudioController>(system);
|
||||
}
|
||||
|
||||
void GetDisplayController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDisplayController>(system);
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>(system);
|
||||
}
|
||||
|
||||
void GetHomeMenuFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IHomeMenuFunctions>(system);
|
||||
}
|
||||
|
||||
void GetGlobalStateController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IGlobalStateController>(system);
|
||||
}
|
||||
|
||||
void GetApplicationCreator(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IApplicationCreator>(system);
|
||||
}
|
||||
|
||||
void GetAppletCommonFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAppletCommonFunctions>(system);
|
||||
}
|
||||
|
||||
void GetDebugFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDebugFunctions>(system);
|
||||
}
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, msg_queue, system);
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
|
||||
}
|
||||
|
||||
AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_)
|
||||
: ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, msg_queue{
|
||||
std::move(msg_queue_)} {
|
||||
AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
|
||||
: ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
|
||||
|
@ -304,8 +29,45 @@ AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
|
|||
|
||||
AppletAE::~AppletAE() = default;
|
||||
|
||||
const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
|
||||
return msg_queue;
|
||||
void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = GetAppletFromContext(ctx)) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, applet, system);
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = GetAppletFromContext(ctx)) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, applet, system);
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
return OpenLibraryAppletProxy(ctx);
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> AppletAE::GetAppletFromContext(HLERequestContext& ctx) {
|
||||
const auto aruid = ctx.GetPID();
|
||||
return system.GetAppletManager().GetByAppletResourceUserId(aruid);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
|
|
@ -18,23 +18,21 @@ class Nvnflinger;
|
|||
|
||||
namespace AM {
|
||||
|
||||
class AppletMessageQueue;
|
||||
struct Applet;
|
||||
|
||||
class AppletAE final : public ServiceFramework<AppletAE> {
|
||||
public:
|
||||
explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
|
||||
explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_);
|
||||
~AppletAE() override;
|
||||
|
||||
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
|
||||
|
||||
private:
|
||||
void OpenSystemAppletProxy(HLERequestContext& ctx);
|
||||
void OpenLibraryAppletProxy(HLERequestContext& ctx);
|
||||
void OpenLibraryAppletProxyOld(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
} // namespace AM
|
||||
|
|
63
src/core/hle/service/am/applet_common_functions.cpp
Normal file
63
src/core/hle/service/am/applet_common_functions.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/applet_common_functions.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
|
||||
std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "SetTerminateResult"},
|
||||
{10, nullptr, "ReadThemeStorage"},
|
||||
{11, nullptr, "WriteThemeStorage"},
|
||||
{20, nullptr, "PushToAppletBoundChannel"},
|
||||
{21, nullptr, "TryPopFromAppletBoundChannel"},
|
||||
{40, nullptr, "GetDisplayLogicalResolution"},
|
||||
{42, nullptr, "SetDisplayMagnification"},
|
||||
{50, nullptr, "SetHomeButtonDoubleClickEnabled"},
|
||||
{51, nullptr, "GetHomeButtonDoubleClickEnabled"},
|
||||
{52, nullptr, "IsHomeButtonShortPressedBlocked"},
|
||||
{60, nullptr, "IsVrModeCurtainRequired"},
|
||||
{61, nullptr, "IsSleepRequiredByHighTemperature"},
|
||||
{62, nullptr, "IsSleepRequiredByLowBattery"},
|
||||
{70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"},
|
||||
{80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
|
||||
{81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
|
||||
{90, nullptr, "OpenNamedChannelAsParent"},
|
||||
{91, nullptr, "OpenNamedChannelAsChild"},
|
||||
{100, nullptr, "SetApplicationCoreUsageMode"},
|
||||
{300, &IAppletCommonFunctions::GetCurrentApplicationId, "GetCurrentApplicationId"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IAppletCommonFunctions::~IAppletCommonFunctions() = default;
|
||||
|
||||
void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->cpu_boost_request_priority = rp.Pop<s32>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IAppletCommonFunctions::GetCurrentApplicationId(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u64>(system.GetApplicationProcessProgramID() & ~0xFFFULL);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
24
src/core/hle/service/am/applet_common_functions.h
Normal file
24
src/core/hle/service/am/applet_common_functions.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
|
||||
public:
|
||||
explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
|
||||
~IAppletCommonFunctions() override;
|
||||
|
||||
private:
|
||||
void SetCpuBoostRequestPriority(HLERequestContext& ctx);
|
||||
void GetCurrentApplicationId(HLERequestContext& ctx);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
67
src/core/hle/service/am/applet_data_broker.cpp
Normal file
67
src/core/hle/service/am/applet_data_broker.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context)
|
||||
: m_event(context) {}
|
||||
AppletStorageChannel::~AppletStorageChannel() = default;
|
||||
|
||||
void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
m_data.emplace_back(std::move(storage));
|
||||
m_event.Signal();
|
||||
}
|
||||
|
||||
Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
SCOPE_EXIT({
|
||||
if (m_data.empty()) {
|
||||
m_event.Clear();
|
||||
}
|
||||
});
|
||||
|
||||
R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
|
||||
|
||||
*out_storage = std::move(m_data.front());
|
||||
m_data.pop_front();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent* AppletStorageChannel::GetEvent() {
|
||||
return m_event.GetHandle();
|
||||
}
|
||||
|
||||
AppletDataBroker::AppletDataBroker(Core::System& system_)
|
||||
: system(system_), context(system_, "AppletDataBroker"), in_data(context),
|
||||
interactive_in_data(context), out_data(context), interactive_out_data(context),
|
||||
state_changed_event(context), is_completed(false) {}
|
||||
|
||||
AppletDataBroker::~AppletDataBroker() = default;
|
||||
|
||||
void AppletDataBroker::SignalCompletion() {
|
||||
{
|
||||
std::scoped_lock lk{lock};
|
||||
|
||||
if (is_completed) {
|
||||
return;
|
||||
}
|
||||
|
||||
is_completed = true;
|
||||
state_changed_event.Signal();
|
||||
}
|
||||
|
||||
system.GetAppletManager().FocusStateChanged();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
80
src/core/hle/service/am/applet_data_broker.h
Normal file
80
src/core/hle/service/am/applet_data_broker.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "core/hle/service/event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
union Result;
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
class IStorage;
|
||||
|
||||
class AppletStorageChannel {
|
||||
public:
|
||||
explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx);
|
||||
~AppletStorageChannel();
|
||||
|
||||
void Push(std::shared_ptr<IStorage> storage);
|
||||
Result Pop(std::shared_ptr<IStorage>* out_storage);
|
||||
Kernel::KReadableEvent* GetEvent();
|
||||
|
||||
private:
|
||||
std::mutex m_lock{};
|
||||
std::deque<std::shared_ptr<IStorage>> m_data{};
|
||||
Event m_event;
|
||||
};
|
||||
|
||||
class AppletDataBroker {
|
||||
public:
|
||||
explicit AppletDataBroker(Core::System& system_);
|
||||
~AppletDataBroker();
|
||||
|
||||
AppletStorageChannel& GetInData() {
|
||||
return in_data;
|
||||
}
|
||||
|
||||
AppletStorageChannel& GetInteractiveInData() {
|
||||
return interactive_in_data;
|
||||
}
|
||||
|
||||
AppletStorageChannel& GetOutData() {
|
||||
return out_data;
|
||||
}
|
||||
|
||||
AppletStorageChannel& GetInteractiveOutData() {
|
||||
return interactive_out_data;
|
||||
}
|
||||
|
||||
Event& GetStateChangedEvent() {
|
||||
return state_changed_event;
|
||||
}
|
||||
|
||||
bool IsCompleted() const {
|
||||
return is_completed;
|
||||
}
|
||||
|
||||
void SignalCompletion();
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
KernelHelpers::ServiceContext context;
|
||||
|
||||
AppletStorageChannel in_data;
|
||||
AppletStorageChannel interactive_in_data;
|
||||
AppletStorageChannel out_data;
|
||||
AppletStorageChannel interactive_out_data;
|
||||
Event state_changed_event;
|
||||
|
||||
std::mutex lock;
|
||||
bool is_completed;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
361
src/core/hle/service/am/applet_manager.cpp
Normal file
361
src/core/hle/service/am/applet_manager.cpp
Normal file
|
@ -0,0 +1,361 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applet_cabinet.h"
|
||||
#include "core/hle/service/am/frontend/applet_controller.h"
|
||||
#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
|
||||
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA;
|
||||
|
||||
struct LaunchParameterAccountPreselectedUser {
|
||||
u32 magic;
|
||||
u32 is_account_selected;
|
||||
Common::UUID current_user;
|
||||
INSERT_PADDING_BYTES(0x70);
|
||||
};
|
||||
static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
|
||||
|
||||
AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system,
|
||||
std::shared_ptr<Applet>& applet) {
|
||||
applet->caller_applet_broker = std::make_shared<AppletDataBroker>(system);
|
||||
return applet->caller_applet_broker->GetInData();
|
||||
}
|
||||
|
||||
void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) {
|
||||
const CommonArguments arguments{
|
||||
.arguments_version = CommonArgumentVersion::Version3,
|
||||
.size = CommonArgumentSize::Version3,
|
||||
.library_version = 1,
|
||||
.theme_color = ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> settings_data{2};
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
|
||||
}
|
||||
|
||||
void PushInShowController(Core::System& system, AppletStorageChannel& channel) {
|
||||
const CommonArguments common_args = {
|
||||
.arguments_version = CommonArgumentVersion::Version3,
|
||||
.size = CommonArgumentSize::Version3,
|
||||
.library_version = static_cast<u32>(Frontend::ControllerAppletVersion::Version8),
|
||||
.theme_color = ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
Frontend::ControllerSupportArgNew user_args = {
|
||||
.header = {.player_count_min = 1,
|
||||
.player_count_max = 4,
|
||||
.enable_take_over_connection = true,
|
||||
.enable_left_justify = false,
|
||||
.enable_permit_joy_dual = true,
|
||||
.enable_single_mode = false,
|
||||
.enable_identification_color = false},
|
||||
.identification_colors = {},
|
||||
.enable_explain_text = false,
|
||||
.explain_text = {},
|
||||
};
|
||||
|
||||
Frontend::ControllerSupportArgPrivate private_args = {
|
||||
.arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate),
|
||||
.arg_size = sizeof(Frontend::ControllerSupportArgNew),
|
||||
.is_home_menu = true,
|
||||
.flag_1 = true,
|
||||
.mode = Frontend::ControllerSupportMode::ShowControllerSupport,
|
||||
.caller = Frontend::ControllerSupportCaller::
|
||||
Application, // switchbrew: Always zero except with
|
||||
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
|
||||
// which sets this to the input param
|
||||
.style_set = Core::HID::NpadStyleSet::None,
|
||||
.joy_hold_type = 0,
|
||||
};
|
||||
std::vector<u8> common_args_data(sizeof(common_args));
|
||||
std::vector<u8> private_args_data(sizeof(private_args));
|
||||
std::vector<u8> user_args_data(sizeof(user_args));
|
||||
|
||||
std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
|
||||
std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
|
||||
std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
|
||||
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(common_args_data)));
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(private_args_data)));
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(user_args_data)));
|
||||
}
|
||||
|
||||
void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) {
|
||||
const CommonArguments arguments{
|
||||
.arguments_version = CommonArgumentVersion::Version3,
|
||||
.size = CommonArgumentSize::Version3,
|
||||
.library_version = static_cast<u32>(Frontend::CabinetAppletVersion::Version1),
|
||||
.theme_color = ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
const Frontend::StartParamForAmiiboSettings amiibo_settings{
|
||||
.param_1 = 0,
|
||||
.applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(),
|
||||
.flags = Frontend::CabinetFlags::None,
|
||||
.amiibo_settings_1 = 0,
|
||||
.device_handle = 0,
|
||||
.tag_info{},
|
||||
.register_info{},
|
||||
.amiibo_settings_3{},
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> settings_data(sizeof(amiibo_settings));
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
|
||||
}
|
||||
|
||||
void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) {
|
||||
struct MiiEditV3 {
|
||||
Frontend::MiiEditAppletInputCommon common;
|
||||
Frontend::MiiEditAppletInputV3 input;
|
||||
};
|
||||
static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size.");
|
||||
|
||||
MiiEditV3 mii_arguments{
|
||||
.common =
|
||||
{
|
||||
.version = Frontend::MiiEditAppletVersion::Version3,
|
||||
.applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit,
|
||||
},
|
||||
.input{},
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(mii_arguments));
|
||||
std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments));
|
||||
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
|
||||
}
|
||||
|
||||
void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) {
|
||||
const CommonArguments arguments{
|
||||
.arguments_version = CommonArgumentVersion::Version3,
|
||||
.size = CommonArgumentSize::Version3,
|
||||
.library_version = static_cast<u32>(Frontend::SwkbdAppletVersion::Version524301),
|
||||
.theme_color = ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
std::vector<char16_t> initial_string(0);
|
||||
|
||||
const Frontend::SwkbdConfigCommon swkbd_config{
|
||||
.type = Frontend::SwkbdType::Qwerty,
|
||||
.ok_text{},
|
||||
.left_optional_symbol_key{},
|
||||
.right_optional_symbol_key{},
|
||||
.use_prediction = false,
|
||||
.key_disable_flags{},
|
||||
.initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start,
|
||||
.header_text{},
|
||||
.sub_text{},
|
||||
.guide_text{},
|
||||
.max_text_length = 500,
|
||||
.min_text_length = 0,
|
||||
.password_mode = Frontend::SwkbdPasswordMode::Disabled,
|
||||
.text_draw_type = Frontend::SwkbdTextDrawType::Box,
|
||||
.enable_return_button = true,
|
||||
.use_utf8 = false,
|
||||
.use_blur_background = true,
|
||||
.initial_string_offset{},
|
||||
.initial_string_length = static_cast<u32>(initial_string.size()),
|
||||
.user_dictionary_offset{},
|
||||
.user_dictionary_entries{},
|
||||
.use_text_check = false,
|
||||
};
|
||||
|
||||
Frontend::SwkbdConfigNew swkbd_config_new{};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new));
|
||||
std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t));
|
||||
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config));
|
||||
std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new,
|
||||
sizeof(Frontend::SwkbdConfigNew));
|
||||
std::memcpy(work_buffer.data(), initial_string.data(),
|
||||
swkbd_config.initial_string_length * sizeof(char16_t));
|
||||
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(swkbd_data)));
|
||||
channel.Push(std::make_shared<IStorage>(system, std::move(work_buffer)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AppletManager::AppletManager(Core::System& system) : m_system(system) {}
|
||||
AppletManager::~AppletManager() {
|
||||
this->Reset();
|
||||
}
|
||||
|
||||
void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
m_applets.emplace(applet->aruid, std::move(applet));
|
||||
}
|
||||
|
||||
void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) {
|
||||
std::shared_ptr<Applet> applet;
|
||||
bool should_stop = false;
|
||||
{
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
const auto it = m_applets.find(aruid);
|
||||
if (it == m_applets.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
applet = it->second;
|
||||
m_applets.erase(it);
|
||||
|
||||
should_stop = m_applets.empty();
|
||||
}
|
||||
|
||||
// Terminate process.
|
||||
applet->process->Terminate();
|
||||
|
||||
// If there were no applets left, stop emulation.
|
||||
if (should_stop) {
|
||||
m_system.Exit();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletManager::CreateAndInsertByFrontendAppletParameters(
|
||||
AppletResourceUserId aruid, const FrontendAppletParameters& params) {
|
||||
// TODO: this should be run inside AM so that the events will have a parent process
|
||||
// TODO: have am create the guest process
|
||||
auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system));
|
||||
|
||||
applet->aruid = aruid;
|
||||
applet->program_id = params.program_id;
|
||||
applet->applet_id = params.applet_id;
|
||||
applet->type = params.applet_type;
|
||||
applet->previous_program_index = params.previous_program_index;
|
||||
|
||||
// Push UserChannel data from previous application
|
||||
if (params.launch_type == LaunchType::ApplicationInitiated) {
|
||||
applet->user_channel_launch_parameter.swap(m_system.GetUserChannel());
|
||||
}
|
||||
|
||||
// TODO: Read whether we need a preselected user from NACP?
|
||||
// TODO: This can be done quite easily from loader
|
||||
{
|
||||
LaunchParameterAccountPreselectedUser lp{};
|
||||
|
||||
lp.magic = LaunchParameterAccountPreselectedUserMagic;
|
||||
lp.is_account_selected = 1;
|
||||
|
||||
Account::ProfileManager profile_manager{};
|
||||
const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
|
||||
ASSERT(uuid.has_value() && uuid->IsValid());
|
||||
lp.current_user = *uuid;
|
||||
|
||||
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
|
||||
std::memcpy(buffer.data(), &lp, buffer.size());
|
||||
|
||||
applet->preselected_user_launch_parameter.push_back(std::move(buffer));
|
||||
}
|
||||
|
||||
// Starting from frontend, some applets require input data.
|
||||
switch (applet->applet_id) {
|
||||
case AppletId::Cabinet:
|
||||
PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
case AppletId::MiiEdit:
|
||||
PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
case AppletId::PhotoViewer:
|
||||
PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
case AppletId::SoftwareKeyboard:
|
||||
PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
case AppletId::Controller:
|
||||
PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Applet was started by frontend, so it is foreground.
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
applet->focus_state = FocusState::InFocus;
|
||||
|
||||
this->InsertApplet(std::move(applet));
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
if (const auto it = m_applets.find(aruid); it != m_applets.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void AppletManager::Reset() {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
m_applets.clear();
|
||||
}
|
||||
|
||||
void AppletManager::RequestExit() {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
for (const auto& [aruid, applet] : m_applets) {
|
||||
applet->message_queue.RequestExit();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletManager::RequestResume() {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
for (const auto& [aruid, applet] : m_applets) {
|
||||
applet->message_queue.RequestResume();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletManager::OperationModeChanged() {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
for (const auto& [aruid, applet] : m_applets) {
|
||||
applet->message_queue.OperationModeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletManager::FocusStateChanged() {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
for (const auto& [aruid, applet] : m_applets) {
|
||||
applet->message_queue.FocusStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
59
src/core/hle/service/am/applet_manager.h
Normal file
59
src/core/hle/service/am/applet_manager.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
#include "core/hle/service/am/applet.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
enum class LaunchType {
|
||||
FrontendInitiated,
|
||||
ApplicationInitiated,
|
||||
};
|
||||
|
||||
struct FrontendAppletParameters {
|
||||
ProgramId program_id{};
|
||||
AppletId applet_id{};
|
||||
AppletType applet_type{};
|
||||
LaunchType launch_type{};
|
||||
s32 program_index{};
|
||||
s32 previous_program_index{-1};
|
||||
};
|
||||
|
||||
class AppletManager {
|
||||
public:
|
||||
explicit AppletManager(Core::System& system);
|
||||
~AppletManager();
|
||||
|
||||
void InsertApplet(std::shared_ptr<Applet> applet);
|
||||
void TerminateAndRemoveApplet(AppletResourceUserId aruid);
|
||||
|
||||
void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid,
|
||||
const FrontendAppletParameters& params);
|
||||
std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const;
|
||||
|
||||
void Reset();
|
||||
|
||||
void RequestExit();
|
||||
void RequestResume();
|
||||
void OperationModeChanged();
|
||||
void FocusStateChanged();
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
mutable std::mutex m_lock{};
|
||||
std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{};
|
||||
|
||||
// AudioController state goes here
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
73
src/core/hle/service/am/applet_message_queue.cpp
Normal file
73
src/core/hle/service/am/applet_message_queue.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/applet_message_queue.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue(Core::System& system)
|
||||
: service_context{system, "AppletMessageQueue"} {
|
||||
on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
|
||||
on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
|
||||
}
|
||||
|
||||
AppletMessageQueue::~AppletMessageQueue() {
|
||||
service_context.CloseEvent(on_new_message);
|
||||
service_context.CloseEvent(on_operation_mode_changed);
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
|
||||
return on_new_message->GetReadableEvent();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
|
||||
return on_operation_mode_changed->GetReadableEvent();
|
||||
}
|
||||
|
||||
void AppletMessageQueue::PushMessage(AppletMessage msg) {
|
||||
{
|
||||
std::scoped_lock lk{lock};
|
||||
messages.push(msg);
|
||||
}
|
||||
on_new_message->Signal();
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
|
||||
std::scoped_lock lk{lock};
|
||||
if (messages.empty()) {
|
||||
on_new_message->Clear();
|
||||
return AppletMessage::None;
|
||||
}
|
||||
auto msg = messages.front();
|
||||
messages.pop();
|
||||
if (messages.empty()) {
|
||||
on_new_message->Clear();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::size_t AppletMessageQueue::GetMessageCount() const {
|
||||
std::scoped_lock lk{lock};
|
||||
return messages.size();
|
||||
}
|
||||
|
||||
void AppletMessageQueue::RequestExit() {
|
||||
PushMessage(AppletMessage::Exit);
|
||||
}
|
||||
|
||||
void AppletMessageQueue::RequestResume() {
|
||||
PushMessage(AppletMessage::Resume);
|
||||
}
|
||||
|
||||
void AppletMessageQueue::FocusStateChanged() {
|
||||
PushMessage(AppletMessage::FocusStateChanged);
|
||||
}
|
||||
|
||||
void AppletMessageQueue::OperationModeChanged() {
|
||||
PushMessage(AppletMessage::OperationModeChanged);
|
||||
PushMessage(AppletMessage::PerformanceModeChanged);
|
||||
on_operation_mode_changed->Signal();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
76
src/core/hle/service/am/applet_message_queue.h
Normal file
76
src/core/hle/service/am/applet_message_queue.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class AppletMessageQueue {
|
||||
public:
|
||||
// This is nn::am::AppletMessage
|
||||
enum class AppletMessage : u32 {
|
||||
None = 0,
|
||||
ChangeIntoForeground = 1,
|
||||
ChangeIntoBackground = 2,
|
||||
Exit = 4,
|
||||
ApplicationExited = 6,
|
||||
FocusStateChanged = 15,
|
||||
Resume = 16,
|
||||
DetectShortPressingHomeButton = 20,
|
||||
DetectLongPressingHomeButton = 21,
|
||||
DetectShortPressingPowerButton = 22,
|
||||
DetectMiddlePressingPowerButton = 23,
|
||||
DetectLongPressingPowerButton = 24,
|
||||
RequestToPrepareSleep = 25,
|
||||
FinishedSleepSequence = 26,
|
||||
SleepRequiredByHighTemperature = 27,
|
||||
SleepRequiredByLowBattery = 28,
|
||||
AutoPowerDown = 29,
|
||||
OperationModeChanged = 30,
|
||||
PerformanceModeChanged = 31,
|
||||
DetectReceivingCecSystemStandby = 32,
|
||||
SdCardRemoved = 33,
|
||||
LaunchApplicationRequested = 50,
|
||||
RequestToDisplay = 51,
|
||||
ShowApplicationLogo = 55,
|
||||
HideApplicationLogo = 56,
|
||||
ForceHideApplicationLogo = 57,
|
||||
FloatingApplicationDetected = 60,
|
||||
DetectShortPressingCaptureButton = 90,
|
||||
AlbumScreenShotTaken = 92,
|
||||
AlbumRecordingSaved = 93,
|
||||
};
|
||||
|
||||
explicit AppletMessageQueue(Core::System& system);
|
||||
~AppletMessageQueue();
|
||||
|
||||
Kernel::KReadableEvent& GetMessageReceiveEvent();
|
||||
Kernel::KReadableEvent& GetOperationModeChangedEvent();
|
||||
void PushMessage(AppletMessage msg);
|
||||
AppletMessage PopMessage();
|
||||
std::size_t GetMessageCount() const;
|
||||
void RequestExit();
|
||||
void RequestResume();
|
||||
void FocusStateChanged();
|
||||
void OperationModeChanged();
|
||||
|
||||
private:
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
Kernel::KEvent* on_new_message;
|
||||
Kernel::KEvent* on_operation_mode_changed;
|
||||
|
||||
mutable std::mutex lock;
|
||||
std::queue<AppletMessage> messages;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
|
@ -1,119 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/application_proxy.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
|
||||
public:
|
||||
explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_,
|
||||
Core::System& system_)
|
||||
: ServiceFramework{system_, "IApplicationProxy"},
|
||||
nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &IApplicationProxy::GetSelfController, "GetSelfController"},
|
||||
{2, &IApplicationProxy::GetWindowController, "GetWindowController"},
|
||||
{3, &IApplicationProxy::GetAudioController, "GetAudioController"},
|
||||
{4, &IApplicationProxy::GetDisplayController, "GetDisplayController"},
|
||||
{10, nullptr, "GetProcessWindingController"},
|
||||
{11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
|
||||
{1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetAudioController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAudioController>(system);
|
||||
}
|
||||
|
||||
void GetDisplayController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDisplayController>(system);
|
||||
}
|
||||
|
||||
void GetDebugFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDebugFunctions>(system);
|
||||
}
|
||||
|
||||
void GetWindowController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IWindowController>(system);
|
||||
}
|
||||
|
||||
void GetSelfController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISelfController>(system, nvnflinger);
|
||||
}
|
||||
|
||||
void GetCommonStateGetter(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>(system);
|
||||
}
|
||||
|
||||
void GetApplicationFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IApplicationFunctions>(system);
|
||||
}
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IApplicationProxy>(nvnflinger, msg_queue, system);
|
||||
}
|
||||
|
||||
AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_)
|
||||
: ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, msg_queue{
|
||||
std::move(msg_queue_)} {
|
||||
AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
|
||||
: ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
|
||||
};
|
||||
|
@ -122,8 +19,24 @@ AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
|
|||
|
||||
AppletOE::~AppletOE() = default;
|
||||
|
||||
const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const {
|
||||
return msg_queue;
|
||||
void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = GetAppletFromContext(ctx)) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IApplicationProxy>(nvnflinger, applet, system);
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> AppletOE::GetAppletFromContext(HLERequestContext& ctx) {
|
||||
const auto aruid = ctx.GetPID();
|
||||
return system.GetAppletManager().GetByAppletResourceUserId(aruid);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
|
|
@ -18,21 +18,19 @@ class Nvnflinger;
|
|||
|
||||
namespace AM {
|
||||
|
||||
class AppletMessageQueue;
|
||||
struct Applet;
|
||||
|
||||
class AppletOE final : public ServiceFramework<AppletOE> {
|
||||
public:
|
||||
explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
|
||||
explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_);
|
||||
~AppletOE() override;
|
||||
|
||||
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
|
||||
|
||||
private:
|
||||
void OpenApplicationProxy(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
} // namespace AM
|
||||
|
|
|
@ -1,338 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/cabinet.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
#include "core/frontend/applets/mii_edit.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||
#include "core/hle/service/am/applets/applet_controller.h"
|
||||
#include "core/hle/service/am/applets/applet_error.h"
|
||||
#include "core/hle/service/am/applets/applet_general_backend.h"
|
||||
#include "core/hle/service/am/applets/applet_mii_edit.h"
|
||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_)
|
||||
: system{system_}, applet_mode{applet_mode_}, service_context{system,
|
||||
"ILibraryAppletAccessor"} {
|
||||
state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent");
|
||||
pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent");
|
||||
pop_interactive_out_data_event =
|
||||
service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
}
|
||||
|
||||
AppletDataBroker::~AppletDataBroker() {
|
||||
service_context.CloseEvent(state_changed_event);
|
||||
service_context.CloseEvent(pop_out_data_event);
|
||||
service_context.CloseEvent(pop_interactive_out_data_event);
|
||||
}
|
||||
|
||||
AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const {
|
||||
std::vector<std::vector<u8>> out_normal;
|
||||
|
||||
for (const auto& storage : in_channel) {
|
||||
out_normal.push_back(storage->GetData());
|
||||
}
|
||||
|
||||
std::vector<std::vector<u8>> out_interactive;
|
||||
|
||||
for (const auto& storage : in_interactive_channel) {
|
||||
out_interactive.push_back(storage->GetData());
|
||||
}
|
||||
|
||||
return {std::move(out_normal), std::move(out_interactive)};
|
||||
}
|
||||
|
||||
std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
|
||||
if (out_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
auto out = std::move(out_channel.front());
|
||||
out_channel.pop_front();
|
||||
pop_out_data_event->Clear();
|
||||
return out;
|
||||
}
|
||||
|
||||
std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
|
||||
if (in_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
auto out = std::move(in_channel.front());
|
||||
in_channel.pop_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
|
||||
if (out_interactive_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
auto out = std::move(out_interactive_channel.front());
|
||||
out_interactive_channel.pop_front();
|
||||
pop_interactive_out_data_event->Clear();
|
||||
return out;
|
||||
}
|
||||
|
||||
std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
|
||||
if (in_interactive_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
auto out = std::move(in_interactive_channel.front());
|
||||
in_interactive_channel.pop_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
|
||||
in_channel.emplace_back(std::move(storage));
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
|
||||
out_channel.emplace_back(std::move(storage));
|
||||
pop_out_data_event->Signal();
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
|
||||
in_interactive_channel.emplace_back(std::move(storage));
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
|
||||
out_interactive_channel.emplace_back(std::move(storage));
|
||||
pop_interactive_out_data_event->Signal();
|
||||
}
|
||||
|
||||
void AppletDataBroker::SignalStateChanged() {
|
||||
state_changed_event->Signal();
|
||||
|
||||
switch (applet_mode) {
|
||||
case LibraryAppletMode::AllForeground:
|
||||
case LibraryAppletMode::AllForegroundInitiallyHidden: {
|
||||
auto applet_oe = system.ServiceManager().GetService<AppletOE>("appletOE");
|
||||
auto applet_ae = system.ServiceManager().GetService<AppletAE>("appletAE");
|
||||
|
||||
if (applet_oe) {
|
||||
applet_oe->GetMessageQueue()->FocusStateChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
if (applet_ae) {
|
||||
applet_ae->GetMessageQueue()->FocusStateChanged();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() {
|
||||
return pop_out_data_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() {
|
||||
return pop_interactive_out_data_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() {
|
||||
return state_changed_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_)
|
||||
: broker{system_, applet_mode_}, applet_mode{applet_mode_} {}
|
||||
|
||||
Applet::~Applet() = default;
|
||||
|
||||
void Applet::Initialize() {
|
||||
const auto common = broker.PopNormalDataToApplet();
|
||||
ASSERT(common != nullptr);
|
||||
|
||||
const auto common_data = common->GetData();
|
||||
|
||||
ASSERT(common_data.size() >= sizeof(CommonArguments));
|
||||
std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
AppletFrontendSet::AppletFrontendSet() = default;
|
||||
|
||||
AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet,
|
||||
ControllerApplet controller_applet, ErrorApplet error_applet,
|
||||
MiiEdit mii_edit_,
|
||||
ParentalControlsApplet parental_controls_applet,
|
||||
PhotoViewer photo_viewer_, ProfileSelect profile_select_,
|
||||
SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
|
||||
: cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
|
||||
error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
|
||||
parental_controls{std::move(parental_controls_applet)},
|
||||
photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
|
||||
software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
|
||||
|
||||
AppletFrontendSet::~AppletFrontendSet() = default;
|
||||
|
||||
AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
|
||||
|
||||
AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
|
||||
|
||||
AppletManager::AppletManager(Core::System& system_) : system{system_} {}
|
||||
|
||||
AppletManager::~AppletManager() = default;
|
||||
|
||||
const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
|
||||
return frontend;
|
||||
}
|
||||
|
||||
NFP::CabinetMode AppletManager::GetCabinetMode() const {
|
||||
return cabinet_mode;
|
||||
}
|
||||
|
||||
AppletId AppletManager::GetCurrentAppletId() const {
|
||||
return current_applet_id;
|
||||
}
|
||||
|
||||
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
||||
if (set.cabinet != nullptr) {
|
||||
frontend.cabinet = std::move(set.cabinet);
|
||||
}
|
||||
|
||||
if (set.controller != nullptr) {
|
||||
frontend.controller = std::move(set.controller);
|
||||
}
|
||||
|
||||
if (set.error != nullptr) {
|
||||
frontend.error = std::move(set.error);
|
||||
}
|
||||
|
||||
if (set.mii_edit != nullptr) {
|
||||
frontend.mii_edit = std::move(set.mii_edit);
|
||||
}
|
||||
|
||||
if (set.parental_controls != nullptr) {
|
||||
frontend.parental_controls = std::move(set.parental_controls);
|
||||
}
|
||||
|
||||
if (set.photo_viewer != nullptr) {
|
||||
frontend.photo_viewer = std::move(set.photo_viewer);
|
||||
}
|
||||
|
||||
if (set.profile_select != nullptr) {
|
||||
frontend.profile_select = std::move(set.profile_select);
|
||||
}
|
||||
|
||||
if (set.software_keyboard != nullptr) {
|
||||
frontend.software_keyboard = std::move(set.software_keyboard);
|
||||
}
|
||||
|
||||
if (set.web_browser != nullptr) {
|
||||
frontend.web_browser = std::move(set.web_browser);
|
||||
}
|
||||
}
|
||||
|
||||
void AppletManager::SetCabinetMode(NFP::CabinetMode mode) {
|
||||
cabinet_mode = mode;
|
||||
}
|
||||
|
||||
void AppletManager::SetCurrentAppletId(AppletId applet_id) {
|
||||
current_applet_id = applet_id;
|
||||
}
|
||||
|
||||
void AppletManager::SetDefaultAppletFrontendSet() {
|
||||
ClearAll();
|
||||
SetDefaultAppletsIfMissing();
|
||||
}
|
||||
|
||||
void AppletManager::SetDefaultAppletsIfMissing() {
|
||||
if (frontend.cabinet == nullptr) {
|
||||
frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
|
||||
}
|
||||
|
||||
if (frontend.controller == nullptr) {
|
||||
frontend.controller =
|
||||
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
|
||||
}
|
||||
|
||||
if (frontend.error == nullptr) {
|
||||
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
|
||||
}
|
||||
|
||||
if (frontend.mii_edit == nullptr) {
|
||||
frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>();
|
||||
}
|
||||
|
||||
if (frontend.parental_controls == nullptr) {
|
||||
frontend.parental_controls =
|
||||
std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
|
||||
}
|
||||
|
||||
if (frontend.photo_viewer == nullptr) {
|
||||
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
|
||||
}
|
||||
|
||||
if (frontend.profile_select == nullptr) {
|
||||
frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
|
||||
}
|
||||
|
||||
if (frontend.software_keyboard == nullptr) {
|
||||
frontend.software_keyboard =
|
||||
std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
|
||||
}
|
||||
|
||||
if (frontend.web_browser == nullptr) {
|
||||
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletManager::ClearAll() {
|
||||
frontend = {};
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const {
|
||||
switch (id) {
|
||||
case AppletId::Auth:
|
||||
return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
|
||||
case AppletId::Cabinet:
|
||||
return std::make_shared<Cabinet>(system, mode, *frontend.cabinet);
|
||||
case AppletId::Controller:
|
||||
return std::make_shared<Controller>(system, mode, *frontend.controller);
|
||||
case AppletId::Error:
|
||||
return std::make_shared<Error>(system, mode, *frontend.error);
|
||||
case AppletId::ProfileSelect:
|
||||
return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
|
||||
case AppletId::MiiEdit:
|
||||
return std::make_shared<MiiEdit>(system, mode, *frontend.mii_edit);
|
||||
case AppletId::Web:
|
||||
case AppletId::Shop:
|
||||
case AppletId::OfflineWeb:
|
||||
case AppletId::LoginShare:
|
||||
case AppletId::WebAuth:
|
||||
return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser);
|
||||
case AppletId::PhotoViewer:
|
||||
return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer);
|
||||
default:
|
||||
UNIMPLEMENTED_MSG(
|
||||
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
|
||||
static_cast<u8>(id));
|
||||
return std::make_shared<StubApplet>(system, id, mode);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
|
@ -1,289 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
union Result;
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::Frontend {
|
||||
class CabinetApplet;
|
||||
class ControllerApplet;
|
||||
class ECommerceApplet;
|
||||
class ErrorApplet;
|
||||
class MiiEditApplet;
|
||||
class ParentalControlsApplet;
|
||||
class PhotoViewerApplet;
|
||||
class ProfileSelectApplet;
|
||||
class SoftwareKeyboardApplet;
|
||||
class WebBrowserApplet;
|
||||
} // namespace Core::Frontend
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::NFP {
|
||||
enum class CabinetMode : u8;
|
||||
} // namespace Service::NFP
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IStorage;
|
||||
|
||||
namespace Applets {
|
||||
|
||||
enum class AppletId : u32 {
|
||||
None = 0x00,
|
||||
Application = 0x01,
|
||||
OverlayDisplay = 0x02,
|
||||
QLaunch = 0x03,
|
||||
Starter = 0x04,
|
||||
Auth = 0x0A,
|
||||
Cabinet = 0x0B,
|
||||
Controller = 0x0C,
|
||||
DataErase = 0x0D,
|
||||
Error = 0x0E,
|
||||
NetConnect = 0x0F,
|
||||
ProfileSelect = 0x10,
|
||||
SoftwareKeyboard = 0x11,
|
||||
MiiEdit = 0x12,
|
||||
Web = 0x13,
|
||||
Shop = 0x14,
|
||||
PhotoViewer = 0x15,
|
||||
Settings = 0x16,
|
||||
OfflineWeb = 0x17,
|
||||
LoginShare = 0x18,
|
||||
WebAuth = 0x19,
|
||||
MyPage = 0x1A,
|
||||
};
|
||||
|
||||
enum class AppletProgramId : u64 {
|
||||
QLaunch = 0x0100000000001000ull,
|
||||
Auth = 0x0100000000001001ull,
|
||||
Cabinet = 0x0100000000001002ull,
|
||||
Controller = 0x0100000000001003ull,
|
||||
DataErase = 0x0100000000001004ull,
|
||||
Error = 0x0100000000001005ull,
|
||||
NetConnect = 0x0100000000001006ull,
|
||||
ProfileSelect = 0x0100000000001007ull,
|
||||
SoftwareKeyboard = 0x0100000000001008ull,
|
||||
MiiEdit = 0x0100000000001009ull,
|
||||
Web = 0x010000000000100Aull,
|
||||
Shop = 0x010000000000100Bull,
|
||||
OverlayDisplay = 0x010000000000100Cull,
|
||||
PhotoViewer = 0x010000000000100Dull,
|
||||
Settings = 0x010000000000100Eull,
|
||||
OfflineWeb = 0x010000000000100Full,
|
||||
LoginShare = 0x0100000000001010ull,
|
||||
WebAuth = 0x0100000000001011ull,
|
||||
Starter = 0x0100000000001012ull,
|
||||
MyPage = 0x0100000000001013ull,
|
||||
MaxProgramId = 0x0100000000001FFFull,
|
||||
};
|
||||
|
||||
enum class LibraryAppletMode : u32 {
|
||||
AllForeground = 0,
|
||||
Background = 1,
|
||||
NoUI = 2,
|
||||
BackgroundIndirectDisplay = 3,
|
||||
AllForegroundInitiallyHidden = 4,
|
||||
};
|
||||
|
||||
enum class CommonArgumentVersion : u32 {
|
||||
Version0,
|
||||
Version1,
|
||||
Version2,
|
||||
Version3,
|
||||
};
|
||||
|
||||
enum class CommonArgumentSize : u32 {
|
||||
Version3 = 0x20,
|
||||
};
|
||||
|
||||
enum class ThemeColor : u32 {
|
||||
BasicWhite = 0,
|
||||
BasicBlack = 3,
|
||||
};
|
||||
|
||||
struct CommonArguments {
|
||||
CommonArgumentVersion arguments_version;
|
||||
CommonArgumentSize size;
|
||||
u32 library_version;
|
||||
ThemeColor theme_color;
|
||||
bool play_startup_sound;
|
||||
u64_le system_tick;
|
||||
};
|
||||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
||||
|
||||
class AppletDataBroker final {
|
||||
public:
|
||||
explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_);
|
||||
~AppletDataBroker();
|
||||
|
||||
struct RawChannelData {
|
||||
std::vector<std::vector<u8>> normal;
|
||||
std::vector<std::vector<u8>> interactive;
|
||||
};
|
||||
|
||||
// Retrieves but does not pop the data sent to applet.
|
||||
RawChannelData PeekDataToAppletForDebug() const;
|
||||
|
||||
std::shared_ptr<IStorage> PopNormalDataToGame();
|
||||
std::shared_ptr<IStorage> PopNormalDataToApplet();
|
||||
|
||||
std::shared_ptr<IStorage> PopInteractiveDataToGame();
|
||||
std::shared_ptr<IStorage> PopInteractiveDataToApplet();
|
||||
|
||||
void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage);
|
||||
void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage);
|
||||
|
||||
void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
|
||||
void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
|
||||
|
||||
void SignalStateChanged();
|
||||
|
||||
Kernel::KReadableEvent& GetNormalDataEvent();
|
||||
Kernel::KReadableEvent& GetInteractiveDataEvent();
|
||||
Kernel::KReadableEvent& GetStateChangedEvent();
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
LibraryAppletMode applet_mode;
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
// Queues are named from applet's perspective
|
||||
|
||||
// PopNormalDataToApplet and PushNormalDataFromGame
|
||||
std::deque<std::shared_ptr<IStorage>> in_channel;
|
||||
|
||||
// PopNormalDataToGame and PushNormalDataFromApplet
|
||||
std::deque<std::shared_ptr<IStorage>> out_channel;
|
||||
|
||||
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
|
||||
std::deque<std::shared_ptr<IStorage>> in_interactive_channel;
|
||||
|
||||
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
|
||||
std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
|
||||
|
||||
Kernel::KEvent* state_changed_event;
|
||||
|
||||
// Signaled on PushNormalDataFromApplet
|
||||
Kernel::KEvent* pop_out_data_event;
|
||||
|
||||
// Signaled on PushInteractiveDataFromApplet
|
||||
Kernel::KEvent* pop_interactive_out_data_event;
|
||||
};
|
||||
|
||||
class Applet {
|
||||
public:
|
||||
explicit Applet(Core::System& system_, LibraryAppletMode applet_mode_);
|
||||
virtual ~Applet();
|
||||
|
||||
virtual void Initialize();
|
||||
|
||||
virtual bool TransactionComplete() const = 0;
|
||||
virtual Result GetStatus() const = 0;
|
||||
virtual void ExecuteInteractive() = 0;
|
||||
virtual void Execute() = 0;
|
||||
virtual Result RequestExit() = 0;
|
||||
|
||||
AppletDataBroker& GetBroker() {
|
||||
return broker;
|
||||
}
|
||||
|
||||
const AppletDataBroker& GetBroker() const {
|
||||
return broker;
|
||||
}
|
||||
|
||||
LibraryAppletMode GetLibraryAppletMode() const {
|
||||
return applet_mode;
|
||||
}
|
||||
|
||||
bool IsInitialized() const {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
protected:
|
||||
CommonArguments common_args{};
|
||||
AppletDataBroker broker;
|
||||
LibraryAppletMode applet_mode;
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
struct AppletFrontendSet {
|
||||
using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
|
||||
using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
|
||||
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
|
||||
using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
|
||||
using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
|
||||
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
|
||||
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
|
||||
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
|
||||
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
|
||||
|
||||
AppletFrontendSet();
|
||||
AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
|
||||
ErrorApplet error_applet, MiiEdit mii_edit_,
|
||||
ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
|
||||
ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
|
||||
WebBrowser web_browser_);
|
||||
~AppletFrontendSet();
|
||||
|
||||
AppletFrontendSet(const AppletFrontendSet&) = delete;
|
||||
AppletFrontendSet& operator=(const AppletFrontendSet&) = delete;
|
||||
|
||||
AppletFrontendSet(AppletFrontendSet&&) noexcept;
|
||||
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
|
||||
|
||||
CabinetApplet cabinet;
|
||||
ControllerApplet controller;
|
||||
ErrorApplet error;
|
||||
MiiEdit mii_edit;
|
||||
ParentalControlsApplet parental_controls;
|
||||
PhotoViewer photo_viewer;
|
||||
ProfileSelect profile_select;
|
||||
SoftwareKeyboard software_keyboard;
|
||||
WebBrowser web_browser;
|
||||
};
|
||||
|
||||
class AppletManager {
|
||||
public:
|
||||
explicit AppletManager(Core::System& system_);
|
||||
~AppletManager();
|
||||
|
||||
const AppletFrontendSet& GetAppletFrontendSet() const;
|
||||
NFP::CabinetMode GetCabinetMode() const;
|
||||
AppletId GetCurrentAppletId() const;
|
||||
|
||||
void SetAppletFrontendSet(AppletFrontendSet set);
|
||||
void SetCabinetMode(NFP::CabinetMode mode);
|
||||
void SetCurrentAppletId(AppletId applet_id);
|
||||
void SetDefaultAppletFrontendSet();
|
||||
void SetDefaultAppletsIfMissing();
|
||||
void ClearAll();
|
||||
|
||||
std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
|
||||
|
||||
private:
|
||||
AppletId current_applet_id{};
|
||||
NFP::CabinetMode cabinet_mode{};
|
||||
|
||||
AppletFrontendSet frontend;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Applets
|
||||
} // namespace Service::AM
|
25
src/core/hle/service/am/application_creator.cpp
Normal file
25
src/core/hle/service/am/application_creator.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/application_creator.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IApplicationCreator::IApplicationCreator(Core::System& system_)
|
||||
: ServiceFramework{system_, "IApplicationCreator"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "CreateApplication"},
|
||||
{1, nullptr, "PopLaunchRequestedApplication"},
|
||||
{10, nullptr, "CreateSystemApplication"},
|
||||
{100, nullptr, "PopFloatingApplicationForDevelopment"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationCreator::~IApplicationCreator() = default;
|
||||
|
||||
} // namespace Service::AM
|
16
src/core/hle/service/am/application_creator.h
Normal file
16
src/core/hle/service/am/application_creator.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
|
||||
public:
|
||||
explicit IApplicationCreator(Core::System& system_);
|
||||
~IApplicationCreator() override;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
594
src/core/hle/service/am/application_functions.cpp
Normal file
594
src/core/hle/service/am/application_functions.cpp
Normal file
|
@ -0,0 +1,594 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/application_functions.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/filesystem/save_data_controller.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
enum class LaunchParameterKind : u32 {
|
||||
UserChannel = 1,
|
||||
AccountPreselectedUser = 2,
|
||||
};
|
||||
|
||||
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "IApplicationFunctions"}, applet{std::move(applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
|
||||
{10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
|
||||
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
|
||||
{12, nullptr, "CreateApplicationAndRequestToStart"},
|
||||
{13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
|
||||
{14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
|
||||
{15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
|
||||
{20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
|
||||
{21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
|
||||
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
|
||||
{23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"},
|
||||
{24, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
|
||||
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
|
||||
{27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
|
||||
{28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"},
|
||||
{29, nullptr, "GetCacheStorageMax"},
|
||||
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
|
||||
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
|
||||
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
|
||||
{33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
|
||||
{34, nullptr, "SelectApplicationLicense"},
|
||||
{35, nullptr, "GetDeviceSaveDataSizeMax"},
|
||||
{36, nullptr, "GetLimitedApplicationLicense"},
|
||||
{37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
|
||||
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
|
||||
{50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
|
||||
{60, nullptr, "SetMediaPlaybackStateForApplication"},
|
||||
{65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"},
|
||||
{66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
|
||||
{67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"},
|
||||
{68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
|
||||
{70, nullptr, "RequestToShutdown"},
|
||||
{71, nullptr, "RequestToReboot"},
|
||||
{72, nullptr, "RequestToSleep"},
|
||||
{80, nullptr, "ExitAndRequestToShowThanksMessage"},
|
||||
{90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
|
||||
{100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"},
|
||||
{101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"},
|
||||
{102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
|
||||
{110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
|
||||
{111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
|
||||
{120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
|
||||
{121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
|
||||
{122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
|
||||
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
|
||||
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
|
||||
{131, nullptr, "SetDelayTimeToAbortOnGpuError"},
|
||||
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
|
||||
{141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
|
||||
{150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"},
|
||||
{151, nullptr, "TryPopFromNotificationStorageChannel"},
|
||||
{160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{170, nullptr, "SetHdcpAuthenticationActivated"},
|
||||
{180, nullptr, "GetLaunchRequiredVersion"},
|
||||
{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
|
||||
{200, nullptr, "GetLastApplicationExitReason"},
|
||||
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
{1000, nullptr, "CreateMovieMaker"},
|
||||
{1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationFunctions::~IApplicationFunctions() = default;
|
||||
|
||||
void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->application_crash_report_enabled = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto is_visible = rp.Pop<bool>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->home_button_long_pressed_blocked = true;
|
||||
applet->home_button_short_pressed_blocked = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->home_button_long_pressed_blocked = false;
|
||||
applet->home_button_short_pressed_blocked = false;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->home_button_long_pressed_blocked = true;
|
||||
applet->home_button_short_pressed_blocked = true;
|
||||
applet->home_button_double_click_enabled = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->home_button_long_pressed_blocked = false;
|
||||
applet->home_button_short_pressed_blocked = false;
|
||||
applet->home_button_double_click_enabled = false;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto kind = rp.PopEnum<LaunchParameterKind>();
|
||||
|
||||
LOG_INFO(Service_AM, "called, kind={:08X}", kind);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
|
||||
auto& channel = kind == LaunchParameterKind::UserChannel
|
||||
? applet->user_channel_launch_parameter
|
||||
: applet->preselected_user_launch_parameter;
|
||||
|
||||
if (channel.empty()) {
|
||||
LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!", kind);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(AM::ResultNoDataInChannel);
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = channel.back();
|
||||
channel.pop_back();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IStorage>(system, std::move(data));
|
||||
}
|
||||
|
||||
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u128 user_id = rp.PopRaw<u128>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
|
||||
|
||||
FileSys::SaveDataAttribute attribute{};
|
||||
attribute.title_id = applet->program_id;
|
||||
attribute.user_id = user_id;
|
||||
attribute.type = FileSys::SaveDataType::SaveData;
|
||||
|
||||
FileSys::VirtualDir save_data{};
|
||||
const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
|
||||
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push<u64>(0);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) {
|
||||
// Takes an input u32 Result, no output.
|
||||
// For example, in some cases official apps use this with error 0x2A2 then
|
||||
// uses svcBreak.
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 result = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->terminate_result = Result(result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
std::array<u8, 0x10> version_string{};
|
||||
|
||||
const auto res = [this] {
|
||||
const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
auto metadata = pm.GetControlMetadata();
|
||||
if (metadata.first != nullptr) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
return pm_update.GetControlMetadata();
|
||||
}();
|
||||
|
||||
if (res.first != nullptr) {
|
||||
const auto& version = res.first->GetVersionString();
|
||||
std::copy(version.begin(), version.end(), version_string.begin());
|
||||
} else {
|
||||
static constexpr char default_version[]{"1.0.0"};
|
||||
std::memcpy(version_string.data(), default_version, sizeof(default_version));
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(version_string);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
|
||||
// TODO(bunnei): This should be configurable
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
// Get supported languages from NACP, if possible
|
||||
// Default to 0 (all languages supported)
|
||||
u32 supported_languages = 0;
|
||||
|
||||
const auto res = [this] {
|
||||
const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
auto metadata = pm.GetControlMetadata();
|
||||
if (metadata.first != nullptr) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
return pm_update.GetControlMetadata();
|
||||
}();
|
||||
|
||||
if (res.first != nullptr) {
|
||||
supported_languages = res.first->GetSupportedLanguages();
|
||||
}
|
||||
|
||||
// Call IApplicationManagerInterface implementation.
|
||||
auto& service_manager = system.ServiceManager();
|
||||
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
|
||||
auto app_man = ns_am2->GetApplicationManagerInterface();
|
||||
|
||||
// Get desired application language
|
||||
u8 desired_language{};
|
||||
const auto res_lang =
|
||||
app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
|
||||
if (res_lang != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert to settings language code.
|
||||
u64 language_code{};
|
||||
const auto res_code =
|
||||
app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
|
||||
if (res_code != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res_code);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(language_code);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(applet->gameplay_recording_supported);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->gameplay_recording_state = rp.PopRaw<GameplayRecordingState>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->is_running = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
// Returns a 128-bit UUID
|
||||
rb.Push<u64>(0);
|
||||
rb.Push<u64>(0);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) {
|
||||
struct Parameters {
|
||||
FileSys::SaveDataType type;
|
||||
u128 user_id;
|
||||
u64 new_normal_size;
|
||||
u64 new_journal_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 40);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_DEBUG(Service_AM,
|
||||
"called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
|
||||
"new_journal={:016X}",
|
||||
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
|
||||
|
||||
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
|
||||
type, applet->program_id, user_id, {new_normal_size, new_journal_size});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
// The following value is used upon failure to help the system recover.
|
||||
// Since we always succeed, this should be 0.
|
||||
rb.Push<u64>(0);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
|
||||
struct Parameters {
|
||||
FileSys::SaveDataType type;
|
||||
u128 user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 24);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto [type, user_id] = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
|
||||
user_id[0]);
|
||||
|
||||
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
|
||||
type, applet->program_id, user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(size.normal);
|
||||
rb.Push(size.journal);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
u16 index;
|
||||
s64 size;
|
||||
s64 journal_size;
|
||||
};
|
||||
static_assert(sizeof(InputParameters) == 24);
|
||||
|
||||
struct OutputParameters {
|
||||
u32 storage_target;
|
||||
u64 required_size;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 16);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto params = rp.PopRaw<InputParameters>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
|
||||
params.index, params.size, params.journal_size);
|
||||
|
||||
const OutputParameters resp{
|
||||
.storage_target = 1,
|
||||
.required_size = 0,
|
||||
};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(resp);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
constexpr u64 size_max_normal = 0xFFFFFFF;
|
||||
constexpr u64 size_max_journal = 0xFFFFFFF;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(size_max_normal);
|
||||
rb.Push(size_max_journal);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
[[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
|
||||
[[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
|
||||
const auto program_index = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
// Swap user channel ownership into the system so that it will be preserved
|
||||
system.GetUserChannel().swap(applet->user_channel_launch_parameter);
|
||||
system.ExecuteProgram(program_index);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
applet->user_channel_launch_parameter.clear();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto storage = rp.PopIpcInterface<IStorage>().lock();
|
||||
if (storage) {
|
||||
applet->user_channel_launch_parameter.push_back(storage->GetData());
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(applet->previous_program_index);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->gpu_error_detected_event.GetHandle());
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->friend_invitation_storage_channel_event.GetHandle());
|
||||
}
|
||||
|
||||
void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(AM::ResultNoDataInChannel);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->notification_storage_channel_event.GetHandle());
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->health_warning_disappeared_system_event.GetHandle());
|
||||
}
|
||||
|
||||
void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->jit_service_launched = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
58
src/core/hle/service/am/application_functions.h
Normal file
58
src/core/hle/service/am/application_functions.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
|
||||
public:
|
||||
explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
|
||||
~IApplicationFunctions() override;
|
||||
|
||||
private:
|
||||
void PopLaunchParameter(HLERequestContext& ctx);
|
||||
void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
|
||||
void EnsureSaveData(HLERequestContext& ctx);
|
||||
void SetTerminateResult(HLERequestContext& ctx);
|
||||
void GetDisplayVersion(HLERequestContext& ctx);
|
||||
void GetDesiredLanguage(HLERequestContext& ctx);
|
||||
void IsGamePlayRecordingSupported(HLERequestContext& ctx);
|
||||
void InitializeGamePlayRecording(HLERequestContext& ctx);
|
||||
void SetGamePlayRecordingState(HLERequestContext& ctx);
|
||||
void NotifyRunning(HLERequestContext& ctx);
|
||||
void GetPseudoDeviceId(HLERequestContext& ctx);
|
||||
void ExtendSaveData(HLERequestContext& ctx);
|
||||
void GetSaveDataSize(HLERequestContext& ctx);
|
||||
void CreateCacheStorage(HLERequestContext& ctx);
|
||||
void GetSaveDataSizeMax(HLERequestContext& ctx);
|
||||
void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
|
||||
void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
|
||||
void BeginBlockingHomeButton(HLERequestContext& ctx);
|
||||
void EndBlockingHomeButton(HLERequestContext& ctx);
|
||||
void EnableApplicationCrashReport(HLERequestContext& ctx);
|
||||
void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
|
||||
void SetApplicationCopyrightImage(HLERequestContext& ctx);
|
||||
void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatistics(HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
|
||||
void ExecuteProgram(HLERequestContext& ctx);
|
||||
void ClearUserChannel(HLERequestContext& ctx);
|
||||
void UnpopToUserChannel(HLERequestContext& ctx);
|
||||
void GetPreviousProgramIndex(HLERequestContext& ctx);
|
||||
void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
|
||||
void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
|
||||
void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
|
||||
void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
|
||||
void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
|
||||
void PrepareForJit(HLERequestContext& ctx);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
115
src/core/hle/service/am/application_proxy.cpp
Normal file
115
src/core/hle/service/am/application_proxy.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/applet_common_functions.h"
|
||||
#include "core/hle/service/am/application_functions.h"
|
||||
#include "core/hle/service/am/application_proxy.h"
|
||||
#include "core/hle/service/am/audio_controller.h"
|
||||
#include "core/hle/service/am/common_state_getter.h"
|
||||
#include "core/hle/service/am/debug_functions.h"
|
||||
#include "core/hle/service/am/display_controller.h"
|
||||
#include "core/hle/service/am/library_applet_creator.h"
|
||||
#include "core/hle/service/am/library_applet_self_accessor.h"
|
||||
#include "core/hle/service/am/process_winding_controller.h"
|
||||
#include "core/hle/service/am/self_controller.h"
|
||||
#include "core/hle/service/am/window_controller.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<Applet> applet_, Core::System& system_)
|
||||
: ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
|
||||
applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &IApplicationProxy::GetSelfController, "GetSelfController"},
|
||||
{2, &IApplicationProxy::GetWindowController, "GetWindowController"},
|
||||
{3, &IApplicationProxy::GetAudioController, "GetAudioController"},
|
||||
{4, &IApplicationProxy::GetDisplayController, "GetDisplayController"},
|
||||
{10, &IApplicationProxy::GetProcessWindingController, "GetProcessWindingController"},
|
||||
{11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
|
||||
{1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationProxy::~IApplicationProxy() = default;
|
||||
|
||||
void IApplicationProxy::GetAudioController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAudioController>(system);
|
||||
}
|
||||
|
||||
void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDisplayController>(system, applet);
|
||||
}
|
||||
|
||||
void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IProcessWindingController>(system, applet);
|
||||
}
|
||||
|
||||
void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDebugFunctions>(system);
|
||||
}
|
||||
|
||||
void IApplicationProxy::GetWindowController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IWindowController>(system, applet);
|
||||
}
|
||||
|
||||
void IApplicationProxy::GetSelfController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
|
||||
}
|
||||
|
||||
void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(system, applet);
|
||||
}
|
||||
|
||||
void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
|
||||
}
|
||||
|
||||
void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IApplicationFunctions>(system, applet);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
33
src/core/hle/service/am/application_proxy.h
Normal file
33
src/core/hle/service/am/application_proxy.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
|
||||
public:
|
||||
explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<Applet> msg_queue_, Core::System& system_);
|
||||
~IApplicationProxy();
|
||||
|
||||
private:
|
||||
void GetAudioController(HLERequestContext& ctx);
|
||||
void GetDisplayController(HLERequestContext& ctx);
|
||||
void GetProcessWindingController(HLERequestContext& ctx);
|
||||
void GetDebugFunctions(HLERequestContext& ctx);
|
||||
void GetWindowController(HLERequestContext& ctx);
|
||||
void GetSelfController(HLERequestContext& ctx);
|
||||
void GetCommonStateGetter(HLERequestContext& ctx);
|
||||
void GetLibraryAppletCreator(HLERequestContext& ctx);
|
||||
void GetApplicationFunctions(HLERequestContext& ctx);
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
91
src/core/hle/service/am/audio_controller.cpp
Normal file
91
src/core/hle/service/am/audio_controller.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/audio_controller.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IAudioController::IAudioController(Core::System& system_)
|
||||
: ServiceFramework{system_, "IAudioController"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"},
|
||||
{1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"},
|
||||
{2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"},
|
||||
{3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"},
|
||||
{4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IAudioController::~IAudioController() = default;
|
||||
|
||||
void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const float main_applet_volume_tmp = rp.Pop<float>();
|
||||
const float library_applet_volume_tmp = rp.Pop<float>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
|
||||
main_applet_volume_tmp, library_applet_volume_tmp);
|
||||
|
||||
// Ensure the volume values remain within the 0-100% range
|
||||
main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
|
||||
library_applet_volume =
|
||||
std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(main_applet_volume);
|
||||
}
|
||||
|
||||
void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(library_applet_volume);
|
||||
}
|
||||
|
||||
void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) {
|
||||
struct Parameters {
|
||||
float volume;
|
||||
s64 fade_time_ns;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 16);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto parameters = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume,
|
||||
parameters.fade_time_ns);
|
||||
|
||||
main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume);
|
||||
fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const float transparent_volume_rate_tmp = rp.Pop<float>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp);
|
||||
|
||||
// Clamp volume range to 0-100%.
|
||||
transparent_volume_rate =
|
||||
std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
36
src/core/hle/service/am/audio_controller.h
Normal file
36
src/core/hle/service/am/audio_controller.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IAudioController final : public ServiceFramework<IAudioController> {
|
||||
public:
|
||||
explicit IAudioController(Core::System& system_);
|
||||
~IAudioController() override;
|
||||
|
||||
private:
|
||||
void SetExpectedMasterVolume(HLERequestContext& ctx);
|
||||
void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
|
||||
void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
|
||||
void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
|
||||
void SetTransparentAudioRate(HLERequestContext& ctx);
|
||||
|
||||
static constexpr float min_allowed_volume = 0.0f;
|
||||
static constexpr float max_allowed_volume = 1.0f;
|
||||
|
||||
float main_applet_volume{0.25f};
|
||||
float library_applet_volume{max_allowed_volume};
|
||||
float transparent_volume_rate{min_allowed_volume};
|
||||
|
||||
// Volume transition fade time in nanoseconds.
|
||||
// e.g. If the main applet volume was 0% and was changed to 50%
|
||||
// with a fade of 50ns, then over the course of 50ns,
|
||||
// the volume will gradually fade up to 50%
|
||||
std::chrono::nanoseconds fade_time_ns{0};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
314
src/core/hle/service/am/common_state_getter.cpp
Normal file
314
src/core/hle/service/am/common_state_getter.cpp
Normal file
|
@ -0,0 +1,314 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/common_state_getter.h"
|
||||
#include "core/hle/service/am/lock_accessor.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/apm/apm_interface.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/pm/pm.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/vi/vi.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "ICommonStateGetter"}, applet{std::move(applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
|
||||
{1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
|
||||
{2, nullptr, "GetThisAppletKind"},
|
||||
{3, nullptr, "AllowToEnterSleep"},
|
||||
{4, nullptr, "DisallowToEnterSleep"},
|
||||
{5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"},
|
||||
{6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"},
|
||||
{7, nullptr, "GetCradleStatus"},
|
||||
{8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
|
||||
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
|
||||
{10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"},
|
||||
{11, nullptr, "ReleaseSleepLock"},
|
||||
{12, nullptr, "ReleaseSleepLockTransiently"},
|
||||
{13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"},
|
||||
{14, nullptr, "GetWakeupCount"},
|
||||
{20, nullptr, "PushToGeneralChannel"},
|
||||
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
|
||||
{31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
|
||||
{32, nullptr, "GetWriterLockAccessorEx"},
|
||||
{40, nullptr, "GetCradleFwVersion"},
|
||||
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
|
||||
{51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
|
||||
{52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
|
||||
{53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
|
||||
{54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
|
||||
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
|
||||
{59, nullptr, "SetVrPositionForDebug"},
|
||||
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
|
||||
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
|
||||
{62, nullptr, "GetHdcpAuthenticationState"},
|
||||
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
|
||||
{64, nullptr, "SetTvPowerStateMatchingMode"},
|
||||
{65, nullptr, "GetApplicationIdByContentActionName"},
|
||||
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
|
||||
{67, nullptr, "CancelCpuBoostMode"},
|
||||
{68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
|
||||
{80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
|
||||
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
|
||||
{91, nullptr, "GetCurrentPerformanceConfiguration"},
|
||||
{100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
|
||||
{110, nullptr, "OpenMyGpuErrorHandler"},
|
||||
{120, &ICommonStateGetter::GetAppletLaunchedHistory, "GetAppletLaunchedHistory"},
|
||||
{200, nullptr, "GetOperationModeSystemInfo"},
|
||||
{300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"},
|
||||
{400, nullptr, "ActivateMigrationService"},
|
||||
{401, nullptr, "DeactivateMigrationService"},
|
||||
{500, nullptr, "DisableSleepTillShutdown"},
|
||||
{501, nullptr, "SuppressDisablingSleepTemporarily"},
|
||||
{502, nullptr, "IsSleepEnabled"},
|
||||
{503, nullptr, "IsDisablingSleepSuppressed"},
|
||||
{900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ICommonStateGetter::~ICommonStateGetter() = default;
|
||||
|
||||
void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->message_queue.GetMessageReceiveEvent());
|
||||
}
|
||||
|
||||
void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
const auto message = applet->message_queue.PopMessage();
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
||||
if (message == AppletMessageQueue::AppletMessage::None) {
|
||||
LOG_ERROR(Service_AM, "Message queue is empty");
|
||||
rb.Push(AM::ResultNoMessages);
|
||||
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u8>(applet->focus_state));
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) {
|
||||
const bool use_docked_mode{Settings::IsDockedMode()};
|
||||
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
|
||||
}
|
||||
|
||||
void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
// Sleep lock is acquired immediately.
|
||||
applet->sleep_lock_event.Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto unknown = rp.Pop<u32>();
|
||||
|
||||
LOG_INFO(Service_AM, "called, unknown={}", unknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILockAccessor>(system);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->sleep_lock_event.GetHandle());
|
||||
}
|
||||
|
||||
void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(applet->vr_mode_enabled);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->vr_mode_enabled = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "VR Mode is {}", applet->vr_mode_enabled ? "on" : "off");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
|
||||
is_lcd_backlight_off_enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->vr_mode_enabled = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->vr_mode_enabled = false;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->message_queue.GetOperationModeChangedEvent());
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
if (Settings::IsDockedMode()) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
|
||||
}
|
||||
}
|
||||
|
||||
void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
|
||||
|
||||
const auto& sm = system.ServiceManager();
|
||||
const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
|
||||
ASSERT(apm_sys != nullptr);
|
||||
|
||||
apm_sys->SetCpuBoostMode(ctx);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(0);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto system_button{rp.PopEnum<SystemButtonType>()};
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetAppletLaunchedHistory(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::shared_ptr<Applet> current_applet = applet;
|
||||
std::vector<AppletId> result;
|
||||
|
||||
const size_t count = ctx.GetWriteBufferNumElements<AppletId>();
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < count && current_applet != nullptr; i++) {
|
||||
result.push_back(current_applet->applet_id);
|
||||
current_applet = current_applet->caller_applet.lock();
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(i));
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(SysPlatformRegion::Global);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->request_exit_to_library_applet_at_execute_next_program_enabled = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
77
src/core/hle/service/am/common_state_getter.h
Normal file
77
src/core/hle/service/am/common_state_getter.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
#include "core/hle/service/am/applet_message_queue.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
public:
|
||||
explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_);
|
||||
~ICommonStateGetter() override;
|
||||
|
||||
private:
|
||||
// This is nn::oe::FocusState
|
||||
enum class FocusState : u8 {
|
||||
InFocus = 1,
|
||||
NotInFocus = 2,
|
||||
Background = 3,
|
||||
};
|
||||
|
||||
// This is nn::oe::OperationMode
|
||||
enum class OperationMode : u8 {
|
||||
Handheld = 0,
|
||||
Docked = 1,
|
||||
};
|
||||
|
||||
// This is nn::am::service::SystemButtonType
|
||||
enum class SystemButtonType {
|
||||
None,
|
||||
HomeButtonShortPressing,
|
||||
HomeButtonLongPressing,
|
||||
PowerButtonShortPressing,
|
||||
PowerButtonLongPressing,
|
||||
ShutdownSystem,
|
||||
CaptureButtonShortPressing,
|
||||
CaptureButtonLongPressing,
|
||||
};
|
||||
|
||||
enum class SysPlatformRegion : s32 {
|
||||
Global = 1,
|
||||
Terra = 2,
|
||||
};
|
||||
|
||||
void GetEventHandle(HLERequestContext& ctx);
|
||||
void ReceiveMessage(HLERequestContext& ctx);
|
||||
void GetCurrentFocusState(HLERequestContext& ctx);
|
||||
void RequestToAcquireSleepLock(HLERequestContext& ctx);
|
||||
void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
|
||||
void GetReaderLockAccessorEx(HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
|
||||
void GetOperationMode(HLERequestContext& ctx);
|
||||
void GetPerformanceMode(HLERequestContext& ctx);
|
||||
void GetBootMode(HLERequestContext& ctx);
|
||||
void IsVrModeEnabled(HLERequestContext& ctx);
|
||||
void SetVrModeEnabled(HLERequestContext& ctx);
|
||||
void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
|
||||
void BeginVrModeEx(HLERequestContext& ctx);
|
||||
void EndVrModeEx(HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolution(HLERequestContext& ctx);
|
||||
void SetCpuBoostMode(HLERequestContext& ctx);
|
||||
void GetBuiltInDisplayType(HLERequestContext& ctx);
|
||||
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
|
||||
void GetAppletLaunchedHistory(HLERequestContext& ctx);
|
||||
void GetSettingsPlatformRegion(HLERequestContext& ctx);
|
||||
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
44
src/core/hle/service/am/debug_functions.cpp
Normal file
44
src/core/hle/service/am/debug_functions.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/debug_functions.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IDebugFunctions::IDebugFunctions(Core::System& system_)
|
||||
: ServiceFramework{system_, "IDebugFunctions"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "NotifyMessageToHomeMenuForDebug"},
|
||||
{1, nullptr, "OpenMainApplication"},
|
||||
{10, nullptr, "PerformSystemButtonPressing"},
|
||||
{20, nullptr, "InvalidateTransitionLayer"},
|
||||
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
|
||||
{31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
|
||||
{40, nullptr, "GetAppletResourceUsageInfo"},
|
||||
{50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
|
||||
{51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
|
||||
{100, nullptr, "SetCpuBoostModeForApplet"},
|
||||
{101, nullptr, "CancelCpuBoostModeForApplet"},
|
||||
{110, nullptr, "PushToAppletBoundChannelForDebug"},
|
||||
{111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
|
||||
{120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
|
||||
{121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
|
||||
{122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
|
||||
{130, nullptr, "FriendInvitationSetApplicationParameter"},
|
||||
{131, nullptr, "FriendInvitationClearApplicationParameter"},
|
||||
{132, nullptr, "FriendInvitationPushApplicationParameter"},
|
||||
{140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
|
||||
{200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
|
||||
{300, nullptr, "TerminateAllRunningApplicationsForDebug"},
|
||||
{900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IDebugFunctions::~IDebugFunctions() = default;
|
||||
|
||||
} // namespace Service::AM
|
16
src/core/hle/service/am/debug_functions.h
Normal file
16
src/core/hle/service/am/debug_functions.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
|
||||
public:
|
||||
explicit IDebugFunctions(Core::System& system_);
|
||||
~IDebugFunctions() override;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
135
src/core/hle/service/am/display_controller.cpp
Normal file
135
src/core/hle/service/am/display_controller.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/display_controller.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
struct OutputParameters {
|
||||
bool was_written;
|
||||
s32 fbshare_layer_index;
|
||||
};
|
||||
|
||||
static_assert(sizeof(OutputParameters) == 8, "OutputParameters has wrong size");
|
||||
} // namespace
|
||||
|
||||
IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetLastForegroundCaptureImage"},
|
||||
{1, nullptr, "UpdateLastForegroundCaptureImage"},
|
||||
{2, nullptr, "GetLastApplicationCaptureImage"},
|
||||
{3, nullptr, "GetCallerAppletCaptureImage"},
|
||||
{4, nullptr, "UpdateCallerAppletCaptureImage"},
|
||||
{5, nullptr, "GetLastForegroundCaptureImageEx"},
|
||||
{6, nullptr, "GetLastApplicationCaptureImageEx"},
|
||||
{7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"},
|
||||
{8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
|
||||
{9, nullptr, "CopyBetweenCaptureBuffers"},
|
||||
{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
|
||||
{11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
|
||||
{12, nullptr, "AcquireLastForegroundCaptureBuffer"},
|
||||
{13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
|
||||
{14, nullptr, "AcquireCallerAppletCaptureBuffer"},
|
||||
{15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
|
||||
{16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
|
||||
{17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
|
||||
{18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
|
||||
{20, nullptr, "ClearCaptureBuffer"},
|
||||
{21, nullptr, "ClearAppletTransitionBuffer"},
|
||||
{22, &IDisplayController::AcquireLastApplicationCaptureSharedBuffer, "AcquireLastApplicationCaptureSharedBuffer"},
|
||||
{23, &IDisplayController::ReleaseLastApplicationCaptureSharedBuffer, "ReleaseLastApplicationCaptureSharedBuffer"},
|
||||
{24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"},
|
||||
{25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"},
|
||||
{26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
|
||||
{27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
|
||||
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IDisplayController::~IDisplayController() = default;
|
||||
|
||||
void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
OutputParameters params{};
|
||||
const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
|
||||
¶ms.was_written, ¶ms.fbshare_layer_index);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.PushRaw(params);
|
||||
}
|
||||
|
||||
void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IDisplayController::AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
OutputParameters params{};
|
||||
const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
|
||||
¶ms.was_written, ¶ms.fbshare_layer_index);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.PushRaw(params);
|
||||
}
|
||||
|
||||
void IDisplayController::ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
OutputParameters params{};
|
||||
const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
|
||||
¶ms.was_written, ¶ms.fbshare_layer_index);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.PushRaw(params);
|
||||
}
|
||||
|
||||
void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
OutputParameters params{};
|
||||
const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
|
||||
¶ms.was_written, ¶ms.fbshare_layer_index);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.PushRaw(params);
|
||||
}
|
||||
|
||||
void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
30
src/core/hle/service/am/display_controller.h
Normal file
30
src/core/hle/service/am/display_controller.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class IDisplayController final : public ServiceFramework<IDisplayController> {
|
||||
public:
|
||||
explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_);
|
||||
~IDisplayController() override;
|
||||
|
||||
private:
|
||||
void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
|
||||
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
|
||||
void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
|
@ -8,16 +8,17 @@
|
|||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||
#include "core/hle/service/am/frontend/applet_cabinet.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::CabinetApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{
|
||||
Cabinet::Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_)
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_}, service_context{
|
||||
system_,
|
||||
"CabinetApplet"} {
|
||||
|
||||
|
@ -30,7 +31,7 @@ Cabinet::~Cabinet() {
|
|||
};
|
||||
|
||||
void Cabinet::Initialize() {
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
|
||||
LOG_INFO(Service_HID, "Initializing Cabinet Applet.");
|
||||
|
||||
|
@ -41,7 +42,7 @@ void Cabinet::Initialize() {
|
|||
common_args.play_startup_sound, common_args.size, common_args.system_tick,
|
||||
common_args.theme_color);
|
||||
|
||||
const auto storage = broker.PopNormalDataToApplet();
|
||||
std::shared_ptr<IStorage> storage = PopInData();
|
||||
ASSERT(storage != nullptr);
|
||||
|
||||
const auto applet_input_data = storage->GetData();
|
||||
|
@ -51,10 +52,6 @@ void Cabinet::Initialize() {
|
|||
sizeof(StartParamForAmiiboSettings));
|
||||
}
|
||||
|
||||
bool Cabinet::TransactionComplete() const {
|
||||
return is_complete;
|
||||
}
|
||||
|
||||
Result Cabinet::GetStatus() const {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@ -160,8 +157,8 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
|
|||
|
||||
is_complete = true;
|
||||
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
void Cabinet::Cancel() {
|
||||
|
@ -175,8 +172,8 @@ void Cabinet::Cancel() {
|
|||
|
||||
is_complete = true;
|
||||
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result Cabinet::RequestExit() {
|
||||
|
@ -184,4 +181,4 @@ Result Cabinet::RequestExit() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -6,7 +6,7 @@
|
|||
#include <array>
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
|
||||
|
@ -23,7 +23,7 @@ namespace Service::NFC {
|
|||
class NfcDevice;
|
||||
}
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
enum class CabinetAppletVersion : u32 {
|
||||
Version1 = 0x1,
|
||||
|
@ -84,15 +84,15 @@ static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188,
|
|||
"ReturnValueForAmiiboSettings is an invalid size");
|
||||
#pragma pack(pop)
|
||||
|
||||
class Cabinet final : public Applet {
|
||||
class Cabinet final : public FrontendApplet {
|
||||
public:
|
||||
explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
explicit Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::CabinetApplet& frontend_);
|
||||
~Cabinet() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -102,7 +102,6 @@ public:
|
|||
|
||||
private:
|
||||
const Core::Frontend::CabinetApplet& frontend;
|
||||
Core::System& system;
|
||||
|
||||
bool is_complete{false};
|
||||
std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
|
||||
|
@ -111,4 +110,4 @@ private:
|
|||
StartParamForAmiiboSettings applet_input_common{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -11,13 +11,14 @@
|
|||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_controller.h"
|
||||
#include "core/hle/service/am/frontend/applet_controller.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "hid_core/frontend/emulated_controller.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/resources/npad/npad.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101};
|
||||
[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID,
|
||||
|
@ -46,14 +47,15 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
|
|||
};
|
||||
}
|
||||
|
||||
Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
Controller::Controller(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ControllerApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
|
||||
|
||||
Controller::~Controller() = default;
|
||||
|
||||
void Controller::Initialize() {
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
|
||||
LOG_INFO(Service_HID, "Initializing Controller Applet.");
|
||||
|
||||
|
@ -66,7 +68,7 @@ void Controller::Initialize() {
|
|||
|
||||
controller_applet_version = ControllerAppletVersion{common_args.library_version};
|
||||
|
||||
const auto private_arg_storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> private_arg_storage = PopInData();
|
||||
ASSERT(private_arg_storage != nullptr);
|
||||
|
||||
const auto& private_arg = private_arg_storage->GetData();
|
||||
|
@ -116,7 +118,7 @@ void Controller::Initialize() {
|
|||
switch (controller_private_arg.mode) {
|
||||
case ControllerSupportMode::ShowControllerSupport:
|
||||
case ControllerSupportMode::ShowControllerStrapGuide: {
|
||||
const auto user_arg_storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> user_arg_storage = PopInData();
|
||||
ASSERT(user_arg_storage != nullptr);
|
||||
|
||||
const auto& user_arg = user_arg_storage->GetData();
|
||||
|
@ -142,7 +144,7 @@ void Controller::Initialize() {
|
|||
break;
|
||||
}
|
||||
case ControllerSupportMode::ShowControllerFirmwareUpdate: {
|
||||
const auto update_arg_storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> update_arg_storage = PopInData();
|
||||
ASSERT(update_arg_storage != nullptr);
|
||||
|
||||
const auto& update_arg = update_arg_storage->GetData();
|
||||
|
@ -152,7 +154,7 @@ void Controller::Initialize() {
|
|||
break;
|
||||
}
|
||||
case ControllerSupportMode::ShowControllerKeyRemappingForSystem: {
|
||||
const auto remapping_arg_storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> remapping_arg_storage = PopInData();
|
||||
ASSERT(remapping_arg_storage != nullptr);
|
||||
|
||||
const auto& remapping_arg = remapping_arg_storage->GetData();
|
||||
|
@ -168,10 +170,6 @@ void Controller::Initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Controller::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
Result Controller::GetStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
@ -260,8 +258,9 @@ void Controller::ConfigurationComplete(bool is_success) {
|
|||
complete = true;
|
||||
out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
|
||||
std::memcpy(out_data.data(), &result_info, out_data.size());
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
broker.SignalStateChanged();
|
||||
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result Controller::RequestExit() {
|
||||
|
@ -269,4 +268,4 @@ Result Controller::RequestExit() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -9,7 +9,7 @@
|
|||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
@ -19,7 +19,7 @@ namespace Core::HID {
|
|||
enum class NpadStyleSet : u32;
|
||||
}
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
using IdentificationColor = std::array<u8, 4>;
|
||||
using ExplainText = std::array<char, 0x81>;
|
||||
|
@ -122,15 +122,15 @@ struct ControllerSupportResultInfo {
|
|||
static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
|
||||
"ControllerSupportResultInfo has incorrect size.");
|
||||
|
||||
class Controller final : public Applet {
|
||||
class Controller final : public FrontendApplet {
|
||||
public:
|
||||
explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
explicit Controller(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ControllerApplet& frontend_);
|
||||
~Controller() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -140,7 +140,6 @@ public:
|
|||
|
||||
private:
|
||||
const Core::Frontend::ControllerApplet& frontend;
|
||||
Core::System& system;
|
||||
|
||||
ControllerAppletVersion controller_applet_version;
|
||||
ControllerSupportArgPrivate controller_private_arg;
|
||||
|
@ -154,4 +153,4 @@ private:
|
|||
std::vector<u8> out_data;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -9,10 +9,11 @@
|
|||
#include "core/core.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_error.h"
|
||||
#include "core/hle/service/am/frontend/applet_error.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
struct ErrorCode {
|
||||
u32 error_category{};
|
||||
|
@ -103,18 +104,18 @@ Result Decode64BitError(u64 error) {
|
|||
|
||||
} // Anonymous namespace
|
||||
|
||||
Error::Error(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
Error::Error(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ErrorApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
|
||||
|
||||
Error::~Error() = default;
|
||||
|
||||
void Error::Initialize() {
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
args = std::make_unique<ErrorArguments>();
|
||||
complete = false;
|
||||
|
||||
const auto storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> storage = PopInData();
|
||||
ASSERT(storage != nullptr);
|
||||
const auto data = storage->GetData();
|
||||
|
||||
|
@ -152,10 +153,6 @@ void Error::Initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Error::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
Result Error::GetStatus() const {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@ -210,8 +207,8 @@ void Error::Execute() {
|
|||
|
||||
void Error::DisplayCompleted() {
|
||||
complete = true;
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{}));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result Error::RequestExit() {
|
||||
|
@ -219,4 +216,4 @@ Result Error::RequestExit() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -4,13 +4,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
enum class ErrorAppletMode : u8 {
|
||||
ShowError = 0,
|
||||
|
@ -22,15 +22,14 @@ enum class ErrorAppletMode : u8 {
|
|||
ShowUpdateEula = 8,
|
||||
};
|
||||
|
||||
class Error final : public Applet {
|
||||
class Error final : public FrontendApplet {
|
||||
public:
|
||||
explicit Error(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ErrorApplet& frontend_);
|
||||
explicit Error(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_);
|
||||
~Error() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -47,7 +46,6 @@ private:
|
|||
std::unique_ptr<ErrorArguments> args;
|
||||
|
||||
bool complete = false;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -5,27 +5,28 @@
|
|||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
#include "core/frontend/applets/general.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_general_backend.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/frontend/applet_general.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
|
||||
|
||||
static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
|
||||
std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet();
|
||||
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
|
||||
static void LogCurrentStorage(std::shared_ptr<Applet> applet, std::string_view prefix) {
|
||||
std::shared_ptr<IStorage> storage;
|
||||
while (R_SUCCEEDED(applet->caller_applet_broker->GetInData().Pop(&storage))) {
|
||||
const auto data = storage->GetData();
|
||||
LOG_INFO(Service_AM,
|
||||
"called (STUBBED), during {} received normal data with size={:08X}, data={}",
|
||||
prefix, data.size(), Common::HexToString(data));
|
||||
}
|
||||
|
||||
storage = broker.PopInteractiveDataToApplet();
|
||||
for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
|
||||
while (R_SUCCEEDED(applet->caller_applet_broker->GetInteractiveInData().Pop(&storage))) {
|
||||
const auto data = storage->GetData();
|
||||
LOG_INFO(Service_AM,
|
||||
"called (STUBBED), during {} received interactive data with size={:08X}, data={}",
|
||||
|
@ -33,17 +34,17 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
|
|||
}
|
||||
}
|
||||
|
||||
Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
Auth::Auth(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_,
|
||||
Core::Frontend::ParentalControlsApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
|
||||
|
||||
Auth::~Auth() = default;
|
||||
|
||||
void Auth::Initialize() {
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
complete = false;
|
||||
|
||||
const auto storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> storage = PopInData();
|
||||
ASSERT(storage != nullptr);
|
||||
const auto data = storage->GetData();
|
||||
ASSERT(data.size() >= 0xC);
|
||||
|
@ -67,10 +68,6 @@ void Auth::Initialize() {
|
|||
arg2 = arg.arg2;
|
||||
}
|
||||
|
||||
bool Auth::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
Result Auth::GetStatus() const {
|
||||
return successful ? ResultSuccess : ERROR_INVALID_PIN;
|
||||
}
|
||||
|
@ -146,8 +143,8 @@ void Auth::AuthFinished(bool is_successful) {
|
|||
std::vector<u8> out(sizeof(Return));
|
||||
std::memcpy(out.data(), &return_, sizeof(Return));
|
||||
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out)));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result Auth::RequestExit() {
|
||||
|
@ -155,27 +152,24 @@ Result Auth::RequestExit() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
PhotoViewer::PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::PhotoViewerApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
|
||||
|
||||
PhotoViewer::~PhotoViewer() = default;
|
||||
|
||||
void PhotoViewer::Initialize() {
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
complete = false;
|
||||
|
||||
const auto storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> storage = PopInData();
|
||||
ASSERT(storage != nullptr);
|
||||
const auto data = storage->GetData();
|
||||
ASSERT(!data.empty());
|
||||
mode = static_cast<PhotoViewerAppletMode>(data[0]);
|
||||
}
|
||||
|
||||
bool PhotoViewer::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
Result PhotoViewer::GetStatus() const {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@ -203,8 +197,8 @@ void PhotoViewer::Execute() {
|
|||
}
|
||||
|
||||
void PhotoViewer::ViewFinished() {
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{}));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::vector<u8>{}));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result PhotoViewer::RequestExit() {
|
||||
|
@ -212,27 +206,17 @@ Result PhotoViewer::RequestExit() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_)
|
||||
: Applet{system_, applet_mode_}, id{id_}, system{system_} {}
|
||||
StubApplet::StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_,
|
||||
LibraryAppletMode applet_mode_)
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, id{id_} {}
|
||||
|
||||
StubApplet::~StubApplet() = default;
|
||||
|
||||
void StubApplet::Initialize() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
|
||||
const auto data = broker.PeekDataToAppletForDebug();
|
||||
system.GetReporter().SaveUnimplementedAppletReport(
|
||||
static_cast<u32>(id), static_cast<u32>(common_args.arguments_version),
|
||||
common_args.library_version, static_cast<u32>(common_args.theme_color),
|
||||
common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive);
|
||||
|
||||
LogCurrentStorage(broker, "Initialize");
|
||||
}
|
||||
|
||||
bool StubApplet::TransactionComplete() const {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
return true;
|
||||
LogCurrentStorage(applet.lock(), "Initialize");
|
||||
}
|
||||
|
||||
Result StubApplet::GetStatus() const {
|
||||
|
@ -242,22 +226,20 @@ Result StubApplet::GetStatus() const {
|
|||
|
||||
void StubApplet::ExecuteInteractive() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
LogCurrentStorage(broker, "ExecuteInteractive");
|
||||
LogCurrentStorage(applet.lock(), "ExecuteInteractive");
|
||||
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
broker.PushInteractiveDataFromApplet(
|
||||
std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
void StubApplet::Execute() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
LogCurrentStorage(broker, "Execute");
|
||||
LogCurrentStorage(applet.lock(), "Execute");
|
||||
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
broker.PushInteractiveDataFromApplet(
|
||||
std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result StubApplet::RequestExit() {
|
||||
|
@ -265,4 +247,4 @@ Result StubApplet::RequestExit() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
enum class AuthAppletType : u32 {
|
||||
ShowParentalAuthentication,
|
||||
|
@ -17,14 +17,14 @@ enum class AuthAppletType : u32 {
|
|||
ChangeParentalPasscode,
|
||||
};
|
||||
|
||||
class Auth final : public Applet {
|
||||
class Auth final : public FrontendApplet {
|
||||
public:
|
||||
explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
explicit Auth(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
Core::Frontend::ParentalControlsApplet& frontend_);
|
||||
~Auth() override;
|
||||
|
||||
void Initialize() override;
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -34,7 +34,6 @@ public:
|
|||
|
||||
private:
|
||||
Core::Frontend::ParentalControlsApplet& frontend;
|
||||
Core::System& system;
|
||||
bool complete = false;
|
||||
bool successful = false;
|
||||
|
||||
|
@ -49,14 +48,14 @@ enum class PhotoViewerAppletMode : u8 {
|
|||
AllApps = 1,
|
||||
};
|
||||
|
||||
class PhotoViewer final : public Applet {
|
||||
class PhotoViewer final : public FrontendApplet {
|
||||
public:
|
||||
explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
explicit PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::PhotoViewerApplet& frontend_);
|
||||
~PhotoViewer() override;
|
||||
|
||||
void Initialize() override;
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -68,17 +67,16 @@ private:
|
|||
const Core::Frontend::PhotoViewerApplet& frontend;
|
||||
bool complete = false;
|
||||
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
class StubApplet final : public Applet {
|
||||
class StubApplet final : public FrontendApplet {
|
||||
public:
|
||||
explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_);
|
||||
explicit StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_,
|
||||
LibraryAppletMode applet_mode_);
|
||||
~StubApplet() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -86,7 +84,6 @@ public:
|
|||
|
||||
private:
|
||||
AppletId id;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -6,16 +6,17 @@
|
|||
#include "core/core.h"
|
||||
#include "core/frontend/applets/mii_edit.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_mii_edit.h"
|
||||
#include "core/hle/service/am/frontend/applet_mii_edit.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/mii/mii.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::MiiEditApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
MiiEdit::MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_)
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
|
||||
|
||||
MiiEdit::~MiiEdit() = default;
|
||||
|
||||
|
@ -24,7 +25,7 @@ void MiiEdit::Initialize() {
|
|||
// Instead, it is initialized by an AppletInput storage with size 0x100 bytes.
|
||||
// Do NOT call Applet::Initialize() here.
|
||||
|
||||
const auto storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> storage = PopInData();
|
||||
ASSERT(storage != nullptr);
|
||||
|
||||
const auto applet_input_data = storage->GetData();
|
||||
|
@ -66,10 +67,6 @@ void MiiEdit::Initialize() {
|
|||
manager->Initialize(metadata);
|
||||
}
|
||||
|
||||
bool MiiEdit::TransactionComplete() const {
|
||||
return is_complete;
|
||||
}
|
||||
|
||||
Result MiiEdit::GetStatus() const {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@ -152,8 +149,8 @@ void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) {
|
|||
|
||||
is_complete = true;
|
||||
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
|
||||
|
@ -168,8 +165,8 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
|
|||
|
||||
is_complete = true;
|
||||
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result MiiEdit::RequestExit() {
|
||||
|
@ -177,4 +174,4 @@ Result MiiEdit::RequestExit() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -4,8 +4,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
@ -16,17 +16,17 @@ struct DatabaseSessionMetadata;
|
|||
class MiiManager;
|
||||
} // namespace Service::Mii
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
class MiiEdit final : public Applet {
|
||||
class MiiEdit final : public FrontendApplet {
|
||||
public:
|
||||
explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
explicit MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::MiiEditApplet& frontend_);
|
||||
~MiiEdit() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -38,7 +38,6 @@ public:
|
|||
|
||||
private:
|
||||
const Core::Frontend::MiiEditApplet& frontend;
|
||||
Core::System& system;
|
||||
|
||||
MiiEditAppletInputCommon applet_input_common{};
|
||||
MiiEditAppletInputV3 applet_input_v3{};
|
||||
|
@ -49,4 +48,4 @@ private:
|
|||
Mii::DatabaseSessionMetadata metadata{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -10,7 +10,7 @@
|
|||
#include "common/uuid.h"
|
||||
#include "core/hle/service/mii/types/char_info.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
enum class MiiEditAppletVersion : s32 {
|
||||
Version3 = 0x3, // 1.0.0 - 10.1.1
|
||||
|
@ -80,4 +80,4 @@ struct MiiEditAppletOutputForCharInfoEditing {
|
|||
static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80,
|
||||
"MiiEditAppletOutputForCharInfoEditing has incorrect size.");
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -9,13 +9,15 @@
|
|||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/hle/service/acc/errors.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||
#include "core/hle/service/am/frontend/applet_profile_select.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
ProfileSelect::ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ProfileSelectApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
|
||||
|
||||
ProfileSelect::~ProfileSelect() = default;
|
||||
|
||||
|
@ -24,10 +26,10 @@ void ProfileSelect::Initialize() {
|
|||
status = ResultSuccess;
|
||||
final_data.clear();
|
||||
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
profile_select_version = ProfileSelectAppletVersion{common_args.library_version};
|
||||
|
||||
const auto user_config_storage = broker.PopNormalDataToApplet();
|
||||
const std::shared_ptr<IStorage> user_config_storage = PopInData();
|
||||
ASSERT(user_config_storage != nullptr);
|
||||
const auto& user_config = user_config_storage->GetData();
|
||||
|
||||
|
@ -50,10 +52,6 @@ void ProfileSelect::Initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
bool ProfileSelect::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
Result ProfileSelect::GetStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
@ -64,7 +62,8 @@ void ProfileSelect::ExecuteInteractive() {
|
|||
|
||||
void ProfileSelect::Execute() {
|
||||
if (complete) {
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(final_data)));
|
||||
Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -111,8 +110,9 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
|
|||
|
||||
final_data = std::vector<u8>(sizeof(UiReturnArg));
|
||||
std::memcpy(final_data.data(), &output, final_data.size());
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
|
||||
broker.SignalStateChanged();
|
||||
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(final_data)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result ProfileSelect::RequestExit() {
|
||||
|
@ -120,4 +120,4 @@ Result ProfileSelect::RequestExit() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -8,13 +8,13 @@
|
|||
#include "common/common_funcs.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
enum class ProfileSelectAppletVersion : u32 {
|
||||
Version1 = 0x1, // 1.0.0+
|
||||
|
@ -111,15 +111,15 @@ struct UiReturnArg {
|
|||
};
|
||||
static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size.");
|
||||
|
||||
class ProfileSelect final : public Applet {
|
||||
class ProfileSelect final : public FrontendApplet {
|
||||
public:
|
||||
explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
explicit ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ProfileSelectApplet& frontend_);
|
||||
~ProfileSelect() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -137,7 +137,6 @@ private:
|
|||
bool complete = false;
|
||||
Result status = ResultSuccess;
|
||||
std::vector<u8> final_data;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -5,9 +5,10 @@
|
|||
#include "core/core.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard.h"
|
||||
#include "core/hle/service/am/frontend/applet_software_keyboard.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -41,14 +42,15 @@ void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply
|
|||
|
||||
} // Anonymous namespace
|
||||
|
||||
SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
Core::Frontend::SoftwareKeyboardApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
|
||||
|
||||
SoftwareKeyboard::~SoftwareKeyboard() = default;
|
||||
|
||||
void SoftwareKeyboard::Initialize() {
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
|
||||
LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}",
|
||||
applet_mode);
|
||||
|
@ -76,10 +78,6 @@ void SoftwareKeyboard::Initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
bool SoftwareKeyboard::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
Result SoftwareKeyboard::GetStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
@ -184,7 +182,7 @@ void SoftwareKeyboard::InitializeForeground() {
|
|||
|
||||
is_background = false;
|
||||
|
||||
const auto swkbd_config_storage = broker.PopNormalDataToApplet();
|
||||
const auto swkbd_config_storage = PopInData();
|
||||
ASSERT(swkbd_config_storage != nullptr);
|
||||
|
||||
const auto& swkbd_config_data = swkbd_config_storage->GetData();
|
||||
|
@ -221,7 +219,7 @@ void SoftwareKeyboard::InitializeForeground() {
|
|||
break;
|
||||
}
|
||||
|
||||
const auto work_buffer_storage = broker.PopNormalDataToApplet();
|
||||
const auto work_buffer_storage = PopInData();
|
||||
ASSERT(work_buffer_storage != nullptr);
|
||||
|
||||
if (swkbd_config_common.initial_string_length == 0) {
|
||||
|
@ -250,7 +248,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
|
|||
|
||||
is_background = true;
|
||||
|
||||
const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet();
|
||||
const auto swkbd_inline_initialize_arg_storage = PopInData();
|
||||
ASSERT(swkbd_inline_initialize_arg_storage != nullptr);
|
||||
|
||||
const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData();
|
||||
|
@ -267,7 +265,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
|
|||
}
|
||||
|
||||
void SoftwareKeyboard::ProcessTextCheck() {
|
||||
const auto text_check_storage = broker.PopInteractiveDataToApplet();
|
||||
const auto text_check_storage = PopInteractiveInData();
|
||||
ASSERT(text_check_storage != nullptr);
|
||||
|
||||
const auto& text_check_data = text_check_storage->GetData();
|
||||
|
@ -314,7 +312,7 @@ void SoftwareKeyboard::ProcessTextCheck() {
|
|||
}
|
||||
|
||||
void SoftwareKeyboard::ProcessInlineKeyboardRequest() {
|
||||
const auto request_data_storage = broker.PopInteractiveDataToApplet();
|
||||
const auto request_data_storage = PopInteractiveInData();
|
||||
ASSERT(request_data_storage != nullptr);
|
||||
|
||||
const auto& request_data = request_data_storage->GetData();
|
||||
|
@ -377,7 +375,7 @@ void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result,
|
|||
submitted_text.size() * sizeof(char16_t));
|
||||
}
|
||||
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
|
||||
ExitKeyboard();
|
||||
}
|
||||
|
@ -410,7 +408,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
|
|||
current_text.size() * sizeof(char16_t));
|
||||
}
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) {
|
||||
|
@ -767,7 +765,7 @@ void SoftwareKeyboard::ExitKeyboard() {
|
|||
|
||||
frontend.ExitKeyboard();
|
||||
|
||||
broker.SignalStateChanged();
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result SoftwareKeyboard::RequestExit() {
|
||||
|
@ -967,7 +965,7 @@ void SoftwareKeyboard::ReplyFinishedInitialize() {
|
|||
|
||||
SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyDefault() {
|
||||
|
@ -977,7 +975,7 @@ void SoftwareKeyboard::ReplyDefault() {
|
|||
|
||||
SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyChangedString() {
|
||||
|
@ -999,7 +997,7 @@ void SoftwareKeyboard::ReplyChangedString() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
|
||||
sizeof(SwkbdChangedStringArg));
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyMovedCursor() {
|
||||
|
@ -1019,7 +1017,7 @@ void SoftwareKeyboard::ReplyMovedCursor() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
|
||||
sizeof(SwkbdMovedCursorArg));
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyMovedTab() {
|
||||
|
@ -1039,7 +1037,7 @@ void SoftwareKeyboard::ReplyMovedTab() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg,
|
||||
sizeof(SwkbdMovedTabArg));
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyDecidedEnter() {
|
||||
|
@ -1058,7 +1056,7 @@ void SoftwareKeyboard::ReplyDecidedEnter() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg,
|
||||
sizeof(SwkbdDecidedEnterArg));
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
|
||||
HideInlineKeyboard();
|
||||
}
|
||||
|
@ -1070,7 +1068,7 @@ void SoftwareKeyboard::ReplyDecidedCancel() {
|
|||
|
||||
SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
|
||||
HideInlineKeyboard();
|
||||
}
|
||||
|
@ -1095,7 +1093,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
|
||||
sizeof(SwkbdChangedStringArg));
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyMovedCursorUtf8() {
|
||||
|
@ -1116,7 +1114,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
|
||||
sizeof(SwkbdMovedCursorArg));
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
|
||||
|
@ -1136,7 +1134,7 @@ void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg,
|
||||
sizeof(SwkbdDecidedEnterArg));
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
|
||||
HideInlineKeyboard();
|
||||
}
|
||||
|
@ -1148,7 +1146,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizeDic() {
|
|||
|
||||
SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
|
||||
|
@ -1158,7 +1156,7 @@ void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
|
|||
|
||||
SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
|
||||
|
@ -1168,7 +1166,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
|
|||
|
||||
SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyChangedStringV2() {
|
||||
|
@ -1194,7 +1192,7 @@ void SoftwareKeyboard::ReplyChangedStringV2() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg),
|
||||
&flag, 1);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyMovedCursorV2() {
|
||||
|
@ -1218,7 +1216,7 @@ void SoftwareKeyboard::ReplyMovedCursorV2() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg),
|
||||
&flag, 1);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
|
||||
|
@ -1245,7 +1243,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg),
|
||||
&flag, 1);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
|
||||
|
@ -1270,7 +1268,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
|
|||
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg),
|
||||
&flag, 1);
|
||||
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
@ -17,17 +17,17 @@ struct KeyboardInitializeParameters;
|
|||
struct InlineAppearParameters;
|
||||
} // namespace Core::Frontend
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
class SoftwareKeyboard final : public Applet {
|
||||
class SoftwareKeyboard final : public FrontendApplet {
|
||||
public:
|
||||
explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
explicit SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
Core::Frontend::SoftwareKeyboardApplet& frontend_);
|
||||
~SoftwareKeyboard() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -156,7 +156,6 @@ private:
|
|||
void ReplyMovedCursorUtf8V2();
|
||||
|
||||
Core::Frontend::SoftwareKeyboardApplet& frontend;
|
||||
Core::System& system;
|
||||
|
||||
SwkbdAppletVersion swkbd_applet_version;
|
||||
|
||||
|
@ -184,4 +183,4 @@ private:
|
|||
Result status{ResultSuccess};
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -11,7 +11,7 @@
|
|||
#include "common/swap.h"
|
||||
#include "common/uuid.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
|
||||
constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
|
||||
|
@ -351,4 +351,4 @@ struct SwkbdDecidedEnterArg {
|
|||
};
|
||||
static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size.");
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -19,12 +19,13 @@
|
|||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser.h"
|
||||
#include "core/hle/service/am/frontend/applet_web_browser.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ns/iplatform_service_manager.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -223,14 +224,15 @@ void ExtractSharedFonts(Core::System& system) {
|
|||
|
||||
} // namespace
|
||||
|
||||
WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::WebBrowserApplet& frontend_)
|
||||
: Applet{system_, applet_mode_}, frontend(frontend_), system{system_} {}
|
||||
: FrontendApplet{system_, applet_, applet_mode_}, frontend(frontend_) {}
|
||||
|
||||
WebBrowser::~WebBrowser() = default;
|
||||
|
||||
void WebBrowser::Initialize() {
|
||||
Applet::Initialize();
|
||||
FrontendApplet::Initialize();
|
||||
|
||||
LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
|
||||
|
||||
|
@ -243,7 +245,7 @@ void WebBrowser::Initialize() {
|
|||
|
||||
web_applet_version = WebAppletVersion{common_args.library_version};
|
||||
|
||||
const auto web_arg_storage = broker.PopNormalDataToApplet();
|
||||
const auto web_arg_storage = PopInData();
|
||||
ASSERT(web_arg_storage != nullptr);
|
||||
|
||||
const auto& web_arg = web_arg_storage->GetData();
|
||||
|
@ -284,10 +286,6 @@ void WebBrowser::Initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
bool WebBrowser::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
Result WebBrowser::GetStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
@ -358,8 +356,8 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url)
|
|||
complete = true;
|
||||
std::vector<u8> out_data(sizeof(WebCommonReturnValue));
|
||||
std::memcpy(out_data.data(), &web_common_return_value, out_data.size());
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
broker.SignalStateChanged();
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
Exit();
|
||||
}
|
||||
|
||||
Result WebBrowser::RequestExit() {
|
||||
|
@ -504,4 +502,4 @@ void WebBrowser::ExecuteLobby() {
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
|
||||
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||
}
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -9,8 +9,8 @@
|
|||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser_types.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applet_web_browser_types.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
@ -20,18 +20,17 @@ namespace FileSys {
|
|||
enum class ContentRecordType : u8;
|
||||
}
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
class WebBrowser final : public Applet {
|
||||
class WebBrowser final : public FrontendApplet {
|
||||
public:
|
||||
WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::WebBrowserApplet& frontend_);
|
||||
WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_);
|
||||
|
||||
~WebBrowser() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
Result GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
@ -80,8 +79,6 @@ private:
|
|||
FileSys::VirtualFile offline_romfs;
|
||||
|
||||
std::string external_url;
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
|
@ -11,7 +11,7 @@
|
|||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
enum class WebAppletVersion : u32_le {
|
||||
Version0 = 0x0, // Only used by WifiWebAuthApplet
|
||||
|
@ -174,4 +174,4 @@ static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has
|
|||
|
||||
using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>;
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
} // namespace Service::AM::Frontend
|
240
src/core/hle/service/am/frontend/applets.cpp
Normal file
240
src/core/hle/service/am/frontend/applets.cpp
Normal file
|
@ -0,0 +1,240 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/cabinet.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/frontend/applets/general.h"
|
||||
#include "core/frontend/applets/mii_edit.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/applet_message_queue.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/frontend/applet_cabinet.h"
|
||||
#include "core/hle/service/am/frontend/applet_controller.h"
|
||||
#include "core/hle/service/am/frontend/applet_error.h"
|
||||
#include "core/hle/service/am/frontend/applet_general.h"
|
||||
#include "core/hle/service/am/frontend/applet_mii_edit.h"
|
||||
#include "core/hle/service/am/frontend/applet_profile_select.h"
|
||||
#include "core/hle/service/am/frontend/applet_software_keyboard.h"
|
||||
#include "core/hle/service/am/frontend/applet_web_browser.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM::Frontend {
|
||||
|
||||
FrontendApplet::FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_)
|
||||
: system{system_}, applet{std::move(applet_)}, applet_mode{applet_mode_} {}
|
||||
|
||||
FrontendApplet::~FrontendApplet() = default;
|
||||
|
||||
void FrontendApplet::Initialize() {
|
||||
std::shared_ptr<IStorage> common = PopInData();
|
||||
ASSERT(common != nullptr);
|
||||
const auto common_data = common->GetData();
|
||||
|
||||
ASSERT(common_data.size() >= sizeof(CommonArguments));
|
||||
std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
std::shared_ptr<IStorage> FrontendApplet::PopInData() {
|
||||
std::shared_ptr<IStorage> ret;
|
||||
applet.lock()->caller_applet_broker->GetInData().Pop(&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<IStorage> FrontendApplet::PopInteractiveInData() {
|
||||
std::shared_ptr<IStorage> ret;
|
||||
applet.lock()->caller_applet_broker->GetInteractiveInData().Pop(&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FrontendApplet::PushOutData(std::shared_ptr<IStorage> storage) {
|
||||
applet.lock()->caller_applet_broker->GetOutData().Push(storage);
|
||||
}
|
||||
|
||||
void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
|
||||
applet.lock()->caller_applet_broker->GetInteractiveOutData().Push(storage);
|
||||
}
|
||||
|
||||
void FrontendApplet::Exit() {
|
||||
applet.lock()->caller_applet_broker->SignalCompletion();
|
||||
}
|
||||
|
||||
FrontendAppletSet::FrontendAppletSet() = default;
|
||||
|
||||
FrontendAppletSet::FrontendAppletSet(CabinetApplet cabinet_applet,
|
||||
ControllerApplet controller_applet, ErrorApplet error_applet,
|
||||
MiiEdit mii_edit_,
|
||||
ParentalControlsApplet parental_controls_applet,
|
||||
PhotoViewer photo_viewer_, ProfileSelect profile_select_,
|
||||
SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
|
||||
: cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
|
||||
error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
|
||||
parental_controls{std::move(parental_controls_applet)},
|
||||
photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
|
||||
software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
|
||||
|
||||
FrontendAppletSet::~FrontendAppletSet() = default;
|
||||
|
||||
FrontendAppletSet::FrontendAppletSet(FrontendAppletSet&&) noexcept = default;
|
||||
|
||||
FrontendAppletSet& FrontendAppletSet::operator=(FrontendAppletSet&&) noexcept = default;
|
||||
|
||||
FrontendAppletHolder::FrontendAppletHolder(Core::System& system_) : system{system_} {}
|
||||
|
||||
FrontendAppletHolder::~FrontendAppletHolder() = default;
|
||||
|
||||
const FrontendAppletSet& FrontendAppletHolder::GetFrontendAppletSet() const {
|
||||
return frontend;
|
||||
}
|
||||
|
||||
NFP::CabinetMode FrontendAppletHolder::GetCabinetMode() const {
|
||||
return cabinet_mode;
|
||||
}
|
||||
|
||||
AppletId FrontendAppletHolder::GetCurrentAppletId() const {
|
||||
return current_applet_id;
|
||||
}
|
||||
|
||||
void FrontendAppletHolder::SetFrontendAppletSet(FrontendAppletSet set) {
|
||||
if (set.cabinet != nullptr) {
|
||||
frontend.cabinet = std::move(set.cabinet);
|
||||
}
|
||||
|
||||
if (set.controller != nullptr) {
|
||||
frontend.controller = std::move(set.controller);
|
||||
}
|
||||
|
||||
if (set.error != nullptr) {
|
||||
frontend.error = std::move(set.error);
|
||||
}
|
||||
|
||||
if (set.mii_edit != nullptr) {
|
||||
frontend.mii_edit = std::move(set.mii_edit);
|
||||
}
|
||||
|
||||
if (set.parental_controls != nullptr) {
|
||||
frontend.parental_controls = std::move(set.parental_controls);
|
||||
}
|
||||
|
||||
if (set.photo_viewer != nullptr) {
|
||||
frontend.photo_viewer = std::move(set.photo_viewer);
|
||||
}
|
||||
|
||||
if (set.profile_select != nullptr) {
|
||||
frontend.profile_select = std::move(set.profile_select);
|
||||
}
|
||||
|
||||
if (set.software_keyboard != nullptr) {
|
||||
frontend.software_keyboard = std::move(set.software_keyboard);
|
||||
}
|
||||
|
||||
if (set.web_browser != nullptr) {
|
||||
frontend.web_browser = std::move(set.web_browser);
|
||||
}
|
||||
}
|
||||
|
||||
void FrontendAppletHolder::SetCabinetMode(NFP::CabinetMode mode) {
|
||||
cabinet_mode = mode;
|
||||
}
|
||||
|
||||
void FrontendAppletHolder::SetCurrentAppletId(AppletId applet_id) {
|
||||
current_applet_id = applet_id;
|
||||
}
|
||||
|
||||
void FrontendAppletHolder::SetDefaultAppletsIfMissing() {
|
||||
if (frontend.cabinet == nullptr) {
|
||||
frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
|
||||
}
|
||||
|
||||
if (frontend.controller == nullptr) {
|
||||
frontend.controller =
|
||||
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
|
||||
}
|
||||
|
||||
if (frontend.error == nullptr) {
|
||||
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
|
||||
}
|
||||
|
||||
if (frontend.mii_edit == nullptr) {
|
||||
frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>();
|
||||
}
|
||||
|
||||
if (frontend.parental_controls == nullptr) {
|
||||
frontend.parental_controls =
|
||||
std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
|
||||
}
|
||||
|
||||
if (frontend.photo_viewer == nullptr) {
|
||||
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
|
||||
}
|
||||
|
||||
if (frontend.profile_select == nullptr) {
|
||||
frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
|
||||
}
|
||||
|
||||
if (frontend.software_keyboard == nullptr) {
|
||||
frontend.software_keyboard =
|
||||
std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
|
||||
}
|
||||
|
||||
if (frontend.web_browser == nullptr) {
|
||||
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
|
||||
}
|
||||
}
|
||||
|
||||
void FrontendAppletHolder::ClearAll() {
|
||||
frontend = {};
|
||||
}
|
||||
|
||||
std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<Applet> applet,
|
||||
AppletId id,
|
||||
LibraryAppletMode mode) const {
|
||||
switch (id) {
|
||||
case AppletId::Auth:
|
||||
return std::make_shared<Auth>(system, applet, mode, *frontend.parental_controls);
|
||||
case AppletId::Cabinet:
|
||||
return std::make_shared<Cabinet>(system, applet, mode, *frontend.cabinet);
|
||||
case AppletId::Controller:
|
||||
return std::make_shared<Controller>(system, applet, mode, *frontend.controller);
|
||||
case AppletId::Error:
|
||||
return std::make_shared<Error>(system, applet, mode, *frontend.error);
|
||||
case AppletId::ProfileSelect:
|
||||
return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select);
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<SoftwareKeyboard>(system, applet, mode,
|
||||
*frontend.software_keyboard);
|
||||
case AppletId::MiiEdit:
|
||||
return std::make_shared<MiiEdit>(system, applet, mode, *frontend.mii_edit);
|
||||
case AppletId::Web:
|
||||
case AppletId::Shop:
|
||||
case AppletId::OfflineWeb:
|
||||
case AppletId::LoginShare:
|
||||
case AppletId::WebAuth:
|
||||
return std::make_shared<WebBrowser>(system, applet, mode, *frontend.web_browser);
|
||||
case AppletId::PhotoViewer:
|
||||
return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
|
||||
default:
|
||||
UNIMPLEMENTED_MSG(
|
||||
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
|
||||
static_cast<u8>(id));
|
||||
return std::make_shared<StubApplet>(system, applet, id, mode);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Frontend
|
146
src/core/hle/service/am/frontend/applets.h
Normal file
146
src/core/hle/service/am/frontend/applets.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
|
||||
union Result;
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::Frontend {
|
||||
class CabinetApplet;
|
||||
class ControllerApplet;
|
||||
class ECommerceApplet;
|
||||
class ErrorApplet;
|
||||
class MiiEditApplet;
|
||||
class ParentalControlsApplet;
|
||||
class PhotoViewerApplet;
|
||||
class ProfileSelectApplet;
|
||||
class SoftwareKeyboardApplet;
|
||||
class WebBrowserApplet;
|
||||
} // namespace Core::Frontend
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::NFP {
|
||||
enum class CabinetMode : u8;
|
||||
} // namespace Service::NFP
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IStorage;
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
class FrontendApplet {
|
||||
public:
|
||||
explicit FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
LibraryAppletMode applet_mode_);
|
||||
virtual ~FrontendApplet();
|
||||
|
||||
virtual void Initialize();
|
||||
|
||||
virtual Result GetStatus() const = 0;
|
||||
virtual void ExecuteInteractive() = 0;
|
||||
virtual void Execute() = 0;
|
||||
virtual Result RequestExit() = 0;
|
||||
|
||||
LibraryAppletMode GetLibraryAppletMode() const {
|
||||
return applet_mode;
|
||||
}
|
||||
|
||||
bool IsInitialized() const {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<IStorage> PopInData();
|
||||
std::shared_ptr<IStorage> PopInteractiveInData();
|
||||
void PushOutData(std::shared_ptr<IStorage> storage);
|
||||
void PushInteractiveOutData(std::shared_ptr<IStorage> storage);
|
||||
void Exit();
|
||||
|
||||
protected:
|
||||
Core::System& system;
|
||||
CommonArguments common_args{};
|
||||
std::weak_ptr<Applet> applet{};
|
||||
LibraryAppletMode applet_mode{};
|
||||
bool initialized{false};
|
||||
};
|
||||
|
||||
struct FrontendAppletSet {
|
||||
using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
|
||||
using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
|
||||
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
|
||||
using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
|
||||
using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
|
||||
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
|
||||
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
|
||||
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
|
||||
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
|
||||
|
||||
FrontendAppletSet();
|
||||
FrontendAppletSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
|
||||
ErrorApplet error_applet, MiiEdit mii_edit_,
|
||||
ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
|
||||
ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
|
||||
WebBrowser web_browser_);
|
||||
~FrontendAppletSet();
|
||||
|
||||
FrontendAppletSet(const FrontendAppletSet&) = delete;
|
||||
FrontendAppletSet& operator=(const FrontendAppletSet&) = delete;
|
||||
|
||||
FrontendAppletSet(FrontendAppletSet&&) noexcept;
|
||||
FrontendAppletSet& operator=(FrontendAppletSet&&) noexcept;
|
||||
|
||||
CabinetApplet cabinet;
|
||||
ControllerApplet controller;
|
||||
ErrorApplet error;
|
||||
MiiEdit mii_edit;
|
||||
ParentalControlsApplet parental_controls;
|
||||
PhotoViewer photo_viewer;
|
||||
ProfileSelect profile_select;
|
||||
SoftwareKeyboard software_keyboard;
|
||||
WebBrowser web_browser;
|
||||
};
|
||||
|
||||
class FrontendAppletHolder {
|
||||
public:
|
||||
explicit FrontendAppletHolder(Core::System& system_);
|
||||
~FrontendAppletHolder();
|
||||
|
||||
const FrontendAppletSet& GetFrontendAppletSet() const;
|
||||
NFP::CabinetMode GetCabinetMode() const;
|
||||
AppletId GetCurrentAppletId() const;
|
||||
|
||||
void SetFrontendAppletSet(FrontendAppletSet set);
|
||||
void SetCabinetMode(NFP::CabinetMode mode);
|
||||
void SetCurrentAppletId(AppletId applet_id);
|
||||
void SetDefaultAppletsIfMissing();
|
||||
void ClearAll();
|
||||
|
||||
std::shared_ptr<FrontendApplet> GetApplet(std::shared_ptr<Applet> applet, AppletId id,
|
||||
LibraryAppletMode mode) const;
|
||||
|
||||
private:
|
||||
AppletId current_applet_id{};
|
||||
NFP::CabinetMode cabinet_mode{};
|
||||
|
||||
FrontendAppletSet frontend;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Frontend
|
||||
} // namespace Service::AM
|
34
src/core/hle/service/am/global_state_controller.cpp
Normal file
34
src/core/hle/service/am/global_state_controller.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/global_state_controller.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IGlobalStateController::IGlobalStateController(Core::System& system_)
|
||||
: ServiceFramework{system_, "IGlobalStateController"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "RequestToEnterSleep"},
|
||||
{1, nullptr, "EnterSleep"},
|
||||
{2, nullptr, "StartSleepSequence"},
|
||||
{3, nullptr, "StartShutdownSequence"},
|
||||
{4, nullptr, "StartRebootSequence"},
|
||||
{9, nullptr, "IsAutoPowerDownRequested"},
|
||||
{10, nullptr, "LoadAndApplyIdlePolicySettings"},
|
||||
{11, nullptr, "NotifyCecSettingsChanged"},
|
||||
{12, nullptr, "SetDefaultHomeButtonLongPressTime"},
|
||||
{13, nullptr, "UpdateDefaultDisplayResolution"},
|
||||
{14, nullptr, "ShouldSleepOnBoot"},
|
||||
{15, nullptr, "GetHdcpAuthenticationFailedEvent"},
|
||||
{30, nullptr, "OpenCradleFirmwareUpdater"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IGlobalStateController::~IGlobalStateController() = default;
|
||||
|
||||
} // namespace Service::AM
|
16
src/core/hle/service/am/global_state_controller.h
Normal file
16
src/core/hle/service/am/global_state_controller.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
|
||||
public:
|
||||
explicit IGlobalStateController(Core::System& system_);
|
||||
~IGlobalStateController() override;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
35
src/core/hle/service/am/hid_registration.cpp
Normal file
35
src/core/hle/service/am/hid_registration.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/hid_registration.h"
|
||||
#include "core/hle/service/am/process.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "hid_core/resource_manager.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) {
|
||||
m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid");
|
||||
|
||||
if (m_process.IsInitialized()) {
|
||||
m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
HidRegistration::~HidRegistration() {
|
||||
if (m_process.IsInitialized()) {
|
||||
m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId(
|
||||
m_process.GetProcessId());
|
||||
}
|
||||
}
|
||||
|
||||
void HidRegistration::EnableAppletToGetInput(bool enable) {
|
||||
if (m_process.IsInitialized()) {
|
||||
m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
32
src/core/hle/service/am/hid_registration.h
Normal file
32
src/core/hle/service/am/hid_registration.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class IHidServer;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class Process;
|
||||
|
||||
class HidRegistration {
|
||||
public:
|
||||
explicit HidRegistration(Core::System& system, Process& process);
|
||||
~HidRegistration();
|
||||
|
||||
void EnableAppletToGetInput(bool enable);
|
||||
|
||||
private:
|
||||
Process& m_process;
|
||||
std::shared_ptr<Service::HID::IHidServer> m_hid_server;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
57
src/core/hle/service/am/home_menu_functions.cpp
Normal file
57
src/core/hle/service/am/home_menu_functions.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/home_menu_functions.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
|
||||
: ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system,
|
||||
"IHomeMenuFunctions"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
|
||||
{11, nullptr, "LockForeground"},
|
||||
{12, nullptr, "UnlockForeground"},
|
||||
{20, nullptr, "PopFromGeneralChannel"},
|
||||
{21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
|
||||
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
|
||||
{31, nullptr, "GetWriterLockAccessorEx"},
|
||||
{40, nullptr, "IsSleepEnabled"},
|
||||
{41, nullptr, "IsRebootEnabled"},
|
||||
{50, nullptr, "LaunchSystemApplet"},
|
||||
{51, nullptr, "LaunchStarter"},
|
||||
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
|
||||
{110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
|
||||
{200, nullptr, "LaunchDevMenu"},
|
||||
{1000, nullptr, "SetLastApplicationExitReason"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
pop_from_general_channel_event =
|
||||
service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent");
|
||||
}
|
||||
|
||||
IHomeMenuFunctions::~IHomeMenuFunctions() {
|
||||
service_context.CloseEvent(pop_from_general_channel_event);
|
||||
}
|
||||
|
||||
void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
25
src/core/hle/service/am/home_menu_functions.h
Normal file
25
src/core/hle/service/am/home_menu_functions.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
|
||||
public:
|
||||
explicit IHomeMenuFunctions(Core::System& system_);
|
||||
~IHomeMenuFunctions() override;
|
||||
|
||||
private:
|
||||
void RequestToGetForeground(HLERequestContext& ctx);
|
||||
void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
Kernel::KEvent* pop_from_general_channel_event;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
202
src/core/hle/service/am/library_applet_accessor.cpp
Normal file
202
src/core/hle/service/am/library_applet_accessor.cpp
Normal file
|
@ -0,0 +1,202 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/library_applet_accessor.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
|
||||
std::shared_ptr<AppletDataBroker> broker_,
|
||||
std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "ILibraryAppletAccessor"}, broker{std::move(broker_)},
|
||||
applet{std::move(applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
|
||||
{1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
|
||||
{10, &ILibraryAppletAccessor::Start, "Start"},
|
||||
{20, &ILibraryAppletAccessor::RequestExit, "RequestExit"},
|
||||
{25, nullptr, "Terminate"},
|
||||
{30, &ILibraryAppletAccessor::GetResult, "GetResult"},
|
||||
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
|
||||
{60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"},
|
||||
{100, &ILibraryAppletAccessor::PushInData, "PushInData"},
|
||||
{101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
|
||||
{102, nullptr, "PushExtraStorage"},
|
||||
{103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
|
||||
{104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
|
||||
{105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
|
||||
{106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
|
||||
{110, nullptr, "NeedsToExitProcess"},
|
||||
{120, nullptr, "GetLibraryAppletInfo"},
|
||||
{150, nullptr, "RequestForAppletToGetForeground"},
|
||||
{160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
|
||||
|
||||
void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(broker->GetStateChangedEvent().GetHandle());
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(broker->IsCompleted());
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(applet->terminate_result);
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::Start(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
applet->process->Run();
|
||||
FrontendExecute();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
ASSERT(applet != nullptr);
|
||||
applet->message_queue.RequestExit();
|
||||
FrontendRequestExit();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
broker->GetInData().Push(rp.PopIpcInterface<IStorage>().lock());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
std::shared_ptr<IStorage> data;
|
||||
const auto res = broker->GetOutData().Pop(&data);
|
||||
|
||||
if (res.IsSuccess()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface(std::move(data));
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
broker->GetInteractiveInData().Push(rp.PopIpcInterface<IStorage>().lock());
|
||||
FrontendExecuteInteractive();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
std::shared_ptr<IStorage> data;
|
||||
const auto res = broker->GetInteractiveOutData().Pop(&data);
|
||||
|
||||
if (res.IsSuccess()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface(std::move(data));
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(broker->GetOutData().GetEvent());
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(broker->GetInteractiveOutData().GetEvent());
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
// We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
|
||||
// actually used anywhere
|
||||
constexpr u64 handle = 0xdeadbeef;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(handle);
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::FrontendExecute() {
|
||||
if (applet->frontend) {
|
||||
applet->frontend->Initialize();
|
||||
applet->frontend->Execute();
|
||||
}
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::FrontendExecuteInteractive() {
|
||||
if (applet->frontend) {
|
||||
applet->frontend->ExecuteInteractive();
|
||||
applet->frontend->Execute();
|
||||
}
|
||||
}
|
||||
|
||||
void ILibraryAppletAccessor::FrontendRequestExit() {
|
||||
if (applet->frontend) {
|
||||
applet->frontend->RequestExit();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
43
src/core/hle/service/am/library_applet_accessor.h
Normal file
43
src/core/hle/service/am/library_applet_accessor.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class AppletDataBroker;
|
||||
struct Applet;
|
||||
|
||||
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
|
||||
public:
|
||||
explicit ILibraryAppletAccessor(Core::System& system_,
|
||||
std::shared_ptr<AppletDataBroker> broker_,
|
||||
std::shared_ptr<Applet> applet_);
|
||||
~ILibraryAppletAccessor();
|
||||
|
||||
protected:
|
||||
void GetAppletStateChangedEvent(HLERequestContext& ctx);
|
||||
void IsCompleted(HLERequestContext& ctx);
|
||||
void GetResult(HLERequestContext& ctx);
|
||||
void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx);
|
||||
void Start(HLERequestContext& ctx);
|
||||
void RequestExit(HLERequestContext& ctx);
|
||||
void PushInData(HLERequestContext& ctx);
|
||||
void PopOutData(HLERequestContext& ctx);
|
||||
void PushInteractiveInData(HLERequestContext& ctx);
|
||||
void PopInteractiveOutData(HLERequestContext& ctx);
|
||||
void GetPopOutDataEvent(HLERequestContext& ctx);
|
||||
void GetPopInteractiveOutDataEvent(HLERequestContext& ctx);
|
||||
void GetIndirectLayerConsumerHandle(HLERequestContext& ctx);
|
||||
|
||||
void FrontendExecute();
|
||||
void FrontendExecuteInteractive();
|
||||
void FrontendRequestExit();
|
||||
|
||||
const std::shared_ptr<AppletDataBroker> broker;
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
271
src/core/hle/service/am/library_applet_creator.cpp
Normal file
271
src/core/hle/service/am/library_applet_creator.cpp
Normal file
|
@ -0,0 +1,271 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/library_applet_accessor.h"
|
||||
#include "core/hle/service/am/library_applet_creator.h"
|
||||
#include "core/hle/service/am/library_applet_storage.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
|
||||
AppletProgramId AppletIdToProgramId(AppletId applet_id) {
|
||||
switch (applet_id) {
|
||||
case AppletId::OverlayDisplay:
|
||||
return AppletProgramId::OverlayDisplay;
|
||||
case AppletId::QLaunch:
|
||||
return AppletProgramId::QLaunch;
|
||||
case AppletId::Starter:
|
||||
return AppletProgramId::Starter;
|
||||
case AppletId::Auth:
|
||||
return AppletProgramId::Auth;
|
||||
case AppletId::Cabinet:
|
||||
return AppletProgramId::Cabinet;
|
||||
case AppletId::Controller:
|
||||
return AppletProgramId::Controller;
|
||||
case AppletId::DataErase:
|
||||
return AppletProgramId::DataErase;
|
||||
case AppletId::Error:
|
||||
return AppletProgramId::Error;
|
||||
case AppletId::NetConnect:
|
||||
return AppletProgramId::NetConnect;
|
||||
case AppletId::ProfileSelect:
|
||||
return AppletProgramId::ProfileSelect;
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return AppletProgramId::SoftwareKeyboard;
|
||||
case AppletId::MiiEdit:
|
||||
return AppletProgramId::MiiEdit;
|
||||
case AppletId::Web:
|
||||
return AppletProgramId::Web;
|
||||
case AppletId::Shop:
|
||||
return AppletProgramId::Shop;
|
||||
case AppletId::PhotoViewer:
|
||||
return AppletProgramId::PhotoViewer;
|
||||
case AppletId::Settings:
|
||||
return AppletProgramId::Settings;
|
||||
case AppletId::OfflineWeb:
|
||||
return AppletProgramId::OfflineWeb;
|
||||
case AppletId::LoginShare:
|
||||
return AppletProgramId::LoginShare;
|
||||
case AppletId::WebAuth:
|
||||
return AppletProgramId::WebAuth;
|
||||
case AppletId::MyPage:
|
||||
return AppletProgramId::MyPage;
|
||||
default:
|
||||
return static_cast<AppletProgramId>(0);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(
|
||||
Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
|
||||
LibraryAppletMode mode) {
|
||||
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
|
||||
if (program_id == 0) {
|
||||
// Unknown applet
|
||||
return {};
|
||||
}
|
||||
|
||||
auto process = std::make_unique<Process>(system);
|
||||
if (!process->Initialize(program_id)) {
|
||||
// Couldn't initialize the guest process
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto applet = std::make_shared<Applet>(system, std::move(process));
|
||||
applet->program_id = program_id;
|
||||
applet->applet_id = applet_id;
|
||||
applet->type = AppletType::LibraryApplet;
|
||||
applet->library_applet_mode = mode;
|
||||
|
||||
// Set focus state
|
||||
switch (mode) {
|
||||
case LibraryAppletMode::AllForeground:
|
||||
case LibraryAppletMode::NoUI:
|
||||
applet->focus_state = FocusState::InFocus;
|
||||
applet->hid_registration.EnableAppletToGetInput(true);
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
break;
|
||||
case LibraryAppletMode::AllForegroundInitiallyHidden:
|
||||
applet->system_buffer_manager.SetWindowVisibility(false);
|
||||
applet->focus_state = FocusState::NotInFocus;
|
||||
applet->hid_registration.EnableAppletToGetInput(false);
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
break;
|
||||
case LibraryAppletMode::Background:
|
||||
case LibraryAppletMode::BackgroundIndirectDisplay:
|
||||
default:
|
||||
applet->focus_state = FocusState::Background;
|
||||
applet->hid_registration.EnableAppletToGetInput(true);
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
break;
|
||||
}
|
||||
|
||||
auto broker = std::make_shared<AppletDataBroker>(system);
|
||||
applet->caller_applet = caller_applet;
|
||||
applet->caller_applet_broker = broker;
|
||||
|
||||
system.GetAppletManager().InsertApplet(applet);
|
||||
|
||||
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
|
||||
}
|
||||
|
||||
[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(
|
||||
Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
|
||||
LibraryAppletMode mode) {
|
||||
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
|
||||
|
||||
auto process = std::make_unique<Process>(system);
|
||||
auto applet = std::make_shared<Applet>(system, std::move(process));
|
||||
applet->program_id = program_id;
|
||||
applet->applet_id = applet_id;
|
||||
applet->type = AppletType::LibraryApplet;
|
||||
applet->library_applet_mode = mode;
|
||||
|
||||
auto storage = std::make_shared<AppletDataBroker>(system);
|
||||
applet->caller_applet = caller_applet;
|
||||
applet->caller_applet_broker = storage;
|
||||
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
|
||||
|
||||
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
|
||||
{1, nullptr, "TerminateAllLibraryApplets"},
|
||||
{2, nullptr, "AreAnyLibraryAppletsLeft"},
|
||||
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
|
||||
{11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
|
||||
{12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletCreator::~ILibraryAppletCreator() = default;
|
||||
|
||||
void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto applet_id = rp.PopRaw<AppletId>();
|
||||
const auto applet_mode = rp.PopRaw<LibraryAppletMode>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
|
||||
applet_mode);
|
||||
|
||||
auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
|
||||
if (!library_applet) {
|
||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
// Applet is created, can now be launched.
|
||||
applet->library_applet_launchable_event.Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletAccessor>(library_applet);
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const s64 size{rp.Pop<s64>()};
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||
|
||||
if (size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> data(size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IStorage>(system, AM::CreateStorage(std::move(data)));
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
struct Parameters {
|
||||
bool is_writable;
|
||||
s64 size;
|
||||
};
|
||||
|
||||
const auto params{rp.PopRaw<Parameters>()};
|
||||
const auto handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, is_writable={}, size={}, handle={:08X}", params.is_writable,
|
||||
params.size, handle);
|
||||
|
||||
if (params.size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||
|
||||
if (transfer_mem.IsNull()) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IStorage>(
|
||||
system, AM::CreateTransferMemoryStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(),
|
||||
params.is_writable, params.size));
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const s64 size{rp.Pop<s64>()};
|
||||
const auto handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
|
||||
|
||||
if (size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||
|
||||
if (transfer_mem.IsNull()) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IStorage>(
|
||||
system, AM::CreateHandleStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), size));
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
26
src/core/hle/service/am/library_applet_creator.h
Normal file
26
src/core/hle/service/am/library_applet_creator.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
|
||||
public:
|
||||
explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_);
|
||||
~ILibraryAppletCreator() override;
|
||||
|
||||
private:
|
||||
void CreateLibraryApplet(HLERequestContext& ctx);
|
||||
void CreateStorage(HLERequestContext& ctx);
|
||||
void CreateTransferMemoryStorage(HLERequestContext& ctx);
|
||||
void CreateHandleStorage(HLERequestContext& ctx);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
143
src/core/hle/service/am/library_applet_proxy.cpp
Normal file
143
src/core/hle/service/am/library_applet_proxy.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/applet_common_functions.h"
|
||||
#include "core/hle/service/am/audio_controller.h"
|
||||
#include "core/hle/service/am/common_state_getter.h"
|
||||
#include "core/hle/service/am/debug_functions.h"
|
||||
#include "core/hle/service/am/display_controller.h"
|
||||
#include "core/hle/service/am/global_state_controller.h"
|
||||
#include "core/hle/service/am/home_menu_functions.h"
|
||||
#include "core/hle/service/am/library_applet_creator.h"
|
||||
#include "core/hle/service/am/library_applet_proxy.h"
|
||||
#include "core/hle/service/am/library_applet_self_accessor.h"
|
||||
#include "core/hle/service/am/process_winding_controller.h"
|
||||
#include "core/hle/service/am/self_controller.h"
|
||||
#include "core/hle/service/am/window_controller.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<Applet> applet_, Core::System& system_)
|
||||
: ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
|
||||
applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
|
||||
{2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"},
|
||||
{3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"},
|
||||
{4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
|
||||
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
|
||||
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
|
||||
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
|
||||
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
|
||||
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
|
||||
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletProxy::~ILibraryAppletProxy() = default;
|
||||
|
||||
void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(system, applet);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IWindowController>(system, applet);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAudioController>(system);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDisplayController>(system, applet);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IProcessWindingController>(system, applet);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system, applet);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAppletCommonFunctions>(system, applet);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IHomeMenuFunctions>(system);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetGlobalStateController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IGlobalStateController>(system);
|
||||
}
|
||||
|
||||
void ILibraryAppletProxy::GetDebugFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDebugFunctions>(system);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
36
src/core/hle/service/am/library_applet_proxy.h
Normal file
36
src/core/hle/service/am/library_applet_proxy.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
|
||||
public:
|
||||
explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
|
||||
std::shared_ptr<Applet> applet_, Core::System& system_);
|
||||
~ILibraryAppletProxy();
|
||||
|
||||
private:
|
||||
void GetCommonStateGetter(HLERequestContext& ctx);
|
||||
void GetSelfController(HLERequestContext& ctx);
|
||||
void GetWindowController(HLERequestContext& ctx);
|
||||
void GetAudioController(HLERequestContext& ctx);
|
||||
void GetDisplayController(HLERequestContext& ctx);
|
||||
void GetProcessWindingController(HLERequestContext& ctx);
|
||||
void GetLibraryAppletCreator(HLERequestContext& ctx);
|
||||
void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx);
|
||||
void GetAppletCommonFunctions(HLERequestContext& ctx);
|
||||
void GetHomeMenuFunctions(HLERequestContext& ctx);
|
||||
void GetGlobalStateController(HLERequestContext& ctx);
|
||||
void GetDebugFunctions(HLERequestContext& ctx);
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
338
src/core/hle/service/am/library_applet_self_accessor.cpp
Normal file
338
src/core/hle/service/am/library_applet_self_accessor.cpp
Normal file
|
@ -0,0 +1,338 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applet_cabinet.h"
|
||||
#include "core/hle/service/am/frontend/applet_controller.h"
|
||||
#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
|
||||
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/library_applet_self_accessor.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
|
||||
AppletIdentityInfo GetCallerIdentity(std::shared_ptr<Applet> applet) {
|
||||
if (const auto caller_applet = applet->caller_applet.lock(); caller_applet) {
|
||||
// TODO: is this actually the application ID?
|
||||
return {
|
||||
.applet_id = caller_applet->applet_id,
|
||||
.application_id = caller_applet->program_id,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
.applet_id = AppletId::QLaunch,
|
||||
.application_id = 0x0100000000001000ull,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_,
|
||||
std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, applet{std::move(applet_)},
|
||||
broker{applet->caller_applet_broker} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"},
|
||||
{1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"},
|
||||
{2, &ILibraryAppletSelfAccessor::PopInteractiveInData, "PopInteractiveInData"},
|
||||
{3, &ILibraryAppletSelfAccessor::PushInteractiveOutData, "PushInteractiveOutData"},
|
||||
{5, &ILibraryAppletSelfAccessor::GetPopInDataEvent, "GetPopInDataEvent"},
|
||||
{6, &ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent, "GetPopInteractiveInDataEvent"},
|
||||
{10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
|
||||
{11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
|
||||
{12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
|
||||
{13, &ILibraryAppletSelfAccessor::CanUseApplicationCore, "CanUseApplicationCore"},
|
||||
{14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
|
||||
{15, nullptr, "GetMainAppletApplicationControlProperty"},
|
||||
{16, nullptr, "GetMainAppletStorageId"},
|
||||
{17, nullptr, "GetCallerAppletIdentityInfoStack"},
|
||||
{18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
|
||||
{19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"},
|
||||
{20, nullptr, "PopExtraStorage"},
|
||||
{25, nullptr, "GetPopExtraStorageEvent"},
|
||||
{30, nullptr, "UnpopInData"},
|
||||
{31, nullptr, "UnpopExtraStorage"},
|
||||
{40, nullptr, "GetIndirectLayerProducerHandle"},
|
||||
{50, nullptr, "ReportVisibleError"},
|
||||
{51, nullptr, "ReportVisibleErrorWithErrorContext"},
|
||||
{60, &ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage, "GetMainAppletApplicationDesiredLanguage"},
|
||||
{70, &ILibraryAppletSelfAccessor::GetCurrentApplicationId, "GetCurrentApplicationId"},
|
||||
{80, nullptr, "RequestExitToSelf"},
|
||||
{90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
|
||||
{100, nullptr, "CreateGameMovieTrimmer"},
|
||||
{101, nullptr, "ReserveResourceForMovieOperation"},
|
||||
{102, nullptr, "UnreserveResourceForMovieOperation"},
|
||||
{110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"},
|
||||
{120, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
|
||||
{140, nullptr, "SetApplicationMemoryReservation"},
|
||||
{150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"},
|
||||
{160, &ILibraryAppletSelfAccessor::Cmd160, "Cmd160"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
|
||||
|
||||
void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
std::shared_ptr<IStorage> data;
|
||||
const auto res = broker->GetInData().Pop(&data);
|
||||
|
||||
if (res.IsSuccess()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface(std::move(data));
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
broker->GetOutData().Push(rp.PopIpcInterface<IStorage>().lock());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
std::shared_ptr<IStorage> data;
|
||||
const auto res = broker->GetInteractiveInData().Pop(&data);
|
||||
|
||||
if (res.IsSuccess()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface(std::move(data));
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushInteractiveOutData(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
broker->GetInteractiveOutData().Push(rp.PopIpcInterface<IStorage>().lock());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetPopInDataEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(broker->GetInData().GetEvent());
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(broker->GetInteractiveInData().GetEvent());
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid);
|
||||
broker->SignalCompletion();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
|
||||
struct LibraryAppletInfo {
|
||||
AppletId applet_id;
|
||||
LibraryAppletMode library_applet_mode;
|
||||
};
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
const LibraryAppletInfo applet_info{
|
||||
.applet_id = applet->applet_id,
|
||||
.library_applet_mode = applet->library_applet_mode,
|
||||
};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(applet_info);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
const AppletIdentityInfo applet_info{
|
||||
.applet_id = AppletId::QLaunch,
|
||||
.application_id = 0x0100000000001000ull,
|
||||
};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(applet_info);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::CanUseApplicationCore(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
// TODO: This appears to read the NPDM from state and check the core mask of the applet.
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(0);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(GetCallerIdentity(applet));
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx) {
|
||||
// FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage
|
||||
auto identity = GetCallerIdentity(applet);
|
||||
|
||||
// TODO(bunnei): This should be configurable
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
// Get supported languages from NACP, if possible
|
||||
// Default to 0 (all languages supported)
|
||||
u32 supported_languages = 0;
|
||||
|
||||
const auto res = [this, identity] {
|
||||
const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
auto metadata = pm.GetControlMetadata();
|
||||
if (metadata.first != nullptr) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
return pm_update.GetControlMetadata();
|
||||
}();
|
||||
|
||||
if (res.first != nullptr) {
|
||||
supported_languages = res.first->GetSupportedLanguages();
|
||||
}
|
||||
|
||||
// Call IApplicationManagerInterface implementation.
|
||||
auto& service_manager = system.ServiceManager();
|
||||
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
|
||||
auto app_man = ns_am2->GetApplicationManagerInterface();
|
||||
|
||||
// Get desired application language
|
||||
u8 desired_language{};
|
||||
const auto res_lang =
|
||||
app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
|
||||
if (res_lang != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert to settings language code.
|
||||
u64 language_code{};
|
||||
const auto res_code =
|
||||
app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
|
||||
if (res_code != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res_code);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(language_code);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetCurrentApplicationId(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
u64 application_id = 0;
|
||||
if (auto caller_applet = applet->caller_applet.lock(); caller_applet) {
|
||||
application_id = caller_applet->program_id;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(application_id);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) {
|
||||
const Service::Account::ProfileManager manager{};
|
||||
bool is_empty{true};
|
||||
s32 user_count{-1};
|
||||
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
if (manager.GetUserCount() > 0) {
|
||||
is_empty = false;
|
||||
user_count = static_cast<s32>(manager.GetUserCount());
|
||||
ctx.WriteBuffer(manager.GetAllUsers());
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_empty);
|
||||
rb.Push(user_count);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(0);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::Cmd160(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u64>(0);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
44
src/core/hle/service/am/library_applet_self_accessor.h
Normal file
44
src/core/hle/service/am/library_applet_self_accessor.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class AppletDataBroker;
|
||||
struct Applet;
|
||||
|
||||
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
|
||||
public:
|
||||
explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet_);
|
||||
~ILibraryAppletSelfAccessor() override;
|
||||
|
||||
private:
|
||||
void PopInData(HLERequestContext& ctx);
|
||||
void PushOutData(HLERequestContext& ctx);
|
||||
void PopInteractiveInData(HLERequestContext& ctx);
|
||||
void PushInteractiveOutData(HLERequestContext& ctx);
|
||||
void GetPopInDataEvent(HLERequestContext& ctx);
|
||||
void GetPopInteractiveInDataEvent(HLERequestContext& ctx);
|
||||
void GetLibraryAppletInfo(HLERequestContext& ctx);
|
||||
void GetMainAppletIdentityInfo(HLERequestContext& ctx);
|
||||
void CanUseApplicationCore(HLERequestContext& ctx);
|
||||
void ExitProcessAndReturn(HLERequestContext& ctx);
|
||||
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
||||
void GetDesirableKeyboardLayout(HLERequestContext& ctx);
|
||||
void GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx);
|
||||
void GetCurrentApplicationId(HLERequestContext& ctx);
|
||||
void GetMainAppletAvailableUsers(HLERequestContext& ctx);
|
||||
void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx);
|
||||
void Cmd160(HLERequestContext& ctx);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
const std::shared_ptr<AppletDataBroker> broker;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
140
src/core/hle/service/am/library_applet_storage.cpp
Normal file
140
src/core/hle/service/am/library_applet_storage.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/library_applet_storage.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
|
||||
Result ValidateOffset(s64 offset, size_t size, size_t data_size) {
|
||||
R_UNLESS(offset >= 0, AM::ResultInvalidOffset);
|
||||
|
||||
const size_t begin = offset;
|
||||
const size_t end = begin + size;
|
||||
|
||||
R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
class BufferLibraryAppletStorage final : public LibraryAppletStorage {
|
||||
public:
|
||||
explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {}
|
||||
~BufferLibraryAppletStorage() = default;
|
||||
|
||||
Result Read(s64 offset, void* buffer, size_t size) override {
|
||||
R_TRY(ValidateOffset(offset, size, m_data.size()));
|
||||
|
||||
std::memcpy(buffer, m_data.data() + offset, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result Write(s64 offset, const void* buffer, size_t size) override {
|
||||
R_TRY(ValidateOffset(offset, size, m_data.size()));
|
||||
|
||||
std::memcpy(m_data.data() + offset, buffer, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
s64 GetSize() override {
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
Kernel::KTransferMemory* GetHandle() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<u8> m_data;
|
||||
};
|
||||
|
||||
class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage {
|
||||
public:
|
||||
explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem, bool is_writable,
|
||||
s64 size)
|
||||
: m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) {
|
||||
m_trmem->Open();
|
||||
}
|
||||
|
||||
~TransferMemoryLibraryAppletStorage() {
|
||||
m_trmem->Close();
|
||||
m_trmem = nullptr;
|
||||
}
|
||||
|
||||
Result Read(s64 offset, void* buffer, size_t size) override {
|
||||
R_TRY(ValidateOffset(offset, size, m_size));
|
||||
|
||||
m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result Write(s64 offset, const void* buffer, size_t size) override {
|
||||
R_UNLESS(m_is_writable, ResultUnknown);
|
||||
R_TRY(ValidateOffset(offset, size, m_size));
|
||||
|
||||
m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
s64 GetSize() override {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
Kernel::KTransferMemory* GetHandle() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
Core::Memory::Memory& m_memory;
|
||||
Kernel::KTransferMemory* m_trmem;
|
||||
bool m_is_writable;
|
||||
s64 m_size;
|
||||
};
|
||||
|
||||
class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage {
|
||||
public:
|
||||
explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem, s64 size)
|
||||
: TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {}
|
||||
~HandleLibraryAppletStorage() = default;
|
||||
|
||||
Kernel::KTransferMemory* GetHandle() override {
|
||||
return m_trmem;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
LibraryAppletStorage::~LibraryAppletStorage() = default;
|
||||
|
||||
std::vector<u8> LibraryAppletStorage::GetData() {
|
||||
std::vector<u8> data(this->GetSize());
|
||||
this->Read(0, data.data(), data.size());
|
||||
return data;
|
||||
}
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) {
|
||||
return std::make_shared<BufferLibraryAppletStorage>(std::move(data));
|
||||
}
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem,
|
||||
bool is_writable, s64 size) {
|
||||
return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size);
|
||||
}
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem,
|
||||
s64 size) {
|
||||
return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
36
src/core/hle/service/am/library_applet_storage.h
Normal file
36
src/core/hle/service/am/library_applet_storage.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KTransferMemory;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class LibraryAppletStorage {
|
||||
public:
|
||||
virtual ~LibraryAppletStorage();
|
||||
virtual Result Read(s64 offset, void* buffer, size_t size) = 0;
|
||||
virtual Result Write(s64 offset, const void* buffer, size_t size) = 0;
|
||||
virtual s64 GetSize() = 0;
|
||||
virtual Kernel::KTransferMemory* GetHandle() = 0;
|
||||
|
||||
std::vector<u8> GetData();
|
||||
};
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data);
|
||||
std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem,
|
||||
bool is_writable, s64 size);
|
||||
std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem, s64 size);
|
||||
|
||||
} // namespace Service::AM
|
71
src/core/hle/service/am/lock_accessor.cpp
Normal file
71
src/core/hle/service/am/lock_accessor.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/lock_accessor.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ILockAccessor::ILockAccessor(Core::System& system_)
|
||||
: ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &ILockAccessor::TryLock, "TryLock"},
|
||||
{2, &ILockAccessor::Unlock, "Unlock"},
|
||||
{3, &ILockAccessor::GetEvent, "GetEvent"},
|
||||
{4,&ILockAccessor::IsLocked, "IsLocked"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
|
||||
}
|
||||
|
||||
ILockAccessor::~ILockAccessor() {
|
||||
service_context.CloseEvent(lock_event);
|
||||
};
|
||||
|
||||
void ILockAccessor::TryLock(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto return_handle = rp.Pop<bool>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
|
||||
|
||||
// TODO: When return_handle is true this function should return the lock handle
|
||||
|
||||
is_locked = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_locked);
|
||||
}
|
||||
|
||||
void ILockAccessor::Unlock(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
is_locked = false;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILockAccessor::GetEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
lock_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(lock_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void ILockAccessor::IsLocked(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_locked);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
28
src/core/hle/service/am/lock_accessor.h
Normal file
28
src/core/hle/service/am/lock_accessor.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
|
||||
public:
|
||||
explicit ILockAccessor(Core::System& system_);
|
||||
~ILockAccessor() override;
|
||||
|
||||
private:
|
||||
void TryLock(HLERequestContext& ctx);
|
||||
void Unlock(HLERequestContext& ctx);
|
||||
void GetEvent(HLERequestContext& ctx);
|
||||
void IsLocked(HLERequestContext& ctx);
|
||||
|
||||
bool is_locked{};
|
||||
|
||||
Kernel::KEvent* lock_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
59
src/core/hle/service/am/managed_layer_holder.cpp
Normal file
59
src/core/hle/service/am/managed_layer_holder.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/managed_layer_holder.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ManagedLayerHolder::ManagedLayerHolder() = default;
|
||||
ManagedLayerHolder::~ManagedLayerHolder() {
|
||||
if (!m_nvnflinger) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& layer : m_managed_display_layers) {
|
||||
m_nvnflinger->DestroyLayer(layer);
|
||||
}
|
||||
|
||||
for (const auto& layer : m_managed_display_recording_layers) {
|
||||
m_nvnflinger->DestroyLayer(layer);
|
||||
}
|
||||
|
||||
m_nvnflinger = nullptr;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
|
||||
m_nvnflinger = nvnflinger;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
const auto display_id = m_nvnflinger->OpenDisplay("Default");
|
||||
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
|
||||
|
||||
m_managed_display_layers.emplace(*layer_id);
|
||||
|
||||
*out_layer = *layer_id;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
|
||||
u64* out_recording_layer) {
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
|
||||
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
|
||||
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
|
||||
// side effects.
|
||||
// TODO: Support multiple layers
|
||||
const auto display_id = m_nvnflinger->OpenDisplay("Default");
|
||||
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
|
||||
|
||||
m_managed_display_layers.emplace(*layer_id);
|
||||
|
||||
*out_layer = *layer_id;
|
||||
*out_recording_layer = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
32
src/core/hle/service/am/managed_layer_holder.h
Normal file
32
src/core/hle/service/am/managed_layer_holder.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class Nvnflinger;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class ManagedLayerHolder {
|
||||
public:
|
||||
ManagedLayerHolder();
|
||||
~ManagedLayerHolder();
|
||||
|
||||
void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
|
||||
void CreateManagedDisplayLayer(u64* out_layer);
|
||||
void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
|
||||
|
||||
private:
|
||||
Nvnflinger::Nvnflinger* m_nvnflinger{};
|
||||
std::set<u64> m_managed_display_layers{};
|
||||
std::set<u64> m_managed_display_recording_layers{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
138
src/core/hle/service/am/process.cpp
Normal file
138
src/core/hle/service/am/process.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/am/process.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
Process::Process(Core::System& system)
|
||||
: m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
|
||||
m_program_id(), m_process_started() {}
|
||||
|
||||
Process::~Process() {
|
||||
this->Finalize();
|
||||
}
|
||||
|
||||
bool Process::Initialize(u64 program_id) {
|
||||
// First, ensure we are not holding another process.
|
||||
this->Finalize();
|
||||
|
||||
// Get the filesystem controller.
|
||||
auto& fsc = m_system.GetFileSystemController();
|
||||
|
||||
// Attempt to load program NCA.
|
||||
const FileSys::RegisteredCache* bis_system{};
|
||||
FileSys::VirtualFile nca{};
|
||||
|
||||
// Get the program NCA from built-in storage.
|
||||
bis_system = fsc.GetSystemNANDContents();
|
||||
if (bis_system) {
|
||||
nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
|
||||
}
|
||||
|
||||
// Ensure we retrieved a program NCA.
|
||||
if (!nca) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the appropriate loader to parse this NCA.
|
||||
auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0);
|
||||
|
||||
// Ensure we have a loader which can parse the NCA.
|
||||
if (!app_loader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the process.
|
||||
auto* const process = Kernel::KProcess::Create(m_system.Kernel());
|
||||
Kernel::KProcess::Register(m_system.Kernel(), process);
|
||||
|
||||
// On exit, ensure we free the additional reference to the process.
|
||||
SCOPE_EXIT({ process->Close(); });
|
||||
|
||||
// Insert process modules into memory.
|
||||
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
|
||||
|
||||
// Ensure loading was successful.
|
||||
if (load_result != Loader::ResultStatus::Success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: remove this, kernel already tracks this
|
||||
m_system.Kernel().AppendNewProcess(process);
|
||||
|
||||
// Note the load parameters from NPDM.
|
||||
m_main_thread_priority = load_parameters->main_thread_priority;
|
||||
m_main_thread_stack_size = load_parameters->main_thread_stack_size;
|
||||
|
||||
// This process has not started yet.
|
||||
m_process_started = false;
|
||||
|
||||
// Take ownership of the process object.
|
||||
m_process = process;
|
||||
m_process->Open();
|
||||
|
||||
// We succeeded.
|
||||
return true;
|
||||
}
|
||||
|
||||
void Process::Finalize() {
|
||||
// Terminate, if we are currently holding a process.
|
||||
this->Terminate();
|
||||
|
||||
// Close the process.
|
||||
if (m_process) {
|
||||
m_process->Close();
|
||||
|
||||
// TODO: remove this, kernel already tracks this
|
||||
m_system.Kernel().RemoveProcess(m_process);
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
m_process = nullptr;
|
||||
m_main_thread_priority = 0;
|
||||
m_main_thread_stack_size = 0;
|
||||
m_program_id = 0;
|
||||
m_process_started = false;
|
||||
}
|
||||
|
||||
bool Process::Run() {
|
||||
// If we already started the process, don't start again.
|
||||
if (m_process_started) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start.
|
||||
if (m_process) {
|
||||
m_process->Run(m_main_thread_priority, m_main_thread_stack_size);
|
||||
}
|
||||
|
||||
// Mark as started.
|
||||
m_process_started = true;
|
||||
|
||||
// We succeeded.
|
||||
return true;
|
||||
}
|
||||
|
||||
void Process::Terminate() {
|
||||
if (m_process) {
|
||||
m_process->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
u64 Process::GetProcessId() const {
|
||||
if (m_process) {
|
||||
return m_process->GetProcessId();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
50
src/core/hle/service/am/process.h
Normal file
50
src/core/hle/service/am/process.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KProcess;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class Process {
|
||||
public:
|
||||
explicit Process(Core::System& system);
|
||||
~Process();
|
||||
|
||||
bool Initialize(u64 program_id);
|
||||
void Finalize();
|
||||
|
||||
bool Run();
|
||||
void Terminate();
|
||||
|
||||
bool IsInitialized() const {
|
||||
return m_process != nullptr;
|
||||
}
|
||||
u64 GetProcessId() const;
|
||||
u64 GetProgramId() const {
|
||||
return m_program_id;
|
||||
}
|
||||
Kernel::KProcess* GetProcess() const {
|
||||
return m_process;
|
||||
}
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
Kernel::KProcess* m_process{};
|
||||
s32 m_main_thread_priority{};
|
||||
u64 m_main_thread_stack_size{};
|
||||
u64 m_program_id{};
|
||||
bool m_process_started{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
56
src/core/hle/service/am/process_winding_controller.cpp
Normal file
56
src/core/hle/service/am/process_winding_controller.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/library_applet_accessor.h"
|
||||
#include "core/hle/service/am/process_winding_controller.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IProcessWindingController::IProcessWindingController(Core::System& system_,
|
||||
std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "IProcessWindingController"}, applet{std::move(applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"},
|
||||
{11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"},
|
||||
{21, nullptr, "PushContext"},
|
||||
{22, nullptr, "PopContext"},
|
||||
{23, nullptr, "CancelWindingReservation"},
|
||||
{30, nullptr, "WindAndDoReserved"},
|
||||
{40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
|
||||
{41, nullptr, "ReserveToStartAndWait"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IProcessWindingController::~IProcessWindingController() = default;
|
||||
|
||||
void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(applet->launch_reason);
|
||||
}
|
||||
|
||||
void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
|
||||
const auto caller_applet = applet->caller_applet.lock();
|
||||
if (caller_applet == nullptr) {
|
||||
LOG_ERROR(Service_AM, "No calling applet available");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet->caller_applet_broker,
|
||||
caller_applet);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
24
src/core/hle/service/am/process_winding_controller.h
Normal file
24
src/core/hle/service/am/process_winding_controller.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
|
||||
public:
|
||||
explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_);
|
||||
~IProcessWindingController() override;
|
||||
|
||||
private:
|
||||
void GetLaunchReason(HLERequestContext& ctx);
|
||||
void OpenCallingLibraryApplet(HLERequestContext& ctx);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
456
src/core/hle/service/am/self_controller.cpp
Normal file
456
src/core/hle/service/am/self_controller.cpp
Normal file
|
@ -0,0 +1,456 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/self_controller.h"
|
||||
#include "core/hle/service/caps/caps_su.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/vi/vi_results.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
Nvnflinger::Nvnflinger& nvnflinger_)
|
||||
: ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, applet{std::move(
|
||||
applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISelfController::Exit, "Exit"},
|
||||
{1, &ISelfController::LockExit, "LockExit"},
|
||||
{2, &ISelfController::UnlockExit, "UnlockExit"},
|
||||
{3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
|
||||
{4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"},
|
||||
{9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
|
||||
{10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
|
||||
{11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
|
||||
{12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"},
|
||||
{13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
|
||||
{14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
|
||||
{15, &ISelfController::SetScreenShotAppletIdentityInfo, "SetScreenShotAppletIdentityInfo"},
|
||||
{16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
|
||||
{17, nullptr, "SetControllerFirmwareUpdateSection"},
|
||||
{18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
|
||||
{19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"},
|
||||
{20, nullptr, "SetDesirableKeyboardLayout"},
|
||||
{21, nullptr, "GetScreenShotProgramId"},
|
||||
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
|
||||
{41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"},
|
||||
{42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"},
|
||||
{43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"},
|
||||
{44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
|
||||
{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
|
||||
{46, nullptr, "SetRecordingLayerCompositionEnabled"},
|
||||
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
|
||||
{51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
|
||||
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
|
||||
{61, nullptr, "SetMediaPlaybackState"},
|
||||
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
|
||||
{63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
|
||||
{64, nullptr, "SetInputDetectionSourceSet"},
|
||||
{65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"},
|
||||
{66, nullptr, "GetCurrentIlluminance"},
|
||||
{67, nullptr, "IsIlluminanceAvailable"},
|
||||
{68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"},
|
||||
{69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
|
||||
{70, nullptr, "ReportMultimediaError"},
|
||||
{71, nullptr, "GetCurrentIlluminanceEx"},
|
||||
{72, nullptr, "SetInputDetectionPolicy"},
|
||||
{80, nullptr, "SetWirelessPriorityMode"},
|
||||
{90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
|
||||
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
|
||||
{100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
|
||||
{110, nullptr, "SetApplicationAlbumUserData"},
|
||||
{120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"},
|
||||
{130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"},
|
||||
{1000, nullptr, "GetDebugStorageChannel"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ISelfController::~ISelfController() = default;
|
||||
|
||||
void ISelfController::Exit(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
// TODO
|
||||
system.Exit();
|
||||
}
|
||||
|
||||
void ISelfController::LockExit(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
system.SetExitLocked(true);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::UnlockExit(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
system.SetExitLocked(false);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
if (system.GetExitRequested()) {
|
||||
system.Exit();
|
||||
}
|
||||
}
|
||||
|
||||
void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->fatal_section_count++;
|
||||
LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", applet->fatal_section_count);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::LeaveFatalSection(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called.");
|
||||
|
||||
// Entry and exit of fatal sections must be balanced.
|
||||
std::scoped_lock lk{applet->lock};
|
||||
if (applet->fatal_section_count == 0) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(AM::ResultFatalSectionCountImbalance);
|
||||
return;
|
||||
}
|
||||
|
||||
applet->fatal_section_count--;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
applet->library_applet_launchable_event.Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->library_applet_launchable_event.GetHandle());
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto permission = rp.PopEnum<ScreenshotPermission>();
|
||||
LOG_DEBUG(Service_AM, "called, permission={}", permission);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->screenshot_permission = permission;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const bool notification_enabled = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->operation_mode_changed_notification_enabled = notification_enabled;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const bool notification_enabled = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->performance_mode_changed_notification_enabled = notification_enabled;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto flags = rp.PopRaw<FocusHandlingMode>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}",
|
||||
flags.unknown0, flags.unknown1, flags.unknown2);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->focus_handling_mode = flags;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->restart_message_enabled = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotAppletIdentityInfo(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->screen_shot_identity = rp.PopRaw<AppletIdentityInfo>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const bool enabled = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
ASSERT(applet->type == AppletType::Application);
|
||||
applet->out_of_focus_suspension_enabled = enabled;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto orientation = rp.PopRaw<Capture::AlbumImageOrientation>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", static_cast<s32>(orientation));
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->album_image_orientation = orientation;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
u64 layer_id{};
|
||||
applet->managed_layer_holder.Initialize(&nvnflinger);
|
||||
applet->managed_layer_holder.CreateManagedDisplayLayer(&layer_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(layer_id);
|
||||
}
|
||||
|
||||
void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
|
||||
}
|
||||
|
||||
void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
u64 buffer_id, layer_id;
|
||||
applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
|
||||
rb.Push<s64>(buffer_id);
|
||||
rb.Push<s64>(layer_id);
|
||||
}
|
||||
|
||||
void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
u64 buffer_id, layer_id;
|
||||
applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
|
||||
rb.Push<s64>(buffer_id);
|
||||
}
|
||||
|
||||
Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) {
|
||||
if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
return VI::ResultOperationFailed;
|
||||
}
|
||||
|
||||
void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
u64 layer_id{};
|
||||
u64 recording_layer_id{};
|
||||
applet->managed_layer_holder.Initialize(&nvnflinger);
|
||||
applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(&layer_id, &recording_layer_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(layer_id);
|
||||
rb.Push(recording_layer_id);
|
||||
}
|
||||
|
||||
void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto extension = rp.PopRaw<IdleTimeDetectionExtension>();
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", extension);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->idle_time_detection_extension = extension;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<IdleTimeDetectionExtension>(applet->idle_time_detection_extension);
|
||||
}
|
||||
|
||||
void ISelfController::ReportUserIsActive(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->auto_sleep_disabled = rp.Pop<bool>();
|
||||
|
||||
// On the system itself, if the previous state of is_auto_sleep_disabled
|
||||
// differed from the current value passed in, it'd signify the internal
|
||||
// window manager to update (and also increment some statistics like update counts)
|
||||
//
|
||||
// It'd also indicate this change to an idle handling context.
|
||||
//
|
||||
// However, given we're emulating this behavior, most of this can be ignored
|
||||
// and it's sufficient to simply set the member variable for querying via
|
||||
// IsAutoSleepDisabled().
|
||||
|
||||
LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", applet->auto_sleep_disabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called.");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(applet->auto_sleep_disabled);
|
||||
}
|
||||
|
||||
void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called.");
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
// This command returns the total number of system ticks since ISelfController creation
|
||||
// where the game was suspended. Since Yuzu doesn't implement game suspension, this command
|
||||
// can just always return 0 ticks.
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u64>(applet->suspended_ticks);
|
||||
}
|
||||
|
||||
void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(applet->accumulated_suspended_tick_changed_event.GetHandle());
|
||||
}
|
||||
|
||||
void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
// This service call sets an internal flag whether a notification is shown when an image is
|
||||
// captured. Currently we do not support capturing images via the capture button, so this can be
|
||||
// stubbed for now.
|
||||
const bool enabled = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->album_image_taken_notification_enabled = enabled;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto report_option = rp.PopEnum<Capture::AlbumReportOption>();
|
||||
|
||||
LOG_INFO(Service_AM, "called, report_option={}", report_option);
|
||||
|
||||
const auto screenshot_service =
|
||||
system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
|
||||
"caps:su");
|
||||
|
||||
if (screenshot_service) {
|
||||
screenshot_service->CaptureAndSaveScreenshot(report_option);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto enabled = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
|
||||
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->record_volume_muted = enabled;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
58
src/core/hle/service/am/self_controller.h
Normal file
58
src/core/hle/service/am/self_controller.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class ISelfController final : public ServiceFramework<ISelfController> {
|
||||
public:
|
||||
explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
Nvnflinger::Nvnflinger& nvnflinger_);
|
||||
~ISelfController() override;
|
||||
|
||||
private:
|
||||
void Exit(HLERequestContext& ctx);
|
||||
void LockExit(HLERequestContext& ctx);
|
||||
void UnlockExit(HLERequestContext& ctx);
|
||||
void EnterFatalSection(HLERequestContext& ctx);
|
||||
void LeaveFatalSection(HLERequestContext& ctx);
|
||||
void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
|
||||
void SetScreenShotPermission(HLERequestContext& ctx);
|
||||
void SetOperationModeChangedNotification(HLERequestContext& ctx);
|
||||
void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
|
||||
void SetFocusHandlingMode(HLERequestContext& ctx);
|
||||
void SetRestartMessageEnabled(HLERequestContext& ctx);
|
||||
void SetScreenShotAppletIdentityInfo(HLERequestContext& ctx);
|
||||
void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
|
||||
void SetAlbumImageOrientation(HLERequestContext& ctx);
|
||||
void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
|
||||
void GetSystemSharedBufferHandle(HLERequestContext& ctx);
|
||||
void GetSystemSharedLayerHandle(HLERequestContext& ctx);
|
||||
void CreateManagedDisplayLayer(HLERequestContext& ctx);
|
||||
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
|
||||
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
|
||||
void ApproveToDisplay(HLERequestContext& ctx);
|
||||
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||
void ReportUserIsActive(HLERequestContext& ctx);
|
||||
void SetAutoSleepDisabled(HLERequestContext& ctx);
|
||||
void IsAutoSleepDisabled(HLERequestContext& ctx);
|
||||
void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
|
||||
void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
|
||||
void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
|
||||
void SaveCurrentScreenshot(HLERequestContext& ctx);
|
||||
void SetRecordVolumeMuted(HLERequestContext& ctx);
|
||||
|
||||
Result EnsureBufferSharingEnabled(Kernel::KProcess* process);
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
59
src/core/hle/service/am/storage.cpp
Normal file
59
src/core/hle/service/am/storage.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/library_applet_storage.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/am/storage_accessor.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_)
|
||||
: ServiceFramework{system_, "IStorage"}, impl{std::move(impl_)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IStorage::Open, "Open"},
|
||||
{1, &IStorage::OpenTransferStorage, "OpenTransferStorage"},
|
||||
};
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IStorage::IStorage(Core::System& system_, std::vector<u8>&& data)
|
||||
: IStorage(system_, CreateStorage(std::move(data))) {}
|
||||
|
||||
IStorage::~IStorage() = default;
|
||||
|
||||
void IStorage::Open(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (impl->GetHandle() != nullptr) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(AM::ResultInvalidStorageType);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IStorageAccessor>(system, impl);
|
||||
}
|
||||
|
||||
void IStorage::OpenTransferStorage(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (impl->GetHandle() == nullptr) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(AM::ResultInvalidStorageType);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ITransferStorageAccessor>(system, impl);
|
||||
}
|
||||
|
||||
std::vector<u8> IStorage::GetData() const {
|
||||
return impl->GetData();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
31
src/core/hle/service/am/storage.h
Normal file
31
src/core/hle/service/am/storage.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class LibraryAppletStorage;
|
||||
|
||||
class IStorage final : public ServiceFramework<IStorage> {
|
||||
public:
|
||||
explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_);
|
||||
explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
|
||||
~IStorage() override;
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> GetImpl() const {
|
||||
return impl;
|
||||
}
|
||||
|
||||
std::vector<u8> GetData() const;
|
||||
|
||||
private:
|
||||
void Open(HLERequestContext& ctx);
|
||||
void OpenTransferStorage(HLERequestContext& ctx);
|
||||
|
||||
const std::shared_ptr<LibraryAppletStorage> impl;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue