[gvfs] [FTP] make the pull callback emit progress callbacks



commit e3288d2f30f592695f3df30b60f21d37f5a64e8a
Author: Benjamin Otte <otte gnome org>
Date:   Mon Jun 8 21:15:46 2009 +0200

    [FTP] make the pull callback emit progress callbacks
    
    The progress callbacks are throttled to at most once per second to not
    overload dbus for very fast connections. This is implemented somewhat
    ugly using a cancellable that interrupts once per second to ensure
    progress updates are sent.
    If someone knows a saner approach, please tell me (or better: provide a
    patch).
---
 daemon/gvfsbackendftp.c |   87 +++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/daemon/gvfsbackendftp.c b/daemon/gvfsbackendftp.c
index 9a0f08a..63bb7d0 100644
--- a/daemon/gvfsbackendftp.c
+++ b/daemon/gvfsbackendftp.c
@@ -1162,6 +1162,19 @@ out:
   g_vfs_ftp_task_done (&task);
 }
 
+static void
+cancel_timer_cb (GCancellable *orig, GCancellable *to_cancel)
+{
+  g_cancellable_cancel (to_cancel);
+}
+
+static gboolean
+cancel_cancellable (gpointer cancellable)
+{
+  g_cancellable_cancel (cancellable);
+  return FALSE;
+}
+
 static gssize
 ftp_output_stream_splice (GOutputStream *output,
                           GInputStream *input,
@@ -1174,36 +1187,88 @@ ftp_output_stream_splice (GOutputStream *output,
   gssize n_read, n_written;
   gssize bytes_copied;
   char buffer[8192], *p;
-  gboolean res;
+  GCancellable *timer_cancel;
+  gulong cancel_cb_id;
 
   bytes_copied = 0;
+  timer_cancel = NULL;
+
   for (;;) 
     {
-      n_read = g_input_stream_read (input, buffer, sizeof (buffer), cancellable, error);
+      n_read = g_input_stream_read (input, buffer, sizeof (buffer), timer_cancel ? timer_cancel : cancellable, error);
       if (n_read == -1)
-        return -1;
-        
+        {
+          if (g_cancellable_is_cancelled (timer_cancel) &&
+              !g_cancellable_is_cancelled (cancellable))
+            {
+              g_cancellable_disconnect (cancellable, cancel_cb_id);
+              g_object_unref (timer_cancel);
+              timer_cancel = NULL;
+              g_clear_error (error);
+              progress_callback (bytes_copied, total_size, progress_callback_data);
+            }
+          else
+            {
+              bytes_copied = -1;
+              break;
+            }
+        }
       if (n_read == 0)
-        return bytes_copied;
+        break;
 
       p = buffer;
       while (n_read > 0)
         {
-          n_written = g_output_stream_write (output, p, n_read, cancellable, error);
+          n_written = g_output_stream_write (output, p, n_read, timer_cancel ? timer_cancel : cancellable, error);
           if (n_written == -1)
-            return -1;
+            {
+              if (g_cancellable_is_cancelled (timer_cancel) &&
+                  !g_cancellable_is_cancelled (cancellable))
+                {
+                  g_cancellable_disconnect (cancellable, cancel_cb_id);
+                  g_object_unref (timer_cancel);
+                  timer_cancel = NULL;
+                  g_clear_error (error);
+                  progress_callback (bytes_copied + n_written, total_size, progress_callback_data);
+                }
+              else
+                {
+                  bytes_copied = -1;
+                  break;
+                }
+            }
 
           p += n_written;
           n_read -= n_written;
           bytes_copied += n_written;
+          if (progress_callback && timer_cancel == NULL)
+            {
+              timer_cancel = g_cancellable_new ();
+              cancel_cb_id = g_cancellable_connect (cancellable, 
+                                                    G_CALLBACK (cancel_timer_cb),
+                                                    timer_cancel,
+                                                    NULL);
+              g_object_ref (timer_cancel);
+              g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
+                                          1,
+                                          cancel_cancellable,
+                                          timer_cancel,
+                                          g_object_unref);
+            }
         }
     }
-  while (res);
 
-  if (res)
-    return bytes_copied;
+  if (timer_cancel != NULL)
+    {
+      /* no need to remove the timeout, it'll remove itself fine and we
+       * don't get into races that way */
+      g_cancellable_disconnect (cancellable, cancel_cb_id);
+      g_object_unref (timer_cancel);
+    }
+  if (bytes_copied >= 0 && progress_callback)
+    progress_callback (bytes_copied, total_size, progress_callback_data);
 
-  return -1;
+  return bytes_copied;
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]