Applets: Reworked how the Applet update event is handled.
Applets are now cleaned up in AppletUpdateEvent after calling their respective Update method.
This commit is contained in:
		| @@ -31,9 +31,8 @@ namespace Applets { | |||||||
|  |  | ||||||
| static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets; | static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets; | ||||||
| static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback. | static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback. | ||||||
| /// The interval at which the Applet update callback will be called. | /// The interval at which the Applet update callback will be called, 16.6ms | ||||||
| static const u64 applet_update_interval_microseconds = 16666; | static const u64 applet_update_interval_us = 16666; | ||||||
| std::shared_ptr<Applet> g_current_applet = nullptr; ///< The applet that is currently executing |  | ||||||
|  |  | ||||||
| ResultCode Applet::Create(Service::APT::AppletId id) { | ResultCode Applet::Create(Service::APT::AppletId id) { | ||||||
|     switch (id) { |     switch (id) { | ||||||
| @@ -57,21 +56,38 @@ std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) { | |||||||
| } | } | ||||||
|  |  | ||||||
| /// Handles updating the current Applet every time it's called. | /// Handles updating the current Applet every time it's called. | ||||||
| static void AppletUpdateEvent(u64, int cycles_late) { | static void AppletUpdateEvent(u64 applet_id, int cycles_late) { | ||||||
|     if (g_current_applet && g_current_applet->IsRunning()) |     Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id); | ||||||
|         g_current_applet->Update(); |     std::shared_ptr<Applet> applet = Applet::Get(id); | ||||||
|  |     ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id); | ||||||
|  |  | ||||||
|     CoreTiming::ScheduleEvent(usToCycles(applet_update_interval) - cycles_late, |     applet->Update(); | ||||||
|         applet_update_event); |  | ||||||
|  |     // If the applet is still running after the last update, reschedule the event | ||||||
|  |     if (applet->IsRunning()) { | ||||||
|  |         CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late, | ||||||
|  |             applet_update_event, applet_id); | ||||||
|  |     } else { | ||||||
|  |         // Otherwise the applet has terminated, in which case we should clean it up | ||||||
|  |         applets[id] = nullptr; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) { | ||||||
|  |     ResultCode result = StartImpl(parameter); | ||||||
|  |     if (result.IsError()) | ||||||
|  |         return result; | ||||||
|  |     // Schedule the update event | ||||||
|  |     CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id)); | ||||||
|  |     return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Init() { | void Init() { | ||||||
|  |     // Register the applet update callback | ||||||
|     applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); |     applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); | ||||||
|     CoreTiming::ScheduleEvent(usToCycles(applet_update_interval), applet_update_event); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void Shutdown() { | void Shutdown() { | ||||||
|     CoreTiming::UnscheduleEvent(applet_update_event, 0); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,10 +12,10 @@ | |||||||
| namespace HLE { | namespace HLE { | ||||||
| namespace Applets { | namespace Applets { | ||||||
|  |  | ||||||
| class Applet : public std::enable_shared_from_this<Applet> { | class Applet { | ||||||
| public: | public: | ||||||
|     virtual ~Applet() {}; |     virtual ~Applet() { } | ||||||
|     Applet(Service::APT::AppletId id) : id(id) {}; |     Applet(Service::APT::AppletId id) : id(id) { } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Creates an instance of the Applet subclass identified by the parameter. |      * Creates an instance of the Applet subclass identified by the parameter. | ||||||
| @@ -37,25 +37,33 @@ public: | |||||||
|      * @param parameter Parameter data to handle. |      * @param parameter Parameter data to handle. | ||||||
|      * @returns ResultCode Whether the operation was successful or not. |      * @returns ResultCode Whether the operation was successful or not. | ||||||
|      */ |      */ | ||||||
|     virtual ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) = 0; |     virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Handles the Applet start event, triggered from the application. |      * Handles the Applet start event, triggered from the application. | ||||||
|      * @param parameter Parameter data to handle. |      * @param parameter Parameter data to handle. | ||||||
|      * @returns ResultCode Whether the operation was successful or not. |      * @returns ResultCode Whether the operation was successful or not. | ||||||
|      */ |      */ | ||||||
|     virtual ResultCode Start(Service::APT::AppletStartupParameter const& parameter) = 0; |     ResultCode Start(const Service::APT::AppletStartupParameter& parameter); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Whether the applet is currently executing instead of the host application or not. |      * Whether the applet is currently executing instead of the host application or not. | ||||||
|      */ |      */ | ||||||
|     virtual bool IsRunning() = 0; |     virtual bool IsRunning() const = 0; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Handles an update tick for the Applet, lets it update the screen, send commands, etc. |      * Handles an update tick for the Applet, lets it update the screen, send commands, etc. | ||||||
|      */ |      */ | ||||||
|     virtual void Update() = 0; |     virtual void Update() = 0; | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     /** | ||||||
|  |      * Handles the Applet start event, triggered from the application. | ||||||
|  |      * @param parameter Parameter data to handle. | ||||||
|  |      * @returns ResultCode Whether the operation was successful or not. | ||||||
|  |      */ | ||||||
|  |     virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0; | ||||||
|  |  | ||||||
|     Service::APT::AppletId id; ///< Id of this Applet |     Service::APT::AppletId id; ///< Id of this Applet | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -65,6 +73,5 @@ void Init(); | |||||||
| /// Shuts down the HLE applets | /// Shuts down the HLE applets | ||||||
| void Shutdown(); | void Shutdown(); | ||||||
|  |  | ||||||
| extern std::shared_ptr<Applet> g_current_applet; ///< Applet that is currently executing |  | ||||||
| } | } | ||||||
| } // namespace | } // namespace | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
|  |  | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
|  | #include "common/string_util.h" | ||||||
|  |  | ||||||
| #include "core/hle/applets/swkbd.h" | #include "core/hle/applets/swkbd.h" | ||||||
| #include "core/hle/service/hid/hid.h" | #include "core/hle/service/hid/hid.h" | ||||||
| @@ -43,7 +44,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con | |||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| ResultCode SoftwareKeyboard::Start(Service::APT::AppletStartupParameter const& parameter) { | ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) { | ||||||
|  |     ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong"); | ||||||
|  |  | ||||||
|     memcpy(&config, parameter.data, parameter.buffer_size); |     memcpy(&config, parameter.data, parameter.buffer_size); | ||||||
|     text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object); |     text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object); | ||||||
|  |  | ||||||
| @@ -52,9 +55,7 @@ ResultCode SoftwareKeyboard::Start(Service::APT::AppletStartupParameter const& p | |||||||
|  |  | ||||||
|     DrawScreenKeyboard(); |     DrawScreenKeyboard(); | ||||||
|  |  | ||||||
|     // Update the current applet so we can get update events |  | ||||||
|     started = true; |     started = true; | ||||||
|     g_current_applet = shared_from_this(); |  | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -98,8 +99,6 @@ void SoftwareKeyboard::Finalize() { | |||||||
|     Service::APT::SendParameter(message); |     Service::APT::SendParameter(message); | ||||||
|  |  | ||||||
|     started = false; |     started = false; | ||||||
|     // Unset the current applet, we are not running anymore |  | ||||||
|     g_current_applet = nullptr; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -42,17 +42,21 @@ struct SoftwareKeyboardConfig { | |||||||
|     INSERT_PADDING_BYTES(0x2B6); |     INSERT_PADDING_BYTES(0x2B6); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The size of this structure (0x400) has been verified via reverse engineering of multiple games | ||||||
|  |  * that use the software keyboard. | ||||||
|  |  */ | ||||||
| static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong"); | static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong"); | ||||||
|  |  | ||||||
| class SoftwareKeyboard : public Applet { | class SoftwareKeyboard final : public Applet { | ||||||
| public: | public: | ||||||
|     SoftwareKeyboard(Service::APT::AppletId id); |     SoftwareKeyboard(Service::APT::AppletId id); | ||||||
|     ~SoftwareKeyboard() {} |     ~SoftwareKeyboard() {} | ||||||
|  |  | ||||||
|     ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) override; |     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||||||
|     ResultCode Start(Service::APT::AppletStartupParameter const& parameter) override; |     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||||||
|     void Update() override; |     void Update() override; | ||||||
|     bool IsRunning() override { return started; } |     bool IsRunning() const override { return started; } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Draws a keyboard to the current bottom screen framebuffer. |      * Draws a keyboard to the current bottom screen framebuffer. | ||||||
| @@ -66,7 +70,7 @@ public: | |||||||
|     void Finalize(); |     void Finalize(); | ||||||
|  |  | ||||||
|     /// TODO(Subv): Find out what this is actually used for. |     /// TODO(Subv): Find out what this is actually used for. | ||||||
|     // It is believed that the application stores the current screen image here. |     /// It is believed that the application stores the current screen image here. | ||||||
|     Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; |     Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; | ||||||
|  |  | ||||||
|     /// SharedMemory where the output text will be stored |     /// SharedMemory where the output text will be stored | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ static u32 cpu_percent; ///< CPU time available to the running application | |||||||
| /// Parameter data to be returned in the next call to Glance/ReceiveParameter | /// Parameter data to be returned in the next call to Glance/ReceiveParameter | ||||||
| static MessageParameter next_parameter; | static MessageParameter next_parameter; | ||||||
|  |  | ||||||
| void SendParameter(MessageParameter const& parameter) { | void SendParameter(const MessageParameter& parameter) { | ||||||
|     next_parameter = parameter; |     next_parameter = parameter; | ||||||
|     // Signal the event to let the application know that a new parameter is ready to be read |     // Signal the event to let the application know that a new parameter is ready to be read | ||||||
|     parameter_event->Signal(); |     parameter_event->Signal(); | ||||||
|   | |||||||
| @@ -63,7 +63,7 @@ enum class AppletId : u32 { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| /// Send a parameter to the currently-running application, which will read it via ReceiveParameter | /// Send a parameter to the currently-running application, which will read it via ReceiveParameter | ||||||
| void SendParameter(MessageParameter const& parameter); | void SendParameter(const MessageParameter& parameter); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * APT::Initialize service function |  * APT::Initialize service function | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user