summaryrefslogtreecommitdiffstats
path: root/src/client/qwaylanddataoffer.cpp
diff options
context:
space:
mode:
authorAndrew Knight <andrew.knight@digia.com>2013-10-21 17:45:11 +0300
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-24 13:41:03 +0200
commit187363886582ba236cf6fed0f956953b699eca53 (patch)
tree5a5e40f5d7fa6226d1a799a9d2de9946488ded07 /src/client/qwaylanddataoffer.cpp
parent3e757f8a441c5089b19428778f66f4dc890fe8fb (diff)
Clipboard: perform non-blocking reads from compositor
Since the compositor recycles file descriptors when offering data to clients, it is possible that a client (or multiple clients) can attempt to read from the same FD simultaneously, creating a situation where one read can wait indefinitely for data. By making the pipe non-blocking, the client can gracefully time-out if data doesn't arrive in a timely manner. This commit also ensures that only one FD is open per client per offered mime type. Change-Id: If052e5bf8198df1cdc8fc4df360f83a77950b2f9 Reviewed-by: Robin Burchell <robin+qt@viroteck.net>
Diffstat (limited to 'src/client/qwaylanddataoffer.cpp')
-rw-r--r--src/client/qwaylanddataoffer.cpp64
1 files changed, 45 insertions, 19 deletions
diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
index adaeb5214..f72330928 100644
--- a/src/client/qwaylanddataoffer.cpp
+++ b/src/client/qwaylanddataoffer.cpp
@@ -84,7 +84,6 @@ QWaylandMimeData::QWaylandMimeData(QWaylandDataOffer *dataOffer, QWaylandDisplay
: QInternalMimeData()
, m_dataOffer(dataOffer)
, m_display(display)
- , m_offered_mime_types()
{
}
@@ -94,46 +93,73 @@ QWaylandMimeData::~QWaylandMimeData()
void QWaylandMimeData::appendFormat(const QString &mimeType)
{
- m_offered_mime_types.append(mimeType);
+ if (m_types.contains(mimeType))
+ close(m_types.take(mimeType)); // Unconsumed data
+ m_data.remove(mimeType); // Clear previous contents
+
+ int pipefd[2];
+ if (::pipe2(pipefd, O_CLOEXEC|O_NONBLOCK) == -1) {
+ qWarning("QWaylandMimeData: pipe2() failed");
+ return;
+ }
+
+ m_dataOffer->receive(mimeType, pipefd[1]);
+ m_display->forceRoundTrip();
+ close(pipefd[1]);
+ m_types.insert(mimeType, pipefd[0]);
}
bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
{
- return m_offered_mime_types.contains(mimeType);
+ return m_types.contains(mimeType) || m_data.contains(mimeType);
}
QStringList QWaylandMimeData::formats_sys() const
{
- return m_offered_mime_types;
+ return m_types.keys() << m_data.keys();
}
QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
{
Q_UNUSED(type);
- if (m_offered_mime_types.isEmpty())
- return QVariant();
+ if (m_data.contains(mimeType))
+ return m_data.value(mimeType);
- int pipefd[2];
- if (qt_safe_pipe(pipefd, O_CLOEXEC) == -1) {
- qWarning("QWaylandMimeData: pipe() failed");
+ if (!m_types.contains(mimeType))
return QVariant();
- }
- m_dataOffer->receive(mimeType, pipefd[1]);
- close(pipefd[1]);
+ QByteArray content;
+ int fd = m_types.take(mimeType);
+ if (readData(fd, content) != 0) {
+ qWarning("QWaylandDataOffer: error reading data for mimeType %s", qPrintable(mimeType));
+ content = QByteArray();
+ }
-// m_display->forceRoundTrip();
+ close(fd);
+ m_data.insert(mimeType, content);
+ return content;
+}
- QByteArray content;
+int QWaylandMimeData::readData(int fd, QByteArray &data) const
+{
char buf[4096];
+ int retryCount = 0;
int n;
- while ((n = QT_READ(pipefd[0], &buf, sizeof buf)) > 0) {
- content.append(buf, n);
+ while (true) {
+ n = QT_READ(fd, buf, sizeof buf);
+ if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) && ++retryCount < 1000)
+ usleep(1000);
+ else
+ break;
}
- close(pipefd[0]);
-
- return content;
+ if (retryCount >= 1000)
+ qWarning("QWaylandDataOffer: timeout reading from pipe");
+ if (n > 0) {
+ data.append(buf, n);
+ n = readData(fd, data);
+ }
+ return n;
}
QT_END_NAMESPACE