So, spice-gtk has supported file transfers from client to guest for quite a while. But there's a longstanding issue that the user has no feedback about whether the file is actually being transferred, or how long it will take. The only real feedback that a user gets is after the file transfer is completed: the vdagent will generally open a file browser window to reveal the transferred file. So I was poking around a bit with adding a file transfer progress indication to virt-viewer, and I found that the file transfer API in spice-gtk does not make this very easy. The main API involved here is this: void spice_main_file_copy_async(SpiceMainChannel *channel, GFile **sources, GFileCopyFlags flags, GCancellable *cancellable, GFileProgressCallback progress_callback, gpointer progress_callback_data, GAsyncReadyCallback callback, gpointer user_data); At first glance, it looks like this gives us everything we need, but there are a few issues with it. The main ones are: 1. It's possible to pass an array of files to be transferred, but the progress_callback is called for each file separately. But the GFileProgressCallback function signature does not provide any way for the caller to determine which file a given progress_callback() call is associated with. For example, if you tried to transfer 2 different files with sizes 100 and 200, you might get the following: - progress_callback(0, 100, progress_callback_data) - progress_callback(0, 200, progress_callback_data) - progress_callback(50, 100, progress_callback_data) - progress_callback(50, 200, progress_callback_data) - progress_callback(100, 100, progress_callback_data) - progress_callback(100, 200, progress_callback_data) - progress_callback(150, 200, progress_callback_data) - progress_callback(200, 200, progress_callback_data) In this case, you could apply some heuristics to figure out which callback applied to which file by examining the file sizes, but that is not ideal, and is not always going to work. A workaround for this is to sum up total progress internally and pass these values to the progress_callback. In that case, you'd get something more like this: - progress_callback(0, 300, progress_callback_data) - progress_callback(0, 300, progress_callback_data) - progress_callback(50, 300, progress_callback_data) - progress_callback(100, 300, progress_callback_data) - progress_callback(150, 300, progress_callback_data) - progress_callback(200, 300, progress_callback_data) - progress_callback(250, 300, progress_callback_data) - progress_callback(300, 300, progress_callback_data) That seems OK, but see #3 below as to why this isn't really a full solution. 2. spice_main_file_copy_async() looks like a single transaction, so you would expect it to call 'callback' after all files are finished being transferred. But in reality, 'callback' is called once for each file that is being transferred. This makes it difficult for the application to keep track of the status of the entire transaction. It would be much better to make it behave like every other gio-style async API and have a single _async() call paired to a single _finish() call. 3. Even if the spice_main_file_copy_async() API mentioned above did not have any problems, it's difficult for an application to make use of it if they also use the SpiceDisplay widget. This is because the SpiceDisplay widget automatically handles drag-and-drop of files onto the display. When a file is dropped, it immediately starts a file transfer. This means that the application cannot use in its own 'progress_callback' or 'callback' functions in order to monitor and display the file transfer progress. There's currently no way to disable this automatic handling of drag-and-drop on the widget. ========== We could deprecate this API, but I don't want to remove or break public API. So we still need to support transfers created with the current function. I'd like to propose a complementary API: Add a new public object SpiceFileTransferTask with the following characteristics: - it represents the transfer of a single file - it has a "progress" property, which represents the percentage of the file that has been transferred. The application can connect to the "notify::progress" signal to be notified when the progress of a transfer changes. - it has a "finished" signal so that the application can tell when the transfer of that file has completed - it has a "filename" property so that the application can display the filename next to the progress of the transfer if desired - it has a "cancel()" method, so that an application can cancel an individual file transfer[0] In addition to this new object, add a "new-file-transfer" signal to SpiceMainChannel. This signal will be emitted whenever a new file transfer task has been initiated (presumably by the drag-and-drop handler of the SpiceDisplay widget). This should allow us to keep our API stable and still allow applications to monitor and display feedback of file transfers. Objections? Alternate suggestions? Since you managed to read this whole long-winded message, here's a little screencast of a preliminary implementation in spicy using the above approach: http://people.freedesktop.org/~jjongsma/spicy-file-transfer-progress.ogv Thanks, Jonathon _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel