20 std::underlying_type_t<T> operator()(T t)
const {
21 return static_cast<std::underlying_type_t<T>
>(t);
28 if (freeList_.empty()) {
32 auto value = *freeList_.begin();
33 freeList_.erase(freeList_.begin());
36 void returnId(
int id) {
37 assert(
id <= maxId_ && freeList_.count(
id) == 0);
41 std::set<int> freeList_;
48 : addonManager_(addonManager) {}
50 void registerAction(
const std::string &name,
int id,
Action *action) {
52 [
this, action](
void *) { unregisterAction(action); });
53 action->setName(name);
55 actions_.emplace(name, std::make_pair(action, std::move(conn)));
56 idToAction_.emplace(action->
id(), action);
59 void unregisterAction(
Action *action) {
60 auto iter = actions_.find(action->
name());
61 if (iter == actions_.end()) {
64 if (std::get<0>(iter->second) != action) {
68 idToAction_.erase(action->
id());
69 ids_.returnId(action->
id());
70 action->setName(std::string());
76 template <UserInterfaceComponent component>
81 std::vector<std::string> uis_;
83 std::unordered_map<std::string, std::pair<Action *, ScopedConnection>>
85 std::unordered_map<int, Action *> idToAction_;
87 using UIUpdateList = std::list<std::pair<
88 InputContext *, std::unordered_set<UserInterfaceComponent, EnumHash>>>;
89 UIUpdateList updateList_;
90 std::unordered_map<InputContext *, UIUpdateList::iterator> updateIndex_;
94 bool isVirtualKeyboardVisible_ =
false;
98 void UserInterfaceManagerPrivate::updateSingleComponent<
100 if (
const auto &virtualKeyboardCallback =
101 ic->inputPanel().customVirtualKeyboardCallback()) {
102 virtualKeyboardCallback(ic);
103 }
else if (ui_ !=
nullptr && ui_->addonInfo() !=
nullptr &&
104 ui_->addonInfo()->uiType() == UIType::OnScreenKeyboard) {
106 }
else if (
const auto &callback =
107 ic->inputPanel().customInputPanelCallback()) {
109 }
else if (ic->capabilityFlags().test(
111 ic->updateClientSideUIImpl();
118 void UserInterfaceManagerPrivate::updateSingleComponent<
127 #define _UI_CASE(COMP) \ 129 updateSingleComponent<COMP>(ic); \ 139 UserInterfaceManager::UserInterfaceManager(
AddonManager *addonManager)
140 : d_ptr(std::make_unique<UserInterfaceManagerPrivate>(addonManager)) {}
142 UserInterfaceManager::~UserInterfaceManager() =
default;
146 auto names = d->addonManager_->addonNames(AddonCategory::UI);
149 if (names.count(uiName)) {
150 auto *ui = d->addonManager_->addon(uiName,
true);
152 d->uis_.push_back(uiName);
156 if (d->uis_.empty()) {
157 d->uis_.insert(d->uis_.end(), names.begin(), names.end());
158 std::sort(d->uis_.begin(), d->uis_.end(),
159 [d](
const std::string &lhs,
const std::string &rhs) {
160 const auto *linfo = d->addonManager_->addonInfo(lhs);
161 const auto *rinfo = d->addonManager_->addonInfo(rhs);
168 auto lp = linfo->uiPriority();
169 auto rp = rinfo->uiPriority();
176 updateAvailability();
181 auto id = d->ids_.allocId();
182 auto name = stringutils::concat(
"$",
id);
183 auto iter = d->actions_.find(name);
185 if (iter != d->actions_.end()) {
186 FCITX_ERROR() <<
"Reserved id is used, how can this be possible?";
187 d->ids_.returnId(
id);
190 d->registerAction(name,
id, action);
197 if (!action->
name().empty() || name.empty()) {
201 FCITX_ERROR() <<
"Action name starts with $ is reserved.";
204 auto iter = d->actions_.find(name);
205 if (iter != d->actions_.end()) {
209 d->registerAction(name, d->ids_.allocId(), action);
215 d->unregisterAction(action);
220 auto iter = d->actions_.find(name);
221 if (iter == d->actions_.end()) {
224 return std::get<0>(iter->second);
229 auto iter = d->idToAction_.find(
id);
230 if (iter == d->idToAction_.end()) {
239 auto iter = d->updateIndex_.find(inputContext);
240 decltype(d->updateList_)::iterator listIter;
241 if (d->updateIndex_.end() == iter) {
242 d->updateList_.emplace_back(std::piecewise_construct,
243 std::forward_as_tuple(inputContext),
244 std::forward_as_tuple());
245 d->updateIndex_[inputContext] = listIter =
246 std::prev(d->updateList_.end());
248 listIter = iter->second;
250 listIter->second.insert(component);
255 auto iter = d->updateIndex_.find(inputContext);
256 if (d->updateIndex_.end() != iter) {
257 d->updateList_.erase(iter->second);
258 d->updateIndex_.erase(iter);
262 void UserInterfaceManager::flush() {
264 auto *instance = d->addonManager_->instance();
265 for (
auto &p : d->updateList_) {
266 for (
auto comp : p.second) {
268 d->updateDispatch(comp, p.first);
271 d->updateIndex_.clear();
272 d->updateList_.clear();
276 InputMethodMode inputMethodMode) {
277 if (userInterface ==
nullptr || !userInterface->available() ||
278 userInterface->addonInfo() ==
nullptr) {
282 return (userInterface->addonInfo()->uiType() == UIType::OnScreenKeyboard &&
283 inputMethodMode == InputMethodMode::OnScreenKeyboard) ||
284 (userInterface->addonInfo()->uiType() == UIType::PhyscialKeyboard &&
285 inputMethodMode == InputMethodMode::PhysicalKeyboard);
290 auto *instance = d->addonManager_->instance();
291 auto *oldUI = d->ui_;
293 std::string newUIName;
294 for (
auto &name : d->uis_) {
296 static_cast<UserInterface *
>(d->addonManager_->addon(name,
true));
297 if (isUserInterfaceValid(ui, instance
298 ? instance->inputMethodMode()
299 : InputMethodMode::PhysicalKeyboard)) {
305 if (oldUI != newUI) {
306 FCITX_DEBUG() <<
"Switching UI addon to " << newUIName;
314 d->uiName_ = std::move(newUIName);
320 updateVirtualKeyboardVisibility();
330 return d->isVirtualKeyboardVisible_;
336 auto *instance = d->addonManager_->instance();
337 if (!instance->virtualKeyboardAutoShow()) {
342 if (ui ==
nullptr || ui->addonInfo() ==
nullptr ||
343 ui->addonInfo()->uiType() != UIType::OnScreenKeyboard) {
348 vkui->showVirtualKeyboard();
354 auto *instance = d->addonManager_->instance();
355 if (!instance->virtualKeyboardAutoHide()) {
360 if (ui ==
nullptr || ui->addonInfo() ==
nullptr ||
361 ui->addonInfo()->uiType() != UIType::OnScreenKeyboard) {
366 vkui->hideVirtualKeyboard();
371 bool oldVisible = d->isVirtualKeyboardVisible_;
372 bool newVisible =
false;
375 if (ui && ui->addonInfo() &&
376 ui->addonInfo()->uiType() == UIType::OnScreenKeyboard) {
378 newVisible = vkui->isVirtualKeyboardVisible();
381 if (oldVisible != newVisible) {
382 d->isVirtualKeyboardVisible_ = newVisible;
384 if (
auto *instance = d->addonManager_->instance()) {
void hideVirtualKeyboard() const
Hide the virtual keyboard.
bool registerAction(const std::string &name, Action *action)
Register an named action.
void unregisterAction(Action *action)
Unregister the action.
The Action class provides an abstraction for user commands that can be added to user interfaces...
void load(const std::string &ui={})
Initialize the UI Addon.
std::string currentUI() const
Return the current active addon ui name.
int id()
Return the unique integer id of action.
Manager class for user interface.
Action * lookupActionById(int id) const
Lookup an action by id.
Base class for User Interface addon.
void updateAvailability()
Invoke by user interface addon to notify if there is any avaiability change.
Events triggered that user interface manager that flush the UI update.
void update(UserInterfaceComponent component, InputContext *inputContext)
Mark a user interface component to be updated for given input context.
void expire(InputContext *inputContext)
Remove all pending updates for a given input context.
Connection that will disconnection when it goes out of scope.
bool isVirtualKeyboardVisible() const
Return if virtual keyboard is visible.
Whether client display input panel by itself.
void updateVirtualKeyboardVisibility()
Invoke by user interface addon to notify if there is any virtual keyboard visibility change...
bool startsWith(std::string_view str, std::string_view prefix)
Check if a string starts with a prefix.
const std::string & name() const
The action name when this action is registered.
void showVirtualKeyboard() const
Show the virtual keyboard.
Action * lookupAction(const std::string &name) const
Lookup an action by the name.
An input context represents a client of Fcitx.