[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