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" 34 #include "sharedlibraryloader_p.h" 44 : info_(name), failed_(
false) {
48 const AddonInfo &info()
const {
return info_; }
50 bool isLoadable()
const {
51 return info_.isValid() && info_.isEnabled() && !failed_;
53 bool isValid()
const {
return info_.isValid() && !failed_; }
55 bool loaded()
const {
return !!instance_; }
59 void setFailed(
bool failed =
true) { failed_ = failed; }
60 void setOverrideEnabled(OverrideEnabled overrideEnabled) {
61 info_.setOverrideEnabled(overrideEnabled);
67 std::unique_ptr<AddonInstance> instance_;
70 enum class DependencyCheckStatus {
81 Addon *addon(
const std::string &name)
const {
82 auto iter = addons_.find(name);
83 if (iter != addons_.end()) {
84 return iter->second.get();
89 DependencyCheckStatus checkDependencies(
const Addon &a) {
90 const auto &dependencies = a.info().dependenciesWithVersion();
91 for (
const auto &[dependency, depVersion] : dependencies) {
92 if (dependency ==
"core") {
93 if (depVersion <= version_) {
96 return DependencyCheckStatus::Failed;
98 Addon *dep = addon(dependency);
99 if (!dep || !dep->isLoadable()) {
100 return DependencyCheckStatus::Failed;
103 if (depVersion > dep->info().version()) {
104 return DependencyCheckStatus::Failed;
107 if (!dep->loaded()) {
108 if (dep->info().onDemand() &&
109 requested_.insert(dep->info().uniqueName()).second) {
110 return DependencyCheckStatus::PendingUpdateRequest;
112 return DependencyCheckStatus::Pending;
115 const auto &optionalDependencies = a.info().optionalDependencies();
116 for (
const auto &dependency : optionalDependencies) {
117 Addon *dep = addon(dependency);
119 if (!dep || !dep->isLoadable()) {
124 if (!dep->loaded() && !dep->info().onDemand()) {
125 return DependencyCheckStatus::Pending;
129 return DependencyCheckStatus::Satisfied;
133 if (instance_ && instance_->exiting()) {
137 throw std::runtime_error(
"loadAddons is not reentrant, do not call " 138 "addon(.., true) in constructor of addon");
140 inLoadAddons_ =
true;
141 bool changed =
false;
145 for (
auto &item : addons_) {
146 changed |= loadAddon(q_ptr, *item.second);
148 if (instance_ && instance_->exiting()) {
154 inLoadAddons_ =
false;
162 if (addon.loaded() || !addon.isLoadable()) {
165 if (addon.info().onDemand() &&
166 !requested_.contains(addon.info().uniqueName())) {
169 auto result = checkDependencies(addon);
170 FCITX_DEBUG() <<
"Call loadAddon() with " << addon.info().uniqueName()
171 <<
" checkDependencies() returns " 172 <<
static_cast<int>(result)
173 <<
" Dep: " << addon.info().dependenciesWithVersion()
175 << addon.info().optionalDependenciesWithVersion();
176 if (result == DependencyCheckStatus::Failed) {
178 }
else if (result == DependencyCheckStatus::Satisfied) {
179 realLoad(q_ptr, addon);
180 if (addon.loaded()) {
181 loadOrder_.push_back(addon.info().uniqueName());
184 }
else if (result == DependencyCheckStatus::PendingUpdateRequest) {
192 if (!addon.isLoadable()) {
196 if (
auto *loader = findValue(loaders_, addon.info().type())) {
197 addon.instance_.reset((*loader)->load(addon.info(), q_ptr));
199 FCITX_ERROR() <<
"Failed to find addon loader for: " 200 << addon.info().type();
202 if (!addon.instance_) {
203 addon.setFailed(
true);
204 FCITX_INFO() <<
"Could not load addon " 205 << addon.info().uniqueName();
207 addon.instance_->d_func()->addonInfo_ = &(addon.info());
208 FCITX_INFO() <<
"Loaded addon " << addon.info().uniqueName();
212 std::string addonConfigDir_ =
"addon";
214 bool unloading_ =
false;
215 bool inLoadAddons_ =
false;
217 std::unordered_map<std::string, std::unique_ptr<Addon>> addons_;
218 std::unordered_map<std::string, std::unique_ptr<AddonLoader>> loaders_;
219 std::unordered_set<std::string> requested_;
221 std::vector<std::string> loadOrder_;
225 int64_t timestamp_ = 0;
227 SemanticVersion::parse(FCITX_VERSION_STRING).value();
229 std::unordered_map<std::string, std::vector<std::string>> options_;
236 d->addonConfigDir_ = addonConfigDir;
244 if (d->loaders_.contains(loader->type())) {
247 d->loaders_.emplace(loader->type(), std::move(loader));
252 d->loaders_.erase(name);
265 const std::unordered_set<std::string> &disabled) {
269 path.timestamp(StandardPathsType::PkgData, d->addonConfigDir_);
270 auto fileNames = path.locate(StandardPathsType::PkgData, d->addonConfigDir_,
271 pathfilter::extension(
".conf"));
272 bool enableAll = enabled.contains(
"all");
273 bool disableAll = disabled.contains(
"all");
274 for (
const auto &[fileName, fullName] : fileNames) {
276 std::string name = fileName.stem().string();
277 if (name ==
"core") {
278 FCITX_ERROR() <<
"\"core\" is not a valid addon name.";
281 if (d->addons_.contains(name)) {
286 readAsIni(config, StandardPathsType::PkgData, fullName);
289 auto addon = std::make_unique<Addon>(name, config);
290 if (
addon->isValid()) {
291 if (enableAll || enabled.contains(name)) {
292 addon->setOverrideEnabled(OverrideEnabled::Enabled);
293 }
else if (disableAll || disabled.contains(name)) {
294 addon->setOverrideEnabled(OverrideEnabled::Disabled);
296 d->addons_[
addon->info().uniqueName()] = std::move(
addon);
308 d->unloading_ =
true;
310 for (
auto iter = d->loadOrder_.rbegin(), end = d->loadOrder_.rend();
311 iter != end; iter++) {
312 FCITX_INFO() <<
"Unloading addon " << *iter;
313 d->addons_.erase(*iter);
315 d->loadOrder_.clear();
316 d->requested_.clear();
317 d->unloading_ =
false;
326 for (
auto iter = d->loadOrder_.rbegin(), end = d->loadOrder_.rend();
327 iter != end; iter++) {
328 if (
auto *addonInst =
addon(*iter)) {
336 auto *
addon = d->addon(name);
340 if (
addon->isLoadable() && !
addon->loaded() &&
addon->info().onDemand() &&
342 d->requested_.insert(name);
345 return addon->instance();
350 auto *
addon = d->addon(name);
352 return &
addon->info();
359 auto *
addon = d->addon(name);
365 return d->loadOrder_;
368 std::unordered_set<std::string>
369 AddonManager::addonNames(AddonCategory category) {
371 std::unordered_set<std::string> result;
372 for (
auto &item : d->addons_) {
373 if (item.second->isValid() &&
374 item.second->info().category() == category) {
375 result.insert(item.first);
399 return d->eventLoop_;
410 StandardPathsType::PkgData, d->addonConfigDir_);
411 return timestamp > d->timestamp_;
415 std::unordered_map<std::string, std::vector<std::string>> options) {
417 d->options_ = std::move(options);
422 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.
A raw configuration tree that stores key-value pairs in a hierarchical structure. ...
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.