summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2022-04-07 15:22:25 +0300
committerTarja Sundqvist <tarja.sundqvist@qt.io>2022-04-07 15:22:25 +0300
commit193420c09f8539da9fba141b05d6c6ae5b6a4760 (patch)
treec5037256e3fe1ff1a1e870cc1de96fd7642208bb
parentf4dd0560032c101fe9fd140ccc2397f5c0184146 (diff)
parent5eddb747e8bb5f452e247ea388ef1f6fa37783e7 (diff)
Merge remote-tracking branch 'origin/tqtc/lts-5.15.4' into tqtc/lts-5.15-opensourcev5.15.4-lts-lgpl
-rw-r--r--.qmake.conf2
-rw-r--r--src/client/qwaylandabstractdecoration.cpp8
-rw-r--r--src/client/qwaylanddisplay.cpp5
-rw-r--r--src/client/qwaylanddisplay_p.h3
-rw-r--r--src/client/qwaylandinputcontext.cpp95
-rw-r--r--src/client/qwaylandinputcontext_p.h21
-rw-r--r--src/client/qwaylandinputdevice.cpp10
-rw-r--r--src/client/qwaylandintegration.cpp8
-rw-r--r--src/client/qwaylandwindow.cpp15
-rw-r--r--src/compositor/extensions/qwaylandtextinputmanager.cpp2
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp9
-rw-r--r--tests/auto/client/surface/tst_surface.cpp33
12 files changed, 182 insertions, 29 deletions
diff --git a/.qmake.conf b/.qmake.conf
index bb8d0645..d1dc9832 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -4,4 +4,4 @@ DEFINES += QT_NO_FOREACH
DEFINES += QT_NO_JAVA_STYLE_ITERATORS
DEFINES += QT_NO_LINKED_LIST
-MODULE_VERSION = 5.15.3
+MODULE_VERSION = 5.15.4
diff --git a/src/client/qwaylandabstractdecoration.cpp b/src/client/qwaylandabstractdecoration.cpp
index 87dd6cea..b6ee43c9 100644
--- a/src/client/qwaylandabstractdecoration.cpp
+++ b/src/client/qwaylandabstractdecoration.cpp
@@ -108,11 +108,11 @@ void QWaylandAbstractDecoration::setWaylandWindow(QWaylandWindow *window)
static QRegion marginsRegion(const QSize &size, const QMargins &margins)
{
QRegion r;
- const int widthWithMargins = margins.left() + size.width() + margins.right();
- r += QRect(0, 0, widthWithMargins, margins.top()); // top
- r += QRect(0, size.height()+margins.top(), widthWithMargins, margins.bottom()); //bottom
+
+ r += QRect(0, 0, size.width(), margins.top()); // top
+ r += QRect(0, size.height()-margins.bottom(), size.width(), margins.bottom()); //bottom
r += QRect(0, margins.top(), margins.left(), size.height()); //left
- r += QRect(size.width()+margins.left(), margins.top(), margins.right(), size.height()); // right
+ r += QRect(size.width()-margins.left(), margins.top(), margins.right(), size.height()-margins.top()); // right
return r;
}
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index fe094f6f..f10c1f79 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -206,10 +206,11 @@ void QWaylandDisplay::checkError() const
int ecode = wl_display_get_error(mDisplay);
if ((ecode == EPIPE || ecode == ECONNRESET)) {
// special case this to provide a nicer error
- qFatal("The Wayland connection broke. Did the Wayland compositor die?");
+ qWarning("The Wayland connection broke. Did the Wayland compositor die?");
} else {
- qFatal("The Wayland connection experienced a fatal error: %s", strerror(ecode));
+ qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
}
+ _exit(1);
}
void QWaylandDisplay::flushRequests()
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index 188e9131..3b092bc8 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -175,8 +175,6 @@ public:
QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); }
QWaylandXdgOutputManagerV1 *xdgOutputManager() const { return mXdgOutputManager.data(); }
- bool usingInputContextFromCompositor() const { return mUsingInputContextFromCompositor; }
-
struct RegistryGlobal {
uint32_t id;
QString interface;
@@ -282,7 +280,6 @@ private:
QReadWriteLock m_frameQueueLock;
bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull();
- bool mUsingInputContextFromCompositor = false;
void registry_global(uint32_t id, const QString &interface, uint32_t version) override;
void registry_global_remove(uint32_t id) override;
diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp
index e9afe05e..ef5aa375 100644
--- a/src/client/qwaylandinputcontext.cpp
+++ b/src/client/qwaylandinputcontext.cpp
@@ -406,6 +406,8 @@ bool QWaylandInputContext::isValid() const
void QWaylandInputContext::reset()
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
+ if (m_composeState)
+ xkb_compose_state_reset(m_composeState);
QPlatformInputContext::reset();
@@ -526,9 +528,14 @@ Qt::LayoutDirection QWaylandInputContext::inputDirection() const
return textInput()->inputDirection();
}
-void QWaylandInputContext::setFocusObject(QObject *)
+void QWaylandInputContext::setFocusObject(QObject *object)
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
+#if QT_CONFIG(xkbcommon)
+ m_focusObject = object;
+#else
+ Q_UNUSED(object);
+#endif
if (!textInput())
return;
@@ -561,6 +568,92 @@ QWaylandTextInput *QWaylandInputContext::textInput() const
return mDisplay->defaultInputDevice()->textInput();
}
+#if QT_CONFIG(xkbcommon)
+
+void QWaylandInputContext::ensureInitialized()
+{
+ if (m_initialized)
+ return;
+
+ if (!m_XkbContext) {
+ qCWarning(qLcQpaInputMethods) << "error: xkb context has not been set on" << metaObject()->className();
+ return;
+ }
+
+ m_initialized = true;
+ const char *locale = setlocale(LC_CTYPE, "");
+ if (!locale)
+ locale = setlocale(LC_CTYPE, nullptr);
+ qCDebug(qLcQpaInputMethods) << "detected locale (LC_CTYPE):" << locale;
+
+ m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
+ if (m_composeTable)
+ m_composeState = xkb_compose_state_new(m_composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
+
+ if (!m_composeTable) {
+ qCWarning(qLcQpaInputMethods, "failed to create compose table");
+ return;
+ }
+ if (!m_composeState) {
+ qCWarning(qLcQpaInputMethods, "failed to create compose state");
+ return;
+ }
+}
+
+bool QWaylandInputContext::filterEvent(const QEvent *event)
+{
+ auto keyEvent = static_cast<const QKeyEvent *>(event);
+ if (keyEvent->type() != QEvent::KeyPress)
+ return false;
+
+ if (!inputMethodAccepted())
+ return false;
+
+ // lazy initialization - we don't want to do this on an app startup
+ ensureInitialized();
+
+ if (!m_composeTable || !m_composeState)
+ return false;
+
+ xkb_compose_state_feed(m_composeState, keyEvent->nativeVirtualKey());
+
+ switch (xkb_compose_state_get_status(m_composeState)) {
+ case XKB_COMPOSE_COMPOSING:
+ return true;
+ case XKB_COMPOSE_CANCELLED:
+ reset();
+ return false;
+ case XKB_COMPOSE_COMPOSED:
+ {
+ const int size = xkb_compose_state_get_utf8(m_composeState, nullptr, 0);
+ QVarLengthArray<char, 32> buffer(size + 1);
+ xkb_compose_state_get_utf8(m_composeState, buffer.data(), buffer.size());
+ QString composedText = QString::fromUtf8(buffer.constData());
+
+ QInputMethodEvent event;
+ event.setCommitString(composedText);
+
+ if (!m_focusObject && qApp)
+ m_focusObject = qApp->focusObject();
+
+ if (m_focusObject)
+ QCoreApplication::sendEvent(m_focusObject, &event);
+ else
+ qCWarning(qLcQpaInputMethods, "no focus object");
+
+ reset();
+ return true;
+ }
+ case XKB_COMPOSE_NOTHING:
+ return false;
+ default:
+ Q_UNREACHABLE();
+ return false;
+ }
+}
+
+#endif
+
}
QT_END_NAMESPACE
diff --git a/src/client/qwaylandinputcontext_p.h b/src/client/qwaylandinputcontext_p.h
index 10132dfe..50db6344 100644
--- a/src/client/qwaylandinputcontext_p.h
+++ b/src/client/qwaylandinputcontext_p.h
@@ -61,6 +61,10 @@
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
#include <qwaylandinputmethodeventbuilder_p.h>
+#include <qtwaylandclientglobal_p.h>
+#if QT_CONFIG(xkbcommon)
+#include <xkbcommon/xkbcommon-compose.h>
+#endif
struct wl_callback;
struct wl_callback_listener;
@@ -155,11 +159,28 @@ public:
void setFocusObject(QObject *object) override;
+#if QT_CONFIG(xkbcommon)
+ bool filterEvent(const QEvent *event) override;
+
+ // This invokable is called from QXkbCommon::setXkbContext().
+ Q_INVOKABLE void setXkbContext(struct xkb_context *context) { m_XkbContext = context; }
+#endif
+
private:
QWaylandTextInput *textInput() const;
QWaylandDisplay *mDisplay = nullptr;
QPointer<QWindow> mCurrentWindow;
+
+#if QT_CONFIG(xkbcommon)
+ void ensureInitialized();
+
+ bool m_initialized = false;
+ QObject *m_focusObject = nullptr;
+ xkb_compose_table *m_composeTable = nullptr;
+ xkb_compose_state *m_composeState = nullptr;
+ struct xkb_context *m_XkbContext = nullptr;
+#endif
};
}
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index ed4a0eb4..613fe862 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -1201,7 +1201,7 @@ void QWaylandInputDevice::Keyboard::handleKey(ulong timestamp, QEvent::Type type
QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
bool filtered = false;
- if (inputContext && !mParent->mQDisplay->usingInputContextFromCompositor()) {
+ if (inputContext) {
QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey,
nativeModifiers, text, autorepeat, count);
event.setTimestamp(timestamp);
@@ -1407,6 +1407,14 @@ void QWaylandInputDevice::handleTouchPoint(int id, Qt::TouchPointState state, co
it = mTouch->mPendingTouchPoints.insert(end, QWindowSystemInterface::TouchPoint());
it->id = id;
}
+ // If the touch points were up and down in same frame, send out frame right away
+ else if ((it->state == Qt::TouchPointPressed && state == Qt::TouchPointReleased)
+ || (it->state == Qt::TouchPointReleased && state == Qt::TouchPointPressed)) {
+ mTouch->touch_frame();
+ it = mTouch->mPendingTouchPoints.insert(mTouch->mPendingTouchPoints.end(), QWindowSystemInterface::TouchPoint());
+ it->id = id;
+ }
+
QWindowSystemInterface::TouchPoint &tp = *it;
// Only moved and pressed needs to update/set position
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
index 7ad8e05e..c53ccb78 100644
--- a/src/client/qwaylandintegration.cpp
+++ b/src/client/qwaylandintegration.cpp
@@ -474,13 +474,11 @@ void QWaylandIntegration::reconfigureInputContext()
#if QT_CONFIG(xkbcommon)
QXkbCommon::setXkbContext(mInputContext.data(), mDisplay->xkbContext());
+ if (QWaylandInputContext* waylandInput = qobject_cast<QWaylandInputContext*>(mInputContext.get())) {
+ waylandInput->setXkbContext(mDisplay->xkbContext());
+ }
#endif
- // Even if compositor-side input context handling has been requested, we fallback to
- // client-side handling if compositor does not provide the text-input extension. This
- // is why we need to check here which input context actually is being used.
- mDisplay->mUsingInputContextFromCompositor = qobject_cast<QWaylandInputContext *>(mInputContext.data());
-
qCDebug(lcQpaWayland) << "using input method:" << inputContext()->metaObject()->className();
}
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index e875af3a..e96d8fe9 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -342,7 +342,12 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect)
if (mSubSurfaceWindow) {
QMargins m = QPlatformWindow::parent()->frameMargins();
mSubSurfaceWindow->set_position(rect.x() + m.left(), rect.y() + m.top());
- mSubSurfaceWindow->parent()->window()->requestUpdate();
+
+ QWaylandWindow *parentWindow = mSubSurfaceWindow->parent();
+ if (parentWindow && parentWindow->isExposed()) {
+ QRect parentExposeGeometry(QPoint(), parentWindow->geometry().size());
+ parentWindow->sendExposeEvent(parentExposeGeometry);
+ }
}
}
@@ -1234,12 +1239,14 @@ bool QWaylandWindow::isOpaque() const
void QWaylandWindow::setOpaqueArea(const QRegion &opaqueArea)
{
- if (opaqueArea == mOpaqueArea || !mSurface)
+ const QRegion translatedOpaqueArea = opaqueArea.translated(frameMargins().left(), frameMargins().top());
+
+ if (translatedOpaqueArea == mOpaqueArea || !mSurface)
return;
- mOpaqueArea = opaqueArea;
+ mOpaqueArea = translatedOpaqueArea;
- struct ::wl_region *region = mDisplay->createRegion(opaqueArea);
+ struct ::wl_region *region = mDisplay->createRegion(translatedOpaqueArea);
mSurface->set_opaque_region(region);
wl_region_destroy(region);
}
diff --git a/src/compositor/extensions/qwaylandtextinputmanager.cpp b/src/compositor/extensions/qwaylandtextinputmanager.cpp
index 495ebae8..d9938d1f 100644
--- a/src/compositor/extensions/qwaylandtextinputmanager.cpp
+++ b/src/compositor/extensions/qwaylandtextinputmanager.cpp
@@ -51,6 +51,8 @@ void QWaylandTextInputManagerPrivate::zwp_text_input_manager_v2_get_text_input(R
textInput = new QWaylandTextInput(seat, compositor);
}
textInput->add(resource->client(), id, wl_resource_get_version(resource->handle));
+ if (!textInput->isInitialized())
+ textInput->initialize();
}
QWaylandTextInputManager::QWaylandTextInputManager()
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index 1c762944..3a1569f7 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -178,9 +178,12 @@ void QWaylandXdgSurface::Toplevel::requestWindowStates(Qt::WindowStates states)
}
if (changedStates & Qt::WindowFullScreen) {
- if (states & Qt::WindowFullScreen)
- set_fullscreen(nullptr);
- else
+ if (states & Qt::WindowFullScreen) {
+ auto screen = m_xdgSurface->window()->waylandScreen();
+ if (screen) {
+ set_fullscreen(screen->output());
+ }
+ } else
unset_fullscreen();
}
diff --git a/tests/auto/client/surface/tst_surface.cpp b/tests/auto/client/surface/tst_surface.cpp
index b8a65f15..95e4e609 100644
--- a/tests/auto/client/surface/tst_surface.cpp
+++ b/tests/auto/client/surface/tst_surface.cpp
@@ -167,17 +167,40 @@ void tst_surface::negotiateShmFormat()
void tst_surface::createSubsurface()
{
QRasterWindow window;
- window.resize(64, 64);
- window.show();
- QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
- QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
+ window.setObjectName("main");
+ window.resize(200, 200);
QRasterWindow subWindow;
+ subWindow.setObjectName("subwindow");
subWindow.setParent(&window);
subWindow.resize(64, 64);
+
+ window.show();
subWindow.show();
+
QCOMPOSITOR_TRY_VERIFY(subSurface());
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
+
+ const Surface *mainSurface = exec([=] {return surface(0);});
+ const Surface *childSurface = exec([=] {return surface(1);});
+ QSignalSpy mainSurfaceCommitSpy(mainSurface, &Surface::commit);
+ QSignalSpy childSurfaceCommitSpy(childSurface, &Surface::commit);
+
+ // Move subsurface. The parent should redraw and commit
+ subWindow.setGeometry(100, 100, 64, 64);
+ // the toplevel should commit to indicate the subsurface moved
+ QCOMPOSITOR_TRY_COMPARE(mainSurfaceCommitSpy.count(), 1);
+ mainSurfaceCommitSpy.clear();
+ childSurfaceCommitSpy.clear();
+
+ // Move and resize the subSurface. The parent should redraw and commit
+ // The child should also redraw
+ subWindow.setGeometry(50, 50, 80, 80);
+ QCOMPOSITOR_TRY_COMPARE(mainSurfaceCommitSpy.count(), 1);
+ QCOMPOSITOR_TRY_COMPARE(childSurfaceCommitSpy.count(), 1);
+
}
// Used to cause a crash in libwayland (QTBUG-79674)