16#include "wayland/datasource.h"
22#include <xcb/xcb_event.h>
23#include <xcb/xfixes.h>
28#include <xwayland_logging.h>
36static const uint32_t s_incrChunkSize = 63 * 1024;
42 , m_timestamp(timestamp)
49 m_notifier =
new QSocketNotifier(m_fd,
type,
this);
73void Transfer::closeFd()
83 qint32 fd, QObject *parent)
98 connect(
socketNotifier(), &QSocketNotifier::activated,
this, [
this](
int socket) {
103int TransferWltoX::flushSourceData()
105 Q_ASSERT(!m_chunks.isEmpty());
106 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
108 xcb_change_property(xcbConn,
109 XCB_PROP_MODE_REPLACE,
110 m_request->requestor,
114 m_chunks.first().first.size(),
115 m_chunks.first().first.data());
118 m_propertyIsSet =
true;
121 const auto rm = m_chunks.takeFirst();
122 return rm.first.size();
125void TransferWltoX::startIncr()
127 Q_ASSERT(m_chunks.size() == 1);
129 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
131 uint32_t mask[] = {XCB_EVENT_MASK_PROPERTY_CHANGE};
132 xcb_change_window_attributes(xcbConn,
133 m_request->requestor,
134 XCB_CW_EVENT_MASK, mask);
137 const uint32_t chunkSpace = 1024 + s_incrChunkSize;
138 xcb_change_property(xcbConn,
139 XCB_PROP_MODE_REPLACE,
140 m_request->requestor,
149 m_flushPropertyOnDelete =
true;
150 m_propertyIsSet =
true;
154void TransferWltoX::readWlSource()
156 if (m_chunks.size() == 0 || m_chunks.last().second == s_incrChunkSize) {
158 auto next = QPair<QByteArray, int>();
159 next.first.resize(s_incrChunkSize);
161 m_chunks.append(next);
164 const auto oldLen = m_chunks.last().second;
165 const auto avail = s_incrChunkSize - m_chunks.last().second;
168 ssize_t readLen = read(
fd(), m_chunks.last().first.data() + oldLen, avail);
170 qCWarning(KWIN_XWL) <<
"Error reading in Wl data.";
176 m_chunks.last().second = oldLen + readLen;
180 m_chunks.last().first.resize(m_chunks.last().second);
184 m_flushPropertyOnDelete =
true;
185 if (!m_propertyIsSet) {
197 }
else if (m_chunks.last().second == s_incrChunkSize) {
200 m_flushPropertyOnDelete =
true;
201 if (!m_propertyIsSet) {
215 if (event->window == m_request->requestor) {
216 if (event->state == XCB_PROPERTY_DELETE && event->atom == m_request->property) {
217 handlePropertyDelete();
224void TransferWltoX::handlePropertyDelete()
230 m_propertyIsSet =
false;
232 if (m_flushPropertyOnDelete) {
235 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
237 uint32_t mask[] = {0};
238 xcb_change_window_attributes(xcbConn,
239 m_request->requestor,
240 XCB_CW_EVENT_MASK, mask);
242 xcb_change_property(xcbConn,
243 XCB_PROP_MODE_REPLACE,
244 m_request->requestor,
249 m_flushPropertyOnDelete =
false;
251 }
else if (!m_chunks.isEmpty()) {
258 xcb_timestamp_t timestamp, xcb_window_t parentWindow,
260 :
Transfer(selection, fd, timestamp, parent)
263 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
264 m_window = xcb_generate_id(xcbConn);
265 const uint32_t values[] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE};
266 xcb_create_window(xcbConn,
267 XCB_COPY_FROM_PARENT,
273 XCB_WINDOW_CLASS_INPUT_OUTPUT,
274 XCB_COPY_FROM_PARENT,
278 xcb_convert_selection(xcbConn,
289 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
290 xcb_destroy_window(xcbConn, m_window);
294 m_receiver =
nullptr;
299 if (event->window == m_window) {
300 if (event->state == XCB_PROPERTY_NEW_VALUE && event->atom ==
atoms->
wl_selection) {
310 if (event->requestor != m_window) {
313 if (event->selection !=
atom()) {
316 if (event->property == XCB_ATOM_NONE) {
317 qCWarning(KWIN_XWL) <<
"Incoming X selection conversion failed";
321 qCWarning(KWIN_XWL) <<
"Received targets too late";
338void TransferXtoWl::startTransfer()
340 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
341 auto cookie = xcb_get_property(xcbConn,
345 XCB_GET_PROPERTY_TYPE_ANY,
349 auto *reply = xcb_get_property_reply(xcbConn, cookie,
nullptr);
350 if (reply ==
nullptr) {
351 qCWarning(KWIN_XWL) <<
"Can't get selection property.";
367void TransferXtoWl::getIncrChunk()
377 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
379 auto cookie = xcb_get_property(xcbConn,
383 XCB_GET_PROPERTY_TYPE_ANY,
387 auto *reply = xcb_get_property_reply(xcbConn, cookie,
nullptr);
389 qCWarning(KWIN_XWL) <<
"Can't get selection property.";
394 if (xcb_get_property_value_length(reply) > 0) {
407 if (m_propertyReply) {
408 free(m_propertyReply);
409 m_propertyReply =
nullptr;
416 m_propertyReply = reply;
418 setData(
static_cast<char *
>(xcb_get_property_value(reply)),
419 xcb_get_property_value_length(reply));
425 m_data = QByteArray::fromRawData(value, length);
430 return QByteArray::fromRawData(m_data.data() + m_propertyStart,
431 m_data.size() - m_propertyStart);
436 m_propertyStart += length;
437 if (m_propertyStart == m_data.size()) {
438 Q_ASSERT(m_propertyReply);
439 free(m_propertyReply);
440 m_propertyReply =
nullptr;
444void TransferXtoWl::dataSourceWrite()
446 QByteArray
property = m_receiver->
data();
448 ssize_t len = write(
fd(), property.constData(), property.size());
450 qCWarning(KWIN_XWL) <<
"X11 to Wayland write error on fd:" <<
fd();
456 if (len == property.size()) {
460 xcb_connection_t *xcbConn = kwinApp()->x11Connection();
461 xcb_delete_property(xcbConn,
472 connect(
socketNotifier(), &QSocketNotifier::activated,
this, [
this](
int socket) {
483#include "moc_transfer.cpp"
void transferFromProperty(xcb_get_property_reply_t *reply)
void setData(const char *value, int length)
void partRead(int length)
xcb_timestamp_t timestamp() const
void clearSocketNotifier()
QSocketNotifier * socketNotifier() const
Transfer(xcb_atom_t selection, qint32 fd, xcb_timestamp_t timestamp, QObject *parent=nullptr)
void createSocketNotifier(QSocketNotifier::Type type)
bool handlePropertyNotify(xcb_property_notify_event_t *event) override
TransferWltoX(xcb_atom_t selection, xcb_selection_request_event_t *request, qint32 fd, QObject *parent=nullptr)
~TransferWltoX() override
void startTransferFromSource()
void selectionNotify(xcb_selection_request_event_t *event, bool success)
bool handleSelectionNotify(xcb_selection_notify_event_t *event)
TransferXtoWl(xcb_atom_t selection, xcb_atom_t target, qint32 fd, xcb_timestamp_t timestamp, xcb_window_t parentWindow, QObject *parent=nullptr)
bool handlePropertyNotify(xcb_property_notify_event_t *event) override
~TransferXtoWl() override
KWIN_EXPORT Atoms * atoms