textinputv3: implement enableSurface() and disableSurface()

When enter() happens, it got enabled unconditionally. Then in
QWaylandInputContext::setFocusObject(), we need to enable() or
disable() it based on real situation.(If previous enter is
not valid on the QObject, it will be disabled by
disableSurface().)

It fixes the issue for wayfire and kwin/plasma 6. Sway still
has issues with input method events with popup menu, with and
without this patch.(Sway doesn't make keyboard_leave/enter
after surface_enter of popups.) See also
https://github.com/swaywm/sway/issues/4406

Fixes: QTBUG-132196
Pick-to: 6.9 6.8
Done-with: Liang Qi <liang.qi@qt.io>
Change-Id: I5b29a86e0256868c8bcbe48f936c09ee013728a6
Reviewed-by: Liang Qi <liang.qi@qt.io>
This commit is contained in:
Inho Lee 2025-01-17 11:02:27 +01:00
parent 005927d089
commit c57da9bb0a
3 changed files with 74 additions and 32 deletions

View File

@ -189,25 +189,30 @@ void QWaylandInputContext::setFocusObject(QObject *object)
QWindow *window = QGuiApplication::focusWindow();
if (mCurrentWindow && mCurrentWindow->handle()) {
if (mCurrentWindow.data() != window || !inputMethodAccepted()) {
auto *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->wlSurface();
if (window && window->handle()) {
if (mCurrentWindow.data() != window) {
if (!inputMethodAccepted()) {
auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
if (surface)
inputInterface->disableSurface(surface);
mCurrentWindow.clear();
}
}
if (window && window->handle() && inputMethodAccepted()) {
if (mCurrentWindow.data() != window) {
} else {
auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
if (surface) {
inputInterface->enableSurface(surface);
mCurrentWindow = window;
} else {
mCurrentWindow.clear();
}
}
}
if (mCurrentWindow)
inputInterface->updateState(Qt::ImQueryAll, QWaylandTextInputInterface::update_state_enter);
return;
}
if (mCurrentWindow)
mCurrentWindow.clear();
}
QWaylandTextInputInterface *QWaylandInputContext::textInput() const

View File

@ -40,12 +40,16 @@ const Qt::InputMethodQueries supportedQueries3 = Qt::ImEnabled |
Qt::ImCursorRectangle;
}
void QWaylandTextInputv3::zwp_text_input_v3_enter(struct ::wl_surface *surface)
void QWaylandTextInputv3::enableSurface(::wl_surface *surface)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << m_surface << surface;
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << surface;
if (m_surface == surface)
return; // already enabled
if (m_surface)
qCWarning(qLcQpaWaylandTextInput()) << Q_FUNC_INFO << "Try to enable surface" << surface << "with focusing surface" << m_surface;
m_surface = surface;
m_pendingPreeditString.clear();
m_pendingCommitString.clear();
m_pendingDeleteBeforeText = 0;
@ -55,27 +59,51 @@ void QWaylandTextInputv3::zwp_text_input_v3_enter(struct ::wl_surface *surface)
updateState(supportedQueries3, update_state_enter);
}
void QWaylandTextInputv3::disableSurface(::wl_surface *surface)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << surface;
if (!m_surface)
return; // already disabled
if (m_surface != surface)
qCWarning(qLcQpaWaylandTextInput()) << Q_FUNC_INFO << "Try to disable surface" << surface << "with focusing surface" << m_surface;
m_currentPreeditString.clear();
m_surface = nullptr;
disable();
commit();
}
void QWaylandTextInputv3::zwp_text_input_v3_enter(struct ::wl_surface *surface)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << m_surface << surface;
if (m_surface)
qCWarning(qLcQpaWaylandTextInput) << Q_FUNC_INFO << "Got enter event without leaving a surface " << m_surface;
enableSurface(surface);
}
void QWaylandTextInputv3::zwp_text_input_v3_leave(struct ::wl_surface *surface)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO;
if (m_surface != surface) {
qCWarning(qLcQpaWaylandTextInput()) << Q_FUNC_INFO << "Got leave event for surface" << surface << "focused surface" << m_surface;
return;
}
if (!m_surface)
return; // Nothing to leave
m_currentPreeditString.clear();
if (m_surface != surface)
qCWarning(qLcQpaWaylandTextInput()) << Q_FUNC_INFO << "Got leave event for surface" << surface << "with focusing surface" << m_surface;
m_surface = nullptr;
disable();
commit();
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << "Done";
disableSurface(surface);
}
void QWaylandTextInputv3::zwp_text_input_v3_preedit_string(const QString &text, int32_t cursorBegin, int32_t cursorEnd)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << text << cursorBegin << cursorEnd;
if (!m_surface) {
qCWarning(qLcQpaWaylandTextInput) << "Got preedit_string event without entering a surface";
return;
}
if (!QGuiApplication::focusObject())
return;
@ -88,6 +116,10 @@ void QWaylandTextInputv3::zwp_text_input_v3_preedit_string(const QString &text,
void QWaylandTextInputv3::zwp_text_input_v3_commit_string(const QString &text)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << text;
if (!m_surface) {
qCWarning(qLcQpaWaylandTextInput) << "Got commit_string event without entering a surface";
return;
}
if (!QGuiApplication::focusObject())
return;
@ -98,6 +130,10 @@ void QWaylandTextInputv3::zwp_text_input_v3_commit_string(const QString &text)
void QWaylandTextInputv3::zwp_text_input_v3_delete_surrounding_text(uint32_t beforeText, uint32_t afterText)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << beforeText << afterText;
if (!m_surface) {
qCWarning(qLcQpaWaylandTextInput) << "Got delete_surrounding_text event without entering a surface";
return;
}
if (!QGuiApplication::focusObject())
return;
@ -110,6 +146,9 @@ void QWaylandTextInputv3::zwp_text_input_v3_done(uint32_t serial)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << "with serial" << serial << m_currentSerial;
if (!m_surface)
return;
// This is a case of double click.
// text_input_v3 will ignore this done signal and just keep the selection of the clicked word.
if (m_cursorPos != m_anchorPos && (m_pendingDeleteBeforeText != 0 || m_pendingDeleteAfterText != 0)) {

View File

@ -48,10 +48,8 @@ public:
QLocale locale() const override;
Qt::LayoutDirection inputDirection() const override;
// doing nothing in zwp_text_input_v3.
// enter() and leave() takes the role to enable/disable the surface
void enableSurface(::wl_surface *) override {};
void disableSurface(::wl_surface *) override {};
void enableSurface(::wl_surface *) override;
void disableSurface(::wl_surface *) override;
protected:
void zwp_text_input_v3_enter(struct ::wl_surface *surface) override;