From fda5626594c3f31bbab08e877a797a623c98c450 Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Wed, 22 Jan 2025 22:27:46 +0800 Subject: [PATCH] xwayland: fix sending large clipboard data (#9134) --- src/xwayland/XWM.cpp | 55 +++++++++++++++++++++++++++----------------- src/xwayland/XWM.hpp | 1 + 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 3486b286..71a7c44c 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1168,6 +1168,11 @@ void CXWM::setClipboardToWayland(SXSelection& sel) { g_pSeatManager->setCurrentSelection(sel.dataSource); } +static int writeDataSource(int fd, uint32_t mask, void* data) { + auto selection = (SXSelection*)data; + return selection->onWrite(); +} + void CXWM::getTransferData(SXSelection& sel) { Debug::log(LOG, "[xwm] getTransferData"); @@ -1179,26 +1184,9 @@ void CXWM::getTransferData(SXSelection& sel) { sel.transfer.reset(); return; } else { - char* property = (char*)xcb_get_property_value(sel.transfer->propertyReply); - int remainder = xcb_get_property_value_length(sel.transfer->propertyReply) - sel.transfer->propertyStart; - - ssize_t len = write(sel.transfer->wlFD, property + sel.transfer->propertyStart, remainder); - if (len == -1) { - Debug::log(ERR, "[xwm] write died in transfer get"); - close(sel.transfer->wlFD); - sel.transfer.reset(); - return; - } - - if (len < remainder) { - sel.transfer->propertyStart += len; - Debug::log(ERR, "[xwm] wl client read partially: len {}", len); - return; - } else { - Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - close(sel.transfer->wlFD); - sel.transfer.reset(); - } + sel.onWrite(); + if (sel.transfer) + sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD, WL_EVENT_WRITABLE, ::writeDataSource, &sel); } } @@ -1370,7 +1358,8 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { fcntl(p[0], F_SETFD, FD_CLOEXEC); fcntl(p[0], F_SETFL, O_NONBLOCK); fcntl(p[1], F_SETFD, FD_CLOEXEC); - fcntl(p[1], F_SETFL, O_NONBLOCK); + // the wayland client might not expect a non-blocking fd + // fcntl(p[1], F_SETFL, O_NONBLOCK); transfer->wlFD = p[0]; @@ -1383,6 +1372,30 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { return true; } +int SXSelection::onWrite() { + char* property = (char*)xcb_get_property_value(transfer->propertyReply); + int remainder = xcb_get_property_value_length(transfer->propertyReply) - transfer->propertyStart; + + ssize_t len = write(transfer->wlFD, property + transfer->propertyStart, remainder); + if (len == -1) { + Debug::log(ERR, "[xwm] write died in transfer get"); + close(transfer->wlFD); + transfer.reset(); + return 0; + } + + if (len < remainder) { + transfer->propertyStart += len; + Debug::log(LOG, "[xwm] wl client read partially: len {}", len); + } else { + Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); + close(transfer->wlFD); + transfer.reset(); + } + + return 1; +} + SXTransfer::~SXTransfer() { if (wlFD) close(wlFD); diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 0455c761..02ade80d 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -50,6 +50,7 @@ struct SXSelection { void onKeyboardFocus(); bool sendData(xcb_selection_request_event_t* e, std::string mime); int onRead(int fd, uint32_t mask); + int onWrite(); struct { CHyprSignalListener setSelection;