Changeset View
Changeset View
Standalone View
Standalone View
src/client/textinput_v3.cpp
- This file was added.
1 | /**************************************************************************** | ||||
---|---|---|---|---|---|
2 | Copyright 2018 Roman Gilg <subdiff@gmail.com> | ||||
3 | | ||||
4 | This library is free software; you can redistribute it and/or | ||||
5 | modify it under the terms of the GNU Lesser General Public | ||||
6 | License as published by the Free Software Foundation; either | ||||
7 | version 2.1 of the License, or (at your option) version 3, or any | ||||
8 | later version accepted by the membership of KDE e.V. (or its | ||||
9 | successor approved by the membership of KDE e.V.), which shall | ||||
10 | act as a proxy defined in Section 6 of version 3 of the license. | ||||
11 | | ||||
12 | This library is distributed in the hope that it will be useful, | ||||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
15 | Lesser General Public License for more details. | ||||
16 | | ||||
17 | You should have received a copy of the GNU Lesser General Public | ||||
18 | License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||||
19 | ****************************************************************************/ | ||||
20 | #include "textinput_p.h" | ||||
21 | #include "event_queue.h" | ||||
22 | #include "seat.h" | ||||
23 | #include "surface.h" | ||||
24 | #include "wayland_pointer_p.h" | ||||
25 | | ||||
26 | #include <wayland-text-input-v3-client-protocol.h> | ||||
27 | | ||||
28 | namespace KWayland | ||||
29 | { | ||||
30 | namespace Client | ||||
31 | { | ||||
32 | | ||||
33 | class TextInputUnstableV3::Private : public TextInput::Private | ||||
34 | { | ||||
35 | public: | ||||
36 | Private(TextInputUnstableV3 *q, Seat *seat); | ||||
37 | | ||||
38 | void setup(zwp_text_input_v3 *textinputmanagerunstablev0); | ||||
39 | | ||||
40 | bool isValid() const override; | ||||
41 | void enable(Surface *surface) override; | ||||
42 | void disable(Surface * surface) override; | ||||
43 | void showInputPanel() override; | ||||
44 | void hideInputPanel() override; | ||||
45 | void setCursorRectangle(const QRect &rect) override; | ||||
46 | void setPreferredLanguage(const QString &lang) override; | ||||
47 | void setSurroundingTextChangeCause(TextInput::ChangeCause cause) override; | ||||
48 | void setSurroundingText(const QString &text, quint32 cursor, quint32 anchor) override; | ||||
49 | void reset() override; | ||||
50 | void setContentType(ContentHints hint, ContentPurpose purpose) override; | ||||
51 | void commit() override; | ||||
52 | | ||||
53 | WaylandPointer<zwp_text_input_v3, zwp_text_input_v3_destroy> textinputunstablev3; | ||||
54 | | ||||
55 | private: | ||||
56 | static void enterCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, wl_surface *surface); | ||||
57 | static void leaveCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, wl_surface *surface); | ||||
58 | static void preeditStringCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, const char *text, int32_t begin, int32_t end); | ||||
59 | static void commitStringCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, const char *text); | ||||
60 | static void deleteSurroundingTextCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, uint32_t before_length, uint32_t after_length); | ||||
61 | static void doneCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, uint32_t serial); | ||||
62 | void done (uint32_t serial); | ||||
63 | | ||||
64 | struct { | ||||
65 | QByteArray text; | ||||
66 | qint32 cursor = 0; | ||||
67 | qint32 anchor = 0; | ||||
68 | } pendingSurrounding; | ||||
69 | | ||||
70 | TextInputUnstableV3 *q; | ||||
71 | | ||||
72 | static const zwp_text_input_v3_listener s_listener; | ||||
73 | }; | ||||
74 | | ||||
75 | const zwp_text_input_v3_listener TextInputUnstableV3::Private::s_listener = { | ||||
76 | enterCallback, | ||||
77 | leaveCallback, | ||||
78 | preeditStringCallback, | ||||
79 | commitStringCallback, | ||||
80 | deleteSurroundingTextCallback, | ||||
81 | doneCallback | ||||
82 | }; | ||||
83 | | ||||
84 | void TextInputUnstableV3::Private::enterCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, wl_surface *surface) | ||||
85 | { | ||||
86 | auto t = reinterpret_cast<TextInputUnstableV3::Private*>(data); | ||||
87 | Q_ASSERT(t->textinputunstablev3 == zwp_text_input_v3); | ||||
88 | t->enteredSurface = Surface::get(surface); | ||||
89 | emit t->q->entered(); | ||||
90 | } | ||||
91 | | ||||
92 | void TextInputUnstableV3::Private::leaveCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, wl_surface *surface) | ||||
93 | { | ||||
94 | Q_UNUSED(surface) | ||||
95 | auto t = reinterpret_cast<TextInputUnstableV3::Private*>(data); | ||||
96 | Q_ASSERT(t->textinputunstablev3 == zwp_text_input_v3); | ||||
97 | t->enteredSurface = nullptr; | ||||
98 | emit t->q->left(); | ||||
99 | } | ||||
100 | | ||||
101 | void TextInputUnstableV3::Private::preeditStringCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, const char *text, int32_t begin, int32_t end) | ||||
102 | { | ||||
103 | auto t = reinterpret_cast<TextInputUnstableV3::Private*>(data); | ||||
104 | Q_ASSERT(t->textinputunstablev3 == zwp_text_input_v3); | ||||
105 | | ||||
106 | t->pendingPreEdit.text = QByteArray(text); | ||||
107 | t->pendingPreEdit.cursor = begin; | ||||
108 | t->pendingPreEdit.cursorEnd = end; | ||||
109 | } | ||||
110 | | ||||
111 | void TextInputUnstableV3::Private::commitStringCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, const char *text) | ||||
112 | { | ||||
113 | auto t = reinterpret_cast<TextInputUnstableV3::Private*>(data); | ||||
114 | Q_ASSERT(t->textinputunstablev3 == zwp_text_input_v3); | ||||
115 | | ||||
116 | t->pendingCommit.textSet = true; | ||||
117 | t->pendingCommit.text = QByteArray(text); | ||||
118 | } | ||||
119 | | ||||
120 | void TextInputUnstableV3::Private::deleteSurroundingTextCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, uint32_t before_length, uint32_t after_length) | ||||
121 | { | ||||
122 | auto t = reinterpret_cast<TextInputUnstableV3::Private*>(data); | ||||
123 | Q_ASSERT(t->textinputunstablev3 == zwp_text_input_v3); | ||||
124 | | ||||
125 | t->pendingCommit.deleteSurrounding.beforeLength = before_length; | ||||
126 | t->pendingCommit.deleteSurrounding.afterLength = after_length; | ||||
127 | } | ||||
128 | | ||||
129 | void TextInputUnstableV3::Private::doneCallback(void *data, zwp_text_input_v3 *zwp_text_input_v3, uint32_t serial) | ||||
130 | { | ||||
131 | auto t = reinterpret_cast<TextInputUnstableV3::Private*>(data); | ||||
132 | Q_ASSERT(t->textinputunstablev3 == zwp_text_input_v3); | ||||
133 | t->done(serial); | ||||
134 | } | ||||
135 | | ||||
136 | void TextInputUnstableV3::Private::done(uint32_t serial) | ||||
137 | { | ||||
138 | // it is a compositor error if a greater serial is sent | ||||
139 | Q_ASSERT(serial <= latestSerial); | ||||
140 | if (serial != latestSerial) { | ||||
141 | // event has been superseded by more recent commits | ||||
142 | return; | ||||
143 | } | ||||
144 | | ||||
145 | if (currentPreEdit.text != pendingPreEdit.text || | ||||
146 | currentPreEdit.cursor != pendingPreEdit.cursor || | ||||
147 | currentPreEdit.cursorEnd != pendingPreEdit.cursorEnd) { | ||||
148 | currentPreEdit.text = pendingPreEdit.text; | ||||
149 | currentPreEdit.cursor = pendingPreEdit.cursor; | ||||
150 | currentPreEdit.cursorEnd = pendingPreEdit.cursorEnd; | ||||
151 | emit q->composingTextChanged(); | ||||
152 | } | ||||
153 | currentCommit.deleteSurrounding = pendingCommit.deleteSurrounding; | ||||
154 | | ||||
155 | if (pendingCommit.textSet) { | ||||
156 | currentCommit.text = pendingCommit.text; | ||||
157 | pendingCommit.text = QByteArray(); | ||||
158 | pendingCommit.textSet = false; | ||||
159 | emit q->committed(); | ||||
160 | } | ||||
161 | } | ||||
162 | | ||||
163 | TextInputUnstableV3::Private::Private(TextInputUnstableV3 *q, Seat *seat) | ||||
164 | : TextInput::Private(seat) | ||||
165 | , q(q) | ||||
166 | { | ||||
167 | pendingCommit.deleteSurrounding = {0,0}; | ||||
168 | currentCommit.deleteSurrounding = {0,0}; | ||||
169 | } | ||||
170 | | ||||
171 | void TextInputUnstableV3::Private::setup(zwp_text_input_v3 *ti) | ||||
172 | { | ||||
173 | Q_ASSERT(ti); | ||||
174 | Q_ASSERT(!textinputunstablev3); | ||||
175 | textinputunstablev3.setup(ti); | ||||
176 | zwp_text_input_v3_add_listener(ti, &s_listener, this); | ||||
177 | } | ||||
178 | | ||||
179 | bool TextInputUnstableV3::Private::isValid() const | ||||
180 | { | ||||
181 | return textinputunstablev3.isValid(); | ||||
182 | } | ||||
183 | | ||||
184 | void TextInputUnstableV3::Private::enable(Surface *surface) | ||||
185 | { | ||||
186 | Q_UNUSED(surface) | ||||
187 | zwp_text_input_v3_enable(textinputunstablev3); | ||||
188 | } | ||||
189 | | ||||
190 | void TextInputUnstableV3::Private::disable(Surface * surface) | ||||
191 | { | ||||
192 | Q_UNUSED(surface) | ||||
193 | zwp_text_input_v3_disable(textinputunstablev3); | ||||
194 | } | ||||
195 | | ||||
196 | void TextInputUnstableV3::Private::showInputPanel() | ||||
197 | { | ||||
198 | // not supported in v3 | ||||
199 | } | ||||
200 | | ||||
201 | void TextInputUnstableV3::Private::hideInputPanel() | ||||
202 | { | ||||
203 | // not supported in v3 | ||||
204 | } | ||||
205 | | ||||
206 | void TextInputUnstableV3::Private::setCursorRectangle(const QRect &rect) | ||||
207 | { | ||||
208 | zwp_text_input_v3_set_cursor_rectangle(textinputunstablev3, rect.x(), rect.y(), rect.width(), rect.height()); | ||||
209 | } | ||||
210 | | ||||
211 | void TextInputUnstableV3::Private::setPreferredLanguage(const QString &lang) | ||||
212 | { | ||||
213 | Q_UNUSED(lang) | ||||
214 | // not supported in v3 | ||||
215 | } | ||||
216 | | ||||
217 | void TextInputUnstableV3::Private::setSurroundingTextChangeCause(TextInput::ChangeCause cause) | ||||
218 | { | ||||
219 | const zwp_text_input_v3_change_cause wlCause = (cause == TextInput::ChangeCause::Other) ? | ||||
220 | ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_OTHER : ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD; | ||||
221 | zwp_text_input_v3_set_text_change_cause(textinputunstablev3, wlCause); | ||||
222 | } | ||||
223 | | ||||
224 | void TextInputUnstableV3::Private::setSurroundingText(const QString &text, quint32 cursor, quint32 anchor) | ||||
225 | { | ||||
226 | pendingSurrounding.text = QByteArray(text.toUtf8().constData()); | ||||
227 | pendingSurrounding.cursor = cursor; | ||||
228 | pendingSurrounding.anchor = anchor; | ||||
229 | zwp_text_input_v3_set_surrounding_text(textinputunstablev3, text.toUtf8().constData(), | ||||
230 | text.leftRef(cursor).toUtf8().length(), | ||||
231 | text.leftRef(anchor).toUtf8().length()); | ||||
232 | } | ||||
233 | | ||||
234 | void TextInputUnstableV3::Private::reset() | ||||
235 | { | ||||
236 | // not supported in v3 | ||||
237 | } | ||||
238 | | ||||
239 | void TextInputUnstableV3::Private::setContentType(ContentHints hints, ContentPurpose purpose) | ||||
240 | { | ||||
241 | uint32_t wlHints = 0; | ||||
242 | uint32_t wlPurpose = 0; | ||||
243 | if (hints.testFlag(ContentHint::AutoCompletion)) { | ||||
244 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION; | ||||
245 | } | ||||
246 | if (hints.testFlag(ContentHint::AutoCorrection)) { | ||||
247 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK; | ||||
248 | } | ||||
249 | if (hints.testFlag(ContentHint::AutoCapitalization)) { | ||||
250 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION; | ||||
251 | } | ||||
252 | if (hints.testFlag(ContentHint::LowerCase)) { | ||||
253 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LOWERCASE; | ||||
254 | } | ||||
255 | if (hints.testFlag(ContentHint::UpperCase)) { | ||||
256 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE; | ||||
257 | } | ||||
258 | if (hints.testFlag(ContentHint::TitleCase)) { | ||||
259 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_TITLECASE; | ||||
260 | } | ||||
261 | if (hints.testFlag(ContentHint::HiddenText)) { | ||||
262 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT; | ||||
263 | } | ||||
264 | if (hints.testFlag(ContentHint::SensitiveData)) { | ||||
265 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA; | ||||
266 | } | ||||
267 | if (hints.testFlag(ContentHint::Latin)) { | ||||
268 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LATIN; | ||||
269 | } | ||||
270 | if (hints.testFlag(ContentHint::MultiLine)) { | ||||
271 | wlHints |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE; | ||||
272 | } | ||||
273 | switch (purpose) { | ||||
274 | case ContentPurpose::Normal: | ||||
275 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL; | ||||
276 | break; | ||||
277 | case ContentPurpose::Alpha: | ||||
278 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ALPHA; | ||||
279 | break; | ||||
280 | case ContentPurpose::Digits: | ||||
281 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DIGITS; | ||||
282 | break; | ||||
283 | case ContentPurpose::Number: | ||||
284 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER; | ||||
285 | break; | ||||
286 | case ContentPurpose::Phone: | ||||
287 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE; | ||||
288 | break; | ||||
289 | case ContentPurpose::Url: | ||||
290 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_URL; | ||||
291 | break; | ||||
292 | case ContentPurpose::Email: | ||||
293 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL; | ||||
294 | break; | ||||
295 | case ContentPurpose::Name: | ||||
296 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NAME; | ||||
297 | break; | ||||
298 | case ContentPurpose::Password: | ||||
299 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD; | ||||
300 | break; | ||||
301 | case ContentPurpose::Pin: | ||||
302 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN; | ||||
303 | break; | ||||
304 | case ContentPurpose::Date: | ||||
305 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATE; | ||||
306 | break; | ||||
307 | case ContentPurpose::Time: | ||||
308 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TIME; | ||||
309 | break; | ||||
310 | case ContentPurpose::DateTime: | ||||
311 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATETIME; | ||||
312 | break; | ||||
313 | case ContentPurpose::Terminal: | ||||
314 | wlPurpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL; | ||||
315 | break; | ||||
316 | } | ||||
317 | zwp_text_input_v3_set_content_type(textinputunstablev3, wlHints, wlPurpose); | ||||
318 | } | ||||
319 | | ||||
320 | void TextInputUnstableV3::Private::commit() | ||||
321 | { | ||||
322 | latestSerial++; | ||||
323 | zwp_text_input_v3_commit(textinputunstablev3); | ||||
324 | } | ||||
325 | | ||||
326 | TextInputUnstableV3::TextInputUnstableV3(Seat *seat, QObject *parent) | ||||
327 | : TextInput(new Private(this, seat), parent) | ||||
328 | { | ||||
329 | } | ||||
330 | | ||||
331 | TextInputUnstableV3::~TextInputUnstableV3() | ||||
332 | { | ||||
333 | release(); | ||||
334 | } | ||||
335 | | ||||
336 | TextInputUnstableV3::Private *TextInputUnstableV3::d_func() const | ||||
337 | { | ||||
338 | return reinterpret_cast<Private*>(d.data()); | ||||
339 | } | ||||
340 | | ||||
341 | void TextInputUnstableV3::setup(zwp_text_input_v3 *textinputunstablev3) | ||||
342 | { | ||||
343 | Q_D(); | ||||
344 | d->setup(textinputunstablev3); | ||||
345 | } | ||||
346 | | ||||
347 | void TextInputUnstableV3::release() | ||||
348 | { | ||||
349 | Q_D(); | ||||
350 | d->textinputunstablev3.release(); | ||||
351 | } | ||||
352 | | ||||
353 | void TextInputUnstableV3::destroy() | ||||
354 | { | ||||
355 | Q_D(); | ||||
356 | d->textinputunstablev3.destroy(); | ||||
357 | } | ||||
358 | | ||||
359 | TextInputUnstableV3::operator zwp_text_input_v3*() | ||||
360 | { | ||||
361 | Q_D(); | ||||
362 | return d->textinputunstablev3; | ||||
363 | } | ||||
364 | | ||||
365 | TextInputUnstableV3::operator zwp_text_input_v3*() const | ||||
366 | { | ||||
367 | Q_D(); | ||||
368 | return d->textinputunstablev3; | ||||
369 | } | ||||
370 | | ||||
371 | class TextInputManagerUnstableV3::Private : public TextInputManager::Private | ||||
372 | { | ||||
373 | public: | ||||
374 | Private() = default; | ||||
375 | | ||||
376 | void release() override; | ||||
377 | void destroy() override; | ||||
378 | bool isValid() override; | ||||
379 | void setupV3(zwp_text_input_manager_v3 *ti) override; | ||||
380 | TextInput *createTextInput(Seat *seat, QObject *parent = nullptr) override; | ||||
381 | using TextInputManager::Private::operator wl_text_input_manager*; | ||||
382 | operator zwp_text_input_manager_v3*() override { | ||||
383 | return textinputmanagerunstablev3; | ||||
384 | } | ||||
385 | operator zwp_text_input_manager_v3*() const override { | ||||
386 | return textinputmanagerunstablev3; | ||||
387 | } | ||||
388 | | ||||
389 | WaylandPointer<zwp_text_input_manager_v3, zwp_text_input_manager_v3_destroy> textinputmanagerunstablev3; | ||||
390 | }; | ||||
391 | | ||||
392 | void TextInputManagerUnstableV3::Private::release() | ||||
393 | { | ||||
394 | textinputmanagerunstablev3.release(); | ||||
395 | } | ||||
396 | | ||||
397 | void TextInputManagerUnstableV3::Private::destroy() | ||||
398 | { | ||||
399 | textinputmanagerunstablev3.destroy(); | ||||
400 | } | ||||
401 | | ||||
402 | bool TextInputManagerUnstableV3::Private::isValid() | ||||
403 | { | ||||
404 | return textinputmanagerunstablev3.isValid(); | ||||
405 | } | ||||
406 | | ||||
407 | TextInputManagerUnstableV3::TextInputManagerUnstableV3(QObject *parent) | ||||
408 | : TextInputManager(new Private, parent) | ||||
409 | { | ||||
410 | } | ||||
411 | | ||||
412 | TextInputManagerUnstableV3::~TextInputManagerUnstableV3() = default; | ||||
413 | | ||||
414 | void TextInputManagerUnstableV3::Private::setupV3(zwp_text_input_manager_v3 *ti) | ||||
415 | { | ||||
416 | Q_ASSERT(ti); | ||||
417 | Q_ASSERT(!textinputmanagerunstablev3); | ||||
418 | textinputmanagerunstablev3.setup(ti); | ||||
419 | } | ||||
420 | | ||||
421 | TextInput *TextInputManagerUnstableV3::Private::createTextInput(Seat *seat, QObject *parent) | ||||
422 | { | ||||
423 | Q_ASSERT(isValid()); | ||||
424 | TextInputUnstableV3 *t = new TextInputUnstableV3(seat, parent); | ||||
425 | auto w = zwp_text_input_manager_v3_get_text_input(textinputmanagerunstablev3, *seat); | ||||
426 | if (queue) { | ||||
427 | queue->addProxy(w); | ||||
428 | } | ||||
429 | t->setup(w); | ||||
430 | return t; | ||||
431 | } | ||||
432 | | ||||
433 | } | ||||
434 | } |