Skip to content

Wayland backend: add host-to-client clipboard sync #1797

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions src/Backends/WaylandBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,13 @@ namespace gamescope
void Wayland_DataSource_Send( struct wl_data_source *pSource, const char *pMime, int nFd );
void Wayland_DataSource_Cancelled( struct wl_data_source *pSource );
static const wl_data_source_listener s_DataSourceListener;

void Wayland_DataDevice_DataOffer( struct wl_data_device *pDevice, struct wl_data_offer *pOffer );
void Wayland_DataDevice_Selection( wl_data_device *pDataDevice, wl_data_offer *pOffer );
static const wl_data_device_listener s_DataDeviceListener;

void Wayland_DataOffer_Offer( struct wl_data_offer *pOffer, const char *pMime );
static const struct wl_data_offer_listener s_DataOfferListener;

void Wayland_PrimarySelectionSource_Send( struct zwp_primary_selection_source_v1 *pSource, const char *pMime, int nFd );
void Wayland_PrimarySelectionSource_Cancelled( struct zwp_primary_selection_source_v1 *pSource );
Expand Down Expand Up @@ -823,6 +830,13 @@ namespace gamescope
.send = WAYLAND_USERDATA_TO_THIS( CWaylandBackend, Wayland_PrimarySelectionSource_Send ),
.cancelled = WAYLAND_USERDATA_TO_THIS( CWaylandBackend, Wayland_PrimarySelectionSource_Cancelled ),
};
const wl_data_device_listener CWaylandBackend::s_DataDeviceListener = {
.data_offer = WAYLAND_USERDATA_TO_THIS( CWaylandBackend, Wayland_DataDevice_DataOffer ),
.selection = WAYLAND_USERDATA_TO_THIS( CWaylandBackend, Wayland_DataDevice_Selection ),
};
const wl_data_offer_listener CWaylandBackend::s_DataOfferListener = {
.offer = WAYLAND_USERDATA_TO_THIS( CWaylandBackend, Wayland_DataOffer_Offer ),
};

//////////////////
// CWaylandFb
Expand Down Expand Up @@ -1859,6 +1873,16 @@ namespace gamescope
xdg_log.errorf( "Failed to initialize input thread" );
return false;
}

// Set up the data device listener
if (m_pDataDeviceManager && !m_pDataDevice) {
m_pDataDevice = wl_data_device_manager_get_data_device(m_pDataDeviceManager, m_pSeat);
if (!m_pDataDevice) {
xdg_log.errorf("Failed to get wl_data_device");
return false;
}
wl_data_device_add_listener(m_pDataDevice, &s_DataDeviceListener, this);
}

return true;
}
Expand Down Expand Up @@ -2497,6 +2521,54 @@ namespace gamescope
zwp_primary_selection_source_v1_destroy( pSource );
}

// Data Device

void CWaylandBackend::Wayland_DataDevice_Selection(wl_data_device *pDataDevice, wl_data_offer *pOffer) {
// An application has set the clipboard contents
if (pOffer == nullptr) {
// Clipboard is empty
m_pClipboard = nullptr;
gamescope_set_selection(std::string{}, GAMESCOPE_SELECTION_CLIPBOARD);
return;
}

int fds[2];
if (pipe(fds) < 0) {
xdg_log.errorf("Failed to create pipe for clipboard data");
return;
}

wl_data_offer_receive(pOffer, "text/plain", fds[1]);
close(fds[1]);

wl_display_roundtrip(m_pDisplay);

// Read the clipboard contents and store it in a member variable.
std::string clipboardData;
char buf[1024];
ssize_t n;
while ((n = read(fds[0], buf, sizeof(buf))) > 0) {
clipboardData.append(buf, n);
}
close(fds[0]);

m_pClipboard = std::make_shared<std::string>(clipboardData);

char *pClipBoard = m_pClipboard->data();
gamescope_set_selection( pClipBoard, GAMESCOPE_SELECTION_CLIPBOARD);

wl_data_offer_destroy(pOffer);
}
void CWaylandBackend::Wayland_DataDevice_DataOffer(struct wl_data_device *pDevice, struct wl_data_offer *pOffer) {
wl_data_offer_add_listener(pOffer, &s_DataOfferListener, nullptr);
}

// Data Offer
void CWaylandBackend::Wayland_DataOffer_Offer(struct wl_data_offer* pOffer, const char* pMime)
{
xdg_log.debugf("Clipboard supports MIME type: %s", pMime);
}

///////////////////////
// CWaylandInputThread
///////////////////////
Expand Down