summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZynix <89567766+alper-han@users.noreply.github.com>2026-01-30 17:14:17 +0300
committerGitHub <noreply@github.com>2026-01-30 14:14:17 +0000
commitb8fc0def97a5b6279b8d0e8e13972575a84c310a (patch)
tree109ce9ab66e8a4efd4905e04006ab57555ef0180
parentc92fb5e85f4a5fd3a0f5ffb5892f6a61cfe1be2b (diff)
xwayland/xwm: handle INCR clipboard transfer chunks correctly (#13125)
Handle XCB_PROPERTY_NEW_VALUE events for incremental selection transfers. Previously only DELETE was handled, causing INCR transfers to fail after the first chunk.
-rw-r--r--src/xwayland/XWM.cpp35
1 files changed, 28 insertions, 7 deletions
diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp
index 5c3d49da..8f306cb9 100644
--- a/src/xwayland/XWM.cpp
+++ b/src/xwayland/XWM.cpp
@@ -33,6 +33,8 @@ static int onX11Event(int fd, uint32_t mask, void* data) {
return g_pXWayland->m_wm->onEvent(fd, mask);
}
+static int writeDataSource(int fd, uint32_t mask, void* data);
+
struct SFreeDeleter {
void operator()(void* ptr) const {
std::free(ptr); // NOLINT(cppcoreguidelines-no-malloc)
@@ -648,19 +650,33 @@ void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) {
}
bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) {
- if (e->state != XCB_PROPERTY_DELETE)
- return false;
-
for (auto* sel : {&m_clipboard, &m_primarySelection, &m_dndSelection}) {
auto it = std::ranges::find_if(sel->transfers, [e](const auto& t) { return t->incomingWindow == e->window; });
- if (it != sel->transfers.end()) {
- if (!(*it)->getIncomingSelectionProp(true)) {
+ if (it == sel->transfers.end())
+ continue;
+
+ auto& transfer = *it;
+
+ if (e->state == XCB_PROPERTY_NEW_VALUE) {
+ if (!transfer->incremental) {
+ getTransferData(*sel);
+ return true;
+ }
+
+ if (!transfer->getIncomingSelectionProp(true) || xcb_get_property_value_length(transfer->propertyReply) == 0) {
sel->transfers.erase(it);
- return false;
+ return true;
+ }
+
+ int result = sel->onWrite();
+
+ if (result == 1 && !transfer->eventSource) {
+ transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_wlEventLoop, transfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, sel);
}
+ } else if (e->state == XCB_PROPERTY_DELETE) {
getTransferData(*sel);
- return true;
}
+ return true;
}
return false;
@@ -1620,6 +1636,11 @@ int SXSelection::onWrite() {
free(transfer->propertyReply); // NOLINT(cppcoreguidelines-no-malloc)
transfer->propertyReply = nullptr;
transfer->propertyStart = 0;
+ if (transfer->eventSource) {
+ wl_event_source_remove(transfer->eventSource);
+ transfer->eventSource = nullptr;
+ }
+ return 0;
}
}