xwl: Use direct way of syncing clipboard

Like the primary selection, sync the clipboard directly without
doing any roudntrips through the internal connection.
This commit is contained in:
David Redondo 2021-08-19 11:34:29 +02:00
parent 66d74f4398
commit bc17d0aebd
7 changed files with 84 additions and 61 deletions

View file

@ -3,6 +3,7 @@ add_subdirectory(lib)
add_library(KWinXwaylandServerModule OBJECT
clipboard.cpp
databridge.cpp
datasource.cpp
dnd.cpp
drag.cpp
drag_wl.cpp

View file

@ -8,21 +8,13 @@
*/
#include "clipboard.h"
#include "databridge.h"
#include "datasource.h"
#include "selection_source.h"
#include "transfer.h"
#include "xwayland.h"
#include "x11client.h"
#include "wayland_server.h"
#include "workspace.h"
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/datadevice.h>
#include <KWayland/Client/datasource.h>
#include <KWaylandServer/datadevice_interface.h>
#include <KWaylandServer/datasource_interface.h>
#include <KWaylandServer/seat_interface.h>
#include <xcb/xcb_event.h>
@ -58,10 +50,6 @@ Clipboard::Clipboard(xcb_atom_t atom, QObject *parent)
connect(waylandServer()->seat(), &KWaylandServer::SeatInterface::selectionChanged,
this, &Clipboard::wlSelectionChanged);
connect(DataBridge::self()->dataDeviceIface(), &KWaylandServer::DataDeviceInterface::selectionChanged, this, [](KWaylandServer::DataSourceInterface *selection) {
waylandServer()->seat()->setSelection(selection);
});
}
void Clipboard::wlSelectionChanged(KWaylandServer::AbstractDataSource *dsi)
@ -84,7 +72,7 @@ void Clipboard::wlSelectionChanged(KWaylandServer::AbstractDataSource *dsi)
bool Clipboard::ownsSelection(KWaylandServer::AbstractDataSource *dsi) const
{
return dsi && dsi->client() == DataBridge::self()->dataDeviceIface()->client();
return dsi && dsi == m_selectionSource.get();
}
void Clipboard::checkWlSource()
@ -110,7 +98,7 @@ void Clipboard::checkWlSource()
// Otherwise the Wayland source gets destroyed to shield
// against snooping X clients.
if (!dsi || (DataBridge::self()->dataDeviceIface()->client() == dsi->client())) {
if (!dsi || ownsSelection(dsi)) {
// Xwayland source or no source
disconnect(m_checkConnection);
m_checkConnection = QMetaObject::Connection();
@ -169,25 +157,24 @@ void Clipboard::x11OffersChanged(const QStringList &added, const QStringList &re
const Mimes offers = source->offers();
if (!offers.isEmpty()) {
// create new Wl DataSource if there is none or when types
// were removed (Wl Data Sources can only add types)
KWayland::Client::DataDeviceManager *dataDeviceManager =
waylandServer()->internalDataDeviceManager();
KWayland::Client::DataSource *dataSource =
dataDeviceManager->createDataSource(source);
// also offers directly the currently available types
source->setDataSource(dataSource);
DataBridge::self()->dataDevice()->setSelection(0, dataSource);
QStringList mimeTypes;
mimeTypes.reserve(offers.size());
std::transform(offers.begin(), offers.end(), std::back_inserter(mimeTypes), [](const Mimes::value_type &pair) {
return pair.first;
});
auto newSelection = std::make_unique<XwlDataSource>();
newSelection->setMimeTypes(mimeTypes);
connect(newSelection.get(), &XwlDataSource::dataRequested, source, &X11Source::startTransfer);
// we keep the old selection around because setSelection needs it to be still alive
std::swap(m_selectionSource, newSelection);
waylandServer()->seat()->setSelection(m_selectionSource.get());
} else {
KWaylandServer::AbstractDataSource *currentSelection = waylandServer()->seat()->selection();
if (!ownsSelection(currentSelection)) {
waylandServer()->seat()->setSelection(nullptr);
m_selectionSource.reset();
}
}
waylandServer()->internalClientConection()->flush();
waylandServer()->dispatch();
}
} // namespace Xwl

View file

@ -11,6 +11,8 @@
#include "selection.h"
#include <memory>
namespace KWaylandServer
{
class AbstractDataSource;
@ -20,6 +22,7 @@ namespace KWin
{
namespace Xwl
{
class XwlDataSource;
/**
* Represents the X clipboard, which is on Wayland side just called
@ -54,6 +57,7 @@ private:
Q_DISABLE_COPY(Clipboard)
bool m_waitingForTargets = false;
std::unique_ptr<XwlDataSource> m_selectionSource;
};
} // namespace Xwl

30
src/xwl/datasource.cpp Normal file
View file

@ -0,0 +1,30 @@
/*
SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "datasource.h"
namespace KWin
{
namespace Xwl
{
void XwlDataSource::requestData(const QString &mimeType, qint32 fd)
{
Q_EMIT dataRequested(mimeType, fd);
}
void XwlDataSource::cancel()
{
}
QStringList XwlDataSource::mimeTypes() const
{
return m_mimeTypes;
}
void XwlDataSource::setMimeTypes(const QStringList &mimeTypes)
{
m_mimeTypes = mimeTypes;
}
}
}

29
src/xwl/datasource.h Normal file
View file

@ -0,0 +1,29 @@
/*
SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <KWaylandServer/abstract_data_source.h>
namespace KWin
{
namespace Xwl
{
class XwlDataSource : public KWaylandServer::AbstractDataSource
{
Q_OBJECT
public:
void requestData(const QString &mimeType, qint32 fd) override;
void cancel() override;
QStringList mimeTypes() const override;
void setMimeTypes(const QStringList &mimeTypes);
Q_SIGNALS:
void dataRequested(const QString &mimeType, qint32 fd);
private:
QStringList m_mimeTypes;
};
}
}

View file

@ -9,13 +9,13 @@
*/
#include "primary.h"
#include "datasource.h"
#include "selection_source.h"
#include "x11client.h"
#include "wayland_server.h"
#include "workspace.h"
#include <KWaylandServer/abstract_data_source.h>
#include <KWaylandServer/seat_interface.h>
#include <xcb/xcb_event.h>
@ -28,31 +28,6 @@ namespace KWin
namespace Xwl
{
class PrimarySelectionSource : public KWaylandServer::AbstractDataSource
{
Q_OBJECT
public:
void requestData(const QString & mimeType, qint32 fd) override
{
Q_EMIT dataRequested(mimeType, fd);
}
void cancel() override
{
}
QStringList mimeTypes() const override
{
return m_mimeTypes;
}
void setMimeTypes(const QStringList &mimeTypes)
{
m_mimeTypes = mimeTypes;
}
Q_SIGNALS:
void dataRequested(const QString &mimeType, qint32 fd);
private:
QStringList m_mimeTypes;
};
Primary::Primary(xcb_atom_t atom, QObject *parent)
: Selection(atom, parent)
{
@ -188,9 +163,9 @@ void Primary::x11OffersChanged(const QStringList &added, const QStringList &remo
std::transform(offers.begin(), offers.end(), std::back_inserter(mimeTypes), [](const Mimes::value_type &pair) {
return pair.first;
});
auto newSelection = std::make_unique<PrimarySelectionSource>();
auto newSelection = std::make_unique<XwlDataSource>();
newSelection->setMimeTypes(mimeTypes);
connect(newSelection.get(), &PrimarySelectionSource::dataRequested, source, &X11Source::startTransfer);
connect(newSelection.get(), &XwlDataSource::dataRequested, source, &X11Source::startTransfer);
// we keep the old selection around because setPrimarySelection needs it to be still alive
std::swap(m_primarySelectionSource, newSelection);
waylandServer()->seat()->setPrimarySelection(m_primarySelectionSource.get());
@ -205,5 +180,3 @@ void Primary::x11OffersChanged(const QStringList &added, const QStringList &remo
} // namespace Xwl
} // namespace KWin
#include "primary.moc"

View file

@ -23,8 +23,7 @@ namespace KWin
{
namespace Xwl
{
class PrimarySelectionSource;
class XwlDataSource;
/**
* Represents the X clipboard, which is on Wayland side just called
@ -59,7 +58,7 @@ private:
Q_DISABLE_COPY(Primary)
bool m_waitingForTargets = false;
std::unique_ptr<PrimarySelectionSource> m_primarySelectionSource;
std::unique_ptr<XwlDataSource> m_primarySelectionSource;
};
} // namespace Xwl