d324ed3634
The compositor previously declared wl_data_offer opcode constants
in protocol.rs (lines 175-182) and OBJECT_TYPE_WL_DATA_OFFER
(line 272) but had no dispatch arm in main.rs and no handler
function in handlers.rs. Copy-paste between Wayland clients and
drag-and-drop could not work because no data_offer objects were
ever created and no data was ever transferred.
This commit implements the full clipboard/drag data transfer
path:
* WL_DATA_DEVICE_SET_SELECTION: when a client sets a selection
with a non-null source_id, the compositor:
1. Allocates a new wl_data_offer object id
2. Looks up the source's mime types and action flags
3. Records the source client's data buffer (the bytes to
transfer, captured when the source called wl_data_source.offer)
4. Stores the new offer in client.data_offers
5. Sends wl_data_offer.offer events for each mime type
6. Sends wl_data_offer.source_actions (if actions were set)
7. Sends wl_data_device.data_offer (linking offer to device)
8. Sends wl_data_device.selection (informing device of new
current selection)
* WL_DATA_OFFER_ACCEPT: records the accepted mime type
in the offer state. Used by WL_DATA_OFFER_RECEIVE to verify
the client is requesting a mime that was offered and accepted.
* WL_DATA_OFFER_RECEIVE: the data transfer event. Looks up
the source buffer and sends it to the requesting client via:
1. Create a pipe(2) on the compositor side
2. Write the source bytes into the write end (so client can
read from the read end via fd-passing)
3. Close the write end (EOF after read)
4. Send the read fd via SCM_RIGHTS ancillary data on the
wl_data_offer.receive event message
5. Client reads the data from the received fd
This implements the canonical Wayland data transfer protocol
with no special kernel support needed beyond pipe(2) and
SCM_RIGHTS.
* WL_DATA_OFFER_FINISH: marks the offer as finished (clipboard
confirmed by destination).
* WL_DATA_OFFER_DESTROY: removes the offer from the client
state and sends the delete_id event.
Also adds:
* use protocol::* in main.rs so the opcode constants are in scope
for the dispatch table
* new fields on DataSourceState (buffer: Option<Vec<u8>>) to
capture the source data when offer() is called, plus the
source_buffer transfer plumbing
* new field on DataDeviceState (selection_offer: Option<u32>) to
track the current selection offer
* new helper write_event_with_fds for events that need to
send ancillary data (the receive fd)
* new helper send_with_rights_fds (fd-only variant of
send_with_rights) for the same purpose
* new helper open_pipe_for_payload that creates a pipe, writes
the buffer to it, closes the write end, and returns the read fd
cargo check passes on the standalone compositor binary (only
pre-existing warnings). The actual roundtrip through a Wayland
client (e.g. wl-copy or a Qt6 clipboard app) requires a
canonical build + QEMU run.