Own the speed dial ActionRegistry in GUI_App and keep it fresh from loader callbacks

This commit is contained in:
Andrew
2026-07-09 16:18:13 +08:00
parent 6463b3d976
commit 3ebb4b274d
2 changed files with 34 additions and 0 deletions

View File

@@ -3171,6 +3171,32 @@ bool GUI_App::on_init_inner()
refresh_plugins_dialog();
});
// why: keep the speed-dial ActionRegistry always-clean. Each loader callback marshals
// a TARGETED refresh onto the UI thread (the callback may fire on a worker thread, so
// it must not touch the registry's vector directly). No custom event - CallAfter is
// the pubsub channel.
auto refresh_pkg = [](const std::string& key, ActionChange change) {
if (!wxTheApp || wxGetApp().is_closing())
return;
wxGetApp().CallAfter([key, change] {
if (!wxGetApp().is_closing())
wxGetApp().action_registry().refresh_package(key, change);
});
};
auto refresh_cap = [](const PluginCapabilityIdentifier& cap, ActionChange change) {
if (cap.type != PluginCapabilityType::Script || !wxTheApp || wxGetApp().is_closing())
return;
const std::string key = cap.plugin_key, name = cap.name;
wxGetApp().CallAfter([key, name, change] {
if (!wxGetApp().is_closing())
wxGetApp().action_registry().refresh_capability(key, name, change);
});
};
plugin_mgr.get_loader().subscribe_on_load_callback([refresh_pkg](const std::string& key) { refresh_pkg(key, ActionChange::Added); });
plugin_mgr.get_loader().subscribe_on_unload_callback([refresh_pkg](const std::string& key) { refresh_pkg(key, ActionChange::Removed); });
plugin_mgr.get_loader().subscribe_on_capability_load_callback([refresh_cap](const PluginCapabilityIdentifier& c) { refresh_cap(c, ActionChange::Added); });
plugin_mgr.get_loader().subscribe_on_capability_unload_callback([refresh_cap](const PluginCapabilityIdentifier& c) { refresh_cap(c, ActionChange::Removed); });
for (const std::string& plugin_key : plugin_mgr.get_catalog().get_enabled_plugin_keys()) {
if (!plugin_mgr.get_loader().is_plugin_loaded(plugin_key)) {
plugin_mgr.get_loader().load_plugin(plugin_mgr.get_catalog(), plugin_key, false);
@@ -3178,6 +3204,11 @@ bool GUI_App::on_init_inner()
}
}
// why: seed the registry once on the UI thread after startup auto-load. The deferred
// per-plugin callbacks above are idempotent (upsert by id), so re-processing the same
// packages is harmless; this guarantees a populated set even before any callback lands.
m_action_registry.build();
if (m_agent)
plugin_mgr.set_cloud_agent(std::dynamic_pointer_cast<OrcaCloudServiceAgent>(m_agent->get_cloud_agent()));

View File

@@ -3,6 +3,7 @@
#include <memory>
#include <string>
#include "ActionRegistry.hpp"
#include "ImGuiWrapper.hpp"
#include "ConfigWizard.hpp"
#include "OpenGLManager.hpp"
@@ -554,6 +555,7 @@ public:
PresetBundleDialog* m_preset_bundle_dlg{nullptr};
PluginsDialog* m_plugins_dlg{nullptr};
TerminalDialog* m_terminal_dlg{nullptr};
ActionRegistry m_action_registry;
void start_http_server(const std::string& provider = ORCA_CLOUD_PROVIDER);
@@ -625,6 +627,7 @@ public:
void open_plugins_dialog(size_t open_on_tab = 0, const std::string& highlight_option = std::string());
void open_terminal_dialog();
void open_speed_dial();
ActionRegistry& action_registry() { return m_action_registry; }
void open_exportpresetbundledialog(size_t open_on_tab = 0, const std::string& highlight_option = std::string());
virtual bool OnExceptionInMainLoop() override;
// Calls wxLaunchDefaultBrowser if user confirms in dialog.