14 #include <unordered_map> 15 #include <unordered_set> 18 #include "fcitx-config/iniparser.h" 19 #include "fcitx-config/rawconfig.h" 21 #include "fcitx-utils/macros.h" 22 #include "fcitx-utils/misc_p.h" 23 #include "fcitx-utils/semver.h" 25 #include "addoninfo.h" 27 #include "addoninstance_p.h" 28 #include "addonloader.h" 29 #include "addonloader_p.h" 40 : info_(name), failed_(
false) {
44 const AddonInfo &info()
const {
return info_; }
46 bool isLoadable()
const {
47 return info_.isValid() && info_.isEnabled() && !failed_;
49 bool isValid()
const {
return info_.isValid() && !failed_; }
51 bool loaded()
const {
return !!instance_; }
55 void setFailed(
bool failed =
true) { failed_ = failed; }
56 void setOverrideEnabled(OverrideEnabled overrideEnabled) {
57 info_.setOverrideEnabled(overrideEnabled);
63 std::unique_ptr<AddonInstance> instance_;
66 enum class DependencyCheckStatus {
77 Addon *addon(
const std::string &name)
const {
78 auto iter = addons_.find(name);
79 if (iter != addons_.end()) {
80 return iter->second.get();
85 DependencyCheckStatus checkDependencies(
const Addon &a) {
86 const auto &dependencies = a.info().dependenciesWithVersion();
87 for (
const auto &[dependency, depVersion] : dependencies) {
88 if (dependency ==
"core") {
89 if (depVersion <= version_) {
92 return DependencyCheckStatus::Failed;
94 Addon *dep = addon(dependency);
95 if (!dep || !dep->isLoadable()) {
96 return DependencyCheckStatus::Failed;
99 if (depVersion > dep->info().version()) {
100 return DependencyCheckStatus::Failed;
103 if (!dep->loaded()) {
104 if (dep->info().onDemand() &&
105 requested_.insert(dep->info().uniqueName()).second) {
106 return DependencyCheckStatus::PendingUpdateRequest;
108 return DependencyCheckStatus::Pending;
111 const auto &optionalDependencies = a.info().optionalDependencies();
112 for (
const auto &dependency : optionalDependencies) {
113 Addon *dep = addon(dependency);
115 if (!dep || !dep->isLoadable()) {
120 if (!dep->loaded() && !dep->info().onDemand()) {
121 return DependencyCheckStatus::Pending;
125 return DependencyCheckStatus::Satisfied;
129 if (instance_ && instance_->exiting()) {
133 throw std::runtime_error(
"loadAddons is not reentrant, do not call " 134 "addon(.., true) in constructor of addon");
136 inLoadAddons_ =
true;
137 bool changed =
false;
141 for (
auto &item : addons_) {
142 changed |= loadAddon(q_ptr, *item.second);
144 if (instance_ && instance_->exiting()) {
150 inLoadAddons_ =
false;
158 if (addon.loaded() || !addon.isLoadable()) {
161 if (addon.info().onDemand() &&
162 !requested_.contains(addon.info().uniqueName())) {
165 auto result = checkDependencies(addon);
166 FCITX_DEBUG() <<
"Call loadAddon() with " << addon.info().uniqueName()
167 <<
" checkDependencies() returns " 168 <<
static_cast<int>(result)
169 <<
" Dep: " << addon.info().dependenciesWithVersion()
171 << addon.info().optionalDependenciesWithVersion();
172 if (result == DependencyCheckStatus::Failed) {
174 }
else if (result == DependencyCheckStatus::Satisfied) {
175 realLoad(q_ptr, addon);
176 if (addon.loaded()) {
177 loadOrder_.push_back(addon.info().uniqueName());
180 }
else if (result == DependencyCheckStatus::PendingUpdateRequest) {
188 if (!addon.isLoadable()) {
192 if (
auto *loader = findValue(loaders_, addon.info().type())) {
193 addon.instance_.reset((*loader)->load(addon.info(), q_ptr));
195 FCITX_ERROR() <<
"Failed to find addon loader for: " 196 << addon.info().type();
198 if (!addon.instance_) {
199 addon.setFailed(
true);
200 FCITX_INFO() <<
"Could not load addon " 201 << addon.info().uniqueName();
203 addon.instance_->d_func()->addonInfo_ = &(addon.info());
204 FCITX_INFO() <<
"Loaded addon " << addon.info().uniqueName();
208 std::string addonConfigDir_ =
"addon";
210 bool unloading_ =
false;
211 bool inLoadAddons_ =
false;
213 std::unordered_map<std::string, std::unique_ptr<Addon>> addons_;
214 std::unordered_map<std::string, std::unique_ptr<AddonLoader>> loaders_;
215 std::unordered_set<std::string> requested_;
217 std::vector<std::string> loadOrder_;
221 int64_t timestamp_ = 0;
223 SemanticVersion::parse(FCITX_VERSION_STRING).value();
225 std::unordered_map<std::string, std::vector<std::string>> options_;
232 d->addonConfigDir_ = addonConfigDir;
240 if (d->loaders_.contains(loader->type())) {
243 d->loaders_.emplace(loader->type(), std::move(loader));
248 d->loaders_.erase(name);
259 const std::unordered_set<std::string> &disabled) {
263 path.timestamp(StandardPathsType::PkgData, d->addonConfigDir_);
264 auto fileNames = path.locate(StandardPathsType::PkgData, d->addonConfigDir_,
265 pathfilter::extension(
".conf"));
266 bool enableAll = enabled.contains(
"all");
267 bool disableAll = disabled.contains(
"all");
268 for (
const auto &[fileName, fullName] : fileNames) {
270 std::string name = fileName.stem().string();
271 if (name ==
"core") {
272 FCITX_ERROR() <<
"\"core\" is not a valid addon name.";
275 if (d->addons_.contains(name)) {
280 readAsIni(config, StandardPathsType::PkgData, fullName);
283 auto addon = std::make_unique<Addon>(name, config);
284 if (
addon->isValid()) {
285 if (enableAll || enabled.contains(name)) {
286 addon->setOverrideEnabled(OverrideEnabled::Enabled);
287 }
else if (disableAll || disabled.contains(name)) {
288 addon->setOverrideEnabled(OverrideEnabled::Disabled);
290 d->addons_[
addon->info().uniqueName()] = std::move(
addon);
302 d->unloading_ =
true;
304 for (
auto iter = d->loadOrder_.rbegin(), end = d->loadOrder_.rend();
305 iter != end; iter++) {
306 FCITX_INFO() <<
"Unloading addon " << *iter;
307 d->addons_.erase(*iter);
309 d->loadOrder_.clear();
310 d->requested_.clear();
311 d->unloading_ =
false;
320 for (
auto iter = d->loadOrder_.rbegin(), end = d->loadOrder_.rend();
321 iter != end; iter++) {
322 if (
auto *addonInst =
addon(*iter)) {
330 auto *
addon = d->addon(name);
334 if (
addon->isLoadable() && !
addon->loaded() &&
addon->info().onDemand() &&
336 d->requested_.insert(name);
339 return addon->instance();
344 auto *
addon = d->addon(name);
346 return &
addon->info();
353 auto *
addon = d->addon(name);
359 return d->loadOrder_;
362 std::unordered_set<std::string>
363 AddonManager::addonNames(AddonCategory category) {
365 std::unordered_set<std::string> result;
366 for (
auto &item : d->addons_) {
367 if (item.second->isValid() &&
368 item.second->info().category() == category) {
369 result.insert(item.first);
393 return d->eventLoop_;
404 StandardPathsType::PkgData, d->addonConfigDir_);
405 return timestamp > d->timestamp_;
409 std::unordered_map<std::string, std::vector<std::string>> options) {
411 d->options_ = std::move(options);
416 if (
auto *options = findValue(d->options_, name)) {
static const StandardPaths & global()
Return the global instance of StandardPath.
void unload()
Destruct all addon, all information is cleared to the initial state.
const std::vector< std::string > & loadedAddonNames() const
Return the loaded addon name in the order of they were loaded.
AddonInstance * addon(const std::string &name, bool load=false)
Get the loaded addon instance.
An instance represents a standalone Fcitx instance.
void registerLoader(std::unique_ptr< AddonLoader > loader)
Register new addon loader.
Provide a Semantic version 2.0 implementation.
EventLoop & eventLoop()
Get the fcitx event loop.
AddonInstance * lookupAddon(const std::string &name) const
Get the currently loaded addon instance.
bool checkUpdate() const
Check directory for quick hint for whether update is required.
void unregisterLoader(const std::string &name)
Unregister addon loader.
AddonManager()
Construct an addon manager.
New Utility classes to handle application specific path.
void load(const std::unordered_set< std::string > &enabled={}, const std::unordered_set< std::string > &disabled={})
Load addon based on given parameter.
Base class for any addon in fcitx.
EventLoop * eventLoop()
Return the associated event loop.
std::vector< std::string > addonOptions(const std::string &name)
Query addon options that set with setAddonOptions for given addon.
void setEventLoop(EventLoop *eventLoop)
Set event loop.
const SemanticVersion & version() const
Return the version number of Fcitx5Core library.
void registerDefaultLoader(StaticAddonRegistry *registry)
Register addon loader, including static and shared library loader.
const AddonInfo * addonInfo(const std::string &name) const
Get addon information for given addon.
Instance * instance()
Return the fcitx instance when it is created by Fcitx.
virtual ~AddonManager()
Destruct and unload all addons.
void saveAll()
Save all addon configuration.
void setAddonOptions(std::unordered_map< std::string, std::vector< std::string >> options)
Set addon parameters that may be used during addon construction.