summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authornyx <nnyyxxxx@protonmail.com>2025-04-08 11:36:29 -0400
committerGitHub <noreply@github.com>2025-04-08 17:36:29 +0200
commit642f394eb3f8fd99a51f4c8279497c458c40ba65 (patch)
tree7894f0983e672370eaa5b8da84805b6bd0dce963 /src
parentb15c2bfff6941bd2072eade13177433d7ab58a00 (diff)
xwayland: sync primary selection with wayland (#9952)
Diffstat (limited to 'src')
-rw-r--r--src/xwayland/XDataSource.cpp8
-rw-r--r--src/xwayland/XWM.cpp71
-rw-r--r--src/xwayland/XWM.hpp1
3 files changed, 62 insertions, 18 deletions
diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp
index 003f6c9f..14656d8b 100644
--- a/src/xwayland/XDataSource.cpp
+++ b/src/xwayland/XDataSource.cpp
@@ -77,7 +77,13 @@ void CXDataSource::send(const std::string& mime, CFileDescriptor fd) {
xcb_create_window(g_pXWayland->pWM->connection, XCB_COPY_FROM_PARENT, transfer->incomingWindow, g_pXWayland->pWM->screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
g_pXWayland->pWM->screen->root_visual, XCB_CW_EVENT_MASK, &MASK);
- xcb_convert_selection(g_pXWayland->pWM->connection, transfer->incomingWindow, HYPRATOMS["CLIPBOARD"], mimeAtom, HYPRATOMS["_WL_SELECTION"], XCB_TIME_CURRENT_TIME);
+ xcb_atom_t selection_atom = HYPRATOMS["CLIPBOARD"];
+ if (&selection == &g_pXWayland->pWM->primarySelection)
+ selection_atom = HYPRATOMS["PRIMARY"];
+ else if (&selection == &g_pXWayland->pWM->dndSelection)
+ selection_atom = HYPRATOMS["XdndSelection"];
+
+ xcb_convert_selection(g_pXWayland->pWM->connection, transfer->incomingWindow, selection_atom, mimeAtom, HYPRATOMS["_WL_SELECTION"], XCB_TIME_CURRENT_TIME);
xcb_flush(g_pXWayland->pWM->connection);
diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp
index efb080d6..6439c491 100644
--- a/src/xwayland/XWM.cpp
+++ b/src/xwayland/XWM.cpp
@@ -586,7 +586,7 @@ void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) {
Debug::log(TRACE, "[xwm] converting selection failed");
sel->transfers.erase(it);
}
- } else if (e->target == HYPRATOMS["TARGETS"] && sel == &clipboard) {
+ } else if (e->target == HYPRATOMS["TARGETS"]) {
if (!focusedSurface) {
Debug::log(TRACE, "[xwm] denying access to write to clipboard because no X client is in focus");
return;
@@ -601,14 +601,16 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) {
if (e->state != XCB_PROPERTY_DELETE)
return false;
- auto it = std::ranges::find_if(clipboard.transfers, [e](const auto& t) { return t->incomingWindow == e->window; });
- if (it != clipboard.transfers.end()) {
- if (!(*it)->getIncomingSelectionProp(true)) {
- clipboard.transfers.erase(it);
- return false;
+ for (auto* sel : {&clipboard, &primarySelection}) {
+ 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)) {
+ sel->transfers.erase(it);
+ return false;
+ }
+ getTransferData(*sel);
+ return true;
}
- getTransferData(clipboard);
- return true;
}
return false;
@@ -617,6 +619,8 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) {
SXSelection* CXWM::getSelection(xcb_atom_t atom) {
if (atom == HYPRATOMS["CLIPBOARD"])
return &clipboard;
+ else if (atom == HYPRATOMS["PRIMARY"])
+ return &primarySelection;
else if (atom == HYPRATOMS["XdndSelection"])
return &dndSelection;
@@ -707,8 +711,12 @@ bool CXWM::handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e) {
return true;
if (e->owner == XCB_WINDOW_NONE) {
- if (sel->owner != sel->window && sel == &clipboard)
- g_pSeatManager->setCurrentSelection(nullptr);
+ if (sel->owner != sel->window) {
+ if (sel == &clipboard)
+ g_pSeatManager->setCurrentSelection(nullptr);
+ else if (sel == &primarySelection)
+ g_pSeatManager->setCurrentPrimarySelection(nullptr);
+ }
sel->owner = 0;
return true;
@@ -721,7 +729,10 @@ bool CXWM::handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e) {
return true;
}
- xcb_convert_selection(connection, sel->window, HYPRATOMS["CLIPBOARD"], HYPRATOMS["TARGETS"], HYPRATOMS["_WL_SELECTION"], e->timestamp);
+ if (sel == &clipboard)
+ xcb_convert_selection(connection, sel->window, HYPRATOMS["CLIPBOARD"], HYPRATOMS["TARGETS"], HYPRATOMS["_WL_SELECTION"], e->timestamp);
+ else if (sel == &primarySelection)
+ xcb_convert_selection(connection, sel->window, HYPRATOMS["PRIMARY"], HYPRATOMS["TARGETS"], HYPRATOMS["_WL_SELECTION"], e->timestamp);
xcb_flush(connection);
return true;
@@ -1171,6 +1182,16 @@ void CXWM::initSelection() {
clipboard.listeners.setSelection = g_pSeatManager->events.setSelection.registerListener([this](std::any d) { clipboard.onSelection(); });
clipboard.listeners.keyboardFocusChange = g_pSeatManager->events.keyboardFocusChange.registerListener([this](std::any d) { clipboard.onKeyboardFocus(); });
+ primarySelection.window = xcb_generate_id(connection);
+ xcb_create_window(connection, XCB_COPY_FROM_PARENT, primarySelection.window, screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual,
+ XCB_CW_EVENT_MASK, mask);
+ xcb_set_selection_owner(connection, primarySelection.window, HYPRATOMS["PRIMARY"], XCB_TIME_CURRENT_TIME);
+
+ xcb_xfixes_select_selection_input(connection, primarySelection.window, HYPRATOMS["PRIMARY"], mask2);
+
+ primarySelection.listeners.setSelection = g_pSeatManager->events.setPrimarySelection.registerListener([this](std::any d) { primarySelection.onSelection(); });
+ primarySelection.listeners.keyboardFocusChange = g_pSeatManager->events.keyboardFocusChange.registerListener([this](std::any d) { primarySelection.onKeyboardFocus(); });
+
dndSelection.window = xcb_generate_id(connection);
xcb_create_window(connection, XCB_COPY_FROM_PARENT, dndSelection.window, screen->root, 0, 0, 8192, 8192, 0, XCB_WINDOW_CLASS_INPUT_ONLY, screen->root_visual, XCB_CW_EVENT_MASK,
mask);
@@ -1182,14 +1203,18 @@ void CXWM::initSelection() {
void CXWM::setClipboardToWayland(SXSelection& sel) {
auto source = makeShared<CXDataSource>(sel);
if (source->mimes().empty()) {
- Debug::log(ERR, "[xwm] can't set clipboard: no MIMEs");
+ Debug::log(ERR, "[xwm] can't set selection: no MIMEs");
return;
}
sel.dataSource = source;
- Debug::log(LOG, "[xwm] X clipboard at {:x} takes clipboard", (uintptr_t)sel.dataSource.get());
- g_pSeatManager->setCurrentSelection(sel.dataSource);
+ Debug::log(LOG, "[xwm] X selection at {:x} takes {}", (uintptr_t)sel.dataSource.get(), (&sel == &clipboard) ? "clipboard" : "primary selection");
+
+ if (&sel == &clipboard)
+ g_pSeatManager->setCurrentSelection(sel.dataSource);
+ else if (&sel == &primarySelection)
+ g_pSeatManager->setCurrentPrimarySelection(sel.dataSource);
}
static int writeDataSource(int fd, uint32_t mask, void* data) {
@@ -1305,22 +1330,32 @@ SP<IDataOffer> CXWM::createX11DataOffer(SP<CWLSurfaceResource> surf, SP<IDataSou
}
void SXSelection::onSelection() {
- if (g_pSeatManager->selection.currentSelection && g_pSeatManager->selection.currentSelection->type() == DATA_SOURCE_TYPE_X11)
+ if ((this == &g_pXWayland->pWM->clipboard && g_pSeatManager->selection.currentSelection && g_pSeatManager->selection.currentSelection->type() == DATA_SOURCE_TYPE_X11) ||
+ (this == &g_pXWayland->pWM->primarySelection && g_pSeatManager->selection.currentPrimarySelection &&
+ g_pSeatManager->selection.currentPrimarySelection->type() == DATA_SOURCE_TYPE_X11))
return;
- if (g_pSeatManager->selection.currentSelection) {
+ if (this == &g_pXWayland->pWM->clipboard && g_pSeatManager->selection.currentSelection) {
xcb_set_selection_owner(g_pXWayland->pWM->connection, g_pXWayland->pWM->clipboard.window, HYPRATOMS["CLIPBOARD"], XCB_TIME_CURRENT_TIME);
xcb_flush(g_pXWayland->pWM->connection);
g_pXWayland->pWM->clipboard.notifyOnFocus = true;
+ } else if (this == &g_pXWayland->pWM->primarySelection && g_pSeatManager->selection.currentPrimarySelection) {
+ xcb_set_selection_owner(g_pXWayland->pWM->connection, g_pXWayland->pWM->primarySelection.window, HYPRATOMS["PRIMARY"], XCB_TIME_CURRENT_TIME);
+ xcb_flush(g_pXWayland->pWM->connection);
+ g_pXWayland->pWM->primarySelection.notifyOnFocus = true;
}
}
void SXSelection::onKeyboardFocus() {
if (!g_pSeatManager->state.keyboardFocusResource || g_pSeatManager->state.keyboardFocusResource->client() != g_pXWayland->pServer->xwaylandClient)
return;
- if (g_pXWayland->pWM->clipboard.notifyOnFocus) {
+
+ if (this == &g_pXWayland->pWM->clipboard && g_pXWayland->pWM->clipboard.notifyOnFocus) {
onSelection();
g_pXWayland->pWM->clipboard.notifyOnFocus = false;
+ } else if (this == &g_pXWayland->pWM->primarySelection && g_pXWayland->pWM->primarySelection.notifyOnFocus) {
+ onSelection();
+ g_pXWayland->pWM->primarySelection.notifyOnFocus = false;
}
}
@@ -1370,6 +1405,8 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) {
WP<IDataSource> selection;
if (this == &g_pXWayland->pWM->clipboard)
selection = g_pSeatManager->selection.currentSelection;
+ else if (this == &g_pXWayland->pWM->primarySelection)
+ selection = g_pSeatManager->selection.currentPrimarySelection;
else if (!g_pXWayland->pWM->dndDataOffers.empty())
selection = g_pXWayland->pWM->dndDataOffers.at(0)->getSource();
diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp
index efd2f85a..25010b0b 100644
--- a/src/xwayland/XWM.hpp
+++ b/src/xwayland/XWM.hpp
@@ -201,6 +201,7 @@ class CXWM {
uint64_t lastFocusSeq = 0;
SXSelection clipboard;
+ SXSelection primarySelection;
SXSelection dndSelection;
SP<CX11DataDevice> dndDataDevice = makeShared<CX11DataDevice>();
std::vector<SP<CX11DataOffer>> dndDataOffers;