Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libqt5-qtwayland for openSUSE:Factory checked in at 2022-01-25 17:35:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libqt5-qtwayland (Old) and /work/SRC/openSUSE:Factory/.libqt5-qtwayland.new.1938 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libqt5-qtwayland" Tue Jan 25 17:35:42 2022 rev:42 rq:948155 version:5.15.2+kde44 Changes: -------- --- /work/SRC/openSUSE:Factory/libqt5-qtwayland/libqt5-qtwayland.changes 2021-12-21 18:40:21.877859461 +0100 +++ /work/SRC/openSUSE:Factory/.libqt5-qtwayland.new.1938/libqt5-qtwayland.changes 2022-01-25 17:36:26.750179080 +0100 @@ -1,0 +2,14 @@ +Thu Jan 20 16:33:58 UTC 2022 - Fabian Vogt <fab...@ritter-vogt.de> + +- Update to version 5.15.2+kde44: + * Move the wayland socket polling to a separate event thread + * Connect flushRequest after forceRoundTrip + * Handle registry_global out of constructor + * Client: Avoid processing of events when showing windows + * Client: Delay deletion of QDrag object until after we're done with it + * Client: Implement DataDeviceV3 + * Set preedit cursor when cursor equals to 0 +- Drop patches, now upstream: + * 0001-Client-Avoid-processing-of-events-when-showing-windo.patch + +------------------------------------------------------------------- Old: ---- 0001-Client-Avoid-processing-of-events-when-showing-windo.patch qtwayland-everywhere-src-5.15.2+kde37.obscpio New: ---- qtwayland-everywhere-src-5.15.2+kde44.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libqt5-qtwayland.spec ++++++ --- /var/tmp/diff_new_pack.eFcU65/_old 2022-01-25 17:36:27.566173460 +0100 +++ /var/tmp/diff_new_pack.eFcU65/_new 2022-01-25 17:36:27.570173433 +0100 @@ -26,7 +26,7 @@ %define so_version 5.15.2 %define tar_version qtwayland-everywhere-src-%{version} Name: libqt5-qtwayland -Version: 5.15.2+kde37 +Version: 5.15.2+kde44 Release: 0 Summary: Qt 5 Wayland Addon # The wayland compositor files are GPL-3.0-or-later @@ -37,8 +37,6 @@ Source1: baselibs.conf # PATCH-FIX-OPENSUSE Patch1: 0001-Revert-Bump-version.patch -# PATCH-FIX-UPSTREAM -Patch2: 0001-Client-Avoid-processing-of-events-when-showing-windo.patch BuildRequires: fdupes BuildRequires: libqt5-qtbase-private-headers-devel >= %{real_version} BuildRequires: libqt5-qtdeclarative-private-headers-devel >= %{real_version} ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.eFcU65/_old 2022-01-25 17:36:27.622173074 +0100 +++ /var/tmp/diff_new_pack.eFcU65/_new 2022-01-25 17:36:27.626173047 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://invent.kde.org/qt/qt/qtwayland.git</param> - <param name="changesrevision">eb422ab5e07498a7a8d086f6a942ee35ab3c9776</param></service></servicedata> + <param name="changesrevision">4644d51f4b52e83fc1b4d02b380d80d9d57e76fa</param></service></servicedata> (No newline at EOF) ++++++ qtwayland-everywhere-src-5.15.2+kde37.obscpio -> qtwayland-everywhere-src-5.15.2+kde44.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatadevice.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatadevice.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatadevice.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatadevice.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -72,6 +72,8 @@ QWaylandDataDevice::~QWaylandDataDevice() { + if (wl_data_device_get_version(object()) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION) + release(); } QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const @@ -110,7 +112,7 @@ return m_dragOffer.data(); } -bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon) +bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon) { auto *seat = m_display->currentInputDevice(); auto *origin = seat->pointerFocus(); @@ -123,8 +125,28 @@ } m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData)); + + if (wl_data_device_get_version(object()) >= 3) + m_dragSource->set_actions(dropActionsToWl(supportedActions)); + connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled); - connect(m_dragSource.data(), &QWaylandDataSource::targetChanged, this, &QWaylandDataDevice::dragSourceTargetChanged); + connect(m_dragSource.data(), &QWaylandDataSource::dndResponseUpdated, this, [this](bool accepted, Qt::DropAction action) { + auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); + // in old versions drop action is not set, so we guess + if (wl_data_source_get_version(m_dragSource->object()) < 3) { + drag->setResponse(accepted); + } else { + QPlatformDropQtResponse response(accepted, action); + drag->setResponse(response); + } + }); + connect(m_dragSource.data(), &QWaylandDataSource::dndDropped, this, [](bool accepted, Qt::DropAction action) { + QPlatformDropQtResponse response(accepted, action); + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setDropResponse(response); + }); + connect(m_dragSource.data(), &QWaylandDataSource::finished, this, []() { + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(); + }); start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial()); return true; @@ -153,7 +175,7 @@ supportedActions = drag->supportedActions(); } else if (m_dragOffer) { dragData = m_dragOffer->mimeData(); - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; + supportedActions = m_dragOffer->supportedActions(); } else { return; } @@ -163,7 +185,11 @@ QGuiApplication::keyboardModifiers()); if (drag) { - static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response); + auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); + drag->setDropResponse(response); + drag->finishDrag(); + } else if (m_dragOffer) { + m_dragOffer->finish(); } } @@ -187,7 +213,7 @@ supportedActions = drag->supportedActions(); } else if (m_dragOffer) { dragData = m_dragOffer->mimeData(); - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; + supportedActions = m_dragOffer->supportedActions(); } const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions, @@ -198,11 +224,7 @@ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response); } - if (response.isAccepted()) { - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData()); - } else { - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr); - } + sendResponse(supportedActions, response); } void QWaylandDataDevice::data_device_leave() @@ -236,10 +258,10 @@ supportedActions = drag->supportedActions(); } else { dragData = m_dragOffer->mimeData(); - supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; + supportedActions = m_dragOffer->supportedActions(); } - QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions, + const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); @@ -247,11 +269,7 @@ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response); } - if (response.isAccepted()) { - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData()); - } else { - wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr); - } + sendResponse(supportedActions, response); } #endif // QT_CONFIG(draganddrop) @@ -281,11 +299,6 @@ m_dragSource.reset(); } -void QWaylandDataDevice::dragSourceTargetChanged(const QString &mimeType) -{ - static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->updateTarget(mimeType); -} - QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) const { QPoint pnt(wl_fixed_to_int(x), wl_fixed_to_int(y)); @@ -298,6 +311,33 @@ } return pnt; } + +void QWaylandDataDevice::sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response) +{ + if (response.isAccepted()) { + if (wl_data_device_get_version(object()) >= 3) + m_dragOffer->set_actions(dropActionsToWl(supportedActions), dropActionsToWl(response.acceptedAction())); + + m_dragOffer->accept(m_enterSerial, m_dragOffer->firstFormat()); + } else { + m_dragOffer->accept(m_enterSerial, QString()); + } +} + +int QWaylandDataDevice::dropActionsToWl(Qt::DropActions actions) +{ + + int wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + if (actions & Qt::CopyAction) + wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + if (actions & (Qt::MoveAction | Qt::TargetMoveAction)) + wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; + + // wayland does not support LinkAction at the time of writing + return wlActions; +} + + #endif // QT_CONFIG(draganddrop) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatadevice_p.h new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatadevice_p.h --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatadevice_p.h 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatadevice_p.h 2022-01-19 17:16:28.000000000 +0100 @@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE class QMimeData; +class QPlatformDragQtResponse; class QWindow; namespace QtWaylandClient { @@ -89,7 +90,7 @@ #if QT_CONFIG(draganddrop) QWaylandDataOffer *dragOffer() const; - bool startDrag(QMimeData *mimeData, QWaylandWindow *icon); + bool startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon); void cancelDrag(); #endif @@ -109,13 +110,16 @@ #if QT_CONFIG(draganddrop) void dragSourceCancelled(); - void dragSourceTargetChanged(const QString &mimeType); #endif private: #if QT_CONFIG(draganddrop) QPoint calculateDragPosition(int x, int y, QWindow *wnd) const; #endif + void sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response); + + static int dropActionsToWl(Qt::DropActions dropActions); + QWaylandDisplay *m_display = nullptr; QWaylandInputDevice *m_inputDevice = nullptr; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatadevicemanager.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatadevicemanager.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatadevicemanager.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatadevicemanager.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -50,8 +50,8 @@ namespace QtWaylandClient { -QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id) - : wl_data_device_manager(display->wl_registry(), id, 1) +QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id) + : wl_data_device_manager(display->wl_registry(), id, qMin(version, 3)) , m_display(display) { // Create transfer devices for all input devices. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatadevicemanager_p.h new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatadevicemanager_p.h --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatadevicemanager_p.h 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatadevicemanager_p.h 2022-01-19 17:16:28.000000000 +0100 @@ -68,7 +68,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandDataDeviceManager : public QtWayland::wl_data_device_manager { public: - QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id); + QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id); ~QWaylandDataDeviceManager() override; QWaylandDataDevice *getDataDevice(QWaylandInputDevice *inputDevice); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddataoffer.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddataoffer.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddataoffer.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddataoffer.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -82,6 +82,15 @@ return m_mimeData.data(); } +Qt::DropActions QWaylandDataOffer::supportedActions() const +{ + if (wl_data_offer_get_version(const_cast<::wl_data_offer*>(object())) < 3) { + return Qt::MoveAction | Qt::CopyAction; + } + + return m_supportedActions; +} + void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd) { receive(mimeType, fd); @@ -93,6 +102,22 @@ m_mimeData->appendFormat(mime_type); } +void QWaylandDataOffer::data_offer_action(uint32_t dnd_action) +{ + Q_UNUSED(dnd_action); + // This is the compositor telling the drag target what action it should perform + // It does not map nicely into Qt final drop semantics, other than pretending there is only one supported action? +} + +void QWaylandDataOffer::data_offer_source_actions(uint32_t source_actions) +{ + m_supportedActions = Qt::DropActions(); + if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) + m_supportedActions |= Qt::MoveAction; + if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) + m_supportedActions |= Qt::CopyAction; +} + QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer) : m_dataOffer(dataOffer) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddataoffer_p.h new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddataoffer_p.h --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddataoffer_p.h 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddataoffer_p.h 2022-01-19 17:16:28.000000000 +0100 @@ -82,6 +82,7 @@ explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer); ~QWaylandDataOffer() override; QMimeData *mimeData() override; + Qt::DropActions supportedActions() const; QString firstFormat() const; @@ -89,10 +90,13 @@ protected: void data_offer_offer(const QString &mime_type) override; + void data_offer_source_actions(uint32_t source_actions) override; + void data_offer_action(uint32_t dnd_action) override; private: QWaylandDisplay *m_display = nullptr; QScopedPointer<QWaylandMimeData> m_mimeData; + Qt::DropActions m_supportedActions; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatasource.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatasource.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatasource.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatasource.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -101,7 +101,32 @@ void QWaylandDataSource::data_source_target(const QString &mime_type) { - Q_EMIT targetChanged(mime_type); + m_accepted = !mime_type.isEmpty(); + Q_EMIT dndResponseUpdated(m_accepted, m_dropAction); +} + +void QWaylandDataSource::data_source_action(uint32_t action) +{ + Qt::DropAction qtAction = Qt::IgnoreAction; + + if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) + qtAction = Qt::MoveAction; + else if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) + qtAction = Qt::CopyAction; + + m_dropAction = qtAction; + Q_EMIT dndResponseUpdated(m_accepted, m_dropAction); +} + +void QWaylandDataSource::data_source_dnd_finished() +{ + Q_EMIT finished(); +} + +void QWaylandDataSource::data_source_dnd_drop_performed() +{ + + Q_EMIT dndDropped(m_accepted, m_dropAction); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatasource_p.h new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatasource_p.h --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddatasource_p.h 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddatasource_p.h 2022-01-19 17:16:28.000000000 +0100 @@ -77,17 +77,25 @@ QMimeData *mimeData() const; Q_SIGNALS: - void targetChanged(const QString &mime_type); void cancelled(); + void finished(); + + void dndResponseUpdated(bool accepted, Qt::DropAction action); + void dndDropped(bool accepted, Qt::DropAction action); protected: void data_source_cancelled() override; void data_source_send(const QString &mime_type, int32_t fd) override; void data_source_target(const QString &mime_type) override; + void data_source_dnd_drop_performed() override; + void data_source_dnd_finished() override; + void data_source_action(uint32_t action) override; private: QWaylandDisplay *m_display = nullptr; QMimeData *m_mime_data = nullptr; + bool m_accepted = false; + Qt::DropAction m_dropAction = Qt::IgnoreAction; }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddisplay.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddisplay.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddisplay.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddisplay.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -85,10 +85,203 @@ #include <errno.h> +#include <tuple> // for std::tie + +static void checkWaylandError(struct wl_display *display) +{ + int ecode = wl_display_get_error(display); + if ((ecode == EPIPE || ecode == ECONNRESET)) { + // special case this to provide a nicer error + qWarning("The Wayland connection broke. Did the Wayland compositor die?"); + } else { + qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode)); + } + _exit(1); +} + QT_BEGIN_NAMESPACE namespace QtWaylandClient { +class EventThread : public QThread +{ + Q_OBJECT +public: + enum OperatingMode { + EmitToDispatch, // Emit the signal, allow dispatching in a differnt thread. + SelfDispatch, // Dispatch the events inside this thread. + }; + + EventThread(struct wl_display * wl, struct wl_event_queue * ev_queue, + OperatingMode mode) + : m_fd(wl_display_get_fd(wl)) + , m_pipefd{ -1, -1 } + , m_wldisplay(wl) + , m_wlevqueue(ev_queue) + , m_mode(mode) + , m_reading(true) + , m_quitting(false) + { + setObjectName(QStringLiteral("WaylandEventThread")); + } + + void readAndDispatchEvents() + { + /* + * Dispatch pending events and flush the requests at least once. If the event thread + * is not reading, try to call _prepare_read() to allow the event thread to poll(). + * If that fails, re-try dispatch & flush again until _prepare_read() is successful. + * + * This allow any call to readAndDispatchEvents() to start event thread's polling, + * not only the one issued from event thread's waitForReading(), which means functions + * called from dispatch_pending() can safely spin an event loop. + */ + for (;;) { + if (dispatchQueuePending() < 0) { + checkWaylandError(m_wldisplay); + return; + } + + wl_display_flush(m_wldisplay); + + // We have to check if event thread is reading every time we dispatch + // something, as that may recursively call this function. + if (m_reading.loadAcquire()) + break; + + if (prepareReadQueue() == 0) { + QMutexLocker l(&m_mutex); + m_reading.storeRelease(true); + m_cond.wakeOne(); + break; + } + } + } + + void stop() + { + // We have to both write to the pipe and set the flag, as the thread may be + // either in the poll() or waiting for _prepare_read(). + if (m_pipefd[1] != -1 && write(m_pipefd[1], "\0", 1) == -1) + qWarning("Failed to write to the pipe: %s.", strerror(errno)); + + { + QMutexLocker l(&m_mutex); + m_quitting = true; + m_cond.wakeOne(); + } + + wait(); + } + +Q_SIGNALS: + void needReadAndDispatch(); + +protected: + void run() override + { + // we use this pipe to make the loop exit otherwise if we simply used a flag on the loop condition, if stop() gets + // called while poll() is blocking the thread will never quit since there are no wayland messages coming anymore. + struct Pipe + { + Pipe(int *fds) + : fds(fds) + { + if (qt_safe_pipe(fds) != 0) + qWarning("Pipe creation failed. Quitting may hang."); + } + ~Pipe() + { + if (fds[0] != -1) { + close(fds[0]); + close(fds[1]); + } + } + + int *fds; + } pipe(m_pipefd); + + // Make the main thread call wl_prepare_read(), dispatch the pending messages and flush the + // outbound ones. Wait until it's done before proceeding, unless we're told to quit. + while (waitForReading()) { + pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_pipefd[0], POLLIN, 0 } }; + poll(fds, 2, -1); + + if (fds[1].revents & POLLIN) { + // we don't really care to read the byte that was written here since we're closing down + wl_display_cancel_read(m_wldisplay); + break; + } + + if (fds[0].revents & POLLIN) + wl_display_read_events(m_wldisplay); + // The polll was succesfull and the event thread did the wl_display_read_events(). On the next iteration of the loop + // the event sent to the main thread will cause it to dispatch the messages just read, unless the loop exits in which + // case we don't care anymore about them. + else + wl_display_cancel_read(m_wldisplay); + } + } + +private: + bool waitForReading() + { + Q_ASSERT(QThread::currentThread() == this); + + m_reading.storeRelease(false); + + if (m_mode == SelfDispatch) { + readAndDispatchEvents(); + } else { + Q_EMIT needReadAndDispatch(); + + QMutexLocker lock(&m_mutex); + // m_reading might be set from our emit or some other invocation of + // readAndDispatchEvents(). + while (!m_reading.loadRelaxed() && !m_quitting) + m_cond.wait(&m_mutex); + } + + return !m_quitting; + } + + int dispatchQueuePending() + { + if (m_wlevqueue) + return wl_display_dispatch_queue_pending(m_wldisplay, m_wlevqueue); + else + return wl_display_dispatch_pending(m_wldisplay); + } + + int prepareReadQueue() + { + if (m_wlevqueue) + return wl_display_prepare_read_queue(m_wldisplay, m_wlevqueue); + else + return wl_display_prepare_read(m_wldisplay); + } + + int m_fd; + int m_pipefd[2]; + wl_display *m_wldisplay; + wl_event_queue *m_wlevqueue; + OperatingMode m_mode; + + /* Concurrency note when operating in EmitToDispatch mode: + * m_reading is set to false inside event thread's waitForReading(), and is + * set to true inside main thread's readAndDispatchEvents(). + * The lock is not taken when setting m_reading to false, as the main thread + * is not actively waiting for it to turn false. However, the lock is taken + * inside readAndDispatchEvents() before setting m_reading to true, + * as the event thread is actively waiting for it under the wait condition. + */ + + QAtomicInteger<bool> m_reading; + bool m_quitting; + QMutex m_mutex; + QWaitCondition m_cond; +}; + Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorized) Wayland platform logging struct wl_surface *QWaylandDisplay::createSurface(void *handle) @@ -158,17 +351,16 @@ if (!mXkbContext) qCWarning(lcQpaWayland, "failed to create xkb context"); #endif - - forceRoundTrip(); - - if (!mWaitingScreens.isEmpty()) { - // Give wl_output.done and zxdg_output_v1.done events a chance to arrive - forceRoundTrip(); - } } QWaylandDisplay::~QWaylandDisplay(void) { + if (m_eventThread) + m_eventThread->stop(); + + if (m_frameEventQueueThread) + m_frameEventQueueThread->stop(); + if (mSyncCallback) wl_callback_destroy(mSyncCallback); @@ -189,6 +381,18 @@ wl_display_disconnect(mDisplay); } +// Steps which is called just after constructor. This separates registry_global() out of the constructor +// so that factory functions in integration can be overridden. +void QWaylandDisplay::initialize() +{ + forceRoundTrip(); + + if (!mWaitingScreens.isEmpty()) { + // Give wl_output.done and zxdg_output_v1.done events a chance to arrive + forceRoundTrip(); + } +} + void QWaylandDisplay::ensureScreen() { if (!mScreens.empty() || mPlaceholderScreen) @@ -203,98 +407,37 @@ void QWaylandDisplay::checkError() const { - int ecode = wl_display_get_error(mDisplay); - if ((ecode == EPIPE || ecode == ECONNRESET)) { - // special case this to provide a nicer error - qWarning("The Wayland connection broke. Did the Wayland compositor die?"); - } else { - qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode)); - } - _exit(1); + checkWaylandError(mDisplay); } +// Called in main thread, either from queued signal or directly. void QWaylandDisplay::flushRequests() { - if (wl_display_prepare_read(mDisplay) == 0) { - wl_display_read_events(mDisplay); - } - - if (wl_display_dispatch_pending(mDisplay) < 0) - checkError(); - - { - QReadLocker locker(&m_frameQueueLock); - for (const FrameQueue &q : mExternalQueues) { - QMutexLocker locker(q.mutex); - while (wl_display_prepare_read_queue(mDisplay, q.queue) != 0) - wl_display_dispatch_queue_pending(mDisplay, q.queue); - wl_display_read_events(mDisplay); - wl_display_dispatch_queue_pending(mDisplay, q.queue); - } - } + m_eventThread->readAndDispatchEvents(); +} - wl_display_flush(mDisplay); +// We have to wait until we have an eventDispatcher before creating the eventThread, +// otherwise forceRoundTrip() may block inside _events_read() because eventThread is +// polling. +void QWaylandDisplay::initEventThread() +{ + m_eventThread.reset( + new EventThread(mDisplay, /* default queue */ nullptr, EventThread::EmitToDispatch)); + connect(m_eventThread.get(), &EventThread::needReadAndDispatch, this, + &QWaylandDisplay::flushRequests, Qt::QueuedConnection); + m_eventThread->start(); + + // wl_display_disconnect() free this. + m_frameEventQueue = wl_display_create_queue(mDisplay); + m_frameEventQueueThread.reset( + new EventThread(mDisplay, m_frameEventQueue, EventThread::SelfDispatch)); + m_frameEventQueueThread->start(); } void QWaylandDisplay::blockingReadEvents() { if (wl_display_dispatch(mDisplay) < 0) - checkError(); -} - -void QWaylandDisplay::destroyFrameQueue(const QWaylandDisplay::FrameQueue &q) -{ - QWriteLocker locker(&m_frameQueueLock); - auto it = std::find_if(mExternalQueues.begin(), - mExternalQueues.end(), - [&q] (const QWaylandDisplay::FrameQueue &other){ return other.queue == q.queue; }); - Q_ASSERT(it != mExternalQueues.end()); - mExternalQueues.erase(it); - if (q.queue != nullptr) - wl_event_queue_destroy(q.queue); - delete q.mutex; -} - -QWaylandDisplay::FrameQueue QWaylandDisplay::createFrameQueue() -{ - QWriteLocker locker(&m_frameQueueLock); - FrameQueue q{createEventQueue()}; - mExternalQueues.append(q); - return q; -} - -wl_event_queue *QWaylandDisplay::createEventQueue() -{ - return wl_display_create_queue(mDisplay); -} - -void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bool ()> condition, int timeout) -{ - if (!condition()) - return; - - QElapsedTimer timer; - timer.start(); - struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN); - while (timeout == -1 || timer.elapsed() < timeout) { - while (wl_display_prepare_read_queue(mDisplay, queue) != 0) - wl_display_dispatch_queue_pending(mDisplay, queue); - - wl_display_flush(mDisplay); - - const int remaining = qMax(timeout - timer.elapsed(), 0ll); - const int pollTimeout = timeout == -1 ? -1 : remaining; - if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0) - wl_display_read_events(mDisplay); - else - wl_display_cancel_read(mDisplay); - - if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0) - checkError(); - - if (!condition()) - break; - } + checkWaylandError(mDisplay); } QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const @@ -354,7 +497,7 @@ mInputDevices.append(inputDevice); #if QT_CONFIG(wayland_datadevice) } else if (interface == QStringLiteral("wl_data_device_manager")) { - mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id)); + mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id)); #endif } else if (interface == QStringLiteral("qt_surface_extension")) { mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1)); @@ -669,4 +812,6 @@ } // namespace QtWaylandClient +#include "qwaylanddisplay.moc" + QT_END_NAMESPACE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddisplay_p.h new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddisplay_p.h --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddisplay_p.h 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddisplay_p.h 2022-01-19 17:16:28.000000000 +0100 @@ -109,6 +109,7 @@ class QWaylandShellIntegration; class QWaylandCursor; class QWaylandCursorTheme; +class EventThread; typedef void (*RegistryListener)(void *data, struct wl_registry *registry, @@ -120,15 +121,11 @@ Q_OBJECT public: - struct FrameQueue { - FrameQueue(wl_event_queue *q = nullptr) : queue(q), mutex(new QMutex) {} - wl_event_queue *queue; - QMutex *mutex; - }; - QWaylandDisplay(QWaylandIntegration *waylandIntegration); ~QWaylandDisplay(void) override; + void initialize(); + #if QT_CONFIG(xkbcommon) struct xkb_context *xkbContext() const { return mXkbContext.get(); } #endif @@ -210,12 +207,11 @@ void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice); void handleWindowDestroyed(QWaylandWindow *window); - wl_event_queue *createEventQueue(); - FrameQueue createFrameQueue(); - void destroyFrameQueue(const FrameQueue &q); - void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1); + wl_event_queue *frameEventQueue() { return m_frameEventQueue; }; bool isKeyboardAvailable() const; + + void initEventThread(); public slots: void blockingReadEvents(); void flushRequests(); @@ -238,6 +234,9 @@ }; struct wl_display *mDisplay = nullptr; + QScopedPointer<EventThread> m_eventThread; + wl_event_queue *m_frameEventQueue = nullptr; + QScopedPointer<EventThread> m_frameEventQueueThread; QtWayland::wl_compositor mCompositor; QScopedPointer<QWaylandShm> mShm; QList<QWaylandScreen *> mWaitingScreens; @@ -274,11 +273,9 @@ QWaylandInputDevice *mLastInputDevice = nullptr; QPointer<QWaylandWindow> mLastInputWindow; QPointer<QWaylandWindow> mLastKeyboardFocus; - QVector<QWaylandWindow *> mActiveWindows; - QVector<FrameQueue> mExternalQueues; + QList<QWaylandWindow *> mActiveWindows; struct wl_callback *mSyncCallback = nullptr; static const wl_callback_listener syncCallbackListener; - QReadWriteLock m_frameQueueLock; bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddnd.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddnd.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddnd.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddnd.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -66,7 +66,7 @@ { QBasicDrag::startDrag(); QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle()); - if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) { + if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), drag()->supportedActions(), icon)) { icon->addAttachOffset(-drag()->hotSpot()); } else { // Cancelling immediately does not work, since the event loop for QDrag::exec is started @@ -80,6 +80,9 @@ QBasicDrag::cancel(); m_display->currentInputDevice()->dataDevice()->cancelDrag(); + + if (drag()) + drag()->deleteLater(); } void QWaylandDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) @@ -103,33 +106,41 @@ m_display->currentInputDevice()->handleEndDrag(); } -void QWaylandDrag::updateTarget(const QString &mimeType) +void QWaylandDrag::setResponse(bool accepted) { - setCanDrop(!mimeType.isEmpty()); - - if (canDrop()) { - updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers())); - } else { - updateCursor(Qt::IgnoreAction); - } + // This method is used for old DataDevices where the drag action is not communicated + Qt::DropAction action = defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()); + setResponse(QPlatformDropQtResponse(accepted, action)); } -void QWaylandDrag::setResponse(const QPlatformDragQtResponse &response) +void QWaylandDrag::setResponse(const QPlatformDropQtResponse &response) { setCanDrop(response.isAccepted()); if (canDrop()) { - updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers())); + updateCursor(response.acceptedAction()); } else { updateCursor(Qt::IgnoreAction); } } -void QWaylandDrag::finishDrag(const QPlatformDropQtResponse &response) +void QWaylandDrag::setDropResponse(const QPlatformDropQtResponse &response) { setExecutedDropAction(response.acceptedAction()); +} + +void QWaylandDrag::finishDrag() +{ QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier); eventFilter(shapedPixmapWindow(), &event); + + if (drag()) + drag()->deleteLater(); +} + +bool QWaylandDrag::ownsDragObject() const +{ + return true; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddnd_p.h new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddnd_p.h --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylanddnd_p.h 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylanddnd_p.h 2022-01-19 17:16:28.000000000 +0100 @@ -71,9 +71,10 @@ QWaylandDrag(QWaylandDisplay *display); ~QWaylandDrag() override; - void updateTarget(const QString &mimeType); - void setResponse(const QPlatformDragQtResponse &response); - void finishDrag(const QPlatformDropQtResponse &response); + void setResponse(bool accepted); + void setResponse(const QPlatformDropQtResponse &response); + void setDropResponse(const QPlatformDropQtResponse &response); + void finishDrag(); protected: void startDrag() override; @@ -82,6 +83,7 @@ void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override; void endDrag() override; + bool ownsDragObject() const override; private: QWaylandDisplay *m_display = nullptr; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylandintegration.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylandintegration.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylandintegration.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylandintegration.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -192,14 +192,18 @@ void QWaylandIntegration::initialize() { + mDisplay->initEventThread(); + + // Call after eventDispatcher is fully connected, for QWaylandDisplay::forceRoundTrip() + mDisplay->initialize(); + + // But the aboutToBlock() and awake() should be connected after initializePlatform(). + // Otherwise the connected flushRequests() may consumes up all events before processEvents starts to wait, + // so that processEvents(QEventLoop::WaitForMoreEvents) may be blocked in the forceRoundTrip(). QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests())); QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests())); - int fd = wl_display_get_fd(mDisplay->wl_display()); - QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data()); - QObject::connect(sn, SIGNAL(activated(QSocketDescriptor)), mDisplay.data(), SLOT(flushRequests())); - // Qt does not support running with no screens mDisplay->ensureScreen(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylandwindow.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylandwindow.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylandwindow.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylandwindow.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -76,7 +76,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display) : QPlatformWindow(window) , mDisplay(display) - , mFrameQueue(mDisplay->createFrameQueue()) , mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP")) { { @@ -95,8 +94,6 @@ QWaylandWindow::~QWaylandWindow() { - mDisplay->destroyFrameQueue(mFrameQueue); - delete mWindowDecoration; if (mSurface) @@ -436,7 +433,6 @@ if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip) activePopups << this; initWindow(); - mDisplay->flushRequests(); setGeometry(windowGeometry()); // Don't flush the events here, or else the newly visible window may start drawing, but since @@ -636,6 +632,8 @@ void QWaylandWindow::handleFrameCallback() { + QMutexLocker locker(&mFrameSyncMutex); + mWaitingForFrameCallback = false; mFrameCallbackElapsedTimer.invalidate(); @@ -657,12 +655,16 @@ mWaitingForUpdateDelivery = true; QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection); } + + mFrameSyncWait.notify_all(); } bool QWaylandWindow::waitForFrameSync(int timeout) { - QMutexLocker locker(mFrameQueue.mutex); - mDisplay->dispatchQueueWhile(mFrameQueue.queue, [&]() { return mWaitingForFrameCallback; }, timeout); + QMutexLocker locker(&mFrameSyncMutex); + + QDeadlineTimer deadline(timeout); + while (mWaitingForFrameCallback && mFrameSyncWait.wait(&mFrameSyncMutex, deadline)) { } if (mWaitingForFrameCallback) { qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed"; @@ -1158,8 +1160,11 @@ Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA // If we have a frame callback all is good and will be taken care of there - if (mWaitingForFrameCallback) - return; + { + QMutexLocker locker(&mFrameSyncMutex); + if (mWaitingForFrameCallback) + return; + } // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet // This is a somewhat redundant behavior and might indicate a bug in the calling code, so log @@ -1172,7 +1177,12 @@ // so use invokeMethod to delay the delivery a bit. QMetaObject::invokeMethod(this, [this] { // Things might have changed in the meantime - if (hasPendingUpdateRequest() && !mWaitingForFrameCallback) + { + QMutexLocker locker(&mFrameSyncMutex); + if (mWaitingForFrameCallback) + return; + } + if (hasPendingUpdateRequest()) deliverUpdateRequest(); }, Qt::QueuedConnection); } @@ -1192,9 +1202,10 @@ if (!mSurface) return; - QMutexLocker locker(mFrameQueue.mutex); + QMutexLocker locker(&mFrameSyncMutex); + struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object())); - wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mFrameQueue.queue); + wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mDisplay->frameEventQueue()); mFrameCallback = wl_surface_frame(wrappedSurface); wl_proxy_wrapper_destroy(wrappedSurface); wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this); @@ -1204,6 +1215,8 @@ // Start a timer for handling the case when the compositor stops sending frame callbacks. if (mFrameCallbackTimeout > 0) { QMetaObject::invokeMethod(this, [this] { + QMutexLocker locker(&mFrameSyncMutex); + if (mWaitingForFrameCallback) { if (mFrameCallbackCheckIntervalTimerId < 0) mFrameCallbackCheckIntervalTimerId = startTimer(mFrameCallbackTimeout); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylandwindow_p.h new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylandwindow_p.h --- old/qtwayland-everywhere-src-5.15.2+kde37/src/client/qwaylandwindow_p.h 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/client/qwaylandwindow_p.h 2022-01-19 17:16:28.000000000 +0100 @@ -232,7 +232,7 @@ int mFrameCallbackCheckIntervalTimerId = -1; QElapsedTimer mFrameCallbackElapsedTimer; struct ::wl_callback *mFrameCallback = nullptr; - QWaylandDisplay::FrameQueue mFrameQueue; + QMutex mFrameSyncMutex; QWaitCondition mFrameSyncWait; // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/src/shared/qwaylandinputmethodeventbuilder.cpp new/qtwayland-everywhere-src-5.15.2+kde44/src/shared/qwaylandinputmethodeventbuilder.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/src/shared/qwaylandinputmethodeventbuilder.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/src/shared/qwaylandinputmethodeventbuilder.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -151,7 +151,7 @@ { QList<QInputMethodEvent::Attribute> attributes; - if (m_preeditCursor < 0) { + if (m_preeditCursor <= 0) { attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant())); } else if (m_preeditCursor > 0) { attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant())); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwayland-everywhere-src-5.15.2+kde37/tests/auto/client/datadevicev1/tst_datadevicev1.cpp new/qtwayland-everywhere-src-5.15.2+kde44/tests/auto/client/datadevicev1/tst_datadevicev1.cpp --- old/qtwayland-everywhere-src-5.15.2+kde37/tests/auto/client/datadevicev1/tst_datadevicev1.cpp 2021-12-09 17:38:43.000000000 +0100 +++ new/qtwayland-everywhere-src-5.15.2+kde44/tests/auto/client/datadevicev1/tst_datadevicev1.cpp 2022-01-19 17:16:28.000000000 +0100 @@ -35,7 +35,7 @@ using namespace MockCompositor; -constexpr int dataDeviceVersion = 1; +constexpr int dataDeviceVersion = 3; class DataDeviceCompositor : public DefaultCompositor { public: ++++++ qtwayland-everywhere-src.obsinfo ++++++ --- /var/tmp/diff_new_pack.eFcU65/_old 2022-01-25 17:36:27.950170815 +0100 +++ /var/tmp/diff_new_pack.eFcU65/_new 2022-01-25 17:36:27.954170788 +0100 @@ -1,6 +1,6 @@ name: qtwayland-everywhere-src -version: 5.15.2+kde37 -mtime: 1639067923 -commit: eb422ab5e07498a7a8d086f6a942ee35ab3c9776 +version: 5.15.2+kde44 +mtime: 1642608988 +commit: 4644d51f4b52e83fc1b4d02b380d80d9d57e76fa