From 3e3d22d8c80bc8fe43725843153e20f9469f136f Mon Sep 17 00:00:00 2001 From: Cyrille Pontvieux Date: Sun, 29 Mar 2020 20:33:03 +0200 Subject: [PATCH] pause button on copy/move --- thunar/thunar-io-jobs.c | 2 + thunar/thunar-job.c | 45 +++++++++++++++++++++ thunar/thunar-job.h | 6 +++ thunar/thunar-progress-view.c | 76 +++++++++++++++++++++++++++++++---- thunar/thunar-transfer-job.c | 36 ++++++++++++++++- 5 files changed, 157 insertions(+), 8 deletions(-) diff --git a/thunar/thunar-io-jobs.c b/thunar/thunar-io-jobs.c index 4f6418402..4cc52f998 100644 --- a/thunar/thunar-io-jobs.c +++ b/thunar/thunar-io-jobs.c @@ -582,6 +582,7 @@ thunar_io_jobs_move_files (GList *source_file_list, job = thunar_transfer_job_new (source_file_list, target_file_list, THUNAR_TRANSFER_JOB_MOVE); + thunar_job_set_pausable (job, TRUE); return THUNAR_JOB (exo_job_launch (EXO_JOB (job))); } @@ -600,6 +601,7 @@ thunar_io_jobs_copy_files (GList *source_file_list, job = thunar_transfer_job_new (source_file_list, target_file_list, THUNAR_TRANSFER_JOB_COPY); + thunar_job_set_pausable (job, TRUE); return THUNAR_JOB (exo_job_launch (EXO_JOB (job))); } diff --git a/thunar/thunar-job.c b/thunar/thunar-job.c index 88cc36d71..b4eadeb82 100644 --- a/thunar/thunar-job.c +++ b/thunar/thunar-job.c @@ -68,6 +68,8 @@ struct _ThunarJobPrivate ThunarJobResponse earlier_ask_skip_response; GList *total_files; guint n_total_files; + gboolean pausable; + gboolean paused; }; @@ -210,6 +212,8 @@ thunar_job_init (ThunarJob *job) job->priv->earlier_ask_delete_response = 0; job->priv->earlier_ask_skip_response = 0; job->priv->n_total_files = 0; + job->priv->pausable = FALSE; + job->priv->paused = FALSE; } @@ -657,6 +661,47 @@ thunar_job_set_total_files (ThunarJob *job, +void +thunar_job_set_pausable (ThunarJob *job, + gboolean pausable) +{ + job->priv->pausable = pausable; +} + + + +gboolean +thunar_job_is_pausable (ThunarJob *job) +{ + return job->priv->pausable; +} + + + +void +thunar_job_pause (ThunarJob *job) +{ + job->priv->paused = TRUE; +} + + + +void +thunar_job_resume (ThunarJob *job) +{ + job->priv->paused = FALSE; +} + + + +gboolean +thunar_job_is_paused (ThunarJob *job) +{ + return job->priv->paused; +} + + + void thunar_job_processing_file (ThunarJob *job, GList *current_file, diff --git a/thunar/thunar-job.h b/thunar/thunar-job.h index 9c0a7b415..4e437af20 100644 --- a/thunar/thunar-job.h +++ b/thunar/thunar-job.h @@ -68,6 +68,12 @@ struct _ThunarJob GType thunar_job_get_type (void) G_GNUC_CONST; void thunar_job_set_total_files (ThunarJob *job, GList *total_files); +void thunar_job_set_pausable (ThunarJob *job, + gboolean pausable); +gboolean thunar_job_is_pausable (ThunarJob *job); +void thunar_job_pause (ThunarJob *job); +void thunar_job_resume (ThunarJob *job); +gboolean thunar_job_is_paused (ThunarJob *job); void thunar_job_processing_file (ThunarJob *job, GList *current_file, guint n_processed); diff --git a/thunar/thunar-progress-view.c b/thunar/thunar-progress-view.c index 299b1c23d..9b9909fb0 100644 --- a/thunar/thunar-progress-view.c +++ b/thunar/thunar-progress-view.c @@ -55,6 +55,8 @@ static void thunar_progress_view_set_property (GObject * guint prop_id, const GValue *value, GParamSpec *pspec); +static void thunar_progress_view_pause_job (ThunarProgressView *view); +static void thunar_progress_view_unpause_job (ThunarProgressView *view); static void thunar_progress_view_cancel_job (ThunarProgressView *view); static ThunarJobResponse thunar_progress_view_ask (ThunarProgressView *view, const gchar *message, @@ -95,6 +97,8 @@ struct _ThunarProgressView GtkWidget *progress_bar; GtkWidget *progress_label; GtkWidget *message_label; + GtkWidget *pause_button; + GtkWidget *unpause_button; gchar *icon_name; gchar *title; @@ -173,7 +177,7 @@ thunar_progress_view_init (ThunarProgressView *view) { GtkWidget *image; GtkWidget *label; - GtkWidget *button; + GtkWidget *cancel_button; GtkWidget *vbox; GtkWidget *vbox2; GtkWidget *vbox3; @@ -228,12 +232,26 @@ thunar_progress_view_init (ThunarProgressView *view) gtk_box_pack_start (GTK_BOX (vbox3), view->progress_label, FALSE, TRUE, 0); gtk_widget_show (view->progress_label); - button = gtk_button_new_from_icon_name ("process-stop", GTK_ICON_SIZE_BUTTON); - gtk_button_set_label (GTK_BUTTON (button), _("Cancel")); - g_signal_connect_swapped (button, "clicked", G_CALLBACK (thunar_progress_view_cancel_job), view); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0); - gtk_widget_set_can_focus (button, FALSE); - gtk_widget_show (button); + view->pause_button = gtk_button_new_from_icon_name ("media-pause", GTK_ICON_SIZE_BUTTON); + gtk_button_set_label (GTK_BUTTON (view->pause_button), _("Pause")); + g_signal_connect_swapped (view->pause_button, "clicked", G_CALLBACK (thunar_progress_view_pause_job), view); + gtk_box_pack_start (GTK_BOX (hbox), view->pause_button, FALSE, FALSE, 0); + gtk_widget_set_can_focus (view->pause_button, FALSE); + gtk_widget_hide (view->pause_button); + + view->unpause_button = gtk_button_new_from_icon_name ("media-play", GTK_ICON_SIZE_BUTTON); + gtk_button_set_label (GTK_BUTTON (view->unpause_button), _("Resume")); + g_signal_connect_swapped (view->unpause_button, "clicked", G_CALLBACK (thunar_progress_view_unpause_job), view); + gtk_box_pack_start (GTK_BOX (hbox), view->unpause_button, FALSE, FALSE, 0); + gtk_widget_set_can_focus (view->unpause_button, FALSE); + gtk_widget_hide (view->unpause_button); + + cancel_button = gtk_button_new_from_icon_name ("process-stop", GTK_ICON_SIZE_BUTTON); + gtk_button_set_label (GTK_BUTTON (cancel_button), _("Cancel")); + g_signal_connect_swapped (cancel_button, "clicked", G_CALLBACK (thunar_progress_view_cancel_job), view); + gtk_box_pack_start (GTK_BOX (hbox), cancel_button, FALSE, FALSE, 0); + gtk_widget_set_can_focus (cancel_button, FALSE); + gtk_widget_show (cancel_button); /* connect the view title to the action label */ exo_binding_new (G_OBJECT (view), "title", G_OBJECT (label), "label"); @@ -331,6 +349,46 @@ thunar_progress_view_set_property (GObject *object, +static void +thunar_progress_view_pause_job (ThunarProgressView *view) +{ + _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view)); + _thunar_return_if_fail (THUNAR_IS_JOB (view->job)); + + if (view->job != NULL) + { + /* pause the job */ + thunar_job_pause (view->job); + + /* update the UI */ + gtk_widget_hide (view->pause_button); + gtk_widget_show (view->unpause_button); + gtk_label_set_text (GTK_LABEL (view->progress_label), _("Paused")); + } +} + + + +static void +thunar_progress_view_unpause_job (ThunarProgressView *view) +{ + _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view)); + _thunar_return_if_fail (THUNAR_IS_JOB (view->job)); + + if (view->job != NULL) + { + /* unpause the job */ + thunar_job_resume (view->job); + + /* update the UI */ + gtk_widget_hide (view->unpause_button); + gtk_widget_show (view->pause_button); + gtk_label_set_text (GTK_LABEL (view->progress_label), _("Resuming...")); + } +} + + + static void thunar_progress_view_cancel_job (ThunarProgressView *view) { @@ -564,6 +622,10 @@ thunar_progress_view_set_job (ThunarProgressView *view, g_signal_connect_swapped (job, "finished", G_CALLBACK (thunar_progress_view_finished), view); g_signal_connect_swapped (job, "info-message", G_CALLBACK (thunar_progress_view_info_message), view); g_signal_connect_swapped (job, "percent", G_CALLBACK (thunar_progress_view_percent), view); + if (thunar_job_is_pausable (job)) + { + gtk_widget_show (view->pause_button); + } } g_object_notify (G_OBJECT (view), "job"); diff --git a/thunar/thunar-transfer-job.c b/thunar/thunar-transfer-job.c index f7d755987..1b6a72243 100644 --- a/thunar/thunar-transfer-job.c +++ b/thunar/thunar-transfer-job.c @@ -275,6 +275,32 @@ thunar_transfer_job_progress (goffset current_num_bytes, +static void +_thunar_transfer_job_check_pause (ThunarTransferJob *job) +{ + _thunar_return_if_fail (THUNAR_IS_TRANSFER_JOB (job)); + while (thunar_job_is_paused (THUNAR_JOB (job)) && !exo_job_is_cancelled (EXO_JOB (job))) + { + g_usleep (500 * 1000); + } +} + + + +static void +_thunar_transfer_job_progress_check_pause (goffset current_num_bytes, + goffset total_num_bytes, + gpointer user_data) +{ + ThunarTransferJob *job = user_data; + + _thunar_return_if_fail (THUNAR_IS_TRANSFER_JOB (job)); + _thunar_transfer_job_check_pause (job); + thunar_transfer_job_progress (current_num_bytes, total_num_bytes, user_data); +} + + + static gboolean thunar_transfer_job_collect_node (ThunarTransferJob *job, ThunarTransferNode *node, @@ -316,6 +342,7 @@ thunar_transfer_job_collect_node (ThunarTransferJob *job, /* add children to the transfer node */ for (lp = file_list; err == NULL && lp != NULL; lp = lp->next) { + _thunar_transfer_job_check_pause (job); /* allocate a new transfer node for the child */ child_node = g_slice_new0 (ThunarTransferNode); child_node->source_file = g_object_ref (lp->data); @@ -370,18 +397,21 @@ ttj_copy_file (ThunarTransferJob *job, if (exo_job_set_error_if_cancelled (EXO_JOB (job), error)) return FALSE; + _thunar_transfer_job_check_pause (job); source_type = g_file_query_file_type (source_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, exo_job_get_cancellable (EXO_JOB (job))); if (exo_job_set_error_if_cancelled (EXO_JOB (job), error)) return FALSE; + _thunar_transfer_job_check_pause (job); target_type = g_file_query_file_type (target_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, exo_job_get_cancellable (EXO_JOB (job))); if (exo_job_set_error_if_cancelled (EXO_JOB (job), error)) return FALSE; + _thunar_transfer_job_check_pause (job); /* check if the target is a symlink and we are in overwrite mode */ if (target_type == G_FILE_TYPE_SYMBOLIC_LINK && (copy_flags & G_FILE_COPY_OVERWRITE) != 0) @@ -397,7 +427,7 @@ ttj_copy_file (ThunarTransferJob *job, /* try to copy the file */ g_file_copy (source_file, target_file, copy_flags, exo_job_get_cancellable (EXO_JOB (job)), - thunar_transfer_job_progress, job, &err); + _thunar_transfer_job_progress_check_pause, job, &err); /* check if there were errors */ if (G_UNLIKELY (err != NULL && err->domain == G_IO_ERROR)) @@ -517,6 +547,7 @@ thunar_transfer_job_copy_file (ThunarTransferJob *job, /* various attempts to copy the file */ while (err == NULL) { + _thunar_transfer_job_check_pause (job); if (G_LIKELY (!g_file_equal (source_file, target_file))) { /* try to copy the file from source_file to the target_file */ @@ -655,6 +686,7 @@ thunar_transfer_job_copy_node (ThunarTransferJob *job, exo_job_info_message (EXO_JOB (job), "%s", g_file_info_get_display_name (info)); retry_copy: + _thunar_transfer_job_check_pause (job); /* copy the item specified by this node (not recursively) */ real_target_file = thunar_transfer_job_copy_file (job, node->source_file, target_file, node->replace_confirmed, &err); @@ -697,6 +729,7 @@ thunar_transfer_job_copy_node (ThunarTransferJob *job, } retry_remove: + _thunar_transfer_job_check_pause (job); /* try to remove the source directory if we are on copy+remove fallback for move */ if (job->type == THUNAR_TRANSFER_JOB_MOVE) { @@ -887,6 +920,7 @@ thunar_transfer_job_execute (ExoJob *job, sp != NULL && tp != NULL && err == NULL; sp = snext, tp = tnext) { + _thunar_transfer_job_check_pause (transfer_job); /* determine the next list items */ snext = sp->next; tnext = tp->next;