diff --git a/app/errors.c b/app/errors.c index ec91a435bd..49b23b7a35 100644 --- a/app/errors.c +++ b/app/errors.c @@ -28,11 +28,20 @@ #include #include +#include +#include + #include "libgimpbase/gimpbase.h" #include "core/core-types.h" #include "core/gimp.h" +#include "core/gimpdrawable.h" +#include "core/gimpimage.h" +#include "core/gimpitem.h" +#include "core/gimpparamspecs.h" + +#include "pdb/gimppdb.h" #include "errors.h" @@ -47,6 +56,7 @@ static gboolean use_debug_handler = FALSE; static GimpStackTraceMode stack_trace_mode = GIMP_STACK_TRACE_QUERY; static gchar *full_prog_name = NULL; static gchar *backtrace_file = NULL; +static gchar *backup_path = NULL; /* local function prototypes */ @@ -122,6 +132,12 @@ errors_init (Gimp *gimp, stack_trace_mode = _stack_trace_mode; full_prog_name = g_strdup (_full_prog_name); backtrace_file = g_strdup (_backtrace_file); + backup_path = g_build_filename (gimp_directory (), "backups", NULL); + + g_mkdir_with_parents (backup_path, S_IRUSR | S_IWUSR | S_IXUSR); + g_free (backup_path); + backup_path = g_build_filename (gimp_directory (), "backups", + "backup-XXX.xcf", NULL); for (i = 0; i < G_N_ELEMENTS (log_domains); i++) g_log_set_handler (log_domains[i], @@ -147,6 +163,10 @@ errors_exit (void) if (backtrace_file) g_free (backtrace_file); + if (full_prog_name) + g_free (full_prog_name); + if (backup_path) + g_free (backup_path); } void @@ -234,9 +254,12 @@ gimp_eek (const gchar *reason, const gchar *message, gboolean use_handler) { - GimpCoreConfig *config = the_errors_gimp->config; - GimpDebugPolicy debug_policy; - gboolean eek_handled = FALSE; + GimpCoreConfig *config = the_errors_gimp->config; + gboolean eek_handled = FALSE; + GimpDebugPolicy debug_policy; + GList *iter; + gint num_idx; + gint i = 0; /* GIMP has 2 ways to handle termination signals and fatal errors: one * is the stack trace mode which is set at start as command line @@ -355,5 +378,52 @@ gimp_eek (const gchar *reason, full_prog_name, MB_OK|MB_ICONERROR); #endif + /* Let's try to back-up all unsaved images! + * It is not 100%: when I tested with various bugs created on purpose, + * I had cases where saving failed. I am not sure if this is because + * of some memory management along the way to XCF saving or some other + * messed up state of GIMP, but this is normal not to expect too much + * during a crash. + * Nevertheless in various test cases, I had successful backups XCF of + * the work in progress. Yeah! + */ + + /* The index of 'XXX' in backup_path string. */ + num_idx = strlen (backup_path) - 7; + + iter = gimp_get_image_iter (the_errors_gimp); + for (; iter && i < 1000; iter = iter->next) + { + GimpImage *image = iter->data; + GimpItem *item; + + if (! gimp_image_is_dirty (image)) + continue; + + item = GIMP_ITEM (gimp_image_get_active_drawable (image)); + + /* This is a trick because we want to avoid any memory + * allocation when the process is abnormally terminated. + * We just assume that you'll never have more than 1000 images + * open (which is already far fetched). + */ + backup_path[num_idx + 2] = '0' + (i % 10); + backup_path[num_idx + 1] = '0' + ((i/10) % 10); + backup_path[num_idx] = '0' + ((i/100) % 10); + + /* Saving. */ + gimp_pdb_execute_procedure_by_name (the_errors_gimp->pdb, + gimp_get_user_context (the_errors_gimp), + NULL, NULL, + "gimp-xcf-save", + GIMP_TYPE_INT32, 0, + GIMP_TYPE_IMAGE_ID, gimp_image_get_ID (image), + GIMP_TYPE_DRAWABLE_ID, gimp_item_get_ID (item), + G_TYPE_STRING, backup_path, + G_TYPE_STRING, backup_path, + G_TYPE_NONE); + i++; + } + exit (EXIT_FAILURE); }