[gimp] app: output a dialog to recover images salvaged after a crash.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: output a dialog to recover images salvaged after a crash.
- Date: Fri, 23 Mar 2018 00:02:38 +0000 (UTC)
commit 25af765fe656c2757ac86fc9dab7b09166ec1a1b
Author: Jehan <jehan girinstud io>
Date: Thu Mar 22 19:29:35 2018 +0100
app: output a dialog to recover images salvaged after a crash.
Since commit d916fedf92, GIMP has had the hidden feature to salvage
images (if possible) during a crash into a backup folder. This commit
finishes the feature by opening a dialog proposing to try and recover
the salvaged images.
This is not perfect yet since it doesn't "remember" the XCF path (in
case it was a previously saved image). The images open as new unsaved
and dirty images, but directly from the contents at crash time. For now,
it is up to people to figure out what they correspond to, if relevant.
app/app.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
app/errors.c | 41 ++++++++++++++++++++++++++++++++++++++
app/errors.h | 20 ++++++++++--------
app/gui/gui.c | 45 ++++++++++++++++++++++++++++++++++++++++++
app/gui/gui.h | 1 +
5 files changed, 156 insertions(+), 11 deletions(-)
---
diff --git a/app/app.c b/app/app.c
index 2bc6f68..d7a7f76 100644
--- a/app/app.c
+++ b/app/app.c
@@ -30,9 +30,12 @@
#include <unistd.h>
#endif
+#include <glib/gstdio.h>
#include <gio/gio.h>
#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
#ifdef G_OS_WIN32
#include <windows.h>
#include <winnls.h>
@@ -53,6 +56,7 @@
#include "core/gimp.h"
#include "core/gimp-batch.h"
#include "core/gimp-user-install.h"
+#include "core/gimpimage.h"
#include "file/file-open.h"
@@ -330,8 +334,60 @@ app_run (const gchar *full_prog_name,
G_CALLBACK (app_exit_after_callback),
&run_loop);
- /* Load the images given on the command-line.
- */
+#ifndef GIMP_CONSOLE_COMPILATION
+ if (run_loop && ! no_interface)
+ {
+ /* Before opening images from command line, check for salvaged images
+ * and query interactively to know if we should recover or discard
+ * them.
+ */
+ GList *recovered_files;
+ GList *iter;
+
+ recovered_files = errors_recovered ();
+ if (recovered_files &&
+ gui_recover (g_list_length (recovered_files)))
+ {
+ for (iter = recovered_files; iter; iter = iter->next)
+ {
+ GFile *file;
+ GimpImage *image;
+ GError *error = NULL;
+ GimpPDBStatusType status;
+
+ file = g_file_new_for_path (iter->data);
+ image = file_open_with_display (gimp,
+ gimp_get_user_context (gimp),
+ NULL,
+ file, as_new,
+ initial_screen,
+ initial_monitor,
+ &status, &error);
+ if (image)
+ {
+ /* Break ties with the backup directory. */
+ gimp_image_set_file (image, NULL);
+ /* One of the rare exceptions where we should call
+ * gimp_image_dirty() directly instead of creating
+ * an undo. We want the image to be dirty from
+ * scratch, without anything to undo.
+ */
+ gimp_image_dirty (image, GIMP_DIRTY_IMAGE);
+ }
+
+ g_object_unref (file);
+ }
+ }
+ /* Delete backup XCF images. */
+ for (iter = recovered_files; iter; iter = iter->next)
+ {
+ g_unlink (iter->data);
+ }
+ g_list_free_full (recovered_files, g_free);
+ }
+#endif
+
+ /* Load the images given on the command-line. */
if (filenames)
{
gint i;
diff --git a/app/errors.c b/app/errors.c
index 930b627..6d63b2d 100644
--- a/app/errors.c
+++ b/app/errors.c
@@ -175,6 +175,47 @@ errors_exit (void)
g_free (backup_path);
}
+GList *
+errors_recovered (void)
+{
+ GList *recovered = NULL;
+ gchar *backup_path = g_build_filename (gimp_directory (), "backups", NULL);
+ GDir *backup_dir = NULL;
+
+ if ((backup_dir = g_dir_open (backup_path, 0, NULL)))
+ {
+ const gchar *file;
+
+ while ((file = g_dir_read_name (backup_dir)))
+ {
+ if (g_str_has_suffix (file, ".xcf"))
+ {
+ gchar *path = g_build_filename (backup_path, file, NULL);
+
+ if (g_file_test (path, G_FILE_TEST_IS_REGULAR) &&
+ ! g_file_test (path, G_FILE_TEST_IS_SYMLINK))
+ {
+ /* A quick basic security check. It is not foolproof,
+ * but better than nothing to make sure we are not
+ * trying to read, then delete a folder or a symlink
+ * to a file outside the backup directory.
+ */
+ recovered = g_list_append (recovered, path);
+ }
+ else
+ {
+ g_free (path);
+ }
+ }
+ }
+
+ g_dir_close (backup_dir);
+ }
+ g_free (backup_path);
+
+ return recovered;
+}
+
void
gimp_fatal_error (const gchar *message)
{
diff --git a/app/errors.h b/app/errors.h
index 18c8e2c..76804cf 100644
--- a/app/errors.h
+++ b/app/errors.h
@@ -23,15 +23,17 @@
#endif
-void errors_init (Gimp *gimp,
- const gchar *full_prog_name,
- gboolean use_debug_handler,
- GimpStackTraceMode stack_trace_mode,
- const gchar *backtrace_file);
-void errors_exit (void);
-
-void gimp_fatal_error (const gchar *message) G_GNUC_NORETURN;
-void gimp_terminate (const gchar *message) G_GNUC_NORETURN;
+void errors_init (Gimp *gimp,
+ const gchar *full_prog_name,
+ gboolean use_debug_handler,
+ GimpStackTraceMode stack_trace_mode,
+ const gchar *backtrace_file);
+void errors_exit (void);
+
+GList * errors_recovered (void);
+
+void gimp_fatal_error (const gchar *message) G_GNUC_NORETURN;
+void gimp_terminate (const gchar *message) G_GNUC_NORETURN;
#endif /* __ERRORS_H__ */
diff --git a/app/gui/gui.c b/app/gui/gui.c
index 26afcbd..9d0a207 100644
--- a/app/gui/gui.c
+++ b/app/gui/gui.c
@@ -307,6 +307,51 @@ gui_init (Gimp *gimp,
return status_callback;
}
+/*
+ * gui_recover:
+ * @n_recoveries: number of recovered files.
+ *
+ * Query the user interactively if files were saved from a previous
+ * crash, asking whether to try and recover or discard them.
+ *
+ * Returns: TRUE if answer is to try and recover, FALSE otherwise.
+ */
+gboolean
+gui_recover (gint n_recoveries)
+{
+ GtkWidget *dialog;
+ GtkWidget *box;
+ gboolean recover;
+
+ dialog = gimp_dialog_new (_("Images recovery"), "gimp-recovery",
+ NULL, GTK_DIALOG_MODAL, NULL, NULL,
+ _("_Discard"), GTK_RESPONSE_CANCEL,
+ _("_Recover"), GTK_RESPONSE_OK,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK);
+
+ box = gimp_message_box_new (GIMP_ICON_WILBER_EEK);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+ box, TRUE, TRUE, 0);
+ gtk_widget_show (box);
+
+ gimp_message_box_set_primary_text (GIMP_MESSAGE_BOX (box),
+ _("Eeek! It looks like GIMP recovered from a crash!"));
+
+ gimp_message_box_set_text (GIMP_MESSAGE_BOX (box),
+ ngettext ("An image was salvaged from the crash. "
+ "Do you want to try and recover it?",
+ "%d images were salvaged from the crash. "
+ "Do you want to try and recover them?",
+ n_recoveries), n_recoveries);
+
+ recover = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+ gtk_widget_destroy (dialog);
+
+ return recover;
+}
+
gint
gui_get_initial_monitor (Gimp *gimp,
GdkScreen **screen)
diff --git a/app/gui/gui.h b/app/gui/gui.h
index bed7c47..82a0295 100644
--- a/app/gui/gui.h
+++ b/app/gui/gui.h
@@ -25,5 +25,6 @@ void gui_abort (const gchar *abort_message);
GimpInitStatusFunc gui_init (Gimp *gimp,
gboolean no_splash);
+gboolean gui_recover (gint n_recoveries);
#endif /* __GUI_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]