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_INPUTCONTEXT_P_H_
8 #define _FCITX_INPUTCONTEXT_P_H_
9 
10 #include <unordered_map>
11 #include <fcitx-utils/intrusivelist.h>
12 #include <fcitx-utils/uuid_p.h>
13 #include <fcitx/inputcontext.h>
14 #include <fcitx/inputcontextmanager.h>
15 #include <fcitx/inputcontextproperty.h>
16 #include <fcitx/inputpanel.h>
17 #include <fcitx/instance.h>
18 #include <fcitx/statusarea.h>
19 
20 namespace fcitx {
21 
22 class InputContextPrivate : public QPtrHolder<InputContext> {
23 public:
InputContextPrivate(InputContext * q,InputContextManager & manager,const std::string & program)24     InputContextPrivate(InputContext *q, InputContextManager &manager,
25                         const std::string &program)
26         : QPtrHolder(q), manager_(manager), group_(nullptr), inputPanel_(q),
27           statusArea_(q), program_(program),
28           isPreeditEnabled_(manager.isPreeditEnabledByDefault()) {}
29 
30     template <typename E>
postEvent(E && event)31     bool postEvent(E &&event) {
32         if (destroyed_) {
33             return true;
34         }
35         if (auto *instance = manager_.instance()) {
36             return instance->postEvent(event);
37         }
38         return false;
39     }
40 
41     template <typename E, typename... Args>
emplaceEvent(Args &&...args)42     bool emplaceEvent(Args &&...args) {
43         if (destroyed_) {
44             return true;
45         }
46         if (auto *instance = manager_.instance()) {
47             return instance->postEvent(E(std::forward<Args>(args)...));
48         }
49         return false;
50     }
51 
52     template <typename E, typename... Args>
pushEvent(Args &&...args)53     void pushEvent(Args &&...args) {
54         if (destroyed_) {
55             return;
56         }
57 
58         if (blockEventToClient_) {
59             blockedEvents_.push_back(
60                 std::make_unique<E>(std::forward<Args>(args)...));
61         } else {
62             E event(std::forward<Args>(args)...);
63             deliverEvent(event, nullptr);
64         }
65     }
66 
registerProperty(int slot,InputContextProperty * property)67     void registerProperty(int slot, InputContextProperty *property) {
68         if (slot < 0) {
69             return;
70         }
71         if (static_cast<size_t>(slot) >= properties_.size()) {
72             properties_.resize(slot + 1);
73         }
74         properties_[slot].reset(property);
75     }
76 
unregisterProperty(int slot)77     void unregisterProperty(int slot) {
78         properties_[slot] = std::move(properties_.back());
79         properties_.pop_back();
80     }
81 
deliverEvent(InputContextEvent & icEvent,std::string * commitBuffer)82     void deliverEvent(InputContextEvent &icEvent, std::string *commitBuffer) {
83         FCITX_Q();
84         if (destroyed_) {
85             return;
86         }
87         if (commitBuffer && !commitBuffer->empty() &&
88             (icEvent.type() != EventType::InputContextCommitString)) {
89             q->commitStringImpl(*commitBuffer);
90             commitBuffer->clear();
91         }
92 
93         switch (icEvent.type()) {
94         case EventType::InputContextCommitString: {
95             auto &event = static_cast<CommitStringEvent &>(icEvent);
96             if (!postEvent(event)) {
97                 if (commitBuffer) {
98                     *commitBuffer += event.text();
99                 } else {
100                     q->commitStringImpl(event.text());
101                 }
102             }
103             break;
104         }
105         case EventType::InputContextForwardKey: {
106             auto &event = static_cast<ForwardKeyEvent &>(icEvent);
107             if (!postEvent(event)) {
108                 q->forwardKeyImpl(event);
109             }
110             break;
111         }
112         case EventType::InputContextUpdatePreedit: {
113             auto &event = static_cast<UpdatePreeditEvent &>(icEvent);
114             if (!postEvent(event)) {
115                 q->updatePreeditImpl();
116             }
117             break;
118         }
119         default:
120             break;
121         }
122     }
123 
deliverBlockedEvents()124     void deliverBlockedEvents() {
125         FCITX_Q();
126         std::string commitBuffer;
127         for (const auto &event : blockedEvents_) {
128             deliverEvent(*event, &commitBuffer);
129         }
130         if (!commitBuffer.empty()) {
131             q->commitStringImpl(commitBuffer);
132         }
133         blockedEvents_.clear();
134     }
135 
property(int slot)136     InputContextProperty *property(int slot) { return properties_[slot].get(); }
137 
138     InputContextManager &manager_;
139     FocusGroup *group_;
140     InputPanel inputPanel_;
141     StatusArea statusArea_;
142     bool hasFocus_ = false;
143     std::string program_;
144     CapabilityFlags capabilityFlags_;
145     bool isPreeditEnabled_ = true;
146     SurroundingText surroundingText_;
147     Rect cursorRect_;
148     double scale_ = 1.0;
149 
150     IntrusiveListNode listNode_;
151     IntrusiveListNode focusedListNode_;
152     ICUUID uuid_;
153     std::vector<std::unique_ptr<InputContextProperty>> properties_;
154     bool destroyed_ = false;
155 
156     std::list<std::unique_ptr<InputContextEvent>> blockedEvents_;
157     bool blockEventToClient_ = false;
158 };
159 } // namespace fcitx
160 
161 #endif // _FCITX_INPUTCONTEXT_P_H_
162