LEFT | RIGHT |
1 /* | 1 /* |
| 2 * $Id$ |
| 3 * |
2 * ***** BEGIN GPL LICENSE BLOCK ***** | 4 * ***** BEGIN GPL LICENSE BLOCK ***** |
3 * | 5 * |
4 * This program is free software; you can redistribute it and/or | 6 * This program is free software; you can redistribute it and/or |
5 * modify it under the terms of the GNU General Public License | 7 * modify it under the terms of the GNU General Public License |
6 * as published by the Free Software Foundation; either version 2 | 8 * as published by the Free Software Foundation; either version 2 |
7 * of the License, or (at your option) any later version. | 9 * of the License, or (at your option) any later version. |
8 * | 10 * |
9 * This program is distributed in the hope that it will be useful, | 11 * This program is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
(...skipping 12 matching lines...) Expand all Loading... |
24 * | 26 * |
25 * ***** END GPL LICENSE BLOCK ***** | 27 * ***** END GPL LICENSE BLOCK ***** |
26 */ | 28 */ |
27 | 29 |
28 /** \file blender/blenkernel/intern/blender.c | 30 /** \file blender/blenkernel/intern/blender.c |
29 * \ingroup bke | 31 * \ingroup bke |
30 */ | 32 */ |
31 | 33 |
32 | 34 |
33 #ifndef _WIN32· | 35 #ifndef _WIN32· |
34 # include <unistd.h> // for read close | 36 » #include <unistd.h> // for read close |
35 #else | 37 #else |
36 # include <io.h> // for open close read | 38 » #include <io.h> // for open close read |
37 # define open _open | 39 » #define open _open |
38 # define read _read | 40 » #define read _read |
39 # define close _close | 41 » #define close _close |
40 # define write _write | 42 » #define write _write |
41 #endif | 43 #endif |
42 | 44 |
43 #include <stdlib.h> | 45 #include <stdlib.h> |
44 #include <stdio.h> | 46 #include <stdio.h> |
45 #include <stddef.h> | 47 #include <stddef.h> |
46 #include <string.h> | 48 #include <string.h> |
47 #include <fcntl.h> /* for open */ | 49 #include <fcntl.h> // for open |
48 #include <errno.h> | |
49 | 50 |
50 #include "MEM_guardedalloc.h" | 51 #include "MEM_guardedalloc.h" |
51 | 52 |
52 #include "DNA_userdef_types.h" | 53 #include "DNA_userdef_types.h" |
53 #include "DNA_scene_types.h" | 54 #include "DNA_scene_types.h" |
54 #include "DNA_screen_types.h" | 55 #include "DNA_screen_types.h" |
55 #include "DNA_sequence_types.h" | 56 #include "DNA_sequence_types.h" |
56 #include "DNA_sound_types.h" | 57 #include "DNA_sound_types.h" |
57 #include "DNA_windowmanager_types.h" | |
58 | 58 |
59 #include "BLI_blenlib.h" | 59 #include "BLI_blenlib.h" |
| 60 #include "BLI_bpath.h" |
60 #include "BLI_dynstr.h" | 61 #include "BLI_dynstr.h" |
| 62 #include "BLI_path_util.h" |
61 #include "BLI_utildefines.h" | 63 #include "BLI_utildefines.h" |
62 #include "BLI_callbacks.h" | 64 #include "BLI_callbacks.h" |
63 | 65 |
64 #include "IMB_imbuf.h" | 66 #include "IMB_imbuf.h" |
65 #include "IMB_moviecache.h" | 67 #include "IMB_moviecache.h" |
66 | 68 |
67 #include "BKE_blender.h" | 69 #include "BKE_blender.h" |
68 #include "BKE_bpath.h" | |
69 #include "BKE_brush.h" | |
70 #include "BKE_context.h" | 70 #include "BKE_context.h" |
71 #include "BKE_depsgraph.h" | 71 #include "BKE_depsgraph.h" |
72 #include "BKE_displist.h" | 72 #include "BKE_displist.h" |
73 #include "BKE_global.h" | 73 #include "BKE_global.h" |
74 #include "BKE_idprop.h" | 74 #include "BKE_idprop.h" |
75 #include "BKE_image.h" | |
76 #include "BKE_ipo.h" | 75 #include "BKE_ipo.h" |
77 #include "BKE_library.h" | 76 #include "BKE_library.h" |
78 #include "BKE_main.h" | 77 #include "BKE_main.h" |
79 #include "BKE_node.h" | 78 #include "BKE_node.h" |
| 79 #include "BKE_report.h" |
| 80 #include "BKE_scene.h" |
80 #include "BKE_screen.h" | 81 #include "BKE_screen.h" |
81 #include "BKE_sequencer.h" | 82 #include "BKE_sequencer.h" |
82 #include "BKE_sound.h" | 83 #include "BKE_sound.h" |
83 | 84 |
84 | 85 |
85 #include "BLO_undofile.h" | 86 #include "BLO_undofile.h" |
| 87 #include "BLO_readfile.h"· |
| 88 #include "BLO_writefile.h"· |
| 89 |
| 90 #include "BKE_utildefines.h" |
| 91 |
| 92 #include "RNA_access.h" |
| 93 |
| 94 #include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove
asap, elubie |
| 95 |
| 96 Global G; |
| 97 UserDef U; |
| 98 /* ListBase = {NULL, NULL}; */ |
| 99 |
| 100 char versionstr[48]= ""; |
| 101 |
| 102 /* ********** free ********** */ |
| 103 |
| 104 /* only to be called on exit blender */ |
| 105 void free_blender(void) |
| 106 { |
| 107 /* samples are in a global list..., also sets G.main->sound->sample NULL
*/ |
| 108 free_main(G.main); |
| 109 G.main= NULL; |
| 110 |
| 111 BKE_spacetypes_free(); /* after free main, it uses space callba
cks */ |
| 112 ········ |
| 113 IMB_exit(); |
| 114 |
| 115 BLI_cb_finalize(); |
| 116 |
| 117 seq_stripelem_cache_destruct(); |
| 118 IMB_moviecache_destruct(); |
| 119 ········ |
| 120 free_nodesystem();······ |
| 121 } |
| 122 |
| 123 void initglobals(void) |
| 124 { |
| 125 memset(&G, 0, sizeof(Global)); |
| 126 ········ |
| 127 U.savetime= 1; |
| 128 |
| 129 G.main= MEM_callocN(sizeof(Main), "initglobals"); |
| 130 |
| 131 strcpy(G.ima, "//"); |
| 132 |
| 133 if(BLENDER_SUBVERSION) |
| 134 BLI_snprintf(versionstr, sizeof(versionstr), "blender.org %d.%d"
, BLENDER_VERSION, BLENDER_SUBVERSION); |
| 135 else |
| 136 BLI_snprintf(versionstr, sizeof(versionstr), "blender.org %d", B
LENDER_VERSION); |
| 137 |
| 138 #ifdef _WIN32 // FULLSCREEN |
| 139 G.windowstate = G_WINDOWSTATE_USERDEF; |
| 140 #endif |
| 141 |
| 142 G.charstart = 0x0000; |
| 143 G.charmin = 0x0000; |
| 144 G.charmax = 0xffff; |
| 145 |
| 146 #ifndef WITH_PYTHON_SECURITY /* default */ |
| 147 G.f |= G_SCRIPT_AUTOEXEC; |
| 148 #else |
| 149 G.f &= ~G_SCRIPT_AUTOEXEC; |
| 150 #endif |
| 151 } |
| 152 |
| 153 /***/ |
| 154 |
| 155 static void clear_global(void)· |
| 156 { |
| 157 // extern short winqueue_break; /* screen.c */ |
| 158 |
| 159 free_main(G.main); /* free all lib data */ |
| 160 ········ |
| 161 // free_vertexpaint(); |
| 162 |
| 163 G.main= NULL; |
| 164 } |
| 165 |
| 166 /* make sure path names are correct for OS */ |
| 167 static void clean_paths(Main *main) |
| 168 { |
| 169 struct BPathIterator *bpi; |
| 170 char filepath_expanded[1024]; |
| 171 Scene *scene; |
| 172 |
| 173 for(BLI_bpathIterator_init(&bpi, main, main->name, BPATH_USE_PACKED); !B
LI_bpathIterator_isDone(bpi); BLI_bpathIterator_step(bpi)) { |
| 174 BLI_bpathIterator_getPath(bpi, filepath_expanded); |
| 175 |
| 176 BLI_clean(filepath_expanded); |
| 177 |
| 178 BLI_bpathIterator_setPath(bpi, filepath_expanded); |
| 179 } |
| 180 |
| 181 BLI_bpathIterator_free(bpi); |
| 182 |
| 183 for(scene= main->scene.first; scene; scene= scene->id.next) { |
| 184 BLI_clean(scene->r.pic); |
| 185 } |
| 186 } |
| 187 |
| 188 /* context matching */ |
| 189 /* handle no-ui case */ |
| 190 |
| 191 /* note, this is called on Undo so any slow conversion functions here |
| 192 * should be avoided or check (mode!='u') */ |
| 193 |
| 194 static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
) |
| 195 { |
| 196 bScreen *curscreen= NULL; |
| 197 Scene *curscene= NULL; |
| 198 int recover; |
| 199 char mode; |
| 200 |
| 201 /* 'u' = undo save, 'n' = no UI load */ |
| 202 if(bfd->main->screen.first==NULL) mode= 'u'; |
| 203 else if(G.fileflags & G_FILE_NO_UI) mode= 'n'; |
| 204 else mode= 0; |
| 205 |
| 206 recover= (G.fileflags & G_FILE_RECOVER); |
| 207 |
| 208 /* Only make filepaths compatible when loading for real (not undo) */ |
| 209 if(mode != 'u') { |
| 210 clean_paths(bfd->main); |
| 211 } |
| 212 |
| 213 /* XXX here the complex windowmanager matching */ |
| 214 ········ |
| 215 /* no load screens? */ |
| 216 if(mode) { |
| 217 /* comes from readfile.c */ |
| 218 extern void lib_link_screen_restore(Main *, bScreen *, Scene *); |
| 219 ················ |
| 220 SWAP(ListBase, G.main->wm, bfd->main->wm); |
| 221 SWAP(ListBase, G.main->screen, bfd->main->screen); |
| 222 SWAP(ListBase, G.main->script, bfd->main->script); |
| 223 ················ |
| 224 /* we re-use current screen */ |
| 225 curscreen= CTX_wm_screen(C); |
| 226 /* but use new Scene pointer */ |
| 227 curscene= bfd->curscene; |
| 228 if(curscene==NULL) curscene= bfd->main->scene.first; |
| 229 /* and we enforce curscene to be in current screen */ |
| 230 if(curscreen) curscreen->scene= curscene; /* can run in bgmode *
/ |
| 231 |
| 232 /* clear_global will free G.main, here we can still restore poin
ters */ |
| 233 lib_link_screen_restore(bfd->main, curscreen, curscene); |
| 234 } |
| 235 ········ |
| 236 /* free G.main Main database */ |
| 237 // CTX_wm_manager_set(C, NULL); |
| 238 clear_global();· |
| 239 ········ |
| 240 /* clear old property update cache, in case some old references are left
dangling */ |
| 241 RNA_property_update_cache_free(); |
| 242 ········ |
| 243 G.main= bfd->main; |
| 244 |
| 245 CTX_data_main_set(C, G.main); |
| 246 |
| 247 sound_init_main(G.main); |
| 248 ········ |
| 249 if (bfd->user) { |
| 250 ················ |
| 251 /* only here free userdef themes... */ |
| 252 BKE_userdef_free(); |
| 253 ················ |
| 254 U= *bfd->user; |
| 255 MEM_freeN(bfd->user); |
| 256 } |
| 257 ········ |
| 258 /* case G_FILE_NO_UI or no screens in file */ |
| 259 if(mode) { |
| 260 /* leave entire context further unaltered? */ |
| 261 CTX_data_scene_set(C, curscene); |
| 262 } |
| 263 else { |
| 264 G.winpos= bfd->winpos; |
| 265 G.displaymode= bfd->displaymode; |
| 266 G.fileflags= bfd->fileflags; |
| 267 CTX_wm_manager_set(C, bfd->main->wm.first); |
| 268 CTX_wm_screen_set(C, bfd->curscreen); |
| 269 CTX_data_scene_set(C, bfd->curscreen->scene); |
| 270 CTX_wm_area_set(C, NULL); |
| 271 CTX_wm_region_set(C, NULL); |
| 272 CTX_wm_menu_set(C, NULL); |
| 273 } |
| 274 ········ |
| 275 /* this can happen when active scene was lib-linked, and doesnt exist an
ymore */ |
| 276 if(CTX_data_scene(C)==NULL) { |
| 277 CTX_data_scene_set(C, bfd->main->scene.first); |
| 278 CTX_wm_screen(C)->scene= CTX_data_scene(C); |
| 279 curscene= CTX_data_scene(C); |
| 280 } |
| 281 |
| 282 /* special cases, override loaded flags: */ |
| 283 if(G.f != bfd->globalf) { |
| 284 const int flags_keep= (G_DEBUG | G_SWAP_EXCHANGE | G_SCRIPT_AUTO
EXEC | G_SCRIPT_OVERRIDE_PREF); |
| 285 bfd->globalf= (bfd->globalf & ~flags_keep) | (G.f & flags_keep); |
| 286 } |
| 287 |
| 288 |
| 289 G.f= bfd->globalf; |
| 290 |
| 291 if (!G.background) { |
| 292 //setscreen(G.curscreen); |
| 293 } |
| 294 ········ |
| 295 // FIXME: this version patching should really be part of the file-readin
g code,· |
| 296 // but we still get too many unrelated data-corruption crashes otherwise
... |
| 297 if (G.main->versionfile < 250) |
| 298 do_versions_ipos_to_animato(G.main); |
| 299 ········ |
| 300 if(recover && bfd->filename[0] && G.relbase_valid) { |
| 301 /* in case of autosave or quit.blend, use original filename inst
ead |
| 302 * use relbase_valid to make sure the file is saved, else we get
<memory2> in the filename */ |
| 303 filepath= bfd->filename; |
| 304 } |
| 305 #if 0 |
| 306 else if (!G.relbase_valid) { |
| 307 /* otherwise, use an empty string as filename, rather than <memo
ry2> */ |
| 308 filepath=""; |
| 309 } |
| 310 #endif |
| 311 ········ |
| 312 /* these are the same at times, should never copy to the same location *
/ |
| 313 if(G.main->name != filepath) |
| 314 BLI_strncpy(G.main->name, filepath, FILE_MAX); |
| 315 |
| 316 /* baseflags, groups, make depsgraph, etc */ |
| 317 set_scene_bg(G.main, CTX_data_scene(C)); |
| 318 ········ |
| 319 MEM_freeN(bfd); |
| 320 |
| 321 (void)curscene; /* quiet warning */ |
| 322 } |
| 323 |
| 324 static int handle_subversion_warning(Main *main, ReportList *reports) |
| 325 { |
| 326 if(main->minversionfile > BLENDER_VERSION || |
| 327 (main->minversionfile == BLENDER_VERSION &&· |
| 328 main->minsubversionfile > BLENDER_SUBVERSION)) { |
| 329 BKE_reportf(reports, RPT_ERROR, "File written by newer Blender b
inary: %d.%d , expect loss of data!", main->minversionfile, main->minsubversionf
ile); |
| 330 } |
| 331 |
| 332 return 1; |
| 333 } |
| 334 |
| 335 static void keymap_item_free(wmKeyMapItem *kmi) |
| 336 { |
| 337 if(kmi->properties) { |
| 338 IDP_FreeProperty(kmi->properties); |
| 339 MEM_freeN(kmi->properties); |
| 340 } |
| 341 if(kmi->ptr) |
| 342 MEM_freeN(kmi->ptr); |
| 343 } |
| 344 |
| 345 void BKE_userdef_free(void) |
| 346 { |
| 347 wmKeyMap *km; |
| 348 wmKeyMapItem *kmi; |
| 349 wmKeyMapDiffItem *kmdi; |
| 350 |
| 351 for(km=U.user_keymaps.first; km; km=km->next) { |
| 352 for(kmdi=km->diff_items.first; kmdi; kmdi=kmdi->next) { |
| 353 if(kmdi->add_item) { |
| 354 keymap_item_free(kmdi->add_item); |
| 355 MEM_freeN(kmdi->add_item); |
| 356 } |
| 357 if(kmdi->remove_item) { |
| 358 keymap_item_free(kmdi->remove_item); |
| 359 MEM_freeN(kmdi->remove_item); |
| 360 } |
| 361 } |
| 362 |
| 363 for(kmi=km->items.first; kmi; kmi=kmi->next) |
| 364 keymap_item_free(kmi); |
| 365 |
| 366 BLI_freelistN(&km->diff_items); |
| 367 BLI_freelistN(&km->items); |
| 368 } |
| 369 ········ |
| 370 BLI_freelistN(&U.uistyles); |
| 371 BLI_freelistN(&U.uifonts); |
| 372 BLI_freelistN(&U.themes); |
| 373 BLI_freelistN(&U.user_keymaps); |
| 374 BLI_freelistN(&U.addons); |
| 375 } |
| 376 |
| 377 int BKE_read_file(bContext *C, const char *filepath, ReportList *reports) |
| 378 { |
| 379 BlendFileData *bfd; |
| 380 int retval= BKE_READ_FILE_OK; |
| 381 |
| 382 if(strstr(filepath, BLENDER_STARTUP_FILE)==NULL) /* dont print user-pref
loading */ |
| 383 printf("read blend: %s\n", filepath); |
| 384 |
| 385 bfd= BLO_read_from_file(filepath, reports); |
| 386 if (bfd) { |
| 387 if(bfd->user) retval= BKE_READ_FILE_OK_USERPREFS; |
| 388 ················ |
| 389 if(0==handle_subversion_warning(bfd->main, reports)) { |
| 390 free_main(bfd->main); |
| 391 MEM_freeN(bfd); |
| 392 bfd= NULL; |
| 393 retval= BKE_READ_FILE_FAIL; |
| 394 } |
| 395 else |
| 396 setup_app_data(C, bfd, filepath); // frees BFD |
| 397 }· |
| 398 else |
| 399 BKE_reports_prependf(reports, "Loading %s failed: ", filepath); |
| 400 ················ |
| 401 return (bfd?retval:BKE_READ_FILE_FAIL); |
| 402 } |
| 403 |
| 404 int BKE_read_file_from_memory(bContext *C, char* filebuf, int filelength, Report
List *reports) |
| 405 { |
| 406 BlendFileData *bfd; |
| 407 |
| 408 bfd= BLO_read_from_memory(filebuf, filelength, reports); |
| 409 if (bfd) |
| 410 setup_app_data(C, bfd, "<memory2>"); |
| 411 else |
| 412 BKE_reports_prepend(reports, "Loading failed: "); |
| 413 |
| 414 return (bfd?1:0); |
| 415 } |
| 416 |
| 417 /* memfile is the undo buffer */ |
| 418 int BKE_read_file_from_memfile(bContext *C, MemFile *memfile, ReportList *report
s) |
| 419 { |
| 420 BlendFileData *bfd; |
| 421 |
| 422 bfd= BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, repo
rts); |
| 423 if (bfd) |
| 424 setup_app_data(C, bfd, "<memory1>"); |
| 425 else |
| 426 BKE_reports_prepend(reports, "Loading failed: "); |
| 427 |
| 428 return (bfd?1:0); |
| 429 } |
| 430 |
| 431 |
| 432 /* ***************** testing for break ************* */ |
| 433 |
| 434 static void (*blender_test_break_cb)(void)= NULL; |
| 435 |
| 436 void set_blender_test_break_cb(void (*func)(void) ) |
| 437 { |
| 438 blender_test_break_cb= func; |
| 439 } |
| 440 |
| 441 |
| 442 int blender_test_break(void) |
| 443 { |
| 444 if (!G.background) { |
| 445 if (blender_test_break_cb) |
| 446 blender_test_break_cb(); |
| 447 } |
| 448 ········ |
| 449 return (G.afbreek==1); |
| 450 } |
| 451 |
| 452 |
| 453 /* ***************** GLOBAL UNDO *************** */ |
| 454 |
| 455 #define UNDO_DISK 0 |
| 456 |
| 457 #define MAXUNDONAME 64 |
| 458 typedef struct UndoElem { |
| 459 struct UndoElem *next, *prev; |
| 460 char str[FILE_MAXDIR+FILE_MAXFILE]; |
| 461 char name[MAXUNDONAME]; |
| 462 MemFile memfile; |
| 463 uintptr_t undosize; |
| 464 } UndoElem; |
| 465 |
| 466 static ListBase undobase={NULL, NULL}; |
| 467 static UndoElem *curundo= NULL; |
| 468 |
| 469 |
| 470 static int read_undosave(bContext *C, UndoElem *uel) |
| 471 { |
| 472 char mainstr[sizeof(G.main->name)]; |
| 473 int success=0, fileflags; |
| 474 ········ |
| 475 /* This is needed so undoing/redoing doesnt crash with threaded previews
going */ |
| 476 WM_jobs_stop_all(CTX_wm_manager(C)); |
| 477 |
| 478 BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal stor
e */ |
| 479 |
| 480 fileflags= G.fileflags; |
| 481 G.fileflags |= G_FILE_NO_UI; |
| 482 |
| 483 if(UNDO_DISK)· |
| 484 success= (BKE_read_file(C, uel->str, NULL) != BKE_READ_FILE_FAIL
); |
| 485 else |
| 486 success= BKE_read_file_from_memfile(C, &uel->memfile, NULL); |
| 487 |
| 488 /* restore */ |
| 489 BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */ |
| 490 G.fileflags= fileflags; |
| 491 |
| 492 if(success) { |
| 493 /* important not to update time here, else non keyed tranforms a
re lost */ |
| 494 DAG_on_visible_update(G.main, FALSE); |
| 495 } |
| 496 |
| 497 return success; |
| 498 } |
| 499 |
| 500 /* name can be a dynamic string */ |
| 501 void BKE_write_undo(bContext *C, const char *name) |
| 502 { |
| 503 uintptr_t maxmem, totmem, memused; |
| 504 int nr /*, success */ /* UNUSED */; |
| 505 UndoElem *uel; |
| 506 ········ |
| 507 if( (U.uiflag & USER_GLOBALUNDO)==0) return; |
| 508 if( U.undosteps==0) return; |
| 509 ········ |
| 510 /* remove all undos after (also when curundo==NULL) */ |
| 511 while(undobase.last != curundo) { |
| 512 uel= undobase.last; |
| 513 BLI_remlink(&undobase, uel); |
| 514 BLO_free_memfile(&uel->memfile); |
| 515 MEM_freeN(uel); |
| 516 } |
| 517 ········ |
| 518 /* make new */ |
| 519 curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file"); |
| 520 BLI_strncpy(uel->name, name, sizeof(uel->name)); |
| 521 BLI_addtail(&undobase, uel); |
| 522 ········ |
| 523 /* and limit amount to the maximum */ |
| 524 nr= 0; |
| 525 uel= undobase.last; |
| 526 while(uel) { |
| 527 nr++; |
| 528 if(nr==U.undosteps) break; |
| 529 uel= uel->prev; |
| 530 } |
| 531 if(uel) { |
| 532 while(undobase.first!=uel) { |
| 533 UndoElem *first= undobase.first; |
| 534 BLI_remlink(&undobase, first); |
| 535 /* the merge is because of compression */ |
| 536 BLO_merge_memfile(&first->memfile, &first->next->memfile
); |
| 537 MEM_freeN(first); |
| 538 } |
| 539 } |
| 540 |
| 541 |
| 542 /* disk save version */ |
| 543 if(UNDO_DISK) { |
| 544 static int counter= 0; |
| 545 char filepath[FILE_MAXDIR+FILE_MAXFILE]; |
| 546 char numstr[32]; |
| 547 int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do fil
e history on undo */ |
| 548 |
| 549 /* calculate current filepath */ |
| 550 counter++; |
| 551 counter= counter % U.undosteps;· |
| 552 ········ |
| 553 BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); |
| 554 BLI_make_file_string("/", filepath, btempdir, numstr); |
| 555 ········ |
| 556 /* success= */ /* UNUSED */ BLO_write_file(CTX_data_main(C), fil
epath, fileflags, NULL, NULL); |
| 557 ················ |
| 558 BLI_strncpy(curundo->str, filepath, sizeof(curundo->str)); |
| 559 } |
| 560 else { |
| 561 MemFile *prevfile=NULL; |
| 562 ················ |
| 563 if(curundo->prev) prevfile= &(curundo->prev->memfile); |
| 564 ················ |
| 565 memused= MEM_get_memory_in_use(); |
| 566 /* success= */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C),
prevfile, &curundo->memfile, G.fileflags); |
| 567 curundo->undosize= MEM_get_memory_in_use() - memused; |
| 568 } |
| 569 |
| 570 if(U.undomemory != 0) { |
| 571 /* limit to maximum memory (afterwards, we can't know in advance
) */ |
| 572 totmem= 0; |
| 573 maxmem= ((uintptr_t)U.undomemory)*1024*1024; |
| 574 |
| 575 /* keep at least two (original + other) */ |
| 576 uel= undobase.last; |
| 577 while(uel && uel->prev) { |
| 578 totmem+= uel->undosize; |
| 579 if(totmem>maxmem) break; |
| 580 uel= uel->prev; |
| 581 } |
| 582 |
| 583 if(uel) { |
| 584 if(uel->prev && uel->prev->prev) |
| 585 uel= uel->prev; |
| 586 |
| 587 while(undobase.first!=uel) { |
| 588 UndoElem *first= undobase.first; |
| 589 BLI_remlink(&undobase, first); |
| 590 /* the merge is because of compression */ |
| 591 BLO_merge_memfile(&first->memfile, &first->next-
>memfile); |
| 592 MEM_freeN(first); |
| 593 } |
| 594 } |
| 595 } |
| 596 } |
| 597 |
| 598 /* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current s
ituation */ |
| 599 void BKE_undo_step(bContext *C, int step) |
| 600 { |
| 601 ········ |
| 602 if(step==0) { |
| 603 read_undosave(C, curundo); |
| 604 } |
| 605 else if(step==1) { |
| 606 /* curundo should never be NULL, after restart or load file it s
hould call undo_save */ |
| 607 if(curundo==NULL || curundo->prev==NULL) ; // XXX error("No undo
available"); |
| 608 else { |
| 609 if(G.f & G_DEBUG) printf("undo %s\n", curundo->name); |
| 610 curundo= curundo->prev; |
| 611 read_undosave(C, curundo); |
| 612 } |
| 613 } |
| 614 else { |
| 615 ················ |
| 616 /* curundo has to remain current situation! */ |
| 617 ················ |
| 618 if(curundo==NULL || curundo->next==NULL) ; // XXX error("No redo
available"); |
| 619 else { |
| 620 read_undosave(C, curundo->next); |
| 621 curundo= curundo->next; |
| 622 if(G.f & G_DEBUG) printf("redo %s\n", curundo->name); |
| 623 } |
| 624 } |
| 625 } |
| 626 |
| 627 void BKE_reset_undo(void) |
| 628 { |
| 629 UndoElem *uel; |
| 630 ········ |
| 631 uel= undobase.first; |
| 632 while(uel) { |
| 633 BLO_free_memfile(&uel->memfile); |
| 634 uel= uel->next; |
| 635 } |
| 636 ········ |
| 637 BLI_freelistN(&undobase); |
| 638 curundo= NULL; |
| 639 } |
| 640 |
| 641 /* based on index nr it does a restore */ |
| 642 void BKE_undo_number(bContext *C, int nr) |
| 643 { |
| 644 curundo= BLI_findlink(&undobase, nr); |
| 645 BKE_undo_step(C, 0); |
| 646 } |
| 647 |
| 648 /* go back to the last occurance of name in stack */ |
| 649 void BKE_undo_name(bContext *C, const char *name) |
| 650 { |
| 651 UndoElem *uel= BLI_rfindstring(&undobase, name, offsetof(UndoElem, name)
); |
| 652 |
| 653 if(uel && uel->prev) { |
| 654 curundo= uel->prev; |
| 655 BKE_undo_step(C, 0); |
| 656 } |
| 657 } |
| 658 |
| 659 /* name optional */ |
| 660 int BKE_undo_valid(const char *name) |
| 661 { |
| 662 if(name) { |
| 663 UndoElem *uel= BLI_rfindstring(&undobase, name, offsetof(UndoEle
m, name)); |
| 664 return uel && uel->prev; |
| 665 } |
| 666 ········ |
| 667 return undobase.last != undobase.first; |
| 668 } |
| 669 |
| 670 /* get name of undo item, return null if no item with this index */ |
| 671 /* if active pointer, set it to 1 if true */ |
| 672 char *BKE_undo_get_name(int nr, int *active) |
| 673 { |
| 674 UndoElem *uel= BLI_findlink(&undobase, nr); |
| 675 ········ |
| 676 if(active) *active= 0; |
| 677 ········ |
| 678 if(uel) { |
| 679 if(active && uel==curundo) |
| 680 *active= 1; |
| 681 return uel->name; |
| 682 } |
| 683 return NULL; |
| 684 } |
| 685 |
| 686 char *BKE_undo_menu_string(void) |
| 687 { |
| 688 UndoElem *uel; |
| 689 DynStr *ds= BLI_dynstr_new(); |
| 690 char *menu; |
| 691 |
| 692 BLI_dynstr_append(ds, "Global Undo History %t"); |
| 693 ········ |
| 694 for(uel= undobase.first; uel; uel= uel->next) { |
| 695 BLI_dynstr_append(ds, "|"); |
| 696 BLI_dynstr_append(ds, uel->name); |
| 697 } |
| 698 |
| 699 menu= BLI_dynstr_get_cstring(ds); |
| 700 BLI_dynstr_free(ds); |
| 701 |
| 702 return menu; |
| 703 } |
| 704 |
| 705 /* saves quit.blend */ |
| 706 void BKE_undo_save_quit(void) |
| 707 { |
| 708 UndoElem *uel; |
| 709 MemFileChunk *chunk; |
| 710 int file; |
| 711 char str[FILE_MAXDIR+FILE_MAXFILE]; |
| 712 ········ |
| 713 if( (U.uiflag & USER_GLOBALUNDO)==0) return; |
| 714 ········ |
| 715 uel= curundo; |
| 716 if(uel==NULL) { |
| 717 printf("No undo buffer to save recovery file\n"); |
| 718 return; |
| 719 } |
| 720 ········ |
| 721 /* no undo state to save */ |
| 722 if(undobase.first==undobase.last) return; |
| 723 ················ |
| 724 BLI_make_file_string("/", str, btempdir, "quit.blend"); |
| 725 |
| 726 file = open(str,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666); |
| 727 if(file == -1) { |
| 728 //XXX error("Unable to save %s, check you have permissions", str
); |
| 729 return; |
| 730 } |
| 731 |
| 732 chunk= uel->memfile.chunks.first; |
| 733 while(chunk) { |
| 734 if( write(file, chunk->buf, chunk->size) != chunk->size) break; |
| 735 chunk= chunk->next; |
| 736 } |
| 737 ········ |
| 738 close(file); |
| 739 ········ |
| 740 if(chunk) ; //XXX error("Unable to save %s, internal error", str); |
| 741 else printf("Saved session recovery to %s\n", str); |
| 742 } |
| 743 |
| 744 /* sets curscene */ |
| 745 Main *BKE_undo_get_main(Scene **scene) |
| 746 { |
| 747 Main *mainp= NULL; |
| 748 BlendFileData *bfd= BLO_read_from_memfile(G.main, G.main->name, &curundo
->memfile, NULL); |
| 749 ········ |
| 750 if(bfd) { |
| 751 mainp= bfd->main; |
| 752 if(scene) |
| 753 *scene= bfd->curscene; |
| 754 ················ |
| 755 MEM_freeN(bfd); |
| 756 } |
| 757 ········ |
| 758 return mainp; |
| 759 } |
| 760 |
LEFT | RIGHT |