1 /****************************************************************************
2 **
3 ** Copyright (C) 2017-2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include "qwaylandtextinput.h"
31 #include "qwaylandtextinput_p.h"
32 
33 #include <QtWaylandCompositor/QWaylandCompositor>
34 #include <QtWaylandCompositor/private/qwaylandseat_p.h>
35 
36 #include "qwaylandsurface.h"
37 #include "qwaylandview.h"
38 #include "qwaylandinputmethodeventbuilder_p.h"
39 
40 #include <QGuiApplication>
41 #include <QInputMethodEvent>
42 
43 #if QT_CONFIG(xkbcommon)
44 #include <QtXkbCommonSupport/private/qxkbcommon_p.h>
45 #endif
46 
47 QT_BEGIN_NAMESPACE
48 
QWaylandTextInputClientState()49 QWaylandTextInputClientState::QWaylandTextInputClientState()
50 {
51 }
52 
updatedQueries(const QWaylandTextInputClientState & other) const53 Qt::InputMethodQueries QWaylandTextInputClientState::updatedQueries(const QWaylandTextInputClientState &other) const
54 {
55     Qt::InputMethodQueries queries;
56 
57     if (hints != other.hints)
58         queries |= Qt::ImHints;
59     if (cursorRectangle != other.cursorRectangle)
60         queries |= Qt::ImCursorRectangle;
61     if (surroundingText != other.surroundingText)
62         queries |= Qt::ImSurroundingText | Qt::ImCurrentSelection;
63     if (cursorPosition != other.cursorPosition)
64         queries |= Qt::ImCursorPosition | Qt::ImCurrentSelection;
65     if (anchorPosition != other.anchorPosition)
66         queries |= Qt::ImAnchorPosition | Qt::ImCurrentSelection;
67     if (preferredLanguage != other.preferredLanguage)
68         queries |= Qt::ImPreferredLanguage;
69 
70     return queries;
71 }
72 
mergeChanged(const QWaylandTextInputClientState & other)73 Qt::InputMethodQueries QWaylandTextInputClientState::mergeChanged(const QWaylandTextInputClientState &other) {
74     Qt::InputMethodQueries queries;
75 
76     if ((other.changedState & Qt::ImHints) && hints != other.hints) {
77         hints = other.hints;
78         queries |= Qt::ImHints;
79     }
80 
81     if ((other.changedState & Qt::ImCursorRectangle) && cursorRectangle != other.cursorRectangle) {
82         cursorRectangle = other.cursorRectangle;
83         queries |= Qt::ImCursorRectangle;
84     }
85 
86     if ((other.changedState & Qt::ImSurroundingText) && surroundingText != other.surroundingText) {
87         surroundingText = other.surroundingText;
88         queries |= Qt::ImSurroundingText | Qt::ImCurrentSelection;
89     }
90 
91     if ((other.changedState & Qt::ImCursorPosition) && cursorPosition != other.cursorPosition) {
92         cursorPosition = other.cursorPosition;
93         queries |= Qt::ImCursorPosition | Qt::ImCurrentSelection;
94     }
95 
96     if ((other.changedState & Qt::ImAnchorPosition) && anchorPosition != other.anchorPosition) {
97         anchorPosition = other.anchorPosition;
98         queries |= Qt::ImAnchorPosition | Qt::ImCurrentSelection;
99     }
100 
101     if ((other.changedState & Qt::ImPreferredLanguage) && preferredLanguage != other.preferredLanguage) {
102         preferredLanguage = other.preferredLanguage;
103         queries |= Qt::ImPreferredLanguage;
104     }
105 
106     return queries;
107 }
108 
QWaylandTextInputPrivate(QWaylandCompositor * compositor)109 QWaylandTextInputPrivate::QWaylandTextInputPrivate(QWaylandCompositor *compositor)
110     : compositor(compositor)
111     , currentState(new QWaylandTextInputClientState)
112     , pendingState(new QWaylandTextInputClientState)
113 {
114 }
115 
sendInputMethodEvent(QInputMethodEvent * event)116 void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event)
117 {
118     Q_Q(QWaylandTextInput);
119 
120     if (!focusResource || !focusResource->handle)
121         return;
122 
123     QWaylandTextInputClientState afterCommit;
124 
125     afterCommit.surroundingText = currentState->surroundingText;
126     afterCommit.cursorPosition = qMin(currentState->cursorPosition, currentState->anchorPosition);
127 
128     // Remove selection
129     afterCommit.surroundingText.remove(afterCommit.cursorPosition, qAbs(currentState->cursorPosition - currentState->anchorPosition));
130 
131     if (event->replacementLength() > 0 || event->replacementStart() != 0) {
132         // Remove replacement
133         afterCommit.cursorPosition = qBound(0, afterCommit.cursorPosition + event->replacementStart(), afterCommit.surroundingText.length());
134         afterCommit.surroundingText.remove(afterCommit.cursorPosition,
135                                            qMin(event->replacementLength(),
136                                                 afterCommit.surroundingText.length() - afterCommit.cursorPosition));
137 
138         if (event->replacementStart() <= 0 && (event->replacementLength() >= -event->replacementStart())) {
139             const int selectionStart = qMin(currentState->cursorPosition, currentState->anchorPosition);
140             const int selectionEnd = qMax(currentState->cursorPosition, currentState->anchorPosition);
141             const int before = QWaylandInputMethodEventBuilder::indexToWayland(currentState->surroundingText, -event->replacementStart(), selectionStart + event->replacementStart());
142             const int after = QWaylandInputMethodEventBuilder::indexToWayland(currentState->surroundingText, event->replacementLength() + event->replacementStart(), selectionEnd);
143             send_delete_surrounding_text(focusResource->handle, before, after);
144         } else {
145             // TODO: Implement this case
146             qWarning() << "Not yet supported case of replacement. Start:" << event->replacementStart() << "length:" << event->replacementLength();
147         }
148     }
149 
150     // Insert commit string
151     afterCommit.surroundingText.insert(afterCommit.cursorPosition, event->commitString());
152     afterCommit.cursorPosition += event->commitString().length();
153     afterCommit.anchorPosition = afterCommit.cursorPosition;
154 
155     for (const QInputMethodEvent::Attribute &attribute : event->attributes()) {
156         if (attribute.type == QInputMethodEvent::Selection) {
157             afterCommit.cursorPosition = attribute.start;
158             afterCommit.anchorPosition = attribute.length;
159             int cursor = QWaylandInputMethodEventBuilder::indexToWayland(afterCommit.surroundingText, qAbs(attribute.start - afterCommit.cursorPosition), qMin(attribute.start, afterCommit.cursorPosition));
160             int anchor = QWaylandInputMethodEventBuilder::indexToWayland(afterCommit.surroundingText, qAbs(attribute.length - afterCommit.cursorPosition), qMin(attribute.length, afterCommit.cursorPosition));
161             send_cursor_position(focusResource->handle,
162                                  attribute.start < afterCommit.cursorPosition ? -cursor : cursor,
163                                  attribute.length < afterCommit.cursorPosition ? -anchor : anchor);
164         }
165     }
166     send_commit_string(focusResource->handle, event->commitString());
167     for (const QInputMethodEvent::Attribute &attribute : event->attributes()) {
168         if (attribute.type == QInputMethodEvent::Cursor) {
169             int index = QWaylandInputMethodEventBuilder::indexToWayland(event->preeditString(), attribute.start);
170             send_preedit_cursor(focusResource->handle, index);
171         } else if (attribute.type == QInputMethodEvent::TextFormat) {
172             int start = QWaylandInputMethodEventBuilder::indexToWayland(event->preeditString(), attribute.start);
173             int length = QWaylandInputMethodEventBuilder::indexToWayland(event->preeditString(), attribute.length, attribute.start);
174             // TODO add support for different stylesQWaylandTextInput
175             send_preedit_styling(focusResource->handle, start, length, preedit_style_default);
176         }
177     }
178     send_preedit_string(focusResource->handle, event->preeditString(), event->preeditString());
179 
180     Qt::InputMethodQueries queries = currentState->updatedQueries(afterCommit);
181     currentState->surroundingText = afterCommit.surroundingText;
182     currentState->cursorPosition = afterCommit.cursorPosition;
183     currentState->anchorPosition = afterCommit.anchorPosition;
184 
185     if (queries) {
186         qCDebug(qLcWaylandCompositorInputMethods) << "QInputMethod::update() after QInputMethodEvent" << queries;
187 
188         emit q->updateInputMethod(queries);
189     }
190 }
191 
sendKeyEvent(QKeyEvent * event)192 void QWaylandTextInputPrivate::sendKeyEvent(QKeyEvent *event)
193 {
194     if (!focusResource || !focusResource->handle)
195         return;
196 
197     // TODO add support for modifiers
198 
199 #if QT_CONFIG(xkbcommon)
200     for (xkb_keysym_t keysym : QXkbCommon::toKeysym(event)) {
201         send_keysym(focusResource->handle, event->timestamp(), keysym,
202                     event->type() == QEvent::KeyPress ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
203                     0);
204     }
205 #else
206     Q_UNUSED(event);
207 #endif
208 }
209 
sendInputPanelState()210 void QWaylandTextInputPrivate::sendInputPanelState()
211 {
212     if (!focusResource || !focusResource->handle)
213         return;
214 
215     QInputMethod *inputMethod = qApp->inputMethod();
216     const QRectF& keyboardRect = inputMethod->keyboardRectangle();
217     const QRectF& sceneInputRect = inputMethod->inputItemTransform().mapRect(inputMethod->inputItemRectangle());
218     const QRectF& localRect = sceneInputRect.intersected(keyboardRect).translated(-sceneInputRect.topLeft());
219 
220     send_input_panel_state(focusResource->handle,
221                            inputMethod->isVisible() ? input_panel_visibility_visible : input_panel_visibility_hidden,
222                            localRect.x(), localRect.y(), localRect.width(), localRect.height());
223 }
224 
sendTextDirection()225 void QWaylandTextInputPrivate::sendTextDirection()
226 {
227     if (!focusResource || !focusResource->handle)
228         return;
229 
230     const Qt::LayoutDirection direction = qApp->inputMethod()->inputDirection();
231     send_text_direction(focusResource->handle,
232                         (direction == Qt::LeftToRight) ? text_direction_ltr :
233                                                          (direction == Qt::RightToLeft) ? text_direction_rtl : text_direction_auto);
234 }
235 
sendLocale()236 void QWaylandTextInputPrivate::sendLocale()
237 {
238     if (!focusResource || !focusResource->handle)
239         return;
240 
241     const QLocale locale = qApp->inputMethod()->locale();
242     send_language(focusResource->handle, locale.bcp47Name());
243 }
244 
inputMethodQuery(Qt::InputMethodQuery property,QVariant argument) const245 QVariant QWaylandTextInputPrivate::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
246 {
247     switch (property) {
248     case Qt::ImHints:
249         return QVariant(static_cast<int>(currentState->hints));
250     case Qt::ImCursorRectangle:
251         return currentState->cursorRectangle;
252     case Qt::ImFont:
253         // Not supported
254         return QVariant();
255     case Qt::ImCursorPosition:
256         return currentState->cursorPosition;
257     case Qt::ImSurroundingText:
258         return currentState->surroundingText;
259     case Qt::ImCurrentSelection:
260         return currentState->surroundingText.mid(qMin(currentState->cursorPosition, currentState->anchorPosition),
261                                                  qAbs(currentState->anchorPosition - currentState->cursorPosition));
262     case Qt::ImMaximumTextLength:
263         // Not supported
264         return QVariant();
265     case Qt::ImAnchorPosition:
266         return currentState->anchorPosition;
267     case Qt::ImAbsolutePosition:
268         // We assume the surrounding text is our whole document for now
269         return currentState->cursorPosition;
270     case Qt::ImTextAfterCursor:
271         if (argument.isValid())
272             return currentState->surroundingText.mid(currentState->cursorPosition, argument.toInt());
273         return currentState->surroundingText.mid(currentState->cursorPosition);
274     case Qt::ImTextBeforeCursor:
275         if (argument.isValid())
276             return currentState->surroundingText.left(currentState->cursorPosition).right(argument.toInt());
277         return currentState->surroundingText.left(currentState->cursorPosition);
278     case Qt::ImPreferredLanguage:
279         return currentState->preferredLanguage;
280 
281     default:
282         return QVariant();
283     }
284 }
285 
setFocus(QWaylandSurface * surface)286 void QWaylandTextInputPrivate::setFocus(QWaylandSurface *surface)
287 {
288     Q_Q(QWaylandTextInput);
289 
290     if (focusResource && focus != surface) {
291         uint32_t serial = compositor->nextSerial();
292         send_leave(focusResource->handle, serial, focus->resource());
293         focusDestroyListener.reset();
294     }
295 
296     Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0;
297 
298     if (resource && (focus != surface || focusResource != resource)) {
299         uint32_t serial = compositor->nextSerial();
300         currentState.reset(new QWaylandTextInputClientState);
301         pendingState.reset(new QWaylandTextInputClientState);
302         send_enter(resource->handle, serial, surface->resource());
303         focusResource = resource;
304         sendInputPanelState();
305         sendLocale();
306         sendTextDirection();
307         focusDestroyListener.listenForDestruction(surface->resource());
308         if (inputPanelVisible && q->isSurfaceEnabled(surface))
309             qApp->inputMethod()->show();
310     }
311 
312     focusResource = resource;
313     focus = surface;
314 }
315 
zwp_text_input_v2_bind_resource(Resource * resource)316 void QWaylandTextInputPrivate::zwp_text_input_v2_bind_resource(Resource *resource)
317 {
318     send_modifiers_map(resource->handle, QByteArray(""));
319 }
320 
zwp_text_input_v2_destroy_resource(Resource * resource)321 void QWaylandTextInputPrivate::zwp_text_input_v2_destroy_resource(Resource *resource)
322 {
323     if (focusResource == resource)
324         focusResource = nullptr;
325 }
326 
zwp_text_input_v2_destroy(Resource * resource)327 void QWaylandTextInputPrivate::zwp_text_input_v2_destroy(Resource *resource)
328 {
329     wl_resource_destroy(resource->handle);
330 }
331 
zwp_text_input_v2_enable(Resource * resource,wl_resource * surface)332 void QWaylandTextInputPrivate::zwp_text_input_v2_enable(Resource *resource, wl_resource *surface)
333 {
334     Q_Q(QWaylandTextInput);
335 
336     QWaylandSurface *s = QWaylandSurface::fromResource(surface);
337     enabledSurfaces.insert(resource, s);
338     emit q->surfaceEnabled(s);
339 }
340 
zwp_text_input_v2_disable(QtWaylandServer::zwp_text_input_v2::Resource * resource,wl_resource *)341 void QWaylandTextInputPrivate::zwp_text_input_v2_disable(QtWaylandServer::zwp_text_input_v2::Resource *resource, wl_resource *)
342 {
343     Q_Q(QWaylandTextInput);
344 
345     QWaylandSurface *s = enabledSurfaces.take(resource);
346     emit q->surfaceDisabled(s);
347 }
348 
zwp_text_input_v2_show_input_panel(Resource *)349 void QWaylandTextInputPrivate::zwp_text_input_v2_show_input_panel(Resource *)
350 {
351     inputPanelVisible = true;
352 
353     qApp->inputMethod()->show();
354 }
355 
zwp_text_input_v2_hide_input_panel(Resource *)356 void QWaylandTextInputPrivate::zwp_text_input_v2_hide_input_panel(Resource *)
357 {
358     inputPanelVisible = false;
359 
360     qApp->inputMethod()->hide();
361 }
362 
zwp_text_input_v2_set_cursor_rectangle(Resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)363 void QWaylandTextInputPrivate::zwp_text_input_v2_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
364 {
365     if (resource != focusResource)
366         return;
367 
368     pendingState->cursorRectangle = QRect(x, y, width, height);
369 
370     pendingState->changedState |= Qt::ImCursorRectangle;
371 }
372 
zwp_text_input_v2_update_state(Resource * resource,uint32_t serial,uint32_t flags)373 void QWaylandTextInputPrivate::zwp_text_input_v2_update_state(Resource *resource, uint32_t serial, uint32_t flags)
374 {
375     Q_Q(QWaylandTextInput);
376 
377     qCDebug(qLcWaylandCompositorInputMethods) << "update_state" << serial << flags;
378 
379     if (resource != focusResource)
380         return;
381 
382     if (flags == update_state_reset || flags == update_state_enter) {
383         qCDebug(qLcWaylandCompositorInputMethods) << "QInputMethod::reset()";
384         qApp->inputMethod()->reset();
385     }
386 
387     this->serial = serial;
388 
389     Qt::InputMethodQueries queries;
390     if (flags == update_state_change) {
391         queries = currentState->mergeChanged(*pendingState.data());
392     } else {
393         queries = pendingState->updatedQueries(*currentState.data());
394         currentState.swap(pendingState);
395     }
396 
397     pendingState.reset(new QWaylandTextInputClientState);
398 
399     if (queries) {
400         qCDebug(qLcWaylandCompositorInputMethods) << "QInputMethod::update()" << queries;
401 
402         emit q->updateInputMethod(queries);
403     }
404 }
405 
zwp_text_input_v2_set_content_type(Resource * resource,uint32_t hint,uint32_t purpose)406 void QWaylandTextInputPrivate::zwp_text_input_v2_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose)
407 {
408     if (resource != focusResource)
409         return;
410 
411     pendingState->hints = Qt::ImhNone;
412 
413     if ((hint & content_hint_auto_completion) == 0
414         && (hint & content_hint_auto_correction) == 0)
415         pendingState->hints |= Qt::ImhNoPredictiveText;
416     if ((hint & content_hint_auto_capitalization) == 0)
417         pendingState->hints |= Qt::ImhNoAutoUppercase;
418     if ((hint & content_hint_lowercase) != 0)
419         pendingState->hints |= Qt::ImhPreferLowercase;
420     if ((hint & content_hint_uppercase) != 0)
421         pendingState->hints |= Qt::ImhPreferUppercase;
422     if ((hint & content_hint_hidden_text) != 0)
423         pendingState->hints |= Qt::ImhHiddenText;
424     if ((hint & content_hint_sensitive_data) != 0)
425         pendingState->hints |= Qt::ImhSensitiveData;
426     if ((hint & content_hint_latin) != 0)
427         pendingState->hints |= Qt::ImhLatinOnly;
428     if ((hint & content_hint_multiline) != 0)
429         pendingState->hints |= Qt::ImhMultiLine;
430 
431     switch (purpose) {
432     case content_purpose_normal:
433         break;
434     case content_purpose_alpha:
435         pendingState->hints |= Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly;
436         break;
437     case content_purpose_digits:
438         pendingState->hints |= Qt::ImhDigitsOnly;
439         break;
440     case content_purpose_number:
441         pendingState->hints |= Qt::ImhFormattedNumbersOnly;
442         break;
443     case content_purpose_phone:
444         pendingState->hints |= Qt::ImhDialableCharactersOnly;
445         break;
446     case content_purpose_url:
447         pendingState->hints |= Qt::ImhUrlCharactersOnly;
448         break;
449     case content_purpose_email:
450         pendingState->hints |= Qt::ImhEmailCharactersOnly;
451         break;
452     case content_purpose_name:
453     case content_purpose_password:
454         break;
455     case content_purpose_date:
456         pendingState->hints |= Qt::ImhDate;
457         break;
458     case content_purpose_time:
459         pendingState->hints |= Qt::ImhTime;
460         break;
461     case content_purpose_datetime:
462         pendingState->hints |= Qt::ImhDate | Qt::ImhTime;
463         break;
464     case content_purpose_terminal:
465     default:
466         break;
467     }
468 
469     pendingState->changedState |= Qt::ImHints;
470 }
471 
zwp_text_input_v2_set_preferred_language(Resource * resource,const QString & language)472 void QWaylandTextInputPrivate::zwp_text_input_v2_set_preferred_language(Resource *resource, const QString &language)
473 {
474     if (resource != focusResource)
475         return;
476 
477     pendingState->preferredLanguage = language;
478 
479     pendingState->changedState |= Qt::ImPreferredLanguage;
480 }
481 
zwp_text_input_v2_set_surrounding_text(Resource * resource,const QString & text,int32_t cursor,int32_t anchor)482 void QWaylandTextInputPrivate::zwp_text_input_v2_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor)
483 {
484     if (resource != focusResource)
485         return;
486 
487     pendingState->surroundingText = text;
488     pendingState->cursorPosition = QWaylandInputMethodEventBuilder::indexFromWayland(text, cursor);
489     pendingState->anchorPosition = QWaylandInputMethodEventBuilder::indexFromWayland(text, anchor);
490 
491     pendingState->changedState |= Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition;
492 }
493 
QWaylandTextInput(QWaylandObject * container,QWaylandCompositor * compositor)494 QWaylandTextInput::QWaylandTextInput(QWaylandObject *container, QWaylandCompositor *compositor)
495     : QWaylandCompositorExtensionTemplate(container, *new QWaylandTextInputPrivate(compositor))
496 {
497     connect(&d_func()->focusDestroyListener, &QWaylandDestroyListener::fired,
498             this, &QWaylandTextInput::focusSurfaceDestroyed);
499 
500     connect(qApp->inputMethod(), &QInputMethod::visibleChanged,
501             this, &QWaylandTextInput::sendInputPanelState);
502     connect(qApp->inputMethod(), &QInputMethod::keyboardRectangleChanged,
503             this, &QWaylandTextInput::sendInputPanelState);
504     connect(qApp->inputMethod(), &QInputMethod::inputDirectionChanged,
505             this, &QWaylandTextInput::sendTextDirection);
506     connect(qApp->inputMethod(), &QInputMethod::localeChanged,
507             this, &QWaylandTextInput::sendLocale);
508 }
509 
~QWaylandTextInput()510 QWaylandTextInput::~QWaylandTextInput()
511 {
512 }
513 
sendInputMethodEvent(QInputMethodEvent * event)514 void QWaylandTextInput::sendInputMethodEvent(QInputMethodEvent *event)
515 {
516     Q_D(QWaylandTextInput);
517 
518     d->sendInputMethodEvent(event);
519 }
520 
sendKeyEvent(QKeyEvent * event)521 void QWaylandTextInput::sendKeyEvent(QKeyEvent *event)
522 {
523     Q_D(QWaylandTextInput);
524 
525     d->sendKeyEvent(event);
526 }
527 
sendInputPanelState()528 void QWaylandTextInput::sendInputPanelState()
529 {
530     Q_D(QWaylandTextInput);
531 
532     d->sendInputPanelState();
533 }
534 
sendTextDirection()535 void QWaylandTextInput::sendTextDirection()
536 {
537     Q_D(QWaylandTextInput);
538 
539     d->sendTextDirection();
540 }
541 
sendLocale()542 void QWaylandTextInput::sendLocale()
543 {
544     Q_D(QWaylandTextInput);
545 
546     d->sendLocale();
547 }
548 
inputMethodQuery(Qt::InputMethodQuery property,QVariant argument) const549 QVariant QWaylandTextInput::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
550 {
551     const Q_D(QWaylandTextInput);
552 
553     return d->inputMethodQuery(property, argument);
554 }
555 
focus() const556 QWaylandSurface *QWaylandTextInput::focus() const
557 {
558     const Q_D(QWaylandTextInput);
559 
560     return d->focus;
561 }
562 
setFocus(QWaylandSurface * surface)563 void QWaylandTextInput::setFocus(QWaylandSurface *surface)
564 {
565     Q_D(QWaylandTextInput);
566 
567     d->setFocus(surface);
568 }
569 
focusSurfaceDestroyed(void *)570 void QWaylandTextInput::focusSurfaceDestroyed(void *)
571 {
572     Q_D(QWaylandTextInput);
573 
574     d->focusDestroyListener.reset();
575 
576     d->focus = nullptr;
577     d->focusResource = nullptr;
578 }
579 
isSurfaceEnabled(QWaylandSurface * surface) const580 bool QWaylandTextInput::isSurfaceEnabled(QWaylandSurface *surface) const
581 {
582     const Q_D(QWaylandTextInput);
583 
584     return d->enabledSurfaces.values().contains(surface);
585 }
586 
add(::wl_client * client,uint32_t id,int version)587 void QWaylandTextInput::add(::wl_client *client, uint32_t id, int version)
588 {
589     Q_D(QWaylandTextInput);
590 
591     d->add(client, id, version);
592 }
593 
interface()594 const wl_interface *QWaylandTextInput::interface()
595 {
596     return QWaylandTextInputPrivate::interface();
597 }
598 
interfaceName()599 QByteArray QWaylandTextInput::interfaceName()
600 {
601     return QWaylandTextInputPrivate::interfaceName();
602 }
603 
604 QT_END_NAMESPACE
605