diff --git a/thunar/thunar-io-jobs.c b/thunar/thunar-io-jobs.c index 4f6418402edbc298656f5535cb647057e1279bb6..34cc33a3a9b03d830f5df6c17ae40e4efda3a880 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 88cc36d7118c4d230795737b3e130b9d464a50cb..7945693477f7ed48e9b900c338795cf3471fba3c 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,52 @@ thunar_job_set_total_files (ThunarJob *job, +void +thunar_job_set_pausable (ThunarJob *job, + gboolean pausable) +{ + _thunar_return_if_fail (THUNAR_IS_JOB (job)); + job->priv->pausable = pausable; +} + + + +gboolean +thunar_job_is_pausable (ThunarJob *job) +{ + _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE); + return job->priv->pausable; +} + + + +void +thunar_job_pause (ThunarJob *job) +{ + _thunar_return_if_fail (THUNAR_IS_JOB (job)); + job->priv->paused = TRUE; +} + + + +void +thunar_job_resume (ThunarJob *job) +{ + _thunar_return_if_fail (THUNAR_IS_JOB (job)); + job->priv->paused = FALSE; +} + + + +gboolean +thunar_job_is_paused (ThunarJob *job) +{ + _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE); + 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 9c0a7b41582eecc649f0f8e6933b46936f276985..b9e7f26d6a2601b663b56d1c5a0dfc985fc5e126 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 299b1c23d7779a5637f7da502d2bb19af8a14bee..b9384ca31231cb1b975e27b2727d81cee81c953b 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-playback-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-playback-start", 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 f7d7559879766ccbd38d6d51258686091e995a3b..3ec41546cc9cc3ad7a3e8d42fc55af967887d78e 100644 --- a/thunar/thunar-transfer-job.c +++ b/thunar/thunar-transfer-job.c @@ -223,6 +223,18 @@ thunar_transfer_job_set_property (GObject *object, +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); /* 500ms pause */ + } +} + + + static void thunar_transfer_job_progress (goffset current_num_bytes, goffset total_num_bytes, @@ -236,6 +248,8 @@ thunar_transfer_job_progress (goffset current_num_bytes, _thunar_return_if_fail (THUNAR_IS_TRANSFER_JOB (job)); + thunar_transfer_job_check_pause (job); + if (G_LIKELY (job->total_size > 0)) { /* update total progress */ @@ -316,6 +330,8 @@ 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 +386,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) @@ -517,6 +536,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 +675,8 @@ 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 +719,8 @@ retry_copy: } 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 +911,8 @@ 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;