summaryrefslogtreecommitdiffstats
path: root/app/file/file-remote.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/file/file-remote.c')
-rw-r--r--app/file/file-remote.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/app/file/file-remote.c b/app/file/file-remote.c
new file mode 100644
index 0000000..498115a
--- /dev/null
+++ b/app/file/file-remote.c
@@ -0,0 +1,401 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * file-remote.c
+ * Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
+ *
+ * Based on: URI plug-in, GIO/GVfs backend
+ * Copyright (C) 2008 Sven Neumann <sven@gimp.org>
+ *
+ * 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 3 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "core/core-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpprogress.h"
+
+#include "file-remote.h"
+
+#include "gimp-intl.h"
+
+
+typedef enum
+{
+ DOWNLOAD,
+ UPLOAD
+} RemoteCopyMode;
+
+typedef struct
+{
+ GimpProgress *progress;
+ GCancellable *cancellable;
+ gboolean cancel;
+ GMainLoop *main_loop;
+ GError *error;
+} RemoteMount;
+
+typedef struct
+{
+ RemoteCopyMode mode;
+ GimpProgress *progress;
+ GCancellable *cancellable;
+ gboolean cancel;
+ gint64 last_time;
+} RemoteProgress;
+
+
+static void file_remote_mount_volume_ready (GFile *file,
+ GAsyncResult *result,
+ RemoteMount *mount);
+static void file_remote_mount_file_cancel (GimpProgress *progress,
+ RemoteMount *mount);
+
+static GFile * file_remote_get_temp_file (Gimp *gimp,
+ GFile *file);
+static gboolean file_remote_copy_file (Gimp *gimp,
+ GFile *src_file,
+ GFile *dest_file,
+ RemoteCopyMode mode,
+ GimpProgress *progress,
+ GError **error);
+static void file_remote_copy_file_cancel (GimpProgress *progress,
+ RemoteProgress *remote_progress);
+
+static void file_remote_progress_callback (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data);
+
+
+/* public functions */
+
+gboolean
+file_remote_mount_file (Gimp *gimp,
+ GFile *file,
+ GimpProgress *progress,
+ GError **error)
+{
+ GMountOperation *operation;
+ RemoteMount mount = { 0, };
+
+ g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+ g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ mount.progress = progress;
+ mount.main_loop = g_main_loop_new (NULL, FALSE);
+
+ operation = gimp_get_mount_operation (gimp, progress);
+
+ if (progress)
+ {
+ gimp_progress_start (progress, TRUE, _("Mounting remote volume"));
+
+ mount.cancellable = g_cancellable_new ();
+
+ g_signal_connect (progress, "cancel",
+ G_CALLBACK (file_remote_mount_file_cancel),
+ &mount);
+ }
+
+ g_file_mount_enclosing_volume (file, G_MOUNT_MOUNT_NONE,
+ operation, mount.cancellable,
+ (GAsyncReadyCallback) file_remote_mount_volume_ready,
+ &mount);
+
+ g_main_loop_run (mount.main_loop);
+ g_main_loop_unref (mount.main_loop);
+
+ if (progress)
+ {
+ g_signal_handlers_disconnect_by_func (progress,
+ file_remote_mount_file_cancel,
+ &mount);
+
+ g_object_unref (mount.cancellable);
+
+ gimp_progress_end (progress);
+ }
+
+ g_object_unref (operation);
+
+ if (mount.error)
+ {
+ if (mount.error->domain != G_IO_ERROR ||
+ mount.error->code != G_IO_ERROR_ALREADY_MOUNTED)
+ {
+ g_propagate_error (error, mount.error);
+ return FALSE;
+ }
+ else
+ {
+ g_clear_error (&mount.error);
+ }
+ }
+
+ return TRUE;
+}
+
+GFile *
+file_remote_download_image (Gimp *gimp,
+ GFile *file,
+ GimpProgress *progress,
+ GError **error)
+{
+ GFile *local_file;
+
+ g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ local_file = file_remote_get_temp_file (gimp, file);
+
+ if (! file_remote_copy_file (gimp, file, local_file, DOWNLOAD,
+ progress, error))
+ {
+ g_object_unref (local_file);
+ return NULL;
+ }
+
+ return local_file;
+}
+
+GFile *
+file_remote_upload_image_prepare (Gimp *gimp,
+ GFile *file,
+ GimpProgress *progress,
+ GError **error)
+{
+ GFile *local_file;
+
+ g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ local_file = file_remote_get_temp_file (gimp, file);
+
+ return local_file;
+}
+
+gboolean
+file_remote_upload_image_finish (Gimp *gimp,
+ GFile *file,
+ GFile *local_file,
+ GimpProgress *progress,
+ GError **error)
+{
+ g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+ g_return_val_if_fail (G_IS_FILE (local_file), FALSE);
+ g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ if (! file_remote_copy_file (gimp, local_file, file, UPLOAD,
+ progress, error))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* private functions */
+
+static void
+file_remote_mount_volume_ready (GFile *file,
+ GAsyncResult *result,
+ RemoteMount *mount)
+{
+ g_file_mount_enclosing_volume_finish (file, result, &mount->error);
+
+ g_main_loop_quit (mount->main_loop);
+}
+
+static void
+file_remote_mount_file_cancel (GimpProgress *progress,
+ RemoteMount *mount)
+{
+ mount->cancel = TRUE;
+
+ g_cancellable_cancel (mount->cancellable);
+}
+
+static GFile *
+file_remote_get_temp_file (Gimp *gimp,
+ GFile *file)
+{
+ gchar *basename;
+ GFile *temp_file = NULL;
+
+ basename = g_path_get_basename (gimp_file_get_utf8_name (file));
+
+ if (basename)
+ {
+ const gchar *ext = strchr (basename, '.');
+
+ if (ext && strlen (ext))
+ temp_file = gimp_get_temp_file (gimp, ext + 1);
+
+ g_free (basename);
+ }
+
+ if (! temp_file)
+ temp_file = gimp_get_temp_file (gimp, "xxx");
+
+ return temp_file;
+}
+
+static gboolean
+file_remote_copy_file (Gimp *gimp,
+ GFile *src_file,
+ GFile *dest_file,
+ RemoteCopyMode mode,
+ GimpProgress *progress,
+ GError **error)
+{
+ RemoteProgress remote_progress = { 0, };
+ gboolean success;
+ GError *my_error = NULL;
+
+ remote_progress.mode = mode;
+ remote_progress.progress = progress;
+
+ if (progress)
+ {
+ gimp_progress_start (progress, TRUE, _("Opening remote file"));
+
+ remote_progress.cancellable = g_cancellable_new ();
+
+ g_signal_connect (progress, "cancel",
+ G_CALLBACK (file_remote_copy_file_cancel),
+ &remote_progress);
+
+ success = g_file_copy (src_file, dest_file, G_FILE_COPY_OVERWRITE,
+ remote_progress.cancellable,
+ file_remote_progress_callback, &remote_progress,
+ &my_error);
+
+ g_signal_handlers_disconnect_by_func (progress,
+ file_remote_copy_file_cancel,
+ &remote_progress);
+
+ g_object_unref (remote_progress.cancellable);
+
+ gimp_progress_set_value (progress, 1.0);
+ gimp_progress_end (progress);
+ }
+ else
+ {
+ success = g_file_copy (src_file, dest_file, G_FILE_COPY_OVERWRITE,
+ NULL, NULL, NULL,
+ &my_error);
+ }
+
+ return success;
+}
+
+static void
+file_remote_copy_file_cancel (GimpProgress *progress,
+ RemoteProgress *remote_progress)
+{
+ remote_progress->cancel = TRUE;
+
+ g_cancellable_cancel (remote_progress->cancellable);
+}
+
+static void
+file_remote_progress_callback (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data)
+{
+ RemoteProgress *progress = user_data;
+ gint64 now;
+
+ /* update the progress only up to 10 times a second */
+ now = g_get_monotonic_time ();
+
+ if ((now - progress->last_time) / 1000 < 100)
+ return;
+
+ progress->last_time = now;
+
+ if (total_num_bytes > 0)
+ {
+ const gchar *format;
+ gchar *done = g_format_size (current_num_bytes);
+ gchar *total = g_format_size (total_num_bytes);
+
+ switch (progress->mode)
+ {
+ case DOWNLOAD:
+ format = _("Downloading image (%s of %s)");
+ break;
+
+ case UPLOAD:
+ format = _("Uploading image (%s of %s)");
+ break;
+
+ default:
+ gimp_assert_not_reached ();
+ }
+
+ gimp_progress_set_text (progress->progress, format, done, total);
+ g_free (total);
+ g_free (done);
+
+ gimp_progress_set_value (progress->progress,
+ (gdouble) current_num_bytes /
+ (gdouble) total_num_bytes);
+ }
+ else
+ {
+ const gchar *format;
+ gchar *done = g_format_size (current_num_bytes);
+
+ switch (progress->mode)
+ {
+ case DOWNLOAD:
+ format = _("Downloaded %s of image data");
+ break;
+
+ case UPLOAD:
+ format = _("Uploaded %s of image data");
+ break;
+
+ default:
+ gimp_assert_not_reached ();
+ }
+
+ gimp_progress_set_text (progress->progress, format, done);
+ g_free (done);
+
+ gimp_progress_pulse (progress->progress);
+ }
+
+ while (! progress->cancel && g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+}