summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKai Uwe Broulik <kde@privat.broulik.de>2023-08-05 16:48:37 +0200
committerLiang Qi <liang.qi@qt.io>2023-11-09 10:51:52 +0000
commit8168df849182aab1424867658254826e8b5ed78e (patch)
treebd36fda3df4a61b2445436e5bf4c584c8d6871dc
parent6644c401194f38b906dd71edeef882223fdddb9c (diff)
client: Convert text/x-moz-urls to text/uri-list
Similar to how it's done in the XCB QPA. This format is used by both Firefox and Chrome for exchanging URLs. Pick-to: 6.5 Change-Id: Icd4406ff6297ea2800f4e1389ffc2878ee1ccb65 Reviewed-by: David Edmundson <davidedmundson@kde.org> (cherry picked from commit 80a3359598553298b544feae0a7e7399d6cfd9a7) Reviewed-by: Liang Qi <liang.qi@qt.io>
-rw-r--r--src/client/qwaylanddataoffer.cpp49
-rw-r--r--tests/auto/client/datadevicev1/tst_datadevicev1.cpp44
2 files changed, 93 insertions, 0 deletions
diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
index 046385e91..b22887495 100644
--- a/src/client/qwaylanddataoffer.cpp
+++ b/src/client/qwaylanddataoffer.cpp
@@ -20,6 +20,47 @@ static QString utf8Text()
return QStringLiteral("text/plain;charset=utf-8");
}
+static QString uriList()
+{
+ return QStringLiteral("text/uri-list");
+}
+
+static QString mozUrl()
+{
+ return QStringLiteral("text/x-moz-url");
+}
+
+static QByteArray convertData(const QString &originalMime, const QString &newMime, const QByteArray &data)
+{
+ if (originalMime == newMime)
+ return data;
+
+ // Convert text/x-moz-url, which is an UTF-16 string of
+ // URL and page title pairs, all separated by line breaks, to text/uri-list.
+ // see also qtbase/src/plugins/platforms/xcb/qxcbmime.cpp
+ if (originalMime == uriList() && newMime == mozUrl()) {
+ if (data.size() > 1) {
+ const QString str = QString::fromUtf16(
+ reinterpret_cast<const char16_t *>(data.constData()), data.size() / 2);
+ if (!str.isNull()) {
+ QByteArray converted;
+ const auto urls = QStringView{str}.split(u'\n');
+ // Only the URL is interesting, skip the page title.
+ for (int i = 0; i < urls.size(); i += 2) {
+ const QUrl url(urls.at(i).trimmed().toString());
+ if (url.isValid()) {
+ converted += url.toEncoded();
+ converted += "\r\n";
+ }
+ }
+ return converted;
+ }
+ }
+ }
+
+ return data;
+}
+
QWaylandDataOffer::QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer)
: QtWayland::wl_data_offer(offer)
, m_display(display)
@@ -105,6 +146,9 @@ bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
if (mimeType == QStringLiteral("text/plain") && m_types.contains(utf8Text()))
return true;
+ if (mimeType == uriList() && m_types.contains(mozUrl()))
+ return true;
+
return false;
}
@@ -126,6 +170,8 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QMetaType t
if (!m_types.contains(mimeType)) {
if (mimeType == QStringLiteral("text/plain") && m_types.contains(utf8Text()))
mime = utf8Text();
+ else if (mimeType == uriList() && m_types.contains(mozUrl()))
+ mime = mozUrl();
else
return QVariant();
}
@@ -147,6 +193,9 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QMetaType t
}
close(pipefd[0]);
+
+ content = convertData(mimeType, mime, content);
+
m_data.insert(mimeType, content);
return content;
}
diff --git a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
index cdbf7379a..bb831564a 100644
--- a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
+++ b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
@@ -31,6 +31,7 @@ private slots:
void initTestCase();
void pasteAscii();
void pasteUtf8();
+ void pasteMozUrl();
void destroysPreviousSelection();
void destroysSelectionWithSurface();
void destroysSelectionOnLeave();
@@ -123,6 +124,49 @@ void tst_datadevicev1::pasteUtf8()
QTRY_COMPARE(window.m_text, "face with tears of joy: 😂");
}
+void tst_datadevicev1::pasteMozUrl()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *) override { m_urls = QGuiApplication::clipboard()->mimeData()->urls(); }
+ QList<QUrl> m_urls;
+ };
+
+ Window window;
+ window.resize(64, 64);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+ exec([&] {
+ auto *client = xdgSurface()->resource()->client();
+ auto *offer = dataDevice()->sendDataOffer(client, {"text/x-moz-url"});
+ connect(offer, &DataOffer::receive, [](QString mimeType, int fd) {
+ QFile file;
+ file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
+ QCOMPARE(mimeType, "text/x-moz-url");
+ const QString content("https://www.qt.io/\nQt\nhttps://www.example.com/\nExample Website");
+ // Need UTF-16.
+ file.write(reinterpret_cast<const char *>(content.data()), content.size() * 2);
+ file.close();
+ });
+ dataDevice()->sendSelection(offer);
+
+ auto *surface = xdgSurface()->m_surface;
+ keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
+
+ pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client);
+ pointer()->sendButton(client, BTN_LEFT, 1);
+ pointer()->sendFrame(client);
+ pointer()->sendButton(client, BTN_LEFT, 0);
+ pointer()->sendFrame(client);
+ });
+
+ QTRY_COMPARE(window.m_urls.count(), 2);
+ QCOMPARE(window.m_urls.at(0), QUrl("https://www.qt.io/"));
+ QCOMPARE(window.m_urls.at(1), QUrl("https://www.example.com/"));
+}
+
void tst_datadevicev1::destroysPreviousSelection()
{
QRasterWindow window;