forked from eden-emu/eden
		
	am: migrate global state to per-applet state structure
This commit is contained in:
		
							parent
							
								
									3155f4e96d
								
							
						
					
					
						commit
						182137a9a4
					
				
					 41 changed files with 692 additions and 753 deletions
				
			
		|  | @ -392,6 +392,7 @@ struct System::Impl { | ||||||
|         // All threads are started, begin main process execution, now that we're in the clear.
 |         // All threads are started, begin main process execution, now that we're in the clear.
 | ||||||
|         main_process->Run(load_parameters->main_thread_priority, |         main_process->Run(load_parameters->main_thread_priority, | ||||||
|                           load_parameters->main_thread_stack_size); |                           load_parameters->main_thread_stack_size); | ||||||
|  |         main_process->Close(); | ||||||
| 
 | 
 | ||||||
|         if (Settings::values.gamecard_inserted) { |         if (Settings::values.gamecard_inserted) { | ||||||
|             if (Settings::values.gamecard_current_game) { |             if (Settings::values.gamecard_current_game) { | ||||||
|  | @ -886,10 +887,6 @@ void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set | ||||||
|     impl->frontend_applets.SetFrontendAppletSet(std::move(set)); |     impl->frontend_applets.SetFrontendAppletSet(std::move(set)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void System::SetDefaultAppletFrontendSet() { |  | ||||||
|     impl->frontend_applets.SetDefaultAppletFrontendSet(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() { | Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() { | ||||||
|     return impl->frontend_applets; |     return impl->frontend_applets; | ||||||
| } | } | ||||||
|  | @ -898,6 +895,10 @@ const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHold | ||||||
|     return impl->frontend_applets; |     return impl->frontend_applets; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Service::AM::AppletManager& System::GetAppletManager() { | ||||||
|  |     return impl->applet_manager; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) { | void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) { | ||||||
|     impl->content_provider = std::move(provider); |     impl->content_provider = std::move(provider); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -350,12 +350,13 @@ public: | ||||||
|                            u64 main_region_size); |                            u64 main_region_size); | ||||||
| 
 | 
 | ||||||
|     void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); |     void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); | ||||||
|     void SetDefaultAppletFrontendSet(); |  | ||||||
| 
 | 
 | ||||||
|     [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder(); |     [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder(); | ||||||
|     [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder() |     [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder() | ||||||
|         const; |         const; | ||||||
| 
 | 
 | ||||||
|  |     [[nodiscard]] Service::AM::AppletManager& GetAppletManager(); | ||||||
|  | 
 | ||||||
|     void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); |     void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); | ||||||
| 
 | 
 | ||||||
|     [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); |     [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); | ||||||
|  |  | ||||||
|  | @ -97,8 +97,14 @@ struct KernelCore::Impl { | ||||||
|         RegisterHostThread(nullptr); |         RegisterHostThread(nullptr); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void TerminateApplicationProcess() { |     void TerminateAllProcesses() { | ||||||
|         application_process.load()->Terminate(); |         std::scoped_lock lk{process_list_lock}; | ||||||
|  |         for (auto& process : process_list) { | ||||||
|  |             process->Terminate(); | ||||||
|  |             process->Close(); | ||||||
|  |             process = nullptr; | ||||||
|  |         } | ||||||
|  |         process_list.clear(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void Shutdown() { |     void Shutdown() { | ||||||
|  | @ -107,18 +113,9 @@ struct KernelCore::Impl { | ||||||
| 
 | 
 | ||||||
|         CloseServices(); |         CloseServices(); | ||||||
| 
 | 
 | ||||||
|         auto* old_process = application_process.exchange(nullptr); |         if (application_process) { | ||||||
|         if (old_process) { |             application_process->Close(); | ||||||
|             old_process->Close(); |             application_process = nullptr; | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         { |  | ||||||
|             std::scoped_lock lk{process_list_lock}; |  | ||||||
|             for (auto* const process : process_list) { |  | ||||||
|                 process->Terminate(); |  | ||||||
|                 process->Close(); |  | ||||||
|             } |  | ||||||
|             process_list.clear(); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         next_object_id = 0; |         next_object_id = 0; | ||||||
|  | @ -354,6 +351,7 @@ struct KernelCore::Impl { | ||||||
| 
 | 
 | ||||||
|     void MakeApplicationProcess(KProcess* process) { |     void MakeApplicationProcess(KProcess* process) { | ||||||
|         application_process = process; |         application_process = process; | ||||||
|  |         application_process->Open(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static inline thread_local u8 host_thread_id = UINT8_MAX; |     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.
 |     // Lists all processes that exist in the current session.
 | ||||||
|     std::mutex process_list_lock; |     std::mutex process_list_lock; | ||||||
|     std::vector<KProcess*> process_list; |     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::GlobalSchedulerContext> global_scheduler_context; | ||||||
|     std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; |     std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; | ||||||
| 
 | 
 | ||||||
|  | @ -1243,7 +1241,7 @@ void KernelCore::SuspendApplication(bool suspended) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void KernelCore::ShutdownCores() { | void KernelCore::ShutdownCores() { | ||||||
|     impl->TerminateApplicationProcess(); |     impl->TerminateAllProcesses(); | ||||||
| 
 | 
 | ||||||
|     KScopedSchedulerLock lk{*this}; |     KScopedSchedulerLock lk{*this}; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,7 +3,6 @@ | ||||||
| 
 | 
 | ||||||
| #include "core/hle/service/am/am.h" | #include "core/hle/service/am/am.h" | ||||||
| #include "core/hle/service/am/applet_ae.h" | #include "core/hle/service/am/applet_ae.h" | ||||||
| #include "core/hle/service/am/applet_message_queue.h" |  | ||||||
| #include "core/hle/service/am/applet_oe.h" | #include "core/hle/service/am/applet_oe.h" | ||||||
| #include "core/hle/service/am/idle.h" | #include "core/hle/service/am/idle.h" | ||||||
| #include "core/hle/service/am/omm.h" | #include "core/hle/service/am/omm.h" | ||||||
|  | @ -13,13 +12,12 @@ | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { | void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { | ||||||
|     auto message_queue = std::make_shared<AppletMessageQueue>(system); |  | ||||||
|     auto server_manager = std::make_unique<ServerManager>(system); |     auto server_manager = std::make_unique<ServerManager>(system); | ||||||
| 
 | 
 | ||||||
|     server_manager->RegisterNamedService( |     server_manager->RegisterNamedService("appletAE", | ||||||
|         "appletAE", std::make_shared<AppletAE>(nvnflinger, message_queue, system)); |                                          std::make_shared<AppletAE>(nvnflinger, system)); | ||||||
|     server_manager->RegisterNamedService( |     server_manager->RegisterNamedService("appletOE", | ||||||
|         "appletOE", std::make_shared<AppletOE>(nvnflinger, message_queue, system)); |                                          std::make_shared<AppletOE>(nvnflinger, system)); | ||||||
|     server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system)); |     server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system)); | ||||||
|     server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system)); |     server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system)); | ||||||
|     server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(system)); |     server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(system)); | ||||||
|  |  | ||||||
|  | @ -10,5 +10,6 @@ namespace Service::AM { | ||||||
| constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; | constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; | ||||||
| constexpr Result ResultNoMessages{ErrorModule::AM, 3}; | constexpr Result ResultNoMessages{ErrorModule::AM, 3}; | ||||||
| constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; | constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; | ||||||
|  | constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512}; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -2,40 +2,15 @@ | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
| 
 | 
 | ||||||
| #include "core/hle/service/am/applet_ae.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/library_applet_proxy.h" | ||||||
| #include "core/hle/service/am/system_applet_proxy.h" | #include "core/hle/service/am/system_applet_proxy.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { | AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_) | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} { | ||||||
| 
 |  | ||||||
|     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_)} { |  | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, |         {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, | ||||||
|  | @ -54,8 +29,45 @@ AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
| 
 | 
 | ||||||
| AppletAE::~AppletAE() = default; | AppletAE::~AppletAE() = default; | ||||||
| 
 | 
 | ||||||
| const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const { | void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { | ||||||
|     return msg_queue; |     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
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -18,23 +18,21 @@ class Nvnflinger; | ||||||
| 
 | 
 | ||||||
| namespace AM { | namespace AM { | ||||||
| 
 | 
 | ||||||
| class AppletMessageQueue; | struct Applet; | ||||||
| 
 | 
 | ||||||
| class AppletAE final : public ServiceFramework<AppletAE> { | class AppletAE final : public ServiceFramework<AppletAE> { | ||||||
| public: | public: | ||||||
|     explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, |     explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_); | ||||||
|                       std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_); |  | ||||||
|     ~AppletAE() override; |     ~AppletAE() override; | ||||||
| 
 | 
 | ||||||
|     const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     void OpenSystemAppletProxy(HLERequestContext& ctx); |     void OpenSystemAppletProxy(HLERequestContext& ctx); | ||||||
|     void OpenLibraryAppletProxy(HLERequestContext& ctx); |     void OpenLibraryAppletProxy(HLERequestContext& ctx); | ||||||
|     void OpenLibraryAppletProxyOld(HLERequestContext& ctx); |     void OpenLibraryAppletProxyOld(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|  |     std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|     Nvnflinger::Nvnflinger& nvnflinger; |     Nvnflinger::Nvnflinger& nvnflinger; | ||||||
|     std::shared_ptr<AppletMessageQueue> msg_queue; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace AM
 | } // namespace AM
 | ||||||
|  |  | ||||||
|  | @ -1,13 +1,15 @@ | ||||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // 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/am/applet_common_functions.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) | IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_, | ||||||
|     : ServiceFramework{system_, "IAppletCommonFunctions"} { |                                                std::shared_ptr<Applet> applet_) | ||||||
|  |     : ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} { | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, nullptr, "SetTerminateResult"}, |         {0, nullptr, "SetTerminateResult"}, | ||||||
|  | @ -40,6 +42,11 @@ IAppletCommonFunctions::~IAppletCommonFunctions() = default; | ||||||
| void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { | void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,13 +7,17 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { | class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { | ||||||
| public: | public: | ||||||
|     explicit IAppletCommonFunctions(Core::System& system_); |     explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_); | ||||||
|     ~IAppletCommonFunctions() override; |     ~IAppletCommonFunctions() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void SetCpuBoostRequestPriority(HLERequestContext& ctx); |     void SetCpuBoostRequestPriority(HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     const std::shared_ptr<Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -294,8 +294,8 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters( | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Applet was started by frontend, so it is foreground.
 |     // Applet was started by frontend, so it is foreground.
 | ||||||
|     applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); |  | ||||||
|     applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); |     applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); | ||||||
|  |     applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); | ||||||
|     applet->focus_state = FocusState::InFocus; |     applet->focus_state = FocusState::InFocus; | ||||||
| 
 | 
 | ||||||
|     this->InsertApplet(std::move(applet)); |     this->InsertApplet(std::move(applet)); | ||||||
|  |  | ||||||
|  | @ -26,11 +26,15 @@ Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AppletMessageQueue::PushMessage(AppletMessage msg) { | void AppletMessageQueue::PushMessage(AppletMessage msg) { | ||||||
|     messages.push(msg); |     { | ||||||
|  |         std::scoped_lock lk{lock}; | ||||||
|  |         messages.push(msg); | ||||||
|  |     } | ||||||
|     on_new_message->Signal(); |     on_new_message->Signal(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { | AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { | ||||||
|  |     std::scoped_lock lk{lock}; | ||||||
|     if (messages.empty()) { |     if (messages.empty()) { | ||||||
|         on_new_message->Clear(); |         on_new_message->Clear(); | ||||||
|         return AppletMessage::None; |         return AppletMessage::None; | ||||||
|  | @ -44,6 +48,7 @@ AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::size_t AppletMessageQueue::GetMessageCount() const { | std::size_t AppletMessageQueue::GetMessageCount() const { | ||||||
|  |     std::scoped_lock lk{lock}; | ||||||
|     return messages.size(); |     return messages.size(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -69,6 +69,7 @@ private: | ||||||
|     Kernel::KEvent* on_new_message; |     Kernel::KEvent* on_new_message; | ||||||
|     Kernel::KEvent* on_operation_mode_changed; |     Kernel::KEvent* on_operation_mode_changed; | ||||||
| 
 | 
 | ||||||
|  |     mutable std::mutex lock; | ||||||
|     std::queue<AppletMessage> messages; |     std::queue<AppletMessage> messages; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,24 +2,15 @@ | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
| 
 | 
 | ||||||
| #include "core/hle/service/am/am.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/applet_oe.h" | ||||||
| #include "core/hle/service/am/application_proxy.h" | #include "core/hle/service/am/application_proxy.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { | AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_) | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} { | ||||||
| 
 |  | ||||||
|     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_)} { |  | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, |         {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, | ||||||
|     }; |     }; | ||||||
|  | @ -28,8 +19,24 @@ AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
| 
 | 
 | ||||||
| AppletOE::~AppletOE() = default; | AppletOE::~AppletOE() = default; | ||||||
| 
 | 
 | ||||||
| const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const { | void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { | ||||||
|     return msg_queue; |     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
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -18,21 +18,19 @@ class Nvnflinger; | ||||||
| 
 | 
 | ||||||
| namespace AM { | namespace AM { | ||||||
| 
 | 
 | ||||||
| class AppletMessageQueue; | struct Applet; | ||||||
| 
 | 
 | ||||||
| class AppletOE final : public ServiceFramework<AppletOE> { | class AppletOE final : public ServiceFramework<AppletOE> { | ||||||
| public: | public: | ||||||
|     explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, |     explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_); | ||||||
|                       std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_); |  | ||||||
|     ~AppletOE() override; |     ~AppletOE() override; | ||||||
| 
 | 
 | ||||||
|     const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     void OpenApplicationProxy(HLERequestContext& ctx); |     void OpenApplicationProxy(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|  |     std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|     Nvnflinger::Nvnflinger& nvnflinger; |     Nvnflinger::Nvnflinger& nvnflinger; | ||||||
|     std::shared_ptr<AppletMessageQueue> msg_queue; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace AM
 | } // namespace AM
 | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include "core/file_sys/savedata_factory.h" | #include "core/file_sys/savedata_factory.h" | ||||||
| #include "core/hle/service/acc/profile_manager.h" | #include "core/hle/service/acc/profile_manager.h" | ||||||
| #include "core/hle/service/am/am_results.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/application_functions.h" | ||||||
| #include "core/hle/service/am/storage.h" | #include "core/hle/service/am/storage.h" | ||||||
| #include "core/hle/service/filesystem/filesystem.h" | #include "core/hle/service/filesystem/filesystem.h" | ||||||
|  | @ -24,19 +25,8 @@ enum class LaunchParameterKind : u32 { | ||||||
|     AccountPreselectedUser = 2, |     AccountPreselectedUser = 2, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; | IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_) | ||||||
| 
 |     : ServiceFramework{system_, "IApplicationFunctions"}, applet{std::move(applet_)} { | ||||||
| struct LaunchParameterAccountPreselectedUser { |  | ||||||
|     u32_le magic; |  | ||||||
|     u32_le is_account_selected; |  | ||||||
|     Common::UUID current_user; |  | ||||||
|     INSERT_PADDING_BYTES(0x70); |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); |  | ||||||
| 
 |  | ||||||
| IApplicationFunctions::IApplicationFunctions(Core::System& system_) |  | ||||||
|     : ServiceFramework{system_, "IApplicationFunctions"}, |  | ||||||
|       service_context{system, "IApplicationFunctions"} { |  | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, |         {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, | ||||||
|  | @ -105,27 +95,16 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | ||||||
|     // clang-format on
 |     // clang-format on
 | ||||||
| 
 | 
 | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| 
 |  | ||||||
|     gpu_error_detected_event = |  | ||||||
|         service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent"); |  | ||||||
|     friend_invitation_storage_channel_event = |  | ||||||
|         service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent"); |  | ||||||
|     notification_storage_channel_event = |  | ||||||
|         service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent"); |  | ||||||
|     health_warning_disappeared_system_event = |  | ||||||
|         service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent"); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IApplicationFunctions::~IApplicationFunctions() { | IApplicationFunctions::~IApplicationFunctions() = default; | ||||||
|     service_context.CloseEvent(gpu_error_detected_event); |  | ||||||
|     service_context.CloseEvent(friend_invitation_storage_channel_event); |  | ||||||
|     service_context.CloseEvent(notification_storage_channel_event); |  | ||||||
|     service_context.CloseEvent(health_warning_disappeared_system_event); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { | void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->application_crash_report_enabled = true; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -157,6 +136,10 @@ void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& | ||||||
| void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { | void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -164,6 +147,10 @@ void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLEReques | ||||||
| void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { | void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -171,6 +158,11 @@ void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestC | ||||||
| void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { | void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -178,6 +170,11 @@ void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { | ||||||
| void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { | void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -188,47 +185,25 @@ void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     LOG_INFO(Service_AM, "called, kind={:08X}", kind); |     LOG_INFO(Service_AM, "called, kind={:08X}", kind); | ||||||
| 
 | 
 | ||||||
|     if (kind == LaunchParameterKind::UserChannel) { |     std::scoped_lock lk{applet->lock}; | ||||||
|         auto channel = system.GetUserChannel(); |  | ||||||
|         if (channel.empty()) { |  | ||||||
|             LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); |  | ||||||
|             IPC::ResponseBuilder rb{ctx, 2}; |  | ||||||
|             rb.Push(AM::ResultNoDataInChannel); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         auto data = channel.back(); |     auto& channel = kind == LaunchParameterKind::UserChannel | ||||||
|         channel.pop_back(); |                         ? applet->user_channel_launch_parameter | ||||||
|  |                         : applet->preselected_user_launch_parameter; | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     if (channel.empty()) { | ||||||
|         rb.Push(ResultSuccess); |         LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!", kind); | ||||||
|         rb.PushIpcInterface<IStorage>(system, std::move(data)); |  | ||||||
|     } else if (kind == LaunchParameterKind::AccountPreselectedUser && |  | ||||||
|                !launch_popped_account_preselect) { |  | ||||||
|         // TODO: Verify this is hw-accurate
 |  | ||||||
|         LaunchParameterAccountPreselectedUser params{}; |  | ||||||
| 
 |  | ||||||
|         params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; |  | ||||||
|         params.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()); |  | ||||||
|         params.current_user = *uuid; |  | ||||||
| 
 |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |  | ||||||
|         rb.Push(ResultSuccess); |  | ||||||
| 
 |  | ||||||
|         std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); |  | ||||||
|         std::memcpy(buffer.data(), ¶ms, buffer.size()); |  | ||||||
| 
 |  | ||||||
|         rb.PushIpcInterface<IStorage>(system, std::move(buffer)); |  | ||||||
|         launch_popped_account_preselect = true; |  | ||||||
|     } else { |  | ||||||
|         LOG_ERROR(Service_AM, "Unknown launch parameter kind."); |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(AM::ResultNoDataInChannel); |         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) { | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) { | ||||||
|  | @ -245,7 +220,7 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); |     LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); | ||||||
| 
 | 
 | ||||||
|     FileSys::SaveDataAttribute attribute{}; |     FileSys::SaveDataAttribute attribute{}; | ||||||
|     attribute.title_id = system.GetApplicationProcessProgramID(); |     attribute.title_id = applet->program_id; | ||||||
|     attribute.user_id = user_id; |     attribute.user_id = user_id; | ||||||
|     attribute.type = FileSys::SaveDataType::SaveData; |     attribute.type = FileSys::SaveDataType::SaveData; | ||||||
| 
 | 
 | ||||||
|  | @ -267,6 +242,9 @@ void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) { | ||||||
|     u32 result = rp.Pop<u32>(); |     u32 result = rp.Pop<u32>(); | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -277,16 +255,14 @@ void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) { | ||||||
|     std::array<u8, 0x10> version_string{}; |     std::array<u8, 0x10> version_string{}; | ||||||
| 
 | 
 | ||||||
|     const auto res = [this] { |     const auto res = [this] { | ||||||
|         const auto title_id = system.GetApplicationProcessProgramID(); |         const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(), | ||||||
| 
 |  | ||||||
|         const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |  | ||||||
|                                        system.GetContentProvider()}; |                                        system.GetContentProvider()}; | ||||||
|         auto metadata = pm.GetControlMetadata(); |         auto metadata = pm.GetControlMetadata(); | ||||||
|         if (metadata.first != nullptr) { |         if (metadata.first != nullptr) { | ||||||
|             return metadata; |             return metadata; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), |         const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id), | ||||||
|                                               system.GetFileSystemController(), |                                               system.GetFileSystemController(), | ||||||
|                                               system.GetContentProvider()}; |                                               system.GetContentProvider()}; | ||||||
|         return pm_update.GetControlMetadata(); |         return pm_update.GetControlMetadata(); | ||||||
|  | @ -314,16 +290,14 @@ void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { | ||||||
|     u32 supported_languages = 0; |     u32 supported_languages = 0; | ||||||
| 
 | 
 | ||||||
|     const auto res = [this] { |     const auto res = [this] { | ||||||
|         const auto title_id = system.GetApplicationProcessProgramID(); |         const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(), | ||||||
| 
 |  | ||||||
|         const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |  | ||||||
|                                        system.GetContentProvider()}; |                                        system.GetContentProvider()}; | ||||||
|         auto metadata = pm.GetControlMetadata(); |         auto metadata = pm.GetControlMetadata(); | ||||||
|         if (metadata.first != nullptr) { |         if (metadata.first != nullptr) { | ||||||
|             return metadata; |             return metadata; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), |         const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id), | ||||||
|                                               system.GetFileSystemController(), |                                               system.GetFileSystemController(), | ||||||
|                                               system.GetContentProvider()}; |                                               system.GetContentProvider()}; | ||||||
|         return pm_update.GetControlMetadata(); |         return pm_update.GetControlMetadata(); | ||||||
|  | @ -368,11 +342,9 @@ void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { | ||||||
| void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) { | void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     constexpr bool gameplay_recording_supported = false; |  | ||||||
| 
 |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push(gameplay_recording_supported); |     rb.Push(applet->gameplay_recording_supported); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) { | void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) { | ||||||
|  | @ -385,6 +357,11 @@ void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) | ||||||
| void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { | void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -392,6 +369,9 @@ void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { | ||||||
| void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { | void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->is_running = true; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
 |     rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
 | ||||||
|  | @ -426,8 +406,7 @@ void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { | ||||||
|               static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); |               static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); | ||||||
| 
 | 
 | ||||||
|     system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( |     system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( | ||||||
|         type, system.GetApplicationProcessProgramID(), user_id, |         type, applet->program_id, user_id, {new_normal_size, new_journal_size}); | ||||||
|         {new_normal_size, new_journal_size}); |  | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -451,7 +430,7 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { | ||||||
|               user_id[0]); |               user_id[0]); | ||||||
| 
 | 
 | ||||||
|     const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( |     const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( | ||||||
|         type, system.GetApplicationProcessProgramID(), user_id); |         type, applet->program_id, user_id); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 6}; |     IPC::ResponseBuilder rb{ctx, 6}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -528,13 +507,15 @@ void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     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); |     system.ExecuteProgram(program_index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { | void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     system.GetUserChannel().clear(); |     applet->user_channel_launch_parameter.clear(); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -546,7 +527,7 @@ void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto storage = rp.PopIpcInterface<IStorage>().lock(); |     const auto storage = rp.PopIpcInterface<IStorage>().lock(); | ||||||
|     if (storage) { |     if (storage) { | ||||||
|         system.GetUserChannel().push_back(storage->GetData()); |         applet->user_channel_launch_parameter.push_back(storage->GetData()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  | @ -558,7 +539,7 @@ void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push<s32>(previous_program_index); |     rb.Push<s32>(applet->previous_program_index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) { | void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) { | ||||||
|  | @ -566,7 +547,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ct | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); |     rb.PushCopyObjects(applet->gpu_error_detected_event.GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { | void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { | ||||||
|  | @ -574,7 +555,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestCon | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); |     rb.PushCopyObjects(applet->friend_invitation_storage_channel_event.GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { | void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { | ||||||
|  | @ -589,7 +570,7 @@ void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent()); |     rb.PushCopyObjects(applet->notification_storage_channel_event.GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { | void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { | ||||||
|  | @ -597,12 +578,15 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestCon | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); |     rb.PushCopyObjects(applet->health_warning_disappeared_system_event.GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { | void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->jit_service_launched = true; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,9 +8,11 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | ||||||
| public: | public: | ||||||
|     explicit IApplicationFunctions(Core::System& system_); |     explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_); | ||||||
|     ~IApplicationFunctions() override; |     ~IApplicationFunctions() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | @ -50,14 +52,7 @@ private: | ||||||
|     void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx); |     void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx); | ||||||
|     void PrepareForJit(HLERequestContext& ctx); |     void PrepareForJit(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     KernelHelpers::ServiceContext service_context; |     const std::shared_ptr<Applet> applet; | ||||||
| 
 |  | ||||||
|     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; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -18,10 +18,9 @@ | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, | IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|                                      std::shared_ptr<AppletMessageQueue> msg_queue_, |                                      std::shared_ptr<Applet> applet_, Core::System& system_) | ||||||
|                                      Core::System& system_) |     : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, applet{std::move( | ||||||
|     : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, |                                                                                    applet_)} { | ||||||
|       msg_queue{std::move(msg_queue_)} { |  | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |         {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, | ||||||
|  | @ -39,6 +38,8 @@ IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | IApplicationProxy::~IApplicationProxy() = default; | ||||||
|  | 
 | ||||||
| void IApplicationProxy::GetAudioController(HLERequestContext& ctx) { | void IApplicationProxy::GetAudioController(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|  | @ -60,7 +61,7 @@ void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<IProcessWindingController>(system); |     rb.PushIpcInterface<IProcessWindingController>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) { | void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) { | ||||||
|  | @ -76,7 +77,7 @@ void IApplicationProxy::GetWindowController(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<IWindowController>(system); |     rb.PushIpcInterface<IWindowController>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { | void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { | ||||||
|  | @ -84,7 +85,7 @@ void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ISelfController>(system, nvnflinger); |     rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { | void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { | ||||||
|  | @ -92,7 +93,7 @@ void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); |     rb.PushIpcInterface<ICommonStateGetter>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { | void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { | ||||||
|  | @ -100,7 +101,7 @@ void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ILibraryAppletCreator>(system); |     rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { | void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { | ||||||
|  | @ -108,7 +109,7 @@ void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<IApplicationFunctions>(system); |     rb.PushIpcInterface<IApplicationFunctions>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -3,16 +3,17 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "core/hle/service/am/applet_message_queue.h" |  | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { | class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { | ||||||
| public: | public: | ||||||
|     explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, |     explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|                                std::shared_ptr<AppletMessageQueue> msg_queue_, |                                std::shared_ptr<Applet> msg_queue_, Core::System& system_); | ||||||
|                                Core::System& system_); |     ~IApplicationProxy(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void GetAudioController(HLERequestContext& ctx); |     void GetAudioController(HLERequestContext& ctx); | ||||||
|  | @ -26,7 +27,7 @@ private: | ||||||
|     void GetApplicationFunctions(HLERequestContext& ctx); |     void GetApplicationFunctions(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     Nvnflinger::Nvnflinger& nvnflinger; |     Nvnflinger::Nvnflinger& nvnflinger; | ||||||
|     std::shared_ptr<AppletMessageQueue> msg_queue; |     std::shared_ptr<Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "common/settings.h" | #include "common/settings.h" | ||||||
| #include "core/hle/service/am/am_results.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/common_state_getter.h" | ||||||
| #include "core/hle/service/am/lock_accessor.h" | #include "core/hle/service/am/lock_accessor.h" | ||||||
| #include "core/hle/service/apm/apm_controller.h" | #include "core/hle/service/apm/apm_controller.h" | ||||||
|  | @ -14,10 +15,8 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| ICommonStateGetter::ICommonStateGetter(Core::System& system_, | ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_) | ||||||
|                                        std::shared_ptr<AppletMessageQueue> msg_queue_) |     : ServiceFramework{system_, "ICommonStateGetter"}, applet{std::move(applet_)} { | ||||||
|     : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, |  | ||||||
|       service_context{system_, "ICommonStateGetter"} { |  | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, |         {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, | ||||||
|  | @ -75,17 +74,9 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, | ||||||
|     // clang-format on
 |     // clang-format on
 | ||||||
| 
 | 
 | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| 
 |  | ||||||
|     sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent"); |  | ||||||
| 
 |  | ||||||
|     // Configure applets to be in foreground state
 |  | ||||||
|     msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); |  | ||||||
|     msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ICommonStateGetter::~ICommonStateGetter() { | ICommonStateGetter::~ICommonStateGetter() = default; | ||||||
|     service_context.CloseEvent(sleep_lock_event); |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { | void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
|  | @ -96,17 +87,17 @@ void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { | void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent()); |     rb.PushCopyObjects(applet->message_queue.GetMessageReceiveEvent()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { | void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     const auto message = msg_queue->PopMessage(); |     const auto message = applet->message_queue.PopMessage(); | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
| 
 | 
 | ||||||
|     if (message == AppletMessageQueue::AppletMessage::None) { |     if (message == AppletMessageQueue::AppletMessage::None) { | ||||||
|  | @ -123,9 +114,11 @@ void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { | ||||||
| void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { | void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "(STUBBED) called"); |     LOG_DEBUG(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push(static_cast<u8>(FocusState::InFocus)); |     rb.Push(static_cast<u8>(applet->focus_state)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { | void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { | ||||||
|  | @ -149,7 +142,7 @@ void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     // Sleep lock is acquired immediately.
 |     // Sleep lock is acquired immediately.
 | ||||||
|     sleep_lock_event->Signal(); |     applet->sleep_lock_event.Signal(); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -172,22 +165,25 @@ void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(sleep_lock_event->GetReadableEvent()); |     rb.PushCopyObjects(applet->sleep_lock_event.GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { | void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push(vr_mode_state); |     rb.Push(applet->vr_mode_enabled); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { | void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     vr_mode_state = rp.Pop<bool>(); |  | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -207,6 +203,9 @@ void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) { | ||||||
| void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { | void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->vr_mode_enabled = true; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -214,6 +213,9 @@ void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { | ||||||
| void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { | void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->vr_mode_enabled = false; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -223,7 +225,7 @@ void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContex | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); |     rb.PushCopyObjects(applet->message_queue.GetOperationModeChangedEvent()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { | void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { | ||||||
|  | @ -281,6 +283,9 @@ void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnable | ||||||
|     HLERequestContext& ctx) { |     HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,10 +10,11 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { | ||||||
| public: | public: | ||||||
|     explicit ICommonStateGetter(Core::System& system_, |     explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_); | ||||||
|                                 std::shared_ptr<AppletMessageQueue> msg_queue_); |  | ||||||
|     ~ICommonStateGetter() override; |     ~ICommonStateGetter() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | @ -69,10 +70,7 @@ private: | ||||||
|     void GetSettingsPlatformRegion(HLERequestContext& ctx); |     void GetSettingsPlatformRegion(HLERequestContext& ctx); | ||||||
|     void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); |     void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<AppletMessageQueue> msg_queue; |     const std::shared_ptr<Applet> applet; | ||||||
|     bool vr_mode_state{}; |  | ||||||
|     Kernel::KEvent* sleep_lock_event; |  | ||||||
|     KernelHelpers::ServiceContext service_context; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
| #include "core/hle/kernel/k_event.h" | #include "core/hle/kernel/k_event.h" | ||||||
| #include "core/hle/service/am/am.h" | #include "core/hle/service/am/am.h" | ||||||
| #include "core/hle/service/am/applet_ae.h" | #include "core/hle/service/am/applet_ae.h" | ||||||
|  | #include "core/hle/service/am/applet_manager.h" | ||||||
| #include "core/hle/service/am/applet_message_queue.h" | #include "core/hle/service/am/applet_message_queue.h" | ||||||
| #include "core/hle/service/am/applet_oe.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_cabinet.h" | ||||||
|  | @ -122,21 +123,11 @@ void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& | ||||||
| void AppletDataBroker::SignalStateChanged() { | void AppletDataBroker::SignalStateChanged() { | ||||||
|     state_changed_event->Signal(); |     state_changed_event->Signal(); | ||||||
| 
 | 
 | ||||||
|  |     // TODO proper window management
 | ||||||
|     switch (applet_mode) { |     switch (applet_mode) { | ||||||
|     case LibraryAppletMode::AllForeground: |     case LibraryAppletMode::AllForeground: | ||||||
|     case LibraryAppletMode::AllForegroundInitiallyHidden: { |     case LibraryAppletMode::AllForegroundInitiallyHidden: { | ||||||
|         auto applet_oe = system.ServiceManager().GetService<AppletOE>("appletOE"); |         system.GetAppletManager().FocusStateChanged(); | ||||||
|         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; |         break; | ||||||
|     } |     } | ||||||
|     default: |     default: | ||||||
|  | @ -255,11 +246,6 @@ void FrontendAppletHolder::SetCurrentAppletId(AppletId applet_id) { | ||||||
|     current_applet_id = applet_id; |     current_applet_id = applet_id; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FrontendAppletHolder::SetDefaultAppletFrontendSet() { |  | ||||||
|     ClearAll(); |  | ||||||
|     SetDefaultAppletsIfMissing(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void FrontendAppletHolder::SetDefaultAppletsIfMissing() { | void FrontendAppletHolder::SetDefaultAppletsIfMissing() { | ||||||
|     if (frontend.cabinet == nullptr) { |     if (frontend.cabinet == nullptr) { | ||||||
|         frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>(); |         frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>(); | ||||||
|  |  | ||||||
|  | @ -188,7 +188,6 @@ public: | ||||||
|     void SetFrontendAppletSet(FrontendAppletSet set); |     void SetFrontendAppletSet(FrontendAppletSet set); | ||||||
|     void SetCabinetMode(NFP::CabinetMode mode); |     void SetCabinetMode(NFP::CabinetMode mode); | ||||||
|     void SetCurrentAppletId(AppletId applet_id); |     void SetCurrentAppletId(AppletId applet_id); | ||||||
|     void SetDefaultAppletFrontendSet(); |  | ||||||
|     void SetDefaultAppletsIfMissing(); |     void SetDefaultAppletsIfMissing(); | ||||||
|     void ClearAll(); |     void ClearAll(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,9 @@ | ||||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // 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/am_results.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_accessor.h" | ||||||
| #include "core/hle/service/am/storage.h" | #include "core/hle/service/am/storage.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
|  | @ -9,8 +11,10 @@ | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, | ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, | ||||||
|                                                std::shared_ptr<Frontend::FrontendApplet> applet_) |                                                std::shared_ptr<AppletStorageHolder> storage_, | ||||||
|     : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { |                                                std::shared_ptr<Applet> applet_) | ||||||
|  |     : ServiceFramework{system_, "ILibraryAppletAccessor"}, storage{std::move(storage_)}, | ||||||
|  |       applet{std::move(applet_)} { | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, |         {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, | ||||||
|  | @ -38,27 +42,31 @@ ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ILibraryAppletAccessor::~ILibraryAppletAccessor() = default; | ||||||
|  | 
 | ||||||
| void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) { | void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent()); |     rb.PushCopyObjects(storage->state_changed_event.GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { | void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push<u32>(applet->TransactionComplete()); |     rb.Push<u32>(applet->is_completed); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { | void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(applet->GetStatus()); |     rb.Push(applet->terminate_result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) { | void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) { | ||||||
|  | @ -71,10 +79,7 @@ void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestConte | ||||||
| void ILibraryAppletAccessor::Start(HLERequestContext& ctx) { | void ILibraryAppletAccessor::Start(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     ASSERT(applet != nullptr); |     applet->process->Run(); | ||||||
| 
 |  | ||||||
|     applet->Initialize(); |  | ||||||
|     applet->Execute(); |  | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -84,16 +89,17 @@ void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     ASSERT(applet != nullptr); |     ASSERT(applet != nullptr); | ||||||
|  |     applet->message_queue.RequestExit(); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(applet->RequestExit()); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { | void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>().lock()); |     storage->in_data.PushData(rp.PopIpcInterface<IStorage>().lock()); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -102,29 +108,24 @@ void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { | ||||||
| void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { | void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     auto storage = applet->GetBroker().PopNormalDataToGame(); |     std::shared_ptr<IStorage> data; | ||||||
|     if (storage == nullptr) { |     const auto res = storage->out_data.PopData(&data); | ||||||
|         LOG_DEBUG(Service_AM, |  | ||||||
|                   "storage is a nullptr. There is no data in the current normal channel"); |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |  | ||||||
|         rb.Push(AM::ResultNoDataInChannel); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     if (res.IsSuccess()) { | ||||||
|     rb.Push(ResultSuccess); |         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.PushIpcInterface<IStorage>(std::move(storage)); |         rb.Push(res); | ||||||
|  |         rb.PushIpcInterface(std::move(data)); | ||||||
|  |     } else { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(res); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { | void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>().lock()); |     storage->interactive_in_data.PushData(rp.PopIpcInterface<IStorage>().lock()); | ||||||
| 
 |  | ||||||
|     ASSERT(applet->IsInitialized()); |  | ||||||
|     applet->ExecuteInteractive(); |  | ||||||
|     applet->Execute(); |  | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -133,18 +134,17 @@ void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { | ||||||
| void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { | void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     auto storage = applet->GetBroker().PopInteractiveDataToGame(); |     std::shared_ptr<IStorage> data; | ||||||
|     if (storage == nullptr) { |     const auto res = storage->interactive_out_data.PopData(&data); | ||||||
|         LOG_DEBUG(Service_AM, |  | ||||||
|                   "storage is a nullptr. There is no data in the current interactive channel"); |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |  | ||||||
|         rb.Push(AM::ResultNoDataInChannel); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     if (res.IsSuccess()) { | ||||||
|     rb.Push(ResultSuccess); |         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.PushIpcInterface<IStorage>(std::move(storage)); |         rb.Push(res); | ||||||
|  |         rb.PushIpcInterface(std::move(data)); | ||||||
|  |     } else { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(res); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { | void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { | ||||||
|  | @ -152,7 +152,7 @@ void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); |     rb.PushCopyObjects(storage->out_data.GetEvent()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { | void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { | ||||||
|  | @ -160,7 +160,7 @@ void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ct | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); |     rb.PushCopyObjects(storage->interactive_out_data.GetEvent()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { | void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { | ||||||
|  |  | ||||||
|  | @ -3,17 +3,21 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "core/hle/service/am/frontend/applets.h" |  | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct AppletStorageHolder; | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { | ||||||
| public: | public: | ||||||
|     explicit ILibraryAppletAccessor(Core::System& system_, |     explicit ILibraryAppletAccessor(Core::System& system_, | ||||||
|                                     std::shared_ptr<Frontend::FrontendApplet> applet_); |                                     std::shared_ptr<AppletStorageHolder> storage_, | ||||||
|  |                                     std::shared_ptr<Applet> applet_); | ||||||
|  |     ~ILibraryAppletAccessor(); | ||||||
| 
 | 
 | ||||||
| private: | protected: | ||||||
|     void GetAppletStateChangedEvent(HLERequestContext& ctx); |     void GetAppletStateChangedEvent(HLERequestContext& ctx); | ||||||
|     void IsCompleted(HLERequestContext& ctx); |     void IsCompleted(HLERequestContext& ctx); | ||||||
|     void GetResult(HLERequestContext& ctx); |     void GetResult(HLERequestContext& ctx); | ||||||
|  | @ -28,7 +32,8 @@ private: | ||||||
|     void GetPopInteractiveOutDataEvent(HLERequestContext& ctx); |     void GetPopInteractiveOutDataEvent(HLERequestContext& ctx); | ||||||
|     void GetIndirectLayerConsumerHandle(HLERequestContext& ctx); |     void GetIndirectLayerConsumerHandle(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<Frontend::FrontendApplet> applet; |     const std::shared_ptr<AppletStorageHolder> storage; | ||||||
|  |     const std::shared_ptr<Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -2,16 +2,112 @@ | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/k_transfer_memory.h" | #include "core/hle/kernel/k_transfer_memory.h" | ||||||
|  | #include "core/hle/service/am/applet_manager.h" | ||||||
| #include "core/hle/service/am/frontend/applets.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_accessor.h" | ||||||
| #include "core/hle/service/am/library_applet_creator.h" | #include "core/hle/service/am/library_applet_creator.h" | ||||||
| #include "core/hle/service/am/storage.h" | #include "core/hle/service/am/storage.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
|  | #include "core/hle/service/sm/sm.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) | namespace { | ||||||
|     : ServiceFramework{system_, "ILibraryAppletCreator"} { | 
 | ||||||
|  | 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); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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; | ||||||
|  | 
 | ||||||
|  |     // Library applet should be foreground
 | ||||||
|  |     applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); | ||||||
|  |     applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); | ||||||
|  |     applet->focus_state = FocusState::InFocus; | ||||||
|  | 
 | ||||||
|  |     auto storage = std::make_shared<AppletStorageHolder>(system); | ||||||
|  |     applet->caller_applet = caller_applet; | ||||||
|  |     applet->caller_applet_storage = storage; | ||||||
|  | 
 | ||||||
|  |     system.GetAppletManager().InsertApplet(applet); | ||||||
|  | 
 | ||||||
|  |     return std::make_shared<ILibraryAppletAccessor>(system, storage, applet); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system, | ||||||
|  |                                                              AppletId applet_id, | ||||||
|  |                                                              LibraryAppletMode mode) { | ||||||
|  |     UNREACHABLE(); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
|  | 
 | ||||||
|  | ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_) | ||||||
|  |     : ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} { | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, |         {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, | ||||||
|         {1, nullptr, "TerminateAllLibraryApplets"}, |         {1, nullptr, "TerminateAllLibraryApplets"}, | ||||||
|  | @ -34,10 +130,11 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, |     LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, | ||||||
|               applet_mode); |               applet_mode); | ||||||
| 
 | 
 | ||||||
|     const auto& holder{system.GetFrontendAppletHolder()}; |     auto library_applet = CreateGuestApplet(system, applet, applet_id, applet_mode); | ||||||
|     const auto applet = holder.GetApplet(applet_id, applet_mode); |     if (!library_applet) { | ||||||
| 
 |         library_applet = CreateFrontendApplet(system, applet_id, applet_mode); | ||||||
|     if (applet == nullptr) { |     } | ||||||
|  |     if (!library_applet) { | ||||||
|         LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); |         LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  | @ -45,10 +142,12 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     // Applet is created, can now be launched.
 | ||||||
|  |     applet->library_applet_launchable_event.Signal(); | ||||||
| 
 | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); |     rb.PushIpcInterface<ILibraryAppletAccessor>(library_applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { | void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { | ||||||
|  |  | ||||||
|  | @ -7,9 +7,11 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { | class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { | ||||||
| public: | public: | ||||||
|     explicit ILibraryAppletCreator(Core::System& system_); |     explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_); | ||||||
|     ~ILibraryAppletCreator() override; |     ~ILibraryAppletCreator() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | @ -17,6 +19,8 @@ private: | ||||||
|     void CreateStorage(HLERequestContext& ctx); |     void CreateStorage(HLERequestContext& ctx); | ||||||
|     void CreateTransferMemoryStorage(HLERequestContext& ctx); |     void CreateTransferMemoryStorage(HLERequestContext& ctx); | ||||||
|     void CreateHandleStorage(HLERequestContext& ctx); |     void CreateHandleStorage(HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     const std::shared_ptr<Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -19,10 +19,9 @@ | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|                                          std::shared_ptr<AppletMessageQueue> msg_queue_, |                                          std::shared_ptr<Applet> applet_, Core::System& system_) | ||||||
|                                          Core::System& system_) |     : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move( | ||||||
|     : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, |                                                                                      applet_)} { | ||||||
|       msg_queue{std::move(msg_queue_)} { |  | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|         static const FunctionInfo functions[] = { |         static const FunctionInfo functions[] = { | ||||||
|             {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |             {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, | ||||||
|  | @ -43,12 +42,14 @@ ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ILibraryAppletProxy::~ILibraryAppletProxy() = default; | ||||||
|  | 
 | ||||||
| void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { | void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); |     rb.PushIpcInterface<ICommonStateGetter>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { | void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { | ||||||
|  | @ -56,7 +57,7 @@ void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ISelfController>(system, nvnflinger); |     rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { | void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { | ||||||
|  | @ -64,7 +65,7 @@ void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<IWindowController>(system); |     rb.PushIpcInterface<IWindowController>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) { | void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) { | ||||||
|  | @ -88,7 +89,7 @@ void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<IProcessWindingController>(system); |     rb.PushIpcInterface<IProcessWindingController>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { | void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { | ||||||
|  | @ -96,7 +97,7 @@ void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ILibraryAppletCreator>(system); |     rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { | void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { | ||||||
|  | @ -104,7 +105,7 @@ void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system); |     rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { | void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { | ||||||
|  | @ -112,7 +113,7 @@ void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<IAppletCommonFunctions>(system); |     rb.PushIpcInterface<IAppletCommonFunctions>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { | void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { | ||||||
|  |  | ||||||
|  | @ -3,16 +3,17 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "core/hle/service/am/applet_message_queue.h" |  | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { | class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { | ||||||
| public: | public: | ||||||
|     explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, |     explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|                                  std::shared_ptr<AppletMessageQueue> msg_queue_, |                                  std::shared_ptr<Applet> applet_, Core::System& system_); | ||||||
|                                  Core::System& system_); |     ~ILibraryAppletProxy(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void GetCommonStateGetter(HLERequestContext& ctx); |     void GetCommonStateGetter(HLERequestContext& ctx); | ||||||
|  | @ -29,7 +30,7 @@ private: | ||||||
|     void GetDebugFunctions(HLERequestContext& ctx); |     void GetDebugFunctions(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     Nvnflinger::Nvnflinger& nvnflinger; |     Nvnflinger::Nvnflinger& nvnflinger; | ||||||
|     std::shared_ptr<AppletMessageQueue> msg_queue; |     std::shared_ptr<Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -1,9 +1,11 @@ | ||||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
| 
 | 
 | ||||||
|  | #include "common/scope_exit.h" | ||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
| #include "core/hle/service/acc/profile_manager.h" | #include "core/hle/service/acc/profile_manager.h" | ||||||
| #include "core/hle/service/am/am_results.h" | #include "core/hle/service/am/am_results.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_cabinet.h" | ||||||
| #include "core/hle/service/am/frontend/applet_controller.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_mii_edit_types.h" | ||||||
|  | @ -16,16 +18,44 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) | namespace { | ||||||
|     : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} { | 
 | ||||||
|  | struct AppletIdentityInfo { | ||||||
|  |     AppletId applet_id; | ||||||
|  |     INSERT_PADDING_BYTES(0x4); | ||||||
|  |     u64 application_id; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); | ||||||
|  | 
 | ||||||
|  | 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 = applet->applet_id, | ||||||
|  |             .application_id = 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_)}, | ||||||
|  |       storage{applet->caller_applet_storage} { | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, |         {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, | ||||||
|         {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, |         {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, | ||||||
|         {2, nullptr, "PopInteractiveInData"}, |         {2, &ILibraryAppletSelfAccessor::PopInteractiveInData, "PopInteractiveInData"}, | ||||||
|         {3, nullptr, "PushInteractiveOutData"}, |         {3, &ILibraryAppletSelfAccessor::PushInteractiveOutData, "PushInteractiveOutData"}, | ||||||
|         {5, nullptr, "GetPopInDataEvent"}, |         {5, &ILibraryAppletSelfAccessor::GetPopInDataEvent, "GetPopInDataEvent"}, | ||||||
|         {6, nullptr, "GetPopInteractiveInDataEvent"}, |         {6, &ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent, "GetPopInteractiveInDataEvent"}, | ||||||
|         {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, |         {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, | ||||||
|         {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, |         {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, | ||||||
|         {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, |         {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, | ||||||
|  | @ -58,26 +88,6 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) | ||||||
|     }; |     }; | ||||||
|     // clang-format on
 |     // clang-format on
 | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| 
 |  | ||||||
|     switch (system.GetFrontendAppletHolder().GetCurrentAppletId()) { |  | ||||||
|     case AppletId::Cabinet: |  | ||||||
|         PushInShowCabinetData(); |  | ||||||
|         break; |  | ||||||
|     case AppletId::MiiEdit: |  | ||||||
|         PushInShowMiiEditData(); |  | ||||||
|         break; |  | ||||||
|     case AppletId::PhotoViewer: |  | ||||||
|         PushInShowAlbum(); |  | ||||||
|         break; |  | ||||||
|     case AppletId::SoftwareKeyboard: |  | ||||||
|         PushInShowSoftwareKeyboard(); |  | ||||||
|         break; |  | ||||||
|     case AppletId::Controller: |  | ||||||
|         PushInShowController(); |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; | ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; | ||||||
|  | @ -85,31 +95,81 @@ ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; | ||||||
| void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { | void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { | ||||||
|     LOG_INFO(Service_AM, "called"); |     LOG_INFO(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     if (queue_data.empty()) { |     std::shared_ptr<IStorage> data; | ||||||
|  |     const auto res = storage->in_data.PopData(&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}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(AM::ResultNoDataInChannel); |         rb.Push(res); | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     auto data = queue_data.front(); |  | ||||||
|     queue_data.pop_front(); |  | ||||||
| 
 |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |  | ||||||
|     rb.Push(ResultSuccess); |  | ||||||
|     rb.PushIpcInterface<IStorage>(system, std::move(data)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { | void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_INFO(Service_AM, "called"); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     storage->out_data.PushData(rp.PopIpcInterface<IStorage>().lock()); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { | void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_INFO(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     system.Exit(); |     std::shared_ptr<IStorage> data; | ||||||
|  |     const auto res = storage->interactive_in_data.PopData(&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}; | ||||||
|  |     storage->interactive_out_data.PushData(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(storage->in_data.GetEvent()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) { | ||||||
|  |     LOG_INFO(Service_AM, "called"); | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.PushCopyObjects(storage->interactive_in_data.GetEvent()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { | ||||||
|  |     LOG_INFO(Service_AM, "called"); | ||||||
|  | 
 | ||||||
|  |     system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid); | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         std::scoped_lock lk{applet->lock}; | ||||||
|  |         applet->is_completed = true; | ||||||
|  |         storage->state_changed_event.Signal(); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -124,8 +184,8 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     const LibraryAppletInfo applet_info{ |     const LibraryAppletInfo applet_info{ | ||||||
|         .applet_id = system.GetFrontendAppletHolder().GetCurrentAppletId(), |         .applet_id = applet->applet_id, | ||||||
|         .library_applet_mode = LibraryAppletMode::AllForeground, |         .library_applet_mode = applet->library_applet_mode, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|  | @ -134,13 +194,6 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { | void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { | ||||||
|     struct AppletIdentityInfo { |  | ||||||
|         AppletId applet_id; |  | ||||||
|         INSERT_PADDING_BYTES(0x4); |  | ||||||
|         u64 application_id; |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); |  | ||||||
| 
 |  | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     const AppletIdentityInfo applet_info{ |     const AppletIdentityInfo applet_info{ | ||||||
|  | @ -154,22 +207,11 @@ void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ct | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { | void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { | ||||||
|     struct AppletIdentityInfo { |  | ||||||
|         AppletId applet_id; |  | ||||||
|         INSERT_PADDING_BYTES(0x4); |  | ||||||
|         u64 application_id; |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); |  | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     const AppletIdentityInfo applet_info{ |  | ||||||
|         .applet_id = AppletId::QLaunch, |  | ||||||
|         .application_id = 0x0100000000001000ull, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 6}; |     IPC::ResponseBuilder rb{ctx, 6}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushRaw(applet_info); |     rb.PushRaw(GetCallerIdentity(applet)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { | void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { | ||||||
|  | @ -207,176 +249,4 @@ void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext | ||||||
|     rb.Push<u8>(0); |     rb.Push<u8>(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ILibraryAppletSelfAccessor::PushInShowAlbum() { |  | ||||||
|     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)); |  | ||||||
|     queue_data.emplace_back(std::move(argument_data)); |  | ||||||
|     queue_data.emplace_back(std::move(settings_data)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ILibraryAppletSelfAccessor::PushInShowController() { |  | ||||||
|     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)); |  | ||||||
| 
 |  | ||||||
|     queue_data.emplace_back(std::move(common_args_data)); |  | ||||||
|     queue_data.emplace_back(std::move(private_args_data)); |  | ||||||
|     queue_data.emplace_back(std::move(user_args_data)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ILibraryAppletSelfAccessor::PushInShowCabinetData() { |  | ||||||
|     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)); |  | ||||||
|     queue_data.emplace_back(std::move(argument_data)); |  | ||||||
|     queue_data.emplace_back(std::move(settings_data)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { |  | ||||||
|     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)); |  | ||||||
| 
 |  | ||||||
|     queue_data.emplace_back(std::move(argument_data)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { |  | ||||||
|     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)); |  | ||||||
| 
 |  | ||||||
|     queue_data.emplace_back(std::move(argument_data)); |  | ||||||
|     queue_data.emplace_back(std::move(swkbd_data)); |  | ||||||
|     queue_data.emplace_back(std::move(work_buffer)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -10,14 +10,21 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct AppletStorageHolder; | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { | class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { | ||||||
| public: | public: | ||||||
|     explicit ILibraryAppletSelfAccessor(Core::System& system_); |     explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet_); | ||||||
|     ~ILibraryAppletSelfAccessor() override; |     ~ILibraryAppletSelfAccessor() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void PopInData(HLERequestContext& ctx); |     void PopInData(HLERequestContext& ctx); | ||||||
|     void PushOutData(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 GetLibraryAppletInfo(HLERequestContext& ctx); | ||||||
|     void GetMainAppletIdentityInfo(HLERequestContext& ctx); |     void GetMainAppletIdentityInfo(HLERequestContext& ctx); | ||||||
|     void ExitProcessAndReturn(HLERequestContext& ctx); |     void ExitProcessAndReturn(HLERequestContext& ctx); | ||||||
|  | @ -26,13 +33,8 @@ private: | ||||||
|     void GetMainAppletAvailableUsers(HLERequestContext& ctx); |     void GetMainAppletAvailableUsers(HLERequestContext& ctx); | ||||||
|     void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); |     void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     void PushInShowAlbum(); |     const std::shared_ptr<Applet> applet; | ||||||
|     void PushInShowCabinetData(); |     const std::shared_ptr<AppletStorageHolder> storage; | ||||||
|     void PushInShowMiiEditData(); |  | ||||||
|     void PushInShowSoftwareKeyboard(); |  | ||||||
|     void PushInShowController(); |  | ||||||
| 
 |  | ||||||
|     std::deque<std::vector<u8>> queue_data; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -8,8 +8,9 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| IProcessWindingController::IProcessWindingController(Core::System& system_) | IProcessWindingController::IProcessWindingController(Core::System& system_, | ||||||
|     : ServiceFramework{system_, "IProcessWindingController"} { |                                                      std::shared_ptr<Applet> applet_) | ||||||
|  |     : ServiceFramework{system_, "IProcessWindingController"}, applet{std::move(applet_)} { | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"}, |         {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"}, | ||||||
|  | @ -31,34 +32,15 @@ IProcessWindingController::~IProcessWindingController() = default; | ||||||
| void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { | void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     struct AppletProcessLaunchReason { |  | ||||||
|         u8 flag; |  | ||||||
|         INSERT_PADDING_BYTES(3); |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(AppletProcessLaunchReason) == 0x4, |  | ||||||
|                   "AppletProcessLaunchReason is an invalid size"); |  | ||||||
| 
 |  | ||||||
|     AppletProcessLaunchReason reason{ |  | ||||||
|         .flag = 0, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushRaw(reason); |     rb.PushRaw(applet->launch_reason); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { | void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { | ||||||
|     const auto applet_id = system.GetFrontendAppletHolder().GetCurrentAppletId(); |     const auto caller_applet = applet->caller_applet.lock(); | ||||||
|     const auto applet_mode = LibraryAppletMode::AllForeground; |     if (caller_applet == nullptr) { | ||||||
| 
 |         LOG_ERROR(Service_AM, "No calling applet available"); | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id, |  | ||||||
|                 applet_mode); |  | ||||||
| 
 |  | ||||||
|     const auto& holder{system.GetFrontendAppletHolder()}; |  | ||||||
|     const auto applet = holder.GetApplet(applet_id, applet_mode); |  | ||||||
| 
 |  | ||||||
|     if (applet == nullptr) { |  | ||||||
|         LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); |  | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(ResultUnknown); |         rb.Push(ResultUnknown); | ||||||
|  | @ -67,7 +49,8 @@ void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); |     rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet->caller_applet_storage, | ||||||
|  |                                                 caller_applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -7,14 +7,18 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { | class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { | ||||||
| public: | public: | ||||||
|     explicit IProcessWindingController(Core::System& system_); |     explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_); | ||||||
|     ~IProcessWindingController() override; |     ~IProcessWindingController() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void GetLaunchReason(HLERequestContext& ctx); |     void GetLaunchReason(HLERequestContext& ctx); | ||||||
|     void OpenCallingLibraryApplet(HLERequestContext& ctx); |     void OpenCallingLibraryApplet(HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     const std::shared_ptr<Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // 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/frontend/applets.h" | ||||||
| #include "core/hle/service/am/self_controller.h" | #include "core/hle/service/am/self_controller.h" | ||||||
| #include "core/hle/service/caps/caps_su.h" | #include "core/hle/service/caps/caps_su.h" | ||||||
|  | @ -12,9 +13,10 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) | ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_, | ||||||
|     : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, |                                  Nvnflinger::Nvnflinger& nvnflinger_) | ||||||
|       service_context{system, "ISelfController"} { |     : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, applet{std::move( | ||||||
|  |                                                                                  applet_)} { | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &ISelfController::Exit, "Exit"}, |         {0, &ISelfController::Exit, "Exit"}, | ||||||
|  | @ -69,24 +71,9 @@ ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& | ||||||
|     // clang-format on
 |     // clang-format on
 | ||||||
| 
 | 
 | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| 
 |  | ||||||
|     launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent"); |  | ||||||
| 
 |  | ||||||
|     // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
 |  | ||||||
|     // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
 |  | ||||||
|     // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
 |  | ||||||
|     // suspended if the event has previously been created by a call to
 |  | ||||||
|     // GetAccumulatedSuspendedTickChangedEvent.
 |  | ||||||
| 
 |  | ||||||
|     accumulated_suspended_tick_changed_event = |  | ||||||
|         service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent"); |  | ||||||
|     accumulated_suspended_tick_changed_event->Signal(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ISelfController::~ISelfController() { | ISelfController::~ISelfController() = default; | ||||||
|     service_context.CloseEvent(launchable_event); |  | ||||||
|     service_context.CloseEvent(accumulated_suspended_tick_changed_event); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void ISelfController::Exit(HLERequestContext& ctx) { | void ISelfController::Exit(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
|  | @ -94,6 +81,7 @@ void ISelfController::Exit(HLERequestContext& ctx) { | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| 
 | 
 | ||||||
|  |     // TODO
 | ||||||
|     system.Exit(); |     system.Exit(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -120,8 +108,10 @@ void ISelfController::UnlockExit(HLERequestContext& ctx) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::EnterFatalSection(HLERequestContext& ctx) { | void ISelfController::EnterFatalSection(HLERequestContext& ctx) { | ||||||
|     ++num_fatal_sections_entered; | 
 | ||||||
|     LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -131,13 +121,14 @@ void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called."); |     LOG_DEBUG(Service_AM, "called."); | ||||||
| 
 | 
 | ||||||
|     // Entry and exit of fatal sections must be balanced.
 |     // Entry and exit of fatal sections must be balanced.
 | ||||||
|     if (num_fatal_sections_entered == 0) { |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     if (applet->fatal_section_count == 0) { | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(Result{ErrorModule::AM, 512}); |         rb.Push(AM::ResultFatalSectionCountImbalance); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     --num_fatal_sections_entered; |     applet->fatal_section_count--; | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -146,11 +137,11 @@ void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { | ||||||
| void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { | void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     launchable_event->Signal(); |     applet->library_applet_launchable_event.Signal(); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(launchable_event->GetReadableEvent()); |     rb.PushCopyObjects(applet->library_applet_launchable_event.GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { | void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { | ||||||
|  | @ -158,7 +149,8 @@ void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { | ||||||
|     const auto permission = rp.PopEnum<ScreenshotPermission>(); |     const auto permission = rp.PopEnum<ScreenshotPermission>(); | ||||||
|     LOG_DEBUG(Service_AM, "called, permission={}", permission); |     LOG_DEBUG(Service_AM, "called, permission={}", permission); | ||||||
| 
 | 
 | ||||||
|     screenshot_permission = permission; |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->screenshot_permission = permission; | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -167,8 +159,11 @@ void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { | ||||||
| void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { | void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
|     bool flag = rp.Pop<bool>(); |     const bool notification_enabled = rp.Pop<bool>(); | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -177,28 +172,27 @@ void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx | ||||||
| void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { | void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
|     bool flag = rp.Pop<bool>(); |     const bool notification_enabled = rp.Pop<bool>(); | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { | void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { | ||||||
|     // Takes 3 input u8s with each field located immediately after the previous
 |  | ||||||
|     // u8, these are bool flags. No output.
 |  | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
|     struct FocusHandlingModeParams { |     const auto flags = rp.PopRaw<FocusHandlingMode>(); | ||||||
|         u8 unknown0; |  | ||||||
|         u8 unknown1; |  | ||||||
|         u8 unknown2; |  | ||||||
|     }; |  | ||||||
|     const auto flags = rp.PopRaw<FocusHandlingModeParams>(); |  | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", |     LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", | ||||||
|                 flags.unknown0, flags.unknown1, flags.unknown2); |                 flags.unknown0, flags.unknown1, flags.unknown2); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->focus_handling_mode = flags; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  | @ -206,24 +200,35 @@ void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { | ||||||
| void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { | void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->restart_message_enabled = true; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { | void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { | ||||||
|     // Takes 3 input u8s with each field located immediately after the previous
 |  | ||||||
|     // u8, these are bool flags. No output.
 |  | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
|     bool enabled = rp.Pop<bool>(); |     const bool enabled = rp.Pop<bool>(); | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { | void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -232,14 +237,13 @@ void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { | ||||||
| void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { | void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): Find out how AM determines the display to use, for now just
 |     u64 layer_id{}; | ||||||
|     // create the layer in the Default display.
 |     applet->managed_layer_holder.Initialize(&nvnflinger); | ||||||
|     const auto display_id = nvnflinger.OpenDisplay("Default"); |     applet->managed_layer_holder.CreateManagedDisplayLayer(&layer_id); | ||||||
|     const auto layer_id = nvnflinger.CreateLayer(*display_id); |  | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push(*layer_id); |     rb.Push(layer_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { | void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { | ||||||
|  | @ -252,56 +256,46 @@ void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { | ||||||
| void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) { | void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 6}; | ||||||
|     rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); |     rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); | ||||||
|     rb.Push<s64>(system_shared_buffer_id); |     rb.Push<s64>(buffer_id); | ||||||
|     rb.Push<s64>(system_shared_layer_id); |     rb.Push<s64>(layer_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { | void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     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}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|     rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); |     rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); | ||||||
|     rb.Push<s64>(system_shared_buffer_id); |     rb.Push<s64>(buffer_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { | Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { | ||||||
|     if (buffer_sharing_enabled) { |     if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) { | ||||||
|         return ResultSuccess; |         return ResultSuccess; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (system.GetFrontendAppletHolder().GetCurrentAppletId() <= AppletId::Application) { |     return VI::ResultOperationFailed; | ||||||
|         return VI::ResultOperationFailed; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const auto display_id = nvnflinger.OpenDisplay("Default"); |  | ||||||
|     const auto result = nvnflinger.GetSystemBufferManager().Initialize( |  | ||||||
|         &system_shared_buffer_id, &system_shared_layer_id, *display_id); |  | ||||||
| 
 |  | ||||||
|     if (result.IsSuccess()) { |  | ||||||
|         buffer_sharing_enabled = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { | void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): Find out how AM determines the display to use, for now just
 |     u64 layer_id{}; | ||||||
|     // create the layer in the Default display.
 |     u64 recording_layer_id{}; | ||||||
|     // This calls nn::vi::CreateRecordingLayer() which creates another layer.
 |     applet->managed_layer_holder.Initialize(&nvnflinger); | ||||||
|     // Currently we do not support more than 1 layer per display, output 1 layer id for now.
 |     applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(&layer_id, &recording_layer_id); | ||||||
|     // 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 = nvnflinger.OpenDisplay("Default"); |  | ||||||
|     const auto layer_id = nvnflinger.CreateLayer(*display_id); |  | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 6}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push(*layer_id); |     rb.Push(layer_id); | ||||||
|  |     rb.Push(recording_layer_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { | void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { | ||||||
|  | @ -320,9 +314,12 @@ void ISelfController::ApproveToDisplay(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
| void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { | void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     idle_time_detection_extension = rp.Pop<u32>(); | 
 | ||||||
|     LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}", |     const auto extension = rp.PopRaw<IdleTimeDetectionExtension>(); | ||||||
|               idle_time_detection_extension); |     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}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -331,9 +328,11 @@ void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { | ||||||
| void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { | void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push<u32>(idle_time_detection_extension); |     rb.PushRaw<IdleTimeDetectionExtension>(applet->idle_time_detection_extension); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { | void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { | ||||||
|  | @ -345,7 +344,9 @@ void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
| void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { | void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     is_auto_sleep_disabled = rp.Pop<bool>(); | 
 | ||||||
|  |     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
 |     // 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
 |     // differed from the current value passed in, it'd signify the internal
 | ||||||
|  | @ -357,7 +358,7 @@ void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { | ||||||
|     // and it's sufficient to simply set the member variable for querying via
 |     // and it's sufficient to simply set the member variable for querying via
 | ||||||
|     // IsAutoSleepDisabled().
 |     // IsAutoSleepDisabled().
 | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled); |     LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", applet->auto_sleep_disabled); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -366,20 +367,23 @@ void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { | ||||||
| void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { | void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called."); |     LOG_DEBUG(Service_AM, "called."); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|  | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push(is_auto_sleep_disabled); |     rb.Push(applet->auto_sleep_disabled); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { | void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called."); |     LOG_DEBUG(Service_AM, "called."); | ||||||
| 
 | 
 | ||||||
|  |     std::scoped_lock lk{applet->lock}; | ||||||
|     // This command returns the total number of system ticks since ISelfController creation
 |     // 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
 |     // where the game was suspended. Since Yuzu doesn't implement game suspension, this command
 | ||||||
|     // can just always return 0 ticks.
 |     // can just always return 0 ticks.
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push<u64>(0); |     rb.Push<u64>(applet->suspended_ticks); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { | void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { | ||||||
|  | @ -387,7 +391,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); |     rb.PushCopyObjects(applet->accumulated_suspended_tick_changed_event.GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) { | void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) { | ||||||
|  | @ -396,10 +400,11 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& c | ||||||
|     // This service call sets an internal flag whether a notification is shown when an image is
 |     // 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
 |     // captured. Currently we do not support capturing images via the capture button, so this can be
 | ||||||
|     // stubbed for now.
 |     // stubbed for now.
 | ||||||
|     const bool album_image_taken_notification_enabled = rp.Pop<bool>(); |     const bool enabled = rp.Pop<bool>(); | ||||||
|  |     LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}", |     std::scoped_lock lk{applet->lock}; | ||||||
|                 album_image_taken_notification_enabled); |     applet->album_image_taken_notification_enabled = enabled; | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  | @ -427,9 +432,11 @@ void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { | ||||||
| void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) { | void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
|     const auto is_record_volume_muted = rp.Pop<bool>(); |     const auto enabled = rp.Pop<bool>(); | ||||||
|  |     LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); |     std::scoped_lock lk{applet->lock}; | ||||||
|  |     applet->record_volume_muted = enabled; | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|  |  | ||||||
|  | @ -8,9 +8,12 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class ISelfController final : public ServiceFramework<ISelfController> { | class ISelfController final : public ServiceFramework<ISelfController> { | ||||||
| public: | public: | ||||||
|     explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_); |     explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_, | ||||||
|  |                              Nvnflinger::Nvnflinger& nvnflinger_); | ||||||
|     ~ISelfController() override; |     ~ISelfController() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | @ -47,26 +50,8 @@ private: | ||||||
| 
 | 
 | ||||||
|     Result EnsureBufferSharingEnabled(Kernel::KProcess* process); |     Result EnsureBufferSharingEnabled(Kernel::KProcess* process); | ||||||
| 
 | 
 | ||||||
|     enum class ScreenshotPermission : u32 { |  | ||||||
|         Inherit = 0, |  | ||||||
|         Enable = 1, |  | ||||||
|         Disable = 2, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     Nvnflinger::Nvnflinger& nvnflinger; |     Nvnflinger::Nvnflinger& nvnflinger; | ||||||
| 
 |     const std::shared_ptr<Applet> applet; | ||||||
|     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; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -20,10 +20,9 @@ | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|                                        std::shared_ptr<AppletMessageQueue> msg_queue_, |                                        std::shared_ptr<Applet> applet_, Core::System& system_) | ||||||
|                                        Core::System& system_) |     : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move( | ||||||
|     : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, |                                                                                     applet_)} { | ||||||
|       msg_queue{std::move(msg_queue_)} { |  | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |         {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, | ||||||
|  | @ -44,12 +43,14 @@ ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ISystemAppletProxy::~ISystemAppletProxy() = default; | ||||||
|  | 
 | ||||||
| void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { | void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_AM, "called"); |     LOG_DEBUG(Service_AM, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); |     rb.PushIpcInterface<ICommonStateGetter>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { | void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { | ||||||
|  | @ -57,7 +58,7 @@ void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ISelfController>(system, nvnflinger); |     rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { | void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { | ||||||
|  | @ -65,7 +66,7 @@ void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<IWindowController>(system); |     rb.PushIpcInterface<IWindowController>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) { | void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) { | ||||||
|  | @ -89,7 +90,7 @@ void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<ILibraryAppletCreator>(system); |     rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { | void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { | ||||||
|  | @ -121,7 +122,7 @@ void ISystemAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.PushIpcInterface<IAppletCommonFunctions>(system); |     rb.PushIpcInterface<IAppletCommonFunctions>(system, applet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { | void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { | ||||||
|  |  | ||||||
|  | @ -8,11 +8,13 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { | class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { | ||||||
| public: | public: | ||||||
|     explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, |     explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, | ||||||
|                                 std::shared_ptr<AppletMessageQueue> msg_queue_, |                                 std::shared_ptr<Applet> applet_, Core::System& system_); | ||||||
|                                 Core::System& system_); |     ~ISystemAppletProxy(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void GetCommonStateGetter(HLERequestContext& ctx); |     void GetCommonStateGetter(HLERequestContext& ctx); | ||||||
|  | @ -28,7 +30,7 @@ private: | ||||||
|     void GetDebugFunctions(HLERequestContext& ctx); |     void GetDebugFunctions(HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     Nvnflinger::Nvnflinger& nvnflinger; |     Nvnflinger::Nvnflinger& nvnflinger; | ||||||
|     std::shared_ptr<AppletMessageQueue> msg_queue; |     std::shared_ptr<Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -1,13 +1,14 @@ | ||||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
| 
 | 
 | ||||||
|  | #include "core/hle/service/am/applet.h" | ||||||
| #include "core/hle/service/am/window_controller.h" | #include "core/hle/service/am/window_controller.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
| IWindowController::IWindowController(Core::System& system_) | IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_) | ||||||
|     : ServiceFramework{system_, "IWindowController"} { |     : ServiceFramework{system_, "IWindowController"}, applet{std::move(applet_)} { | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, nullptr, "CreateWindow"}, |         {0, nullptr, "CreateWindow"}, | ||||||
|  | @ -27,23 +28,22 @@ IWindowController::IWindowController(Core::System& system_) | ||||||
| IWindowController::~IWindowController() = default; | IWindowController::~IWindowController() = default; | ||||||
| 
 | 
 | ||||||
| void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { | void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { | ||||||
|     const u64 process_id = system.ApplicationProcess()->GetProcessId(); |  | ||||||
| 
 |  | ||||||
|     LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); |  | ||||||
| 
 |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push<u64>(process_id); |     rb.Push<u64>(applet->aruid); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { | void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { | ||||||
|     const u64 process_id = 0; |     u64 aruid = 0; | ||||||
|  |     if (auto caller = applet->caller_applet.lock(); caller) { | ||||||
|  |         aruid = caller->aruid; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push<u64>(process_id); |     rb.Push<u64>(aruid); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { | void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { | ||||||
|  |  | ||||||
|  | @ -7,15 +7,19 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::AM { | namespace Service::AM { | ||||||
| 
 | 
 | ||||||
|  | struct Applet; | ||||||
|  | 
 | ||||||
| class IWindowController final : public ServiceFramework<IWindowController> { | class IWindowController final : public ServiceFramework<IWindowController> { | ||||||
| public: | public: | ||||||
|     explicit IWindowController(Core::System& system_); |     explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_); | ||||||
|     ~IWindowController() override; |     ~IWindowController() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void GetAppletResourceUserId(HLERequestContext& ctx); |     void GetAppletResourceUserId(HLERequestContext& ctx); | ||||||
|     void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); |     void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); | ||||||
|     void AcquireForegroundRights(HLERequestContext& ctx); |     void AcquireForegroundRights(HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     const std::shared_ptr<Applet> applet; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::AM
 | } // namespace Service::AM
 | ||||||
|  |  | ||||||
|  | @ -535,6 +535,12 @@ public: | ||||||
|         RegisterHandlers(functions); |         RegisterHandlers(functions); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     ~IApplicationDisplayService() { | ||||||
|  |         for (const auto layer_id : stray_layer_ids) { | ||||||
|  |             nvnflinger.DestroyLayer(layer_id); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     enum class ConvertedScaleMode : u64 { |     enum class ConvertedScaleMode : u64 { | ||||||
|         Freeze = 0, |         Freeze = 0, | ||||||
|  | @ -770,6 +776,7 @@ private: | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         stray_layer_ids.push_back(*layer_id); | ||||||
|         const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); |         const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); | ||||||
|         if (!buffer_queue_id) { |         if (!buffer_queue_id) { | ||||||
|             LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); |             LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); | ||||||
|  | @ -916,6 +923,7 @@ private: | ||||||
| 
 | 
 | ||||||
|     Nvnflinger::Nvnflinger& nvnflinger; |     Nvnflinger::Nvnflinger& nvnflinger; | ||||||
|     Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; |     Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; | ||||||
|  |     std::vector<u64> stray_layer_ids; | ||||||
|     bool vsync_event_fetched{false}; |     bool vsync_event_fetched{false}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/hle/service/am/am.h" | #include "core/hle/service/am/am.h" | ||||||
| #include "core/hle/service/am/applet_ae.h" | #include "core/hle/service/am/applet_ae.h" | ||||||
|  | #include "core/hle/service/am/applet_manager.h" | ||||||
| #include "core/hle/service/am/applet_message_queue.h" | #include "core/hle/service/am/applet_message_queue.h" | ||||||
| #include "core/hle/service/am/applet_oe.h" | #include "core/hle/service/am/applet_oe.h" | ||||||
| #include "core/hle/service/sm/sm.h" | #include "core/hle/service/sm/sm.h" | ||||||
|  | @ -48,22 +49,8 @@ void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system) | ||||||
|     if (!system.IsPoweredOn()) { |     if (!system.IsPoweredOn()) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     Service::SM::ServiceManager& sm = system.ServiceManager(); |  | ||||||
| 
 | 
 | ||||||
|     // Message queue is shared between these services, we just need to signal an operation
 |     system.GetAppletManager().OperationModeChanged(); | ||||||
|     // change to one and it will handle both automatically
 |  | ||||||
|     auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE"); |  | ||||||
|     auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE"); |  | ||||||
|     bool has_signalled = false; |  | ||||||
| 
 |  | ||||||
|     if (applet_oe != nullptr) { |  | ||||||
|         applet_oe->GetMessageQueue()->OperationModeChanged(); |  | ||||||
|         has_signalled = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (applet_ae != nullptr && !has_signalled) { |  | ||||||
|         applet_ae->GetMessageQueue()->OperationModeChanged(); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) | ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) | ||||||
|  |  | ||||||
|  | @ -4783,36 +4783,12 @@ void GMainWindow::RequestGameExit() { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto& sm{system->ServiceManager()}; |  | ||||||
|     auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE"); |  | ||||||
|     auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE"); |  | ||||||
|     bool has_signalled = false; |  | ||||||
| 
 |  | ||||||
|     system->SetExitRequested(true); |     system->SetExitRequested(true); | ||||||
| 
 |     system->GetAppletManager().RequestExit(); | ||||||
|     if (applet_oe != nullptr) { |  | ||||||
|         applet_oe->GetMessageQueue()->RequestExit(); |  | ||||||
|         has_signalled = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (applet_ae != nullptr && !has_signalled) { |  | ||||||
|         applet_ae->GetMessageQueue()->RequestExit(); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GMainWindow::RequestGameResume() { | void GMainWindow::RequestGameResume() { | ||||||
|     auto& sm{system->ServiceManager()}; |     system->GetAppletManager().RequestResume(); | ||||||
|     auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE"); |  | ||||||
|     auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE"); |  | ||||||
| 
 |  | ||||||
|     if (applet_oe != nullptr) { |  | ||||||
|         applet_oe->GetMessageQueue()->RequestResume(); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (applet_ae != nullptr) { |  | ||||||
|         applet_ae->GetMessageQueue()->RequestResume(); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GMainWindow::filterBarSetChecked(bool state) { | void GMainWindow::filterBarSetChecked(bool state) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Liam
						Liam