summaryrefslogtreecommitdiff
path: root/mate-screenshot/src/screenshot-xfer.c
diff options
context:
space:
mode:
Diffstat (limited to 'mate-screenshot/src/screenshot-xfer.c')
-rw-r--r--mate-screenshot/src/screenshot-xfer.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/mate-screenshot/src/screenshot-xfer.c b/mate-screenshot/src/screenshot-xfer.c
new file mode 100644
index 00000000..a4cfeac1
--- /dev/null
+++ b/mate-screenshot/src/screenshot-xfer.c
@@ -0,0 +1,393 @@
+/* screenshot-xfer.c - file transfer functions for MATE Screenshot
+ *
+ * Copyright (C) 2001-2006 Jonathan Blandford <[email protected]>
+ * Copyright (C) 2008 Cosimo Cecchi <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ */
+
+#include "config.h"
+
+#include "screenshot-xfer.h"
+
+#include <time.h>
+#include <glib/gi18n.h>
+
+typedef struct
+{
+ GtkWidget *dialog;
+ GtkWidget *progress_bar;
+ GCancellable *cancellable;
+} TransferDialog;
+
+typedef struct
+{
+ GFile *source;
+ GFile *dest;
+ GFileCopyFlags flags;
+ TransferCallback callback;
+ gpointer callback_data;
+ GCancellable *cancellable;
+ GtkWidget *parent;
+ TransferDialog *dialog;
+ TransferResult result;
+ GIOSchedulerJob *io_job;
+ char *error;
+ gint dialog_timeout_id;
+ goffset total_bytes;
+ goffset current_bytes;
+} TransferJob;
+
+typedef struct
+{
+ int resp;
+ GtkWidget *parent;
+ char *basename;
+} ErrorDialogData;
+
+static gboolean
+do_run_overwrite_confirm_dialog (gpointer _data)
+{
+ ErrorDialogData *data = _data;
+ GtkWidget *dialog;
+ gint response;
+
+ /* we need to ask the user if they want to overwrite this file */
+ dialog = gtk_message_dialog_new (GTK_WINDOW (data->parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("File already exists"));
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("The file \"%s\" already exists. "
+ "Would you like to replace it?"),
+ data->basename);
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("_Replace"),
+ GTK_RESPONSE_OK);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ data->resp = response;
+
+ return FALSE;
+}
+
+static void
+transfer_dialog_response_cb (GtkDialog *d,
+ gint response,
+ GCancellable *cancellable)
+{
+ if (response == GTK_RESPONSE_CANCEL)
+ {
+ if (!g_cancellable_is_cancelled (cancellable))
+ {
+ g_cancellable_cancel (cancellable);
+ }
+ }
+}
+
+static gboolean
+transfer_progress_dialog_new (TransferJob *job)
+{
+ TransferDialog *dialog;
+ GtkWidget *gdialog;
+ GtkWidget *widget;
+
+ dialog = g_new0 (TransferDialog, 1);
+
+ gdialog = gtk_message_dialog_new (GTK_WINDOW (job->parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_OTHER,
+ GTK_BUTTONS_CANCEL,
+ _("Saving file..."));
+ widget = gtk_progress_bar_new ();
+ gtk_box_pack_start (GTK_BOX (gtk_message_dialog_get_message_area GTK_MESSAGE_DIALOG (gdialog)),
+ widget, FALSE, 0, 0);
+ gtk_widget_show (widget);
+ dialog->progress_bar = widget;
+ dialog->dialog = gdialog;
+
+ g_signal_connect (gdialog,
+ "response",
+ G_CALLBACK (transfer_dialog_response_cb),
+ job->cancellable);
+
+ job->dialog = dialog;
+ gtk_widget_show (gdialog);
+
+ return FALSE;
+}
+
+static void
+transfer_progress_dialog_start (TransferJob *job)
+{
+ /* sends to the mainloop and schedules show */
+ if (job->dialog_timeout_id == 0)
+ job->dialog_timeout_id = g_timeout_add_seconds (1,
+ (GSourceFunc) transfer_progress_dialog_new,
+ job);
+}
+
+static int
+run_overwrite_confirm_dialog (TransferJob *job)
+{
+ ErrorDialogData *data;
+ gboolean need_timeout;
+ int response;
+ char *basename;
+
+ basename = g_file_get_basename (job->dest);
+
+ data = g_slice_new0 (ErrorDialogData);
+ data->parent = job->parent;
+ data->basename = basename;
+
+ need_timeout = (job->dialog_timeout_id > 0);
+
+ if (need_timeout)
+ {
+ g_source_remove (job->dialog_timeout_id);
+ job->dialog_timeout_id = 0;
+ }
+
+ g_io_scheduler_job_send_to_mainloop (job->io_job,
+ do_run_overwrite_confirm_dialog,
+ data,
+ NULL);
+ response = data->resp;
+
+ if (need_timeout)
+ transfer_progress_dialog_start (job);
+
+ g_free (basename);
+ g_slice_free (ErrorDialogData, data);
+
+ return response;
+}
+
+static gboolean
+transfer_progress_dialog_update (TransferJob *job)
+{
+ TransferDialog *dialog = job->dialog;
+ double fraction;
+
+ fraction = ((double) job->current_bytes) / ((double) job->total_bytes);
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (dialog->progress_bar),
+ fraction);
+
+ return FALSE;
+}
+
+static gboolean
+transfer_job_done (gpointer user_data)
+{
+ TransferJob *job = user_data;
+ TransferDialog *dialog;
+
+ dialog = job->dialog;
+
+ if (job->dialog_timeout_id)
+ {
+ g_source_remove (job->dialog_timeout_id);
+ job->dialog_timeout_id = 0;
+ }
+ if (dialog)
+ gtk_widget_destroy (dialog->dialog);
+
+ if (job->callback)
+ {
+ (job->callback) (job->result,
+ job->error,
+ job->callback_data);
+ }
+
+ g_object_unref (job->source);
+ g_object_unref (job->dest);
+ g_object_unref (job->cancellable);
+
+ g_free (dialog);
+ g_free (job->error);
+ g_slice_free (TransferJob, job);
+
+ return FALSE;
+}
+
+static void
+transfer_progress_cb (goffset current_num_bytes,
+ goffset total_num_bytes,
+ TransferJob *job)
+{
+ job->current_bytes = current_num_bytes;
+
+ if (!job->dialog)
+ return;
+
+ g_io_scheduler_job_send_to_mainloop_async (job->io_job,
+ (GSourceFunc) transfer_progress_dialog_update,
+ job,
+ NULL);
+}
+
+static goffset
+get_file_size (GFile *file)
+{
+ GFileInfo *file_info;
+ goffset size;
+
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ 0, NULL, NULL);
+ if (file_info != NULL)
+ {
+ size = g_file_info_get_size (file_info);
+ g_object_unref (file_info);
+ }
+ else
+ {
+ /* this should never fail as the source file is always local and in /tmp,
+ * but you never know.
+ */
+ size = -1;
+ }
+
+ return size;
+}
+
+static gboolean
+transfer_file (GIOSchedulerJob *io_job,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ TransferJob *job = user_data;
+ GError *error;
+
+ job->io_job = io_job;
+ job->total_bytes = get_file_size (job->source);
+ if (job->total_bytes == -1)
+ {
+ /* we can't access the source file, abort early */
+ error = NULL;
+ job->result = TRANSFER_ERROR;
+ job->error = g_strdup (_("Can't access source file"));
+
+ goto out;
+ }
+
+ transfer_progress_dialog_start (job);
+
+retry:
+ error = NULL;
+ if (!g_file_copy (job->source,
+ job->dest,
+ job->flags,
+ job->cancellable,
+ (GFileProgressCallback) transfer_progress_cb,
+ job,
+ &error))
+ {
+ if (error->code == G_IO_ERROR_EXISTS)
+ {
+ int response;
+ /* ask the user if he wants to overwrite, otherwise
+ * return and report what happened.
+ */
+ response = run_overwrite_confirm_dialog (job);
+ if (response == GTK_RESPONSE_OK)
+ {
+ job->flags |= G_FILE_COPY_OVERWRITE;
+ g_error_free (error);
+
+ goto retry;
+ }
+ else
+ {
+ g_cancellable_cancel (job->cancellable);
+ job->result = TRANSFER_OVERWRITE;
+ goto out;
+ }
+ }
+ else if (error->code == G_IO_ERROR_CANCELLED)
+ {
+ job->result = TRANSFER_CANCELLED;
+
+ goto out;
+ }
+ else
+ {
+ /* other vfs error, abort the transfer and report
+ * the error.
+ */
+ g_cancellable_cancel (job->cancellable);
+ job->result = TRANSFER_ERROR;
+ job->error = g_strdup (error->message);
+
+ goto out;
+ }
+ }
+ else
+ {
+ /* success */
+ job->result = TRANSFER_OK;
+
+ goto out;
+ }
+
+out:
+ if (error)
+ g_error_free (error);
+
+ g_io_scheduler_job_send_to_mainloop_async (io_job,
+ transfer_job_done,
+ job,
+ NULL);
+ return FALSE;
+}
+
+void
+screenshot_xfer_uri (GFile *source_file,
+ GFile *target_file,
+ GtkWidget *parent,
+ TransferCallback done_callback,
+ gpointer done_callback_data)
+{
+ TransferJob *job;
+ GCancellable *cancellable;
+
+ cancellable = g_cancellable_new ();
+
+ job = g_slice_new0 (TransferJob);
+ job->parent = parent;
+ job->source = g_object_ref (source_file);
+ job->dest = g_object_ref (target_file);
+ job->flags = 0;
+ job->error = NULL;
+ job->dialog = NULL;
+ job->callback = done_callback;
+ job->callback_data = done_callback_data;
+ job->cancellable = cancellable;
+
+ g_io_scheduler_push_job (transfer_file,
+ job,
+ NULL, 0,
+ job->cancellable);
+}
+