summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'xfce-base/thunar/files/thunar-queuedtransfer-20160702.patch')
-rw-r--r--xfce-base/thunar/files/thunar-queuedtransfer-20160702.patch721
1 files changed, 721 insertions, 0 deletions
diff --git a/xfce-base/thunar/files/thunar-queuedtransfer-20160702.patch b/xfce-base/thunar/files/thunar-queuedtransfer-20160702.patch
new file mode 100644
index 0000000..3cbccee
--- /dev/null
+++ b/xfce-base/thunar/files/thunar-queuedtransfer-20160702.patch
@@ -0,0 +1,721 @@
+From 50c67c23cd9bfeb0bb4f0cdd5b5ec614c850c8bd Mon Sep 17 00:00:00 2001
+From: Cyrille Pontvieux <jrd@enialis.net>
+Date: Wed, 29 Jun 2016 05:43:26 +0200
+Subject: Simultaneous or queued copies
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When a new copy process occurs and another copy process exists,
+the source devices and target devices are compared.
+If one match (either source or target), then the files are appended to
+the currently running copy process instead of trying to simultaneous
+copy them.
+Some thresholds are defined though:
+- 100 MB minumum for the new copy process, if less, the copy is done
+aside.
+- 10 seconds minimum of estimated remaining time for the running copy
+process.
+One can change some settings using three preferences:
+- Simultaneous max file copies (0 for ∞, default value)
+- Copying files from same devices behavior:
+ - Ask everytime
+ - Copy simultaneously (default value)
+ - Queue files
+- Copying files to same devices behavior: same values as "from"
+
+The default behavior is the same as the current Thunar.
+---
+ thunar/thunar-enum-types.c | 23 +
+ thunar/thunar-enum-types.h | 20 +
+ thunar/thunar-job.c | 24 +
+ thunar/thunar-job.h | 3 +
+ thunar/thunar-preferences-dialog.c | 57 ++
+ thunar/thunar-preferences.c | 46 ++
+ thunar/thunar-transfer-job.c | 333 +++++++++-
+ 7 files changed, 1221 insertions(+), 510 deletions(-)
+
+diff --git a/thunar/thunar-enum-types.c b/thunar/thunar-enum-types.c
+index 479bbcf..d97128e 100644
+--- a/thunar/thunar-enum-types.c
++++ b/thunar/thunar-enum-types.c
+@@ -162,6 +162,29 @@ thunar_recursive_permissions_get_type (void)
+
+
+ GType
++thunar_copy_same_device_get_type (void)
++{
++ static GType type = G_TYPE_INVALID;
++
++ if (G_UNLIKELY (type == G_TYPE_INVALID))
++ {
++ static const GEnumValue values[] =
++ {
++ { THUNAR_COPY_SAME_DEVICE_ASK, "THUNAR_COPY_SAME_DEVICE_ASK", "ask", },
++ { THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY, "THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY", "simultaneous", },
++ { THUNAR_COPY_SAME_DEVICE_QUEUE, "THUNAR_COPY_SAME_DEVICE_QUEUE", "queue", },
++ { 0, NULL, NULL, },
++ };
++
++ type = g_enum_register_static (I_("ThunarCopySameDeviceMode"), values);
++ }
++
++ return type;
++}
++
++
++
++GType
+ thunar_zoom_level_get_type (void)
+ {
+ static GType type = G_TYPE_INVALID;
+diff --git a/thunar/thunar-enum-types.h b/thunar/thunar-enum-types.h
+index 9fb34a7..8d293b3 100644
+--- a/thunar/thunar-enum-types.h
++++ b/thunar/thunar-enum-types.h
+@@ -180,6 +180,26 @@ typedef enum
+ GType thunar_recursive_permissions_get_type (void) G_GNUC_CONST;
+
+
++#define THUNAR_TYPE_COPY_SAME_DEVICE (thunar_copy_same_device_get_type ())
++
++/**
++ * ThunarCopySameDeviceMode:
++ * @THUNAR_COPY_SAME_DEVICE_ASK : ask the user for simultaneous copy (or not) everytime a copy is done using a same device.
++ * @THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY : always copy simultaneously when using a same device (if not max simultaneous copies reached).
++ * @THUNAR_COPY_SAME_DEVICE_QUEUE : always queue the copy when using a same device.
++ *
++ * Modus operandi when copying using a same device.
++ **/
++typedef enum
++{
++ THUNAR_COPY_SAME_DEVICE_ASK,
++ THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY,
++ THUNAR_COPY_SAME_DEVICE_QUEUE,
++} ThunarCopySameDeviceMode;
++
++GType thunar_copy_same_device_get_type (void) G_GNUC_CONST;
++
++
+ #define THUNAR_TYPE_ZOOM_LEVEL (thunar_zoom_level_get_type ())
+
+ /**
+diff --git a/thunar/thunar-job.c b/thunar/thunar-job.c
+index f4ce28e..d692f0d 100644
+--- a/thunar/thunar-job.c
++++ b/thunar/thunar-job.c
+@@ -546,6 +546,30 @@ thunar_job_ask_no_size (ThunarJob *job,
+
+
+
++ThunarJobResponse
++thunar_job_ask_queue_copy (ThunarJob *job,
++ const gchar *format,
++ ...)
++{
++ ThunarJobResponse response;
++ va_list var_args;
++ _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
++ _thunar_return_val_if_fail (format != NULL, THUNAR_JOB_RESPONSE_CANCEL);
++ /* check if the user already cancelled the job */
++ if (G_UNLIKELY (exo_job_is_cancelled (EXO_JOB (job))))
++ return THUNAR_JOB_RESPONSE_CANCEL;
++ /* ask the user what he wants to do */
++ va_start (var_args, format);
++ response = _thunar_job_ask_valist (job, format, var_args,
++ _("Do you want to queue this copy?"),
++ THUNAR_JOB_RESPONSE_YES
++ | THUNAR_JOB_RESPONSE_NO);
++ va_end (var_args);
++ return response;
++}
++
++
++
+ gboolean
+ thunar_job_files_ready (ThunarJob *job,
+ GList *file_list)
+diff --git a/thunar/thunar-job.h b/thunar/thunar-job.h
+index f1f636b..f1372ed 100644
+--- a/thunar/thunar-job.h
++++ b/thunar/thunar-job.h
+@@ -84,6 +84,9 @@ ThunarJobResponse thunar_job_ask_replace (ThunarJob *job,
+ ThunarJobResponse thunar_job_ask_skip (ThunarJob *job,
+ const gchar *format,
+ ...);
++ThunarJobResponse thunar_job_ask_queue_copy (ThunarJob *job,
++ const gchar *format,
++ ...);
+ gboolean thunar_job_ask_no_size (ThunarJob *job,
+ const gchar *format,
+ ...);
+diff --git a/thunar/thunar-preferences-dialog.c b/thunar/thunar-preferences-dialog.c
+index 057766e..8db1e56 100644
+--- a/thunar/thunar-preferences-dialog.c
++++ b/thunar/thunar-preferences-dialog.c
+@@ -206,6 +206,7 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog)
+ GtkWidget *button;
+ GtkWidget *align;
+ GtkWidget *combo;
++ GtkWidget *spinbutton;
+ GtkWidget *frame;
+ GtkWidget *label;
+ GtkWidget *range;
+@@ -626,6 +627,62 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog)
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
+ gtk_widget_show (frame);
+
++ label = gtk_label_new (_("Simultaneous file copies"));
++ gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_bold ());
++ gtk_frame_set_label_widget (GTK_FRAME (frame), label);
++ gtk_widget_show (label);
++
++ table = gtk_table_new (3, 2, FALSE);
++ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
++ gtk_table_set_col_spacings (GTK_TABLE (table), 12);
++ gtk_container_set_border_width (GTK_CONTAINER (table), 12);
++ gtk_container_add (GTK_CONTAINER (frame), table);
++ gtk_widget_show (table);
++
++ label = gtk_label_new_with_mnemonic (_("Simultaneous _max file copies:"));
++ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
++ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
++ gtk_widget_show (label);
++
++ spinbutton = gtk_spin_button_new_with_range (0, 100, 1);
++ exo_mutual_binding_new (G_OBJECT (dialog->preferences), "misc-max-simultaneous-copies", G_OBJECT (spinbutton), "value");
++ gtk_table_attach (GTK_TABLE (table), spinbutton, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
++ thunar_gtk_label_set_a11y_relation (GTK_LABEL (label), spinbutton);
++ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
++ gtk_widget_show (spinbutton);
++
++ label = gtk_label_new_with_mnemonic (_("Copying files _from same devices:"));
++ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
++ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
++ gtk_widget_show (label);
++
++ combo = gtk_combo_box_text_new ();
++ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Ask everytime"));
++ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Copy simultaneously"));
++ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Queue files"));
++ exo_mutual_binding_new (G_OBJECT (dialog->preferences), "misc-copy-from-same-device", G_OBJECT (combo), "active");
++ gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
++ thunar_gtk_label_set_a11y_relation (GTK_LABEL (label), combo);
++ gtk_widget_show (combo);
++
++ label = gtk_label_new_with_mnemonic (_("Copying files _to same devices:"));
++ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
++ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
++ gtk_widget_show (label);
++
++ combo = gtk_combo_box_text_new ();
++ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Ask everytime"));
++ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Copy simultaneously"));
++ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Queue files"));
++ exo_mutual_binding_new (G_OBJECT (dialog->preferences), "misc-copy-to-same-device", G_OBJECT (combo), "active");
++ gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
++ thunar_gtk_label_set_a11y_relation (GTK_LABEL (label), combo);
++ gtk_widget_show (combo);
++
++ frame = g_object_new (GTK_TYPE_FRAME, "border-width", 0, "shadow-type", GTK_SHADOW_NONE, NULL);
++ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
++ gtk_widget_show (frame);
++
+ label = gtk_label_new (_("Volume Management"));
+ gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_bold ());
+ gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+diff --git a/thunar/thunar-preferences.c b/thunar/thunar-preferences.c
+index 9a86ae1..8db7ac3 100644
+--- a/thunar/thunar-preferences.c
++++ b/thunar/thunar-preferences.c
+@@ -82,6 +82,9 @@ enum
+ PROP_MISC_IMAGE_SIZE_IN_STATUSBAR,
+ PROP_MISC_MIDDLE_CLICK_IN_TAB,
+ PROP_MISC_RECURSIVE_PERMISSIONS,
++ PROP_MISC_MAX_SIMULTANEOUS_COPIES,
++ PROP_MISC_COPY_FROM_SAME_DEVICE,
++ PROP_MISC_COPY_TO_SAME_DEVICE,
+ PROP_MISC_REMEMBER_GEOMETRY,
+ PROP_MISC_SHOW_ABOUT_TEMPLATES,
+ PROP_MISC_SINGLE_CLICK,
+@@ -587,6 +590,49 @@ thunar_preferences_class_init (ThunarPreferencesClass *klass)
+ EXO_PARAM_READWRITE);
+
+ /**
++ * ThunarPreferences:misc-max-simultaneous-copies:
++ *
++ * Max number of simultaneous file copies than can occur.
++ * 0 means infinite (default value)
++ * When the max number occurs, any new copy will be appended
++ * to the last running copy.
++ **/
++ preferences_props[PROP_MISC_MAX_SIMULTANEOUS_COPIES] =
++ g_param_spec_uint ("misc-max-simultaneous-copies",
++ "MiscMaxSimultaneousCopies",
++ NULL,
++ 0,
++ 100,
++ 0,
++ EXO_PARAM_READWRITE);
++
++ /**
++ * ThunarPreferences:misc-copy-from-same-device:
++ *
++ * Specify what to do when copying files from the same device.
++ **/
++ preferences_props[PROP_MISC_COPY_FROM_SAME_DEVICE] =
++ g_param_spec_enum ("misc-copy-from-same-device",
++ "MiscCopyFromSameDevice",
++ NULL,
++ THUNAR_TYPE_COPY_SAME_DEVICE,
++ THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY,
++ EXO_PARAM_READWRITE);
++
++ /**
++ * ThunarPreferences:misc-copy-to-same-device:
++ *
++ * Specify what to do when copying files to the same device.
++ **/
++ preferences_props[PROP_MISC_COPY_TO_SAME_DEVICE] =
++ g_param_spec_enum ("misc-copy-to-same-device",
++ "MiscCopyToSameDevice",
++ NULL,
++ THUNAR_TYPE_COPY_SAME_DEVICE,
++ THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY,
++ EXO_PARAM_READWRITE);
++
++ /**
+ * ThunarPreferences:misc-remember-geometry:
+ *
+ * Whether Thunar should remember the size of windows and apply
+diff --git a/thunar/thunar-transfer-job.c b/thunar/thunar-transfer-job.c
+index 82482e0..a432c93 100644
+--- a/thunar/thunar-transfer-job.c
++++ b/thunar/thunar-transfer-job.c
+@@ -26,6 +26,7 @@
+ #include <gio/gio.h>
+
+ #include <thunar/thunar-application.h>
++#include <thunar/thunar-enum-types.h>
+ #include <thunar/thunar-gio-extensions.h>
+ #include <thunar/thunar-io-scan-directory.h>
+ #include <thunar/thunar-io-jobs-util.h>
+@@ -39,7 +40,9 @@
+
+ /* seconds before we show the transfer rate + remaining time */
+ #define MINIMUM_TRANSFER_TIME (10 * G_USEC_PER_SEC) /* 10 seconds */
+-
++/* minimum size (in bytes) for one job to be queued in another */
++#define QUEUE_MIN_SIZE (100 * 1024 * 1024) /* 100 MB */
++#define QUEUE_MIN_SEC 10
+
+
+ /* Property identifiers */
+@@ -47,6 +50,9 @@ enum
+ {
+ PROP_0,
+ PROP_FILE_SIZE_BINARY,
++ PROP_MAX_SIMULTANEOUS_COPIES,
++ PROP_COPY_FROM_SAME_DEVICE,
++ PROP_COPY_TO_SAME_DEVICE,
+ };
+
+
+@@ -84,6 +90,7 @@ struct _ThunarTransferJob
+ ThunarTransferJobType type;
+ GList *source_node_list;
+ GList *target_file_list;
++ GList *added_jobs;
+
+ gint64 start_time;
+ gint64 last_update_time;
+@@ -96,6 +103,9 @@ struct _ThunarTransferJob
+
+ ThunarPreferences *preferences;
+ gboolean file_size_binary;
++ guint16 max_simultaneous_copies;
++ guint16 copy_from_same_device;
++ guint16 copy_to_same_device;
+ };
+
+ struct _ThunarTransferNode
+@@ -109,6 +119,9 @@ struct _ThunarTransferNode
+
+ G_DEFINE_TYPE (ThunarTransferJob, thunar_transfer_job, THUNAR_TYPE_JOB)
+
++G_LOCK_DEFINE_STATIC(active_jobs);
++static GList *active_jobs = NULL;
++
+
+
+ static void
+@@ -137,6 +150,33 @@ thunar_transfer_job_class_init (ThunarTransferJobClass *klass)
+ NULL,
+ FALSE,
+ EXO_PARAM_READWRITE));
++ /*
++ g_object_class_install_property (gobject_class,
++ PROP_MAX_SIMULTANEOUS_COPIES,
++ g_param_spec_uint ("max-simultaneous-copies",
++ "MaxSimultaneousCopies",
++ NULL,
++ 0,
++ 100,
++ 0,
++ EXO_PARAM_READWRITE));
++ g_object_class_install_property (gobject_class,
++ PROP_COPY_FROM_SAME_DEVICE,
++ g_param_spec_enum ("copy-from-same-device",
++ "CopyFromSameDevice",
++ NULL,
++ THUNAR_TYPE_COPY_SAME_DEVICE,
++ THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY,
++ EXO_PARAM_READWRITE));
++ g_object_class_install_property (gobject_class,
++ PROP_COPY_TO_SAME_DEVICE,
++ g_param_spec_enum ("copy-to-same-device",
++ "CopyToSameDevice",
++ NULL,
++ THUNAR_TYPE_COPY_SAME_DEVICE,
++ THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY,
++ EXO_PARAM_READWRITE));
++ */
+ }
+
+
+@@ -147,10 +187,10 @@ thunar_transfer_job_init (ThunarTransferJob *job)
+ job->preferences = thunar_preferences_get ();
+ exo_binding_new (G_OBJECT (job->preferences), "misc-file-size-binary",
+ G_OBJECT (job), "file-size-binary");
+-
+ job->type = 0;
+ job->source_node_list = NULL;
+ job->target_file_list = NULL;
++ job->added_jobs = NULL;
+ job->total_size = 0;
+ job->total_progress = 0;
+ job->file_progress = 0;
+@@ -163,16 +203,32 @@ thunar_transfer_job_init (ThunarTransferJob *job)
+
+
+ static void
++thunar_transfer_job_free (gpointer data)
++{
++ ThunarTransferJob *job = data;
++ g_object_unref (job);
++}
++
++
++
++static void
+ thunar_transfer_job_finalize (GObject *object)
+ {
+ ThunarTransferJob *job = THUNAR_TRANSFER_JOB (object);
++ GList *ljob;
+
+ g_list_free_full (job->source_node_list, thunar_transfer_node_free);
+-
+ thunar_g_file_list_free (job->target_file_list);
+-
+ g_object_unref (job->preferences);
+-
++ if (job->added_jobs != NULL)
++ g_list_free_full(job->added_jobs, thunar_transfer_job_free);
++ G_LOCK (active_jobs);
++ ljob = g_list_find (active_jobs, job);
++ if (G_LIKELY (ljob != NULL))
++ {
++ active_jobs = g_list_remove_link (active_jobs, ljob);
++ }
++ G_UNLOCK (active_jobs);
+ (*G_OBJECT_CLASS (thunar_transfer_job_parent_class)->finalize) (object);
+ }
+
+@@ -846,26 +902,207 @@ thunar_transfer_job_verify_destination (ThunarTransferJob *transfer_job,
+
+
+
++static GList *
++thunar_transfer_job_list (void)
++{
++ GList *job_list;
++ G_LOCK (active_jobs);
++ job_list = g_list_copy(active_jobs);
++ G_UNLOCK (active_jobs);
++ return job_list;
++}
++
++
++
++static gboolean
++thunar_transfer_job_matching_fs(ThunarTransferJob *newjob,
++ GFile *file1,
++ GFile *file2)
++{
++ GFileInfo *info1;
++ GFileInfo *info2;
++ guint32 unix_device1;
++ guint32 unix_device2;
++ GError *err = NULL;
++
++ info1 = g_file_query_info (file1,
++ G_FILE_ATTRIBUTE_UNIX_DEVICE,
++ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
++ exo_job_get_cancellable (EXO_JOB (newjob)),
++ &err);
++ if (G_UNLIKELY (info1 == NULL || err != NULL))
++ return FALSE;
++ unix_device1 = g_file_info_get_attribute_uint32(info1, G_FILE_ATTRIBUTE_UNIX_DEVICE);
++ err = NULL;
++ info2 = g_file_query_info (file2,
++ G_FILE_ATTRIBUTE_UNIX_DEVICE,
++ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
++ exo_job_get_cancellable (EXO_JOB (newjob)),
++ &err);
++ if (G_UNLIKELY (info2 == NULL || err != NULL))
++ return FALSE;
++ unix_device2 = g_file_info_get_attribute_uint32(info2, G_FILE_ATTRIBUTE_UNIX_DEVICE);
++ return (unix_device1 == unix_device2);
++}
++
++
++
++static gboolean
++thunar_transfer_job_matching_source_fs(ThunarTransferJob *job,
++ ThunarTransferJob *newjob)
++{
++ ThunarTransferNode *node;
++ GFile *file1;
++ GFile *file2;
++
++ _thunar_return_val_if_fail (job != NULL, FALSE);
++ _thunar_return_val_if_fail (newjob != NULL, FALSE);
++ node = job->source_node_list->data;
++ file1 = node->source_file;
++ node = newjob->source_node_list->data;
++ file2 = node->source_file;
++ return thunar_transfer_job_matching_fs (newjob, file1, file2);
++}
++
++
++
++static gboolean
++thunar_transfer_job_matching_target_fs(ThunarTransferJob *job,
++ ThunarTransferJob *newjob)
++{
++ GFile *file1;
++ GFile *file2;
++
++ _thunar_return_val_if_fail (job != NULL, FALSE);
++ _thunar_return_val_if_fail (newjob != NULL, FALSE);
++ file1 = job->target_file_list->data;
++ file2 = newjob->target_file_list->data;
++ return thunar_transfer_job_matching_fs (newjob, file1, file2);
++}
++
++
++
++/**
++ * thunar_transfer_job_find_one_to_queue:
++ * @job : a #ThunarTransferJob.
++ * @max_simultaneous_copies : 0 = infinite, other = number of
++ * concurrent simultaneous copies allowed
++ * @copy_from_same_device : behavior when the source device is the
++ * same as another
++ * @copy_to_same_device : behavior when the target device is the
++ * same as another
++ *
++ * Tries to find a job to queue current file copy,
++ * rather than executing it on this job.
++ *
++ * Return value: the job to queue onto, or %NULL if none found matching
++ * the preferences.
++ **/
++static ThunarTransferJob *
++thunar_transfer_job_find_one_to_queue (ThunarTransferJob *job,
++ guint max_simultaneous_copies,
++ ThunarCopySameDeviceMode copy_from_same_device_mode,
++ ThunarCopySameDeviceMode copy_to_same_device_mode)
++{
++ ThunarTransferJob *queue_job = NULL;
++ GList *job_list;
++ GList *ljob;
++ ThunarTransferJob *inspected_job;
++ guint64 remaining_time_sec;
++ gboolean should_ask = FALSE;
++ ThunarJobResponse response;
++
++ job_list = thunar_transfer_job_list();
++ if (max_simultaneous_copies == 0 || g_list_length (job_list) < max_simultaneous_copies)
++ {
++ if (copy_from_same_device_mode == THUNAR_COPY_SAME_DEVICE_ASK || copy_to_same_device_mode == THUNAR_COPY_SAME_DEVICE_ASK)
++ {
++ for (ljob = job_list;
++ ljob != NULL;
++ ljob = ljob->next)
++ {
++ inspected_job = ljob->data;
++ remaining_time_sec = inspected_job->transfer_rate == 0 ? QUEUE_MIN_SEC + 1 : (inspected_job->total_size - inspected_job->total_progress) / inspected_job->transfer_rate;
++ if (inspected_job->total_size > QUEUE_MIN_SIZE && remaining_time_sec > QUEUE_MIN_SEC
++ && (
++ (copy_from_same_device_mode == THUNAR_COPY_SAME_DEVICE_ASK && thunar_transfer_job_matching_source_fs (inspected_job, job))
++ || (copy_to_same_device_mode == THUNAR_COPY_SAME_DEVICE_ASK && thunar_transfer_job_matching_target_fs (inspected_job, job))
++ ))
++ {
++ should_ask = TRUE;
++ break;
++ }
++ }
++ }
++ if (should_ask)
++ {
++ // ask the user for simultaneous or queue
++ response = thunar_job_ask_queue_copy (THUNAR_JOB (job),
++ _("This copy share source or target device to another copy in progress."));
++ if (response == THUNAR_JOB_RESPONSE_YES)
++ {
++ copy_from_same_device_mode = copy_to_same_device_mode = THUNAR_COPY_SAME_DEVICE_QUEUE;
++ }
++ else
++ {
++ copy_from_same_device_mode = copy_to_same_device_mode = THUNAR_COPY_SAME_DEVICE_SIMULTANEOUSLY;
++ }
++ g_list_free (job_list);
++ job_list = thunar_transfer_job_list();
++ }
++ if (!should_ask || max_simultaneous_copies == 0 || g_list_length (job_list) < max_simultaneous_copies)
++ {
++ for (ljob = job_list;
++ ljob != NULL;
++ ljob = ljob->next)
++ {
++ inspected_job = ljob->data;
++ remaining_time_sec = inspected_job->transfer_rate == 0 ? QUEUE_MIN_SEC + 1 : (inspected_job->total_size - inspected_job->total_progress) / inspected_job->transfer_rate;
++ if (inspected_job->total_size > QUEUE_MIN_SIZE && remaining_time_sec > QUEUE_MIN_SEC)
++ {
++ if ((copy_from_same_device_mode == THUNAR_COPY_SAME_DEVICE_QUEUE && thunar_transfer_job_matching_source_fs (inspected_job, job))
++ || (copy_to_same_device_mode == THUNAR_COPY_SAME_DEVICE_QUEUE && thunar_transfer_job_matching_target_fs (inspected_job, job)))
++ {
++ queue_job = inspected_job;
++ break;
++ }
++ }
++ }
++ }
++ }
++ g_list_free (job_list);
++ return queue_job;
++}
++
++
++
+ static gboolean
+ thunar_transfer_job_execute (ExoJob *job,
+ GError **error)
+ {
+- ThunarThumbnailCache *thumbnail_cache;
+- ThunarTransferNode *node;
+- ThunarApplication *application;
+- ThunarJobResponse response;
+- ThunarTransferJob *transfer_job = THUNAR_TRANSFER_JOB (job);
+- GFileInfo *info;
+- gboolean parent_exists;
+- GError *err = NULL;
+- GList *new_files_list = NULL;
+- GList *snext;
+- GList *sp;
+- GList *tnext;
+- GList *tp;
+- GFile *target_parent;
+- gchar *base_name;
+- gchar *parent_display_name;
++ guint max_simultaneous_copies;
++ ThunarCopySameDeviceMode copy_from_same_device_mode;
++ ThunarCopySameDeviceMode copy_to_same_device_mode;
++ ThunarThumbnailCache *thumbnail_cache;
++ ThunarTransferNode *node;
++ ThunarApplication *application;
++ ThunarJobResponse response;
++ ThunarTransferJob *transfer_job = THUNAR_TRANSFER_JOB (job);
++ ThunarTransferJob *queue_job = NULL;
++ ThunarTransferJob *added_job = NULL;
++ GFileInfo *info;
++ gboolean parent_exists;
++ GError *err = NULL;
++ GList *new_files_list = NULL;
++ GList *snext;
++ GList *sp;
++ GList *sp_added;
++ GList *tnext;
++ GList *tp;
++ GList *tp_added;
++ GFile *target_parent;
++ gchar *base_name;
++ gchar *parent_display_name;
+
+ _thunar_return_val_if_fail (THUNAR_IS_TRANSFER_JOB (job), FALSE);
+ _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+@@ -1050,16 +1287,52 @@ thunar_transfer_job_execute (ExoJob *job,
+ }
+ }
+
+- /* transfer starts now */
+- transfer_job->start_time = g_get_real_time ();
+-
+- /* perform the copy recursively for all source transfer nodes */
+- for (sp = transfer_job->source_node_list, tp = transfer_job->target_file_list;
+- sp != NULL && tp != NULL && err == NULL;
+- sp = sp->next, tp = tp->next)
++ g_object_get (G_OBJECT (transfer_job->preferences), "misc-max-simultaneous-copies", &max_simultaneous_copies, "misc-copy-from-same-device", &copy_from_same_device_mode, "misc-copy-to-same-device", &copy_to_same_device_mode, NULL);
++ queue_job = thunar_transfer_job_find_one_to_queue (transfer_job, max_simultaneous_copies, copy_from_same_device_mode, copy_to_same_device_mode);
++ if (queue_job == NULL)
++ {
++ G_LOCK (active_jobs);
++ active_jobs = g_list_prepend (active_jobs, transfer_job);
++ G_UNLOCK (active_jobs);
++ /* transfer starts now */
++ transfer_job->start_time = g_get_real_time ();
++ /* perform the copy recursively for all source transfer nodes */
++ for (sp = transfer_job->source_node_list, tp = transfer_job->target_file_list;
++ sp != NULL && tp != NULL && err == NULL;
++ sp = sp->next, tp = tp->next)
++ {
++ thunar_transfer_job_copy_node (transfer_job, sp->data, tp->data, NULL,
++ &new_files_list, &err);
++ }
++ while (transfer_job->added_jobs != NULL)
++ {
++ added_job = transfer_job->added_jobs->data;
++ transfer_job->added_jobs = g_list_remove_link(transfer_job->added_jobs, transfer_job->added_jobs);
++ if (G_LIKELY (err == NULL))
++ {
++ for (sp_added = added_job->source_node_list, tp_added = added_job->target_file_list;
++ sp_added != NULL && tp_added != NULL && err == NULL;
++ sp_added = sp_added->next, tp_added = tp_added->next)
++ {
++ thunar_transfer_job_copy_node (transfer_job, sp_added->data, tp_added->data, NULL,
++ &new_files_list, &err);
++ }
++ }
++ g_object_unref (added_job);
++ }
++ }
++ else
+ {
+- thunar_transfer_job_copy_node (transfer_job, sp->data, tp->data, NULL,
+- &new_files_list, &err);
++ added_job = g_object_new (THUNAR_TYPE_TRANSFER_JOB, NULL);
++ added_job->type = transfer_job->type;
++ added_job->source_node_list = transfer_job->source_node_list;
++ added_job->target_file_list = transfer_job->target_file_list;
++ // transfer_job will be finalized/free and same for its resources
++ // fake it to have no resource
++ transfer_job->source_node_list = NULL;
++ transfer_job->target_file_list = NULL;
++ queue_job->added_jobs = g_list_append(queue_job->added_jobs, added_job);
++ queue_job->total_size += transfer_job->total_size;
+ }
+ }
+
+--
+2.8.2