1
2
3
4
5
6
7
8
|
=== modified file 'src/main.c'--- src/main.c 2011-03-10 18:14:21 +0000+++ src/main.c 2011-03-10 18:17:31 +0000@@ -60,6 +60,7 @@ // initialize data ui.default_page.bg->canvas_item = NULL; ui.layerbox_length = 0;+ ui.autosave_defers = 0; if (argc > 2 || (argc == 2 && argv[1][0] == '-')) { printf(_("Invalid command line parameters.\n"@@ -271,27 +272,6 @@ init_mru(); - // and finally, open a file specified on the command line- // (moved here because display parameters weren't initialized yet...)- - if (argc == 1) return;- set_cursor_busy(TRUE);- if (g_path_is_absolute(argv[1]))- tmpfn = g_strdup(argv[1]);- else {- tmppath = g_get_current_dir();- tmpfn = g_build_filename(tmppath, argv[1], NULL);- g_free(tmppath);- }- success = open_journal(tmpfn);- g_free(tmpfn);- set_cursor_busy(FALSE);- if (!success) {- w = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,- GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error opening file '%s'"), argv[1]);- gtk_dialog_run(GTK_DIALOG(w));- gtk_widget_destroy(w);- } } @@ -328,6 +308,17 @@ winMain = create_winMain (); init_stuff (argc, argv);++ if (argc <= 1) {+ // if any autosaves have been restored by spawning child processes, we exit+ // this instance of xournal.+ if (check_and_restore_autosaves (argc, argv))+ return 0;+ }+ else+ open_argv_file_or_its_autosave (argc, argv);++ gtk_window_set_icon(GTK_WINDOW(winMain), create_pixbuf("xournal.png")); gtk_main ();@@ -336,6 +327,8 @@ save_mru_list(); if (ui.auto_save_prefs) save_config_to_file();++ clear_autosave_entry(); return 0; }
=== modified file 'src/xo-callbacks.c'--- src/xo-callbacks.c 2011-03-10 18:14:21 +0000+++ src/xo-callbacks.c 2011-03-10 18:17:31 +0000@@ -447,7 +447,7 @@ double tmp_x, tmp_y; gchar *tmpstr; GnomeCanvasGroup *group;- + signal_canvas_changed(); end_text(); if (undo == NULL) return; // nothing to undo! reset_selection(); // safer@@ -662,6 +662,8 @@ gchar *tmpstr; GnomeCanvasGroup *group; + signal_canvas_changed();+ end_text(); if (redo == NULL) return; // nothing to redo! reset_selection(); // safer@@ -864,6 +866,7 @@ on_editCut_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); selection_to_clip(); selection_delete();@@ -874,6 +877,7 @@ on_editCopy_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); selection_to_clip(); }@@ -883,6 +887,7 @@ on_editPaste_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); clipboard_paste(); }@@ -892,6 +897,7 @@ on_editDelete_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); selection_delete(); }@@ -1059,6 +1065,7 @@ { struct Page *pg; + signal_canvas_changed(); end_text(); reset_selection(); pg = new_page(ui.cur_page);@@ -1079,6 +1086,7 @@ { struct Page *pg; + signal_canvas_changed(); end_text(); reset_selection(); pg = new_page(ui.cur_page);@@ -1099,6 +1107,7 @@ { struct Page *pg; + signal_canvas_changed(); end_text(); reset_selection(); pg = new_page((struct Page *)g_list_last(journal.pages)->data);@@ -1120,6 +1129,7 @@ GList *layerlist, *itemlist; struct Layer *l; + signal_canvas_changed(); end_text(); if (journal.npages == 1) return; reset_selection(); @@ -1155,6 +1165,7 @@ { struct Layer *l; + signal_canvas_changed(); end_text(); reset_selection(); l = g_new(struct Layer, 1);@@ -1183,7 +1194,7 @@ gpointer user_data) { GList *list;- + signal_canvas_changed(); end_text(); if (ui.cur_layer == NULL) return; reset_selection();@@ -1307,6 +1318,7 @@ on_papercolorWhite_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_papercolor_activate(menuitem, COLOR_WHITE, predef_bgcolors_rgba[COLOR_WHITE]); }@@ -1316,6 +1328,7 @@ on_papercolorYellow_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_papercolor_activate(menuitem, COLOR_YELLOW, predef_bgcolors_rgba[COLOR_YELLOW]); }@@ -1325,6 +1338,7 @@ on_papercolorPink_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_papercolor_activate(menuitem, COLOR_RED, predef_bgcolors_rgba[COLOR_RED]); }@@ -1334,6 +1348,7 @@ on_papercolorOrange_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_papercolor_activate(menuitem, COLOR_ORANGE, predef_bgcolors_rgba[COLOR_ORANGE]); }@@ -1343,6 +1358,7 @@ on_papercolorBlue_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_papercolor_activate(menuitem, COLOR_BLUE, predef_bgcolors_rgba[COLOR_BLUE]); }@@ -1352,6 +1368,7 @@ on_papercolorGreen_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_papercolor_activate(menuitem, COLOR_GREEN, predef_bgcolors_rgba[COLOR_GREEN]); }@@ -1367,6 +1384,7 @@ guint rgba; GdkColor gdkcolor; + signal_canvas_changed(); end_text(); dialog = gtk_color_selection_dialog_new(_("Pick a Paper Color")); colorsel = GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dialog)->colorsel);@@ -1387,6 +1405,7 @@ on_paperstylePlain_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_paperstyle_activate(menuitem, RULING_NONE); }@@ -1396,6 +1415,7 @@ on_paperstyleLined_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_paperstyle_activate(menuitem, RULING_LINED); }@@ -1405,6 +1425,7 @@ on_paperstyleRuled_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_paperstyle_activate(menuitem, RULING_RULED); }@@ -1414,6 +1435,7 @@ on_paperstyleGraph_activate (GtkMenuItem *menuitem, gpointer user_data) {+ signal_canvas_changed(); end_text(); process_paperstyle_activate(menuitem, RULING_GRAPH); }@@ -1432,6 +1454,7 @@ char *filename; gboolean attach; + signal_canvas_changed(); end_text(); dialog = gtk_file_chooser_dialog_new(_("Open Background"), GTK_WINDOW (winMain), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,@@ -1549,6 +1572,7 @@ { struct Background *bg; + signal_canvas_changed(); end_text(); reset_selection(); gtk_window_iconify(GTK_WINDOW(winMain)); // hide ourselves@@ -1595,7 +1619,7 @@ gpointer user_data) { gboolean active;- + signal_canvas_changed(); end_text(); active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)); if (active == ui.bg_apply_all_pages) return;@@ -1649,6 +1673,7 @@ if (ui.toolno[ui.cur_mapping] == TOOL_PEN) return; ui.cur_mapping = 0; // don't use switch_mapping() (refreshes buttons too soon)+ end_text(); reset_selection(); ui.toolno[ui.cur_mapping] = TOOL_PEN;@@ -2337,7 +2362,7 @@ // abort any page changes pending in the spin button, and take the focus gtk_spin_button_set_value(GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo")), ui.pageno+1); reset_focus();- + signal_canvas_changed(); is_core = (event->device == gdk_device_get_core_pointer()); if (!ui.use_xinput && !is_core) return FALSE; if (ui.use_xinput && is_core && ui.discard_corepointer) return FALSE;@@ -2497,6 +2522,7 @@ gpointer user_data) { gboolean is_core;+ signal_canvas_changed(); #ifdef INPUT_DEBUG printf("DEBUG: ButtonRelease (%s) (x,y)=(%.2f,%.2f), button %d, modifier %x\n", @@ -2558,6 +2584,7 @@ gdk_device_set_mode(dev, GDK_MODE_SCREEN); } }+ //signal_canvas_changed(); return FALSE; } @@ -2580,6 +2607,7 @@ gdk_device_set_mode(dev, GDK_MODE_DISABLED); } }+ signal_canvas_changed(); return FALSE; } @@ -2589,6 +2617,7 @@ GdkEventExpose *event, gpointer user_data) {+ //signal_canvas_changed(); if (ui.view_continuous && ui.progressive_bg) rescale_bg_pixmaps(); return FALSE; }@@ -2685,7 +2714,7 @@ printf("DEBUG: MotionNotify (%s) (x,y)=(%.2f,%.2f), modifier %x\n", is_core?"core":"xinput", event->x, event->y, event->state); #endif- + ui.block_autosave = TRUE; looks_wrong = !(event->state & (1<<(7+ui.which_mouse_button))); if (looks_wrong) { gdk_device_get_state(ui.stroke_device, event->window, NULL, &mask);@@ -2748,6 +2777,7 @@ if (ui.in_update_page_stuff) return; // avoid a bad retroaction + signal_canvas_changed(); end_text(); val = gtk_combo_box_get_active(combobox);@@ -2878,6 +2908,7 @@ if (!GTK_WIDGET_HAS_FOCUS(spinbutton)) gtk_widget_grab_focus(GTK_WIDGET(canvas));+ signal_canvas_changed(); end_text(); val = gtk_spin_button_get_value_as_int(spinbutton) - 1;@@ -2901,6 +2932,7 @@ struct Page *pg; GList *pglist; + signal_canvas_changed(); end_text(); reset_selection(); @@ -2937,6 +2969,7 @@ { if (ui.cur_page->bg->type != BG_SOLID) return; + signal_canvas_changed(); end_text(); prepare_new_undo(); undo->type = ITEM_NEW_DEFAULT_BG;@@ -2960,6 +2993,7 @@ int val; gchar text[20]; + signal_canvas_changed(); if (papersize_need_init) { gtk_combo_box_set_active(combobox, papersize_std); papersize_need_init = FALSE;@@ -2996,6 +3030,7 @@ gchar *ptr; GtkComboBox *comboStdSizes; + signal_canvas_changed(); text = gtk_entry_get_text(GTK_ENTRY(editable)); val = strtod(text, &ptr); papersize_width_valid = (*ptr == 0 && val > 0.);@@ -3018,6 +3053,7 @@ gchar *ptr; GtkComboBox *comboStdSizes; + signal_canvas_changed(); text = gtk_entry_get_text(GTK_ENTRY(editable)); val = strtod(text, &ptr); papersize_height_valid = (*ptr == 0 && val > 0.);@@ -3039,6 +3075,7 @@ int val; gchar text[20]; + signal_canvas_changed(); val = gtk_combo_box_get_active(combobox); if (val == -1 || val == papersize_unit) return; papersize_unit = val;@@ -3094,6 +3131,7 @@ active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)); if (ui.progressive_bg == active) return;+ signal_canvas_changed(); end_text(); ui.progressive_bg = active; if (!ui.progressive_bg) rescale_bg_pixmaps();@@ -3471,6 +3509,7 @@ { gchar *str; + signal_canvas_changed(); str = g_strdup(gtk_font_button_get_font_name(fontbutton)); process_font_sel(str); }@@ -3528,6 +3567,16 @@ } void+on_optionsEnableAutoSave_activate (GtkMenuItem *menuitem,+ gpointer user_data)+{+ end_text();+ + ui.enable_autosave = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem));+}+++void on_optionsPressureSensitive_activate (GtkMenuItem *menuitem, gpointer user_data) {@@ -3540,6 +3589,19 @@ update_mappings_menu(); } +gboolean+on_autosave_activate_deferred (gpointer user_data)+{+ gchar *name;+ // autosaves are not allowed; usually this is because there is a pen+ // stroke or it's during an interval after a stroke+ if (ui.autosave_defers-- != 1) return FALSE;+ if (ui.block_autosave) return FALSE;+ name = get_autosave_filename();+ save_journal(name);+ g_free(name);+ return FALSE;+} void on_buttonColorChooser_set (GtkColorButton *colorbutton,
=== modified file 'src/xo-callbacks.h'--- src/xo-callbacks.h 2011-03-10 18:14:21 +0000+++ src/xo-callbacks.h 2011-03-10 18:17:31 +0000@@ -617,6 +617,9 @@ on_optionsAutoSavePrefs_activate (GtkMenuItem *menuitem, gpointer user_data); +gboolean+on_autosave_activate_deferred (gpointer user_data);+ void on_toolsReco_activate (GtkMenuItem *menuitem, gpointer user_data);
=== modified file 'src/xo-file.c'--- src/xo-file.c 2011-03-10 18:14:21 +0000+++ src/xo-file.c 2011-03-10 18:17:31 +0000@@ -1270,6 +1270,10 @@ void new_mru_entry(char *name) { int i, j;++ // do not add autosave files to the mru list+ if (g_str_has_suffix (name, AUTOSAVE_SUFFIX))+ return; for (i=0;i<MRU_SIZE;i++) if (ui.mru[i]!=NULL && !strcmp(ui.mru[i], name)) {@@ -1343,6 +1347,7 @@ ui.pressure_sensitivity = FALSE; ui.width_minimum_multiplier = 0.0; ui.width_maximum_multiplier = 1.25;+ ui.enable_autosave = TRUE; ui.button_switch_mapping = FALSE; ui.autoload_pdf_xoj = FALSE; @@ -1513,7 +1518,9 @@ update_keyval("general", "autosave_prefs", _(" auto-save preferences on exit (true/false)"), g_strdup(ui.auto_save_prefs?"true":"false"));-+ update_keyval("general", "enable_autosave",+ _(" automatically save documents for crash recovery"),+ g_strdup(ui.enable_autosave?"true":"false")); update_keyval("paper", "width", _(" the default page width, in points (1/72 in)"), g_strdup_printf("%.2f", ui.default_page.width));@@ -1877,7 +1884,7 @@ if (str!=NULL) { g_free(ui.shorten_menu_items); ui.shorten_menu_items = str; } parse_keyval_float("general", "highlighter_opacity", &ui.hiliter_opacity, 0., 1.); parse_keyval_boolean("general", "autosave_prefs", &ui.auto_save_prefs);- + parse_keyval_boolean("general", "enable_autosave", &ui.enable_autosave); parse_keyval_float("paper", "width", &ui.default_page.width, 1., 5000.); parse_keyval_float("paper", "height", &ui.default_page.height, 1., 5000.); parse_keyval_enum_color("paper", "color", @@ -1952,3 +1959,289 @@ parse_keyval_float("tools", "default_font_size", &ui.default_font_size, 1., 200.); #endif }++gchar *autosave_filename=NULL;++void+set_autosave_filename(gchar *fn)+{+ if (autosave_filename)+ g_free (autosave_filename);+ + autosave_filename = g_strdup(fn);++ // make an entry in ~/.xournal/autosaves+ gchar *autosave_table_dir = g_build_filename(g_get_home_dir(), CONFIG_DIR,+ AUTOSAVES_DIR,+ NULL);+ if(!g_file_test(autosave_table_dir, G_FILE_TEST_EXISTS))+ g_mkdir(autosave_table_dir,0755);++ gint pid = getpid();+ gchar *pid_str = g_strdup_printf("%d", pid);+ gchar *autosave_table_entry_filename = g_build_filename(autosave_table_dir,+ pid_str,+ NULL);+ g_free(pid_str);+ g_free(autosave_table_dir);++ g_file_set_contents(autosave_table_entry_filename, fn, -1, NULL);++ g_free(autosave_table_entry_filename);+}++gchar*+get_autosave_filename()+{+ gchar *default_basename;+ gchar *retval = NULL;+ if(ui.filename == NULL) {+ if(autosave_filename == NULL) { + /* if the file has not been saved yet, make a generic autosave name+ in the user's homedir */+ default_basename = g_strdup_printf("xournal-%d.xoj%s", getpid(), AUTOSAVE_SUFFIX, NULL);+ retval = g_build_filename(g_get_home_dir(), default_basename, NULL); + g_free(default_basename);+ set_autosave_filename(retval);+ }+ else+ /* return this generic name if it has already been generated */+ retval = g_strdup(autosave_filename);+ } else {+ /* use the filename with .autosave~ suffix if the file has been saved */+ if(autosave_filename != NULL)+ // remove the "generic" autosave in the homedir+ g_unlink(autosave_filename);+ retval = g_strconcat(ui.filename, AUTOSAVE_SUFFIX, NULL);+ set_autosave_filename(retval);+ }+ return retval;+}++void clear_autosave_entry() {+ // remove our entry in ~/.xournal/autosaves+ gchar *autosave_table_dir = g_build_filename(g_get_home_dir(), CONFIG_DIR,+ AUTOSAVES_DIR,+ NULL);+ gint pid = getpid();+ gchar *pid_str = g_strdup_printf("%d", pid);+ gchar *autosave_table_entry_filename = g_build_filename(autosave_table_dir,+ pid_str,+ NULL);+ g_free(pid_str);+ g_free(autosave_table_dir);++ g_unlink(autosave_table_entry_filename);++ g_free(autosave_table_entry_filename);++}++void clear_autosave_entry_by_contents(char *contents) {+ gchar *autosave_table_dir = g_build_filename(g_get_home_dir(), CONFIG_DIR,+ AUTOSAVES_DIR,+ NULL);+ GDir *dir = g_dir_open (autosave_table_dir, 0, NULL);+ const gchar *filename;+ while (filename = g_dir_read_name (dir) ) {+ gchar *full_filename = g_build_filename(autosave_table_dir, filename, NULL);+ gchar *autosave_filename;+ if (g_file_get_contents (full_filename, &autosave_filename, NULL, NULL) ) {+ if(g_strcmp0(autosave_filename, contents) == 0)+ g_unlink(full_filename);+ }+ g_free(full_filename);+ g_free(autosave_filename);+ }+ g_dir_close(dir);+ g_free(autosave_table_dir);+}++// return value: TRUE if any autosaves have been restored by spawning child+// processes. In this case, this instance of xournal should exit.+gboolean check_and_restore_autosaves(int argc, char *argv[]) {+ // check whether ~/.xournal/autosaves contains any entries which have+ // process ids that currently do not correspond to a xournal pid.++ gchar *autosave_table_dir = g_build_filename(g_get_home_dir(), CONFIG_DIR,+ AUTOSAVES_DIR,+ NULL);+ GDir *dir = g_dir_open (autosave_table_dir, 0, NULL);++ // get all PIDs that currently belong to xournal+ gchar *current_pids;+ g_spawn_command_line_sync ("pidof xournal", ¤t_pids, NULL, NULL, NULL);++ GList *autosave_filenames = NULL;++ const gchar *filename;+ while (filename = g_dir_read_name (dir) ) {+ // check if any of the filenames are not currently xournal PIDs+ if(g_strstr_len (current_pids,-1, filename) == NULL) {+ // if so, open the file. Its contents should be the name of an autosave filename+ gchar *full_filename = g_build_filename(autosave_table_dir, filename, NULL);+ gchar *autosave_filename;+ if (g_file_get_contents (full_filename, &autosave_filename, NULL, NULL) ) {+ // delete the entry in ~/.xournal/autosaves+ g_unlink(full_filename);+ // if the file exists, add the filename to the list+ if (g_file_test (autosave_filename, G_FILE_TEST_EXISTS))+ autosave_filenames = g_list_prepend(autosave_filenames, autosave_filename);+ }+ g_free(full_filename);+ }+ }+ g_free (current_pids);+ g_free(autosave_table_dir);+ g_dir_close (dir);++ // ask user's confirmation before loading+ gint autosave_count = g_list_length(autosave_filenames);+ if(autosave_count != 0) {+ GtkWidget *w = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,+ _("Found %d autosave file(s). Do you want to recover these files?"), autosave_count);+ gtk_dialog_add_buttons(GTK_DIALOG(w), _("Recover"), 0, _("Delete"), 1, NULL);+ gint result = gtk_dialog_run(GTK_DIALOG(w));+ gtk_widget_destroy(w);+ if (result == 0) {+ // spawn all child processes+ GList *iter;+ for(iter = g_list_first(autosave_filenames); + iter;+ iter = iter->next) {+ + gchar *cmdline = g_strconcat(argv[0], " "", iter->data, """, NULL);+ g_spawn_command_line_async(cmdline, NULL);+ g_free(cmdline);+ g_free(iter->data);+ }+ g_list_free(autosave_filenames);+ return TRUE;+ }+ else if (result == 1) {+ GList *iter;+ for(iter = g_list_first(autosave_filenames); + iter;+ iter = iter->next) {+ g_unlink(iter->data);+ g_free(iter->data);+ + }+ }+ }+ g_list_free(autosave_filenames);+ return FALSE;+}++void open_file_and_autosave (gchar *filename, gchar *autosavename)+{+ int success;+ GtkWidget *w;++ set_cursor_busy (TRUE);+ if (autosavename)+ success = open_journal (autosavename);+ else+ success = open_journal (filename);+ signal_canvas_changed ();+ set_cursor_busy (FALSE);+ + if (!success) {+ if(autosavename)+ w = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error opening file '%s'"), autosavename);+ else+ w = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error opening file '%s'"), filename);+ + gtk_dialog_run(GTK_DIALOG(w));+ gtk_widget_destroy(w);+ } else {+ update_file_name(g_strdup(filename));+ if(autosavename) {+ set_autosave_filename(autosavename);+ ui.saved=FALSE;+ }+ else+ ui.saved=TRUE; + }+}++void open_argv_file_or_its_autosave (int argc, char *argv[])+{+ gchar *tmpfn, *tmppath, *tmpautofn;+ int success;+ GtkWidget *w;+ + if(argc<=1) return;++ // make an absolute path+ if (g_path_is_absolute(argv[1]))+ tmpfn = g_strdup(argv[1]);+ else {+ tmppath = g_get_current_dir();+ tmpfn = g_build_filename(tmppath, argv[1], NULL);+ g_free(tmppath);+ }+ /* check if the argument is an autosave file. If it is, this instance of xournal+ was probably spawned by check_and_restore_autosaves() and we do not have to+ ask for user's confirmation */+ if (g_str_has_suffix (tmpfn, AUTOSAVE_SUFFIX)) {+ tmpautofn = g_strdup(tmpfn);+ g_strrstr(tmpfn, AUTOSAVE_SUFFIX)[0] = 0;+ // check if the autosave comes with an 'official' saved version+ if (!g_file_test (tmpfn, G_FILE_TEST_EXISTS)) {+ g_free(tmpfn);+ tmpfn = NULL;+ }+ } else {+ // if it is not, we check if an autosave of this file exists+ tmpautofn = g_strconcat(tmpfn, AUTOSAVE_SUFFIX, NULL);+ if (g_file_test (tmpautofn, G_FILE_TEST_EXISTS)) {+ // we only want to load the autosave file if it is newer+ GFile *tmp = g_file_new_for_path(tmpfn);+ GFile *tmpauto = g_file_new_for_path(tmpautofn);+ GFileInfo *tmp_info = g_file_query_info(tmp, G_FILE_ATTRIBUTE_TIME_MODIFIED,+ 0, NULL, NULL);+ GFileInfo *tmpauto_info = g_file_query_info(tmpauto, G_FILE_ATTRIBUTE_TIME_MODIFIED,+ 0, NULL, NULL);+ + guint64 tmptime = g_file_info_get_attribute_uint64(tmp_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);+ guint64 tmpautotime = g_file_info_get_attribute_uint64(tmpauto_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);+ g_object_unref(tmp_info);+ g_object_unref(tmpauto_info);+ g_object_unref(tmp);+ g_object_unref(tmpauto);+ if(tmptime < tmpautotime) {+ // take ownership of this autosave+ clear_autosave_entry_by_contents(tmpautofn);++ // ask user's confirmation before loading+ w = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,+ _("Found an autosave file for '%s'. Do you want to recover this file?"), tmpfn);+ gtk_dialog_add_buttons(GTK_DIALOG(w), _("Recover"), 0, _("Delete"), 1, NULL);+ gint result = gtk_dialog_run(GTK_DIALOG(w));+ gtk_widget_destroy(w);+ if (result == 1) {+ // otherwise, delete the autosave+ g_unlink(tmpautofn);+ g_free(tmpautofn);+ tmpautofn = NULL;+ }+ } else {+ // if the autosave file is older, then we should just delete the autosave+ g_unlink(tmpautofn);+ g_free(tmpautofn);+ tmpautofn = NULL;+ }+ } else {+ // if it does not exist, there is no autosave to load+ g_free(tmpautofn);+ tmpautofn = NULL;+ }+ }++ open_file_and_autosave(tmpfn, tmpautofn);+ g_free(tmpfn);+ g_free(tmpautofn);+}
=== modified file 'src/xo-file.h'--- src/xo-file.h 2011-03-10 18:14:21 +0000+++ src/xo-file.h 2011-03-10 18:17:31 +0000@@ -36,3 +36,8 @@ void init_config_default(void); void load_config_from_file(void); void save_config_to_file(void);++gchar* get_autosave_filename(void);+void clear_autosave_entry(void);+gboolean check_and_restore_autosaves(int argc, char *argv[]);+void open_argv_file_or_its_autosave(int argc, char *argv[]);\ No newline at end of file
=== modified file 'src/xo-misc.c'--- src/xo-misc.c 2011-03-10 18:14:21 +0000+++ src/xo-misc.c 2011-03-10 18:17:31 +0000@@ -1658,7 +1658,11 @@ GtkWidget *dialog; GtkResponseType response; - if (ui.saved) return TRUE;+ if (ui.saved)+ {+ g_unlink(get_autosave_filename());+ return TRUE;+ } dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Save changes to '%s'?"), (ui.filename!=NULL) ? ui.filename:_("Untitled"));@@ -1671,6 +1675,7 @@ on_fileSave_activate(NULL, NULL); if (!ui.saved) return FALSE; // if save failed, then we abort }+ g_unlink(get_autosave_filename()); return TRUE; } @@ -2176,3 +2181,28 @@ if(GTK_IS_CONTAINER(w)) gtk_container_forall(GTK_CONTAINER(w), install_focus_hooks, data); }++// This function should be called at the beginning of pertinent event handlers.+// If Xournal ever becomes multithreaded, note that we assume 2 seconds is long+// enough for the event handler to do what needs to get done--if this is not+// acceptable you will need to split it up into two functions, the increment+// done at the beginning of the event handler and the registration of the callback+// at the end.+void signal_canvas_changed(void)+{+ if (ui.enable_autosave) {+ ui.block_autosave = FALSE;+ ui.autosave_defers++;++ // If there were no deferrals in the last two seconds:+ // ui.autosave_defers == 1+ // Otherwise,+ // ui.autosave_defers == 1 number of deferrals+ // If no deferrals occur in the next two seconds, ui.autosave_defers+ // will equal 1 again.+ // ui.autosave_defers == 0+ // indicates there are no deferred autosaves pending++ g_timeout_add_seconds(2, on_autosave_activate_deferred, NULL);+ }+}
=== modified file 'src/xo-misc.h'--- src/xo-misc.h 2011-03-10 18:14:21 +0000+++ src/xo-misc.h 2011-03-10 18:17:31 +0000@@ -94,6 +94,7 @@ gboolean is_event_within_textview(GdkEventButton *event); void hide_unimplemented(void);+void signal_canvas_changed(void); void do_fullscreen(gboolean active);
=== modified file 'src/xournal.h'--- src/xournal.h 2011-03-10 18:14:21 +0000+++ src/xournal.h 2011-03-10 18:17:31 +0000@@ -23,6 +23,8 @@ #define MRU_FILE "recent-files" #define MRU_SIZE 8 #define CONFIG_FILE "config"+#define AUTOSAVES_DIR "autosaves"+#define AUTOSAVE_SUFFIX ".autosave~" // DATA STRUCTURES AND CONSTANTS @@ -282,6 +284,9 @@ gboolean shorten_menus; // shorten menus ? gchar *shorten_menu_items; // which items to hide gboolean is_sel_cursor; // displaying a selection-related cursor+ gboolean enable_autosave; // whether or not autosave is allowed+ guint autosave_defers; // number of stacked deferrals+ gboolean block_autosave; // block autosave from occurring when true #if GTK_CHECK_VERSION(2,10,0) GtkPrintSettings *print_settings; #endif
|