Fcitx
addoninstance.h
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_ADDONINSTANCE_H_
8 #define _FCITX_ADDONINSTANCE_H_
9 
10 #include <functional>
11 #include <memory>
12 #include <string>
13 #include <fcitx-config/configuration.h>
14 #include <fcitx-config/rawconfig.h>
15 #include <fcitx-utils/macros.h>
16 #include <fcitx-utils/metastring.h>
17 #include <fcitx/addoninfo.h>
18 #include <fcitx/addoninstance_details.h> // IWYU pragma: export
19 #include <fcitx/fcitxcore_export.h>
20 
21 /// \addtogroup FcitxCore
22 /// \{
23 /// \file
24 /// \brief Addon For fcitx.
25 
26 namespace fcitx {
27 
28 class AddonManagerPrivate;
29 
30 /// \brief Base class for any addon in fcitx.
31 /// To implement addon in fcitx, you will need to create a sub class for this
32 /// class.
33 ///
34 /// To make an SharedLibrary Addon, you will also need to use
35 /// FCITX_ADDON_FACTORY to export the factory for addon.
36 ///
37 /// An addon can export several function to be invoked by other addons.
38 /// When you need to do so, you will need some extra command in your
39 /// CMakeLists.txt, and using FCITX_ADDON_DECLARE_FUNCTION and
40 /// FCITX_ADDON_EXPORT_FUNCTION.
41 /// \code{.unparsed}
42 /// fcitx5_export_module(XCB
43 /// TARGET xcb
44 /// BUILD_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}"
45 /// HEADERS xcb_public.h INSTALL)
46 /// \endcode
47 ///
48 /// First you will need to create a header file with exported addon function.
49 /// E.g. dummyaddon_public.h
50 /// \code{.cpp}
51 /// FCITX_ADDON_DECLARE_FUNCTION(DummyAddon, addOne, int(int));
52 /// \endcode
53 /// This file declares a function addOne for DummyAddon, with function signature
54 /// int(int).
55 ///
56 /// Then, when you implement the class, add using the macro
57 /// FCITX_ADDON_EXPORT_FUNCTION to the addon class.
58 /// \code{.cpp}
59 /// class DummyAddon : public fcitx::AddonInstance {
60 /// public:
61 /// int addOne(int a) { return a + 1; }
62 ///
63 /// FCITX_ADDON_EXPORT_FUNCTION(DummyAddon, addOne);
64 /// };
65 /// \endcode
66 /// This macro will register the function and check the signature against the
67 /// actual function to make sure they have the same signature.
68 ///
69 /// In order to invoke the function in other code, you will need to first obtain
70 /// the pointer to the addon via AddonManager. Then invoke it by
71 /// \code{.cpp}
72 /// addon->call<fcitx::IDummyAddon::addOne>(7);
73 /// \endcode
74 class FCITXCORE_EXPORT AddonInstance {
75  friend class AddonManagerPrivate;
76 
77 public:
78  AddonInstance();
79  virtual ~AddonInstance();
80 
81  /// Reload configuration from disk.
82  virtual void reloadConfig() {}
83 
84  /// Save any relevant data. Usually, it will be invoked when fcitx exits.
85  virtual void save() {}
86 
87  /// Get the configuration.
88  virtual const Configuration *getConfig() const { return nullptr; }
89 
90  /// Set configuration from Raw Config.
91  virtual void setConfig(const RawConfig & /*unused*/) {}
92  virtual const Configuration *
93  getSubConfig(const std::string & /*unused*/) const {
94  return nullptr;
95  }
96  virtual void setSubConfig(const std::string & /*unused*/,
97  const RawConfig & /*unused*/) {}
98 
99  template <typename Signature, typename... Args>
100  typename std::function<Signature>::result_type
101  callWithSignature(const std::string &name, Args &&...args) {
102  auto *adaptor = findCall(name);
103  auto erasureAdaptor =
104  static_cast<AddonFunctionAdaptorErasure<Signature> *>(adaptor);
105  return erasureAdaptor->callback(std::forward<Args>(args)...);
106  }
107  template <typename MetaSignatureString, typename... Args>
108  AddonFunctionSignatureReturnType<MetaSignatureString>
109  callWithMetaString(Args &&...args) {
110  return callWithSignature<
111  AddonFunctionSignatureType<MetaSignatureString>>(
112  MetaSignatureString::data(), std::forward<Args>(args)...);
113  }
114 
115  /// Call an exported function for this addon.
116  template <typename MetaType, typename... Args>
117  AddonFunctionSignatureReturnType<typename MetaType::Name>
118  call(Args &&...args) {
119  return callWithSignature<typename MetaType::Signature>(
120  MetaType::Name::data(), std::forward<Args>(args)...);
121  }
122 
123  void registerCallback(const std::string &name,
124  AddonFunctionAdaptorBase *adaptor);
125 
126  const AddonInfo *addonInfo() const;
127 
128  /**
129  * Check if this addon can safely restart.
130  *
131  * When the existing fcitx 5 instance returns false, fcitx5 -r, or
132  * Instance::restart will just be no-op.
133  *
134  * @return whether it is safe for fcitx to restart on its own.
135  * @see AddonInstance::setCanRestart
136  * @since 5.1.6
137  */
138  bool canRestart() const;
139 
140 protected:
141  /**
142  * Set if this addon can safely restart.
143  *
144  * In certain cases, it is not a good idea to allow restart fcitx 5.
145  * Otherwise fcitx will lose permission. For example, when fcitx is
146  * launching with WAYLAND_SOCKET. In that case, user is recommended to use
147  * other way to restart fcitx.
148  *
149  * The value will be false be default, but it will default to true when
150  * running as fcitx5 binary. After initialize addon, addon may change it
151  * back to false, for example, wayland module.
152  *
153  * @param canRestart Whether fcitx is allowed to restart on its own.
154  * @see Instance::restart
155  * @since 5.1.6
156  */
157  void setCanRestart(bool canRestart);
158 
159 private:
160  AddonFunctionAdaptorBase *findCall(const std::string &name);
161  std::unique_ptr<AddonInstancePrivate> d_ptr;
162  FCITX_DECLARE_PRIVATE(AddonInstance);
163 };
164 } // namespace fcitx
165 
166 #if defined(_WIN32)
167 #define FCITX_ADDON_EXPORT __declspec(dllexport)
168 #else
169 #define FCITX_ADDON_EXPORT __attribute__((visibility("default")))
170 #endif
171 
172 #define FCITX_ADDON_DECLARE_FUNCTION(NAME, FUNCTION, SIGNATURE...) \
173  namespace fcitx { \
174  template <> \
175  struct AddonFunctionSignature<fcitxMakeMetaString(#NAME "::" #FUNCTION)> { \
176  using type = \
177  std::remove_reference_t<decltype(std::declval<SIGNATURE>())>; \
178  }; \
179  namespace I##NAME { \
180  struct FUNCTION { \
181  using Name = fcitxMakeMetaString(#NAME "::" #FUNCTION); \
182  using Signature = AddonFunctionSignatureType<Name>; \
183  }; \
184  } \
185  }
186 
187 #define FCITX_ADDON_EXPORT_FUNCTION(CLASS, FUNCTION) \
188  static_assert(std::is_same_v<::fcitx::I##CLASS::FUNCTION::Name, \
189  fcitxMakeMetaString(#CLASS "::" #FUNCTION)>, \
190  ""); \
191  decltype(::fcitx::MakeAddonFunctionAdaptor( \
192  &CLASS::FUNCTION)) FUNCTION##Adaptor{#CLASS "::" #FUNCTION, this, \
193  &CLASS::FUNCTION}; \
194  static_assert( \
195  std::is_same_v<decltype(::fcitx::MakeAddonFunctionAdaptor( \
196  &CLASS::FUNCTION))::Signature, \
197  ::fcitx::AddonFunctionSignatureType< \
198  fcitxMakeMetaString(#CLASS "::" #FUNCTION)>>, \
199  "Signature doesn't match");
200 
201 #define FCITX_ADDON_FACTORY(ClassName) \
202  extern "C" { \
203  FCITX_ADDON_EXPORT ::fcitx::AddonFactory *fcitx_addon_factory_instance() { \
204  static ClassName factory; \
205  return &factory; \
206  } \
207  }
208 
209 #define FCITX_ADDON_FACTORY_V2(AddonName, ClassName) \
210  extern "C" { \
211  FCITX_ADDON_EXPORT ::fcitx::AddonFactory * \
212  fcitx_addon_factory_instance_##AddonName() { \
213  static ClassName factory; \
214  return &factory; \
215  } \
216  }
217 
218 #define FCITX_DEFINE_STATIC_ADDON_REGISTRY(Name, ...) \
219  ::fcitx::StaticAddonRegistry &Name() { \
220  static ::fcitx::StaticAddonRegistry registry{__VA_ARGS__}; \
221  return registry; \
222  }
223 
224 #define FCITX_ADDON_FACTORY_V2_BACKWARDS(AddonName, ClassName) \
225  FCITX_ADDON_FACTORY_V2(AddonName, ClassName) \
226  FCITX_ADDON_FACTORY(ClassName)
227 
228 #define FCITX_IMPORT_ADDON_FACTORY(StaticRegistryGetter, AddonName) \
229  extern "C" { \
230  ::fcitx::AddonFactory *fcitx_addon_factory_instance_##AddonName(); \
231  } \
232  class StaticAddonRegistrar_##AddonName { \
233  public: \
234  StaticAddonRegistrar_##AddonName() { \
235  (StaticRegistryGetter)().emplace( \
236  FCITX_STRINGIFY(AddonName), \
237  fcitx_addon_factory_instance_##AddonName()); \
238  } \
239  }; \
240  StaticAddonRegistrar_##AddonName staticAddonRegistrar_##AddonName
241 
242 /// A convenient macro to obtain the addon pointer of another addon.
243 #define FCITX_ADDON_DEPENDENCY_LOADER(NAME, ADDONMANAGER) \
244  auto NAME() { \
245  if (_##NAME##FirstCall_) { \
246  _##NAME##_ = (ADDONMANAGER).addon(#NAME, true); \
247  _##NAME##FirstCall_ = false; \
248  } \
249  return _##NAME##_; \
250  } \
251  bool _##NAME##FirstCall_ = true; \
252  ::fcitx::AddonInstance *_##NAME##_ = nullptr;
253 
254 #endif // _FCITX_ADDONINSTANCE_H_
virtual void reloadConfig()
Reload configuration from disk.
Definition: addoninstance.h:82
virtual const Configuration * getConfig() const
Get the configuration.
Definition: addoninstance.h:88
virtual void setConfig(const RawConfig &)
Set configuration from Raw Config.
Definition: addoninstance.h:91
Definition: action.cpp:17
virtual void save()
Save any relevant data. Usually, it will be invoked when fcitx exits.
Definition: addoninstance.h:85
Base class for any addon in fcitx.
Definition: addoninstance.h:74
AddonFunctionSignatureReturnType< typename MetaType::Name > call(Args &&...args)
Call an exported function for this addon.
Static string based on template argument.