Transferring expensive data via Drag-and-Drop: The Delayed Transfer protocol for the X Window System [proposal]

Introduction The Delayed Transfer protocol (XDT) builds on top of the XDND protocol to allow clients to transfer data that is large in size or takes time to generate without blocking the X server. In particular, users should be able to initiate XDND transfers while an XDT transfer is ongoing. Current version: 0.0 Last updated: June 5, 2006 Rationale A major failing of the XDND protocol is that only one XDND transfer can be ongoing at any one time. This is because it uses the X selection protocol; if another client takes ownership of XdndSelection while the drag is ongoing, then the requestor's XConvertSelection request will be passed to the wrong window. Most implementors work around this by grabbing the pointer and mouse until XdndFinished is received by the source. This is obviously unsatisfactory: the drag data may take time to prepare (for example, dragging files from an archiving program) or to transfer (sending large files via XDirectSave). Example walk-through Step 0: There is no step 0. Step 1: When sending XdndEnter, XdndDelayedTransfer is set on XdndTypeList and/or in the target list fields; the XdndDelayedTransferTypeList property is set to a list of data types which the client is capable of generating; otherwise, the XdndTypeList is set to those data types which the client is capable of sending immediately. This allows the client to generate and cache data while the drag is ongoing, and update the XdndTypeList appropriately. The XdndDelayedTransferTypeList need not be a superset of the XdndTypeList; it is suggested but not required that the XdndDelayedTransferTypeList only contain data types that have not yet been generated or will take time to transfer. Step 2: When the destination receives XdndPosition, it checks for the XdndDelayedTransfer target and, if present, for the XdndDelayedTransferTypeList property. It uses this in addition to the XdndTypeList to determine whether it will accept the drop. Step 3: If the destination receives XdndDrop and decides to use a delayed transfer, it requests XdndDelayedTransfer from the XdndSelection selection. It then indicates visually that a transfer is ongoing and sends XdndFinished. The source receives XdndFinished and indicates visually that a transfer is ongoing. Now the fun starts... Step 3a: In Step 3, both source and destination record the ongoing XDT transfer in a stack. The timestamp of the XConvertSelection is used thereon to unambiguously identify the transfer to both sides. Step 4: The destination uses SendEvent to send SelectionRequest to the source, specifying the requested data type and a selection of XdndDelayedTransferSelection. The time is set to the identifying timestamp. The property is chosen to avoid collision if more than one XDT transfer is running on the destination. It is suggested that clients use XdndDelayedTransfer0, etc. and toolkits use e.g. GDK_DND_DELAYED_TRANSFER_0, etc. This reduces Atom pollution while avoiding client/toolkit nastiness. Step 5: The source receives SelectionRequest, looking up the timestamp to discover which transfer is being referred to. If the source is unable to fulfil the request it responds with SelectionNotify with a property argument of None. The source then begins to prepare the data for transfer. Step 6: If the destination fails to receive any response from the source for 300 seconds it assumes that the source is dead. It sends XdndDelayedTransferFinished to the source and tears down any associated resources. Step 7: If the data takes more than a trivial amount of time to prepare, and at least every 10 seconds, the source notifies the destination of its progress with XdndDelayedTransferProgress. If preparing the data fails the source sends SelectionNotify with a property argument of None. Step 8: When the data is ready, the source stores the data on the destination and sends SelectionNotify. When the destination receives SelectionNotify it deletes the property. At any point the destination may continue to request data. Step 9: When the destination is finished requesting data, it sends XdndDelayedTransferFinished. Both sides tear down resources and indicate that the transfer is finished.