diff --git a/dde-clipboard-daemon/readpipedatatask.cpp b/dde-clipboard-daemon/readpipedatatask.cpp deleted file mode 100644 index 25e0448..0000000 --- a/dde-clipboard-daemon/readpipedatatask.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-FileCopyrightText: 2011 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "readpipedatatask.h" - -#include -#include -#include - -#include -#include - -#include - -#include - -#include - -std::mutex PIPELINE_GUARD; - -constexpr int BYTE_MAX = 1024 * 4; - -ReadPipeDataTask::ReadPipeDataTask(ConnectionThread *connectionThread, DataControlOfferV1 *offerV1, const QString &mimeType, QObject *parent) - : QObject(parent) - , m_mimeType(mimeType) - , m_pipeIsForcedClosed(false) - , m_pOffer(offerV1) - , m_pConnectionThread(connectionThread) -{ - -} - -void ReadPipeDataTask::run() -{ - if (!m_pConnectionThread || !m_pOffer || m_mimeType.isEmpty()) - return; - - int pipeFds[2]; - if (pipe(pipeFds) != 0) { - qWarning() << "Create pipe failed."; - - // 避免返回数据量少 - Q_EMIT dataReady((qint64)m_pOffer, m_mimeType, QByteArray()); - return; - } - - // 根据mime类取数据,写入pipe中 - m_pOffer->receive(m_mimeType, pipeFds[1]); - m_pConnectionThread->roundtrip(); - close(pipeFds[1]); - - // force to close the piepline - connect(this, &ReadPipeDataTask::forceClosePipeLine, this, [pipeFds, this] { - std::lock_guard guard(PIPELINE_GUARD); - m_pipeIsForcedClosed = true; - close(pipeFds[0]); - }); - - QtConcurrent::run([this, pipeFds] { - QByteArray data; - readData(pipeFds[0], data); - std::lock_guard guard(PIPELINE_GUARD); - this->deleteLater(); - if (m_pipeIsForcedClosed) { - qDebug() << "pipeline is block here;" << "mimetype is: " << m_mimeType; - return ; - } - - Q_EMIT dataReady((qint64)m_pOffer, m_mimeType, data); - - close(pipeFds[0]); - }); -} - -bool ReadPipeDataTask::readData(int fd, QByteArray &data) -{ - QFile readPipe; - if (!readPipe.open(fd, QIODevice::ReadOnly)) { - return false; - } - - if (!readPipe.isReadable()) { - qWarning() << "Pipe is not readable"; - readPipe.close(); - return false; - } - - int retCount = BYTE_MAX; - do { - QByteArray bytes = readPipe.read(BYTE_MAX); - retCount = bytes.count(); - if (!bytes.isEmpty()) - data.append(bytes); - } while (retCount == BYTE_MAX); - - readPipe.close(); - - return true; -} - - diff --git a/dde-clipboard-daemon/readpipedatatask.h b/dde-clipboard-daemon/readpipedatatask.h deleted file mode 100644 index 16fda80..0000000 --- a/dde-clipboard-daemon/readpipedatatask.h +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: 2011 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef READ_PIPE_DATA_TASK_H -#define READ_PIPE_DATA_TASK_H - -#include - -namespace KWayland -{ - namespace Client - { - class ConnectionThread; - class DataControlOfferV1; - } //Client -} //KWayland - -using namespace KWayland::Client; - -class ReadPipeDataTask : public QObject -{ - Q_OBJECT -public: - explicit ReadPipeDataTask(ConnectionThread *connectionThread, DataControlOfferV1 *offerV1, - const QString &mimeType, QObject *parent = nullptr); - - void run(); - -signals: - void dataReady(qint64, const QString &, const QByteArray &); - // In some applications like chrome, when it sends data, seems kwin cannot handle the request good enough, sometimes also firefox - // then sometimes it will block in the action of reading pipeline - // ReadPipeDataTask will be auto deleted if its task is finished, but if the action is blocked, it will be alive. - // Here, if next request of dataOffer comes, and if the task never ends, it will force to close the pipeline, make pipeline read action finished - void forceClosePipeLine(); - -private: - bool readData(int fd, QByteArray &data); - -private: - QString m_mimeType; - bool m_pipeIsForcedClosed; - - DataControlOfferV1 *m_pOffer; - ConnectionThread *m_pConnectionThread; -}; - -#endif //READ_PIPE_DATA_TASK_H diff --git a/dde-clipboard-daemon/waylandcopyclient.cpp b/dde-clipboard-daemon/waylandcopyclient.cpp index 35f916e..66236cd 100644 --- a/dde-clipboard-daemon/waylandcopyclient.cpp +++ b/dde-clipboard-daemon/waylandcopyclient.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "waylandcopyclient.h" -#include "readpipedatatask.h" #include #include @@ -22,6 +21,11 @@ #include #include +#include + +static std::mutex PIPELINE_GUARD; + +constexpr int BYTE_MAX = 1024 * 4; static const QString ApplicationXQtImageLiteral QStringLiteral("application/x-qt-image"); @@ -167,6 +171,7 @@ void WaylandCopyClient::init() m_connectionThread->start(); m_connectionThreadObject->initConnection(); connect(this, &WaylandCopyClient::dataCopied, this, &WaylandCopyClient::onDataCopied); + connect(this, &WaylandCopyClient::dataReady, this, &WaylandCopyClient::taskDataReady); } void WaylandCopyClient::setupRegistry(Registry *registry) @@ -217,13 +222,89 @@ void WaylandCopyClient::onDataOffered(KWayland::Client::DataControlOfferV1* offe // NOTE: no thread, this should be block void WaylandCopyClient::execTask(const QStringList &mimeTypes, DataControlOfferV1 *offer) { + m_pipeIsForcedClosed = false; for (const QString &mimeType : mimeTypes) { - ReadPipeDataTask *task = new ReadPipeDataTask(m_connectionThreadObject, offer, mimeType, this); - connect(this, &WaylandCopyClient::dataOfferedNew, task, &ReadPipeDataTask::forceClosePipeLine); - connect(task, &ReadPipeDataTask::dataReady, this, &WaylandCopyClient::taskDataReady); + onDataOfferedTask(offer, mimeType); + } +} - task->run(); +void WaylandCopyClient::onDataOfferedTask(DataControlOfferV1 *offer, const QString &mimeType) +{ + if (!m_connectionThreadObject || !offer || mimeType.isEmpty()) { + return; } + int pipeFds[2]; + + if (pipe(pipeFds) != 0) { + qWarning() << "Create pipe failed."; + + // 避免返回数据量少 + Q_EMIT dataReady((qint64)offer, mimeType, QByteArray()); + return; + } + + // 根据mime类取数据,写入pipe中 + offer->receive(mimeType, pipeFds[1]); + m_connectionThreadObject->roundtrip(); + close(pipeFds[1]); + + // force to close the piepline + connect(this, &WaylandCopyClient::dataOfferedNew, this, [pipeFds, this] { + std::lock_guard guard(PIPELINE_GUARD); + m_pipeIsForcedClosed = true; + close(pipeFds[0]); + }); + + qint64 offerId = (qint64)offer; + + // FIXME: in QtConcurrent run , when signal is emit, sometimes it cannot be recepted + // So sometimes copy will not succcessed + QtConcurrent::run([this, pipeFds, mimeType, offerId] { + QByteArray data; + bool is_successed = readData(pipeFds[0], data); + std::lock_guard guard(PIPELINE_GUARD); + if (m_pipeIsForcedClosed) { + qDebug() << "pipeline is block here;" << "mimetype is: " << mimeType; + m_pipeIsForcedClosed = false; + return; + } + + if (!is_successed) { + qDebug() << "Cannot open pipeline"; + return; + } + + Q_EMIT dataReady(offerId, mimeType, data); + m_pipeIsForcedClosed = false; + close(pipeFds[0]); + }); + +} + +bool WaylandCopyClient::readData(int fd, QByteArray &data) +{ + QFile readPipe; + if (!readPipe.open(fd, QIODevice::ReadOnly)) { + return false; + } + + if (!readPipe.isReadable()) { + qWarning() << "Pipe is not readable"; + readPipe.close(); + return false; + } + + int retCount = BYTE_MAX; + do { + QByteArray bytes = readPipe.read(BYTE_MAX); + retCount = bytes.count(); + if (!bytes.isEmpty()) + data.append(bytes); + } while (retCount == BYTE_MAX); + + readPipe.close(); + + return true; } void WaylandCopyClient::taskDataReady(qint64 offer, const QString &mimeType, const QByteArray &data) diff --git a/dde-clipboard-daemon/waylandcopyclient.h b/dde-clipboard-daemon/waylandcopyclient.h index b62b7b4..9772ef0 100644 --- a/dde-clipboard-daemon/waylandcopyclient.h +++ b/dde-clipboard-daemon/waylandcopyclient.h @@ -63,6 +63,7 @@ class WaylandCopyClient : public QObject void dataCopied(); // when a new dataOffer request in ,then send it void dataOfferedNew(); + void dataReady(qint64, const QString &, const QByteArray &); protected slots: void onSendDataRequest(const QString &mimeType, qint32 fd) const; @@ -73,6 +74,9 @@ protected slots: void execTask(const QStringList &mimeTypes, DataControlOfferV1 *offer); void taskDataReady(qint64, const QString &mimeType, const QByteArray &data); + void onDataOfferedTask(DataControlOfferV1 *offer, const QString &mimeType); + bool readData(int fd, QByteArray &data); + private: QThread *m_connectionThread; ConnectionThread *m_connectionThreadObject; @@ -85,6 +89,7 @@ protected slots: qint64 m_curOffer; QStringList m_curMimeTypes; + bool m_pipeIsForcedClosed = false; }; #endif // COPYCLIENT_H