[Pkg-privacy-commits] [nautilus-wipe] 02/224: First working attempt for asynchronous spawning.

Ulrike Uhlig u-guest at moszumanska.debian.org
Thu Jul 7 19:45:28 UTC 2016


This is an automated email from the git hooks/post-receive script.

u-guest pushed a commit to branch master
in repository nautilus-wipe.

commit 96628bcbf98a839cff540f6afee7c97c9551b65c
Author: Colomban Wendling <ban at herbesfolles.org>
Date:   Sun Sep 27 23:34:45 2009 +0200

    First working attempt for asynchronous spawning.
    
    The subprocess is now spawned asynchronously and watched through a
    timeout function until it finishes. We don't use threads here as
    it seems useless and slightly harder to get properly working without
    any side effect (tried, but never perfectly worked).
    We gain here two important things:
     1. We don't freeze Nautilus anymore;
     2. We have a nice (huh) progress dialog (just pulses right now, but
        could probably be implemented).
---
 nautilus-srm/nautilus-srm.c | 262 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 241 insertions(+), 21 deletions(-)

diff --git a/nautilus-srm/nautilus-srm.c b/nautilus-srm/nautilus-srm.c
index 6fa56a8..c38647a 100644
--- a/nautilus-srm/nautilus-srm.c
+++ b/nautilus-srm/nautilus-srm.c
@@ -31,6 +31,8 @@
 
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
 
 /* if GLib doesn't provide g_dngettext(), wrap it from dngettext() */
 #if (! GLIB_CHECK_VERSION (2, 18, 0) && ! defined (g_dngettext))
@@ -216,8 +218,9 @@ nautilus_srm_register_type (GTypeModule *module)
 
 static void     menu_activate_cb             (NautilusMenuItem  *menu,
                                               NautilusSrm *srm);
-static gboolean do_srm                       (GList    *files,
-                                              GError  **error);
+static gboolean do_srm                       (GList      *files,
+                                              GtkWindow  *parent_window,
+                                              GError    **error);
 
 
 static GList *
@@ -291,7 +294,7 @@ menu_activate_cb (NautilusMenuItem *menu,
   {
     GError *err = NULL;
     
-    if (! do_srm (priv->files, &err)) {
+    if (! do_srm (priv->files, priv->parent_window, &err)) {
       dialog = gtk_message_dialog_new (priv->parent_window, 
                                        GTK_DIALOG_MODAL,
                                        GTK_MESSAGE_ERROR,
@@ -311,9 +314,213 @@ menu_activate_cb (NautilusMenuItem *menu,
   g_free (files_names_str);
 }
 
+
+typedef struct _ProgressDialog {
+  GtkWindow      *window;
+  GtkProgressBar *progress_bar;
+} ProgressDialog;
+
+static ProgressDialog *
+build_progress_dialog (const gchar *title,
+                       GtkWindow   *parent,
+                       const gchar *format,
+                       ...)
+{
+  ProgressDialog *dialog;
+  va_list         ap;
+  gchar          *text;
+  GtkWidget      *label;
+  GtkWidget      *box;
+  
+  dialog = g_new0 (ProgressDialog, 1);
+  dialog->window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
+  gtk_window_set_title (dialog->window, title);
+  gtk_window_set_deletable (dialog->window, FALSE);
+  gtk_window_set_transient_for (dialog->window, parent);
+  gtk_window_set_position (dialog->window, GTK_WIN_POS_CENTER_ON_PARENT);
+  gtk_window_set_skip_pager_hint (dialog->window, TRUE);
+  gtk_window_set_skip_taskbar_hint (dialog->window, TRUE);
+  gtk_container_set_border_width (GTK_CONTAINER (dialog->window), 10);
+  
+  dialog->progress_bar = GTK_PROGRESS_BAR (gtk_progress_bar_new ());
+  gtk_progress_bar_set_pulse_step (dialog->progress_bar, 0.1);
+  
+  va_start (ap, format);
+  text = g_strdup_vprintf (format, ap);
+  va_end (ap);
+  label = gtk_label_new (text);
+  g_free (text);
+  
+  box = gtk_vbox_new (FALSE, 10);
+  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (dialog->progress_bar), FALSE, FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (dialog->window), box);
+  
+  gtk_widget_show_all (box);
+  
+  return dialog;
+}
+
+static void
+destroy_progress_dialog (ProgressDialog *dialog)
+{
+  gtk_widget_destroy (GTK_WIDGET (dialog->window));
+  g_free (dialog);
+}
+
+
+/* readstrdup:
+ * 
+ * @fd: a file descriptor
+ * @n_bytes: number of bytes to read from @fd, or -1 to read all @fd
+ * 
+ * Reads content of a file as a C string (0-terminated).
+ * 
+ * Returns: a newly allocated string containing data in @fd that should be freed
+ *          when no longer needed using g_free().
+ */
+static gchar *
+readstrdup (int     fd,
+            gssize  n_bytes)
+{
+  gchar *buf = NULL;
+  
+  if (n_bytes > 0) {
+    gssize n_read;
+    
+    buf = g_malloc (n_bytes + 1);
+    n_read = read (fd, buf, n_bytes);
+    if (n_read < 0) {
+      g_free (buf), buf = NULL;
+    } else {
+      buf[n_read] = 0;
+    }
+  } else {
+    static const gsize packet_size = 64;
+    gsize              n_read = 0;
+    gssize read_rv;
+    
+    n_bytes = 0;
+    do {
+      buf = g_realloc (buf, n_bytes + packet_size + 1);
+      
+      read_rv = read (fd, &buf[n_bytes], packet_size);
+      if (read_rv >= 0) {
+        n_read += read_rv;
+      }
+      
+      n_bytes += packet_size;
+    } while (n_bytes > 0 /* don't underflow */ &&
+             read_rv >= 0 &&
+             read_rv == packet_size);
+    
+    if (read_rv < 0) {
+      g_free (buf), buf = NULL;
+    } else {
+      buf[n_read] = 0;
+    }
+  }
+  
+  return buf;
+}
+
+typedef struct _SrmChildInfo {
+  gchar **argv; /* just to be able to free it */
+  gint    fd_out;
+  gint    fd_err;
+  GPid    pid;
+  
+  ProgressDialog *progress_dialog;
+  GtkWindow *parent_window;
+} SrmChildInfo;
+
+static void
+dump_srm_child_info (SrmChildInfo *info)
+{
+  printf ("=== SrmChildInfo dump ===\n"
+          "info.argv   = %p\n"
+          "info.fd_out = %d\n"
+          "info.fd_err = %d\n"
+          "info.pid    = %d\n"
+          "info.parent_window = %p\n"
+          "======= dump  end =======\n",
+          info->argv, info->fd_out, info->fd_err, info->pid, info->parent_window);
+}
+
+/* waits for the child process to finish and display a dialog on error
+ * It also display a progress dialog for the user to know something is
+ * happening.
+ * 
+ * This function is designed to be used as a GSourceFunc function. */
+static gboolean
+wait_srm_child (gpointer data)
+{
+  SrmChildInfo *child_info = data;
+  gboolean finished = FALSE;
+  gboolean success  = FALSE;
+  int      exit_status;
+  pid_t    wait_rv;
+  
+  wait_rv = waitpid (child_info->pid, &exit_status, WNOHANG);
+  if (G_UNLIKELY (wait_rv < 0)) {
+    g_warning ("waitpid() failed: %s", g_strerror (errno));
+    /* if we cannot watch the child, try to kill it */
+    if (kill (child_info->pid, 15) < 0) {
+      g_warning ("kill() failed: %s", g_strerror (errno));
+    } else {
+      g_message ("Subprocess killed.");
+    }
+  } else if (G_LIKELY (wait_rv == 0)) {
+    /* nothing to do, just wait until next call */
+    gtk_progress_bar_pulse (child_info->progress_dialog->progress_bar);
+  } else {
+    finished = TRUE;
+    if (WIFEXITED (exit_status) && WEXITSTATUS (exit_status) == 0) {
+      success = TRUE;
+      g_message ("Subprocess succeed.");
+    } else {
+      g_message ("Subprocess failed.");
+    }
+  }
+  
+  if (G_UNLIKELY (finished)) {
+    destroy_progress_dialog (child_info->progress_dialog);
+    
+    if (! success) {
+      GtkWidget *dialog;
+      gchar     *error_output = NULL;
+      
+      error_output = readstrdup (child_info->fd_err, -1);
+      
+      dialog = gtk_message_dialog_new (child_info->parent_window, 
+                                       GTK_DIALOG_MODAL,
+                                       GTK_MESSAGE_ERROR,
+                                       GTK_BUTTONS_CLOSE,
+                                       _("Suppression failed"));
+      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                "%s", error_output);
+      gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+      
+      g_free (error_output);
+    }
+    
+    /* cleanup */
+    g_spawn_close_pid (child_info->pid);
+    close (child_info->fd_err);
+    close (child_info->fd_out);
+    g_strfreev (child_info->argv);
+    g_object_unref (child_info->parent_window);
+    g_free (child_info);
+  }
+  
+  return ! finished;
+}
+
 static gboolean
-do_srm (GList    *files,
-        GError  **error)
+do_srm (GList      *files,
+        GtkWindow  *parent_window,
+        GError    **error)
 {
   GList    *file;
   gchar   **argv;
@@ -350,35 +557,48 @@ do_srm (GList    *files,
   argv[i] = NULL;
   
   if (success) {
-    gint exit_status;
-    gchar *error_output;
     GError *err = NULL;
+    SrmChildInfo *child_info;
+    
+    child_info = g_new0 (SrmChildInfo, 1);
+    child_info->argv = argv; /* we let the child free its args as the GLib
+                              * doesn't seems to manage or free it */
+    child_info->fd_out = -1;
+    child_info->fd_err = -1;
+    child_info->parent_window = g_object_ref (parent_window);
     
-    if (! g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
-                        NULL, NULL,
-                        NULL, &error_output,
-                        &exit_status,
-                        &err)) {
+    if (! g_spawn_async_with_pipes (NULL, argv, NULL,
+                                    G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+                                    NULL, NULL,
+                                    &child_info->pid,
+                                    NULL,
+                                    &child_info->fd_out, &child_info->fd_err,
+                                    &err)) {
       g_set_error (error, NAUTILUS_SRM_ERROR, NAUTILUS_SRM_ERROR_SPAWN_FAILED,
                    _("Failed to spawn subprocess: %s"),
                    err->message);
       g_error_free (err);
       success = FALSE;
     } else {
-      if (! WIFEXITED (exit_status) || WEXITSTATUS (exit_status) != 0) {
-        g_set_error (error, NAUTILUS_SRM_ERROR, NAUTILUS_SRM_ERROR_CHILD_FAILED,
-                     _("Suppression failed: %s"),
-                     error_output);
-        success = FALSE;
-      }
-      g_free (error_output);
+      g_message ("Suppressing...");
+      
+      child_info->progress_dialog = build_progress_dialog (_("Progress"), parent_window, _("Removing files..."));
+      gtk_widget_show (GTK_WIDGET (child_info->progress_dialog->window));
+      /* add timeout function */
+      g_timeout_add (100, wait_srm_child, child_info);
+    }
+    
+    if (! success) {
+      g_free (child_info);
     }
   }
   
-  for (i = 0; argv[i] != NULL; i++) {
-    g_free (argv[i]);
+  if (! success) {
+    g_strfreev (argv);
   }
   
+  g_message ("end of caller");
+  
   return success;
 }
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/nautilus-wipe.git



More information about the Pkg-privacy-commits mailing list