Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #ifndef _WIN32 00034 #include <unistd.h> // for read close 00035 #else 00036 #include <io.h> // for open close read 00037 #define open _open 00038 #define read _read 00039 #define close _close 00040 #define write _write 00041 #endif 00042 00043 #include <stdlib.h> 00044 #include <stdio.h> 00045 #include <stddef.h> 00046 #include <string.h> 00047 #include <fcntl.h> // for open 00048 00049 #include "MEM_guardedalloc.h" 00050 00051 #include "DNA_userdef_types.h" 00052 #include "DNA_scene_types.h" 00053 #include "DNA_screen_types.h" 00054 #include "DNA_sequence_types.h" 00055 #include "DNA_sound_types.h" 00056 00057 #include "BLI_blenlib.h" 00058 #include "BLI_bpath.h" 00059 #include "BLI_dynstr.h" 00060 #include "BLI_utildefines.h" 00061 #include "BLI_callbacks.h" 00062 00063 #include "IMB_imbuf.h" 00064 #include "IMB_moviecache.h" 00065 00066 #include "BKE_blender.h" 00067 #include "BKE_context.h" 00068 #include "BKE_depsgraph.h" 00069 #include "BKE_displist.h" 00070 #include "BKE_global.h" 00071 #include "BKE_idprop.h" 00072 #include "BKE_ipo.h" 00073 #include "BKE_library.h" 00074 #include "BKE_main.h" 00075 #include "BKE_node.h" 00076 #include "BKE_report.h" 00077 #include "BKE_scene.h" 00078 #include "BKE_screen.h" 00079 #include "BKE_sequencer.h" 00080 #include "BKE_sound.h" 00081 00082 00083 #include "BLO_undofile.h" 00084 #include "BLO_readfile.h" 00085 #include "BLO_writefile.h" 00086 00087 #include "BKE_utildefines.h" 00088 00089 #include "RNA_access.h" 00090 00091 #include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie 00092 00093 Global G; 00094 UserDef U; 00095 /* ListBase = {NULL, NULL}; */ 00096 00097 char versionstr[48]= ""; 00098 00099 /* ********** free ********** */ 00100 00101 /* only to be called on exit blender */ 00102 void free_blender(void) 00103 { 00104 /* samples are in a global list..., also sets G.main->sound->sample NULL */ 00105 free_main(G.main); 00106 G.main= NULL; 00107 00108 BKE_spacetypes_free(); /* after free main, it uses space callbacks */ 00109 00110 IMB_exit(); 00111 00112 BLI_cb_finalize(); 00113 00114 seq_stripelem_cache_destruct(); 00115 IMB_moviecache_destruct(); 00116 00117 free_nodesystem(); 00118 } 00119 00120 void initglobals(void) 00121 { 00122 memset(&G, 0, sizeof(Global)); 00123 00124 U.savetime= 1; 00125 00126 G.main= MEM_callocN(sizeof(Main), "initglobals"); 00127 00128 strcpy(G.ima, "//"); 00129 00130 if(BLENDER_SUBVERSION) 00131 BLI_snprintf(versionstr, sizeof(versionstr), "blender.org %d.%d", BLENDER_VERSION, BLENDER_SUBVERSION); 00132 else 00133 BLI_snprintf(versionstr, sizeof(versionstr), "blender.org %d", BLENDER_VERSION); 00134 00135 #ifdef _WIN32 // FULLSCREEN 00136 G.windowstate = G_WINDOWSTATE_USERDEF; 00137 #endif 00138 00139 G.charstart = 0x0000; 00140 G.charmin = 0x0000; 00141 G.charmax = 0xffff; 00142 00143 #ifndef WITH_PYTHON_SECURITY /* default */ 00144 G.f |= G_SCRIPT_AUTOEXEC; 00145 #else 00146 G.f &= ~G_SCRIPT_AUTOEXEC; 00147 #endif 00148 } 00149 00150 /***/ 00151 00152 static void clear_global(void) 00153 { 00154 // extern short winqueue_break; /* screen.c */ 00155 00156 free_main(G.main); /* free all lib data */ 00157 00158 // free_vertexpaint(); 00159 00160 G.main= NULL; 00161 } 00162 00163 static int clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src) 00164 { 00165 strcpy(path_dst, path_src); 00166 BLI_clean(path_dst); 00167 return (strcmp(path_dst, path_src) == 0) ? FALSE : TRUE; 00168 } 00169 00170 /* make sure path names are correct for OS */ 00171 static void clean_paths(Main *main) 00172 { 00173 Scene *scene; 00174 00175 bpath_traverse_main(main, clean_paths_visit_cb, BPATH_TRAVERSE_SKIP_MULTIFILE, NULL); 00176 00177 for(scene= main->scene.first; scene; scene= scene->id.next) { 00178 BLI_clean(scene->r.pic); 00179 } 00180 } 00181 00182 /* context matching */ 00183 /* handle no-ui case */ 00184 00185 /* note, this is called on Undo so any slow conversion functions here 00186 * should be avoided or check (mode!='u') */ 00187 00188 static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath) 00189 { 00190 bScreen *curscreen= NULL; 00191 Scene *curscene= NULL; 00192 int recover; 00193 char mode; 00194 00195 /* 'u' = undo save, 'n' = no UI load */ 00196 if(bfd->main->screen.first==NULL) mode= 'u'; 00197 else if(G.fileflags & G_FILE_NO_UI) mode= 'n'; 00198 else mode= 0; 00199 00200 recover= (G.fileflags & G_FILE_RECOVER); 00201 00202 /* Only make filepaths compatible when loading for real (not undo) */ 00203 if(mode != 'u') { 00204 clean_paths(bfd->main); 00205 } 00206 00207 /* XXX here the complex windowmanager matching */ 00208 00209 /* no load screens? */ 00210 if(mode) { 00211 /* comes from readfile.c */ 00212 extern void lib_link_screen_restore(Main *, bScreen *, Scene *); 00213 00214 SWAP(ListBase, G.main->wm, bfd->main->wm); 00215 SWAP(ListBase, G.main->screen, bfd->main->screen); 00216 SWAP(ListBase, G.main->script, bfd->main->script); 00217 00218 /* we re-use current screen */ 00219 curscreen= CTX_wm_screen(C); 00220 /* but use new Scene pointer */ 00221 curscene= bfd->curscene; 00222 if(curscene==NULL) curscene= bfd->main->scene.first; 00223 /* and we enforce curscene to be in current screen */ 00224 if(curscreen) curscreen->scene= curscene; /* can run in bgmode */ 00225 00226 /* clear_global will free G.main, here we can still restore pointers */ 00227 lib_link_screen_restore(bfd->main, curscreen, curscene); 00228 } 00229 00230 /* free G.main Main database */ 00231 // CTX_wm_manager_set(C, NULL); 00232 clear_global(); 00233 00234 /* clear old property update cache, in case some old references are left dangling */ 00235 RNA_property_update_cache_free(); 00236 00237 G.main= bfd->main; 00238 00239 CTX_data_main_set(C, G.main); 00240 00241 sound_init_main(G.main); 00242 00243 if (bfd->user) { 00244 00245 /* only here free userdef themes... */ 00246 BKE_userdef_free(); 00247 00248 U= *bfd->user; 00249 MEM_freeN(bfd->user); 00250 } 00251 00252 /* case G_FILE_NO_UI or no screens in file */ 00253 if(mode) { 00254 /* leave entire context further unaltered? */ 00255 CTX_data_scene_set(C, curscene); 00256 } 00257 else { 00258 G.winpos= bfd->winpos; 00259 G.displaymode= bfd->displaymode; 00260 G.fileflags= bfd->fileflags; 00261 CTX_wm_manager_set(C, bfd->main->wm.first); 00262 CTX_wm_screen_set(C, bfd->curscreen); 00263 CTX_data_scene_set(C, bfd->curscreen->scene); 00264 CTX_wm_area_set(C, NULL); 00265 CTX_wm_region_set(C, NULL); 00266 CTX_wm_menu_set(C, NULL); 00267 } 00268 00269 /* this can happen when active scene was lib-linked, and doesnt exist anymore */ 00270 if(CTX_data_scene(C)==NULL) { 00271 CTX_data_scene_set(C, bfd->main->scene.first); 00272 CTX_wm_screen(C)->scene= CTX_data_scene(C); 00273 curscene= CTX_data_scene(C); 00274 } 00275 00276 /* special cases, override loaded flags: */ 00277 if(G.f != bfd->globalf) { 00278 const int flags_keep= (G_DEBUG | G_SWAP_EXCHANGE | G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF); 00279 bfd->globalf= (bfd->globalf & ~flags_keep) | (G.f & flags_keep); 00280 } 00281 00282 00283 G.f= bfd->globalf; 00284 00285 if (!G.background) { 00286 //setscreen(G.curscreen); 00287 } 00288 00289 // FIXME: this version patching should really be part of the file-reading code, 00290 // but we still get too many unrelated data-corruption crashes otherwise... 00291 if (G.main->versionfile < 250) 00292 do_versions_ipos_to_animato(G.main); 00293 00294 if(recover && bfd->filename[0] && G.relbase_valid) { 00295 /* in case of autosave or quit.blend, use original filename instead 00296 * use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */ 00297 filepath= bfd->filename; 00298 } 00299 #if 0 00300 else if (!G.relbase_valid) { 00301 /* otherwise, use an empty string as filename, rather than <memory2> */ 00302 filepath=""; 00303 } 00304 #endif 00305 00306 /* these are the same at times, should never copy to the same location */ 00307 if(G.main->name != filepath) 00308 BLI_strncpy(G.main->name, filepath, FILE_MAX); 00309 00310 /* baseflags, groups, make depsgraph, etc */ 00311 set_scene_bg(G.main, CTX_data_scene(C)); 00312 00313 MEM_freeN(bfd); 00314 00315 (void)curscene; /* quiet warning */ 00316 } 00317 00318 static int handle_subversion_warning(Main *main, ReportList *reports) 00319 { 00320 if(main->minversionfile > BLENDER_VERSION || 00321 (main->minversionfile == BLENDER_VERSION && 00322 main->minsubversionfile > BLENDER_SUBVERSION)) { 00323 BKE_reportf(reports, RPT_ERROR, "File written by newer Blender binary: %d.%d , expect loss of data!", main->minversionfile, main->minsubversionfile); 00324 } 00325 00326 return 1; 00327 } 00328 00329 static void keymap_item_free(wmKeyMapItem *kmi) 00330 { 00331 if(kmi->properties) { 00332 IDP_FreeProperty(kmi->properties); 00333 MEM_freeN(kmi->properties); 00334 } 00335 if(kmi->ptr) 00336 MEM_freeN(kmi->ptr); 00337 } 00338 00339 void BKE_userdef_free(void) 00340 { 00341 wmKeyMap *km; 00342 wmKeyMapItem *kmi; 00343 wmKeyMapDiffItem *kmdi; 00344 00345 for(km=U.user_keymaps.first; km; km=km->next) { 00346 for(kmdi=km->diff_items.first; kmdi; kmdi=kmdi->next) { 00347 if(kmdi->add_item) { 00348 keymap_item_free(kmdi->add_item); 00349 MEM_freeN(kmdi->add_item); 00350 } 00351 if(kmdi->remove_item) { 00352 keymap_item_free(kmdi->remove_item); 00353 MEM_freeN(kmdi->remove_item); 00354 } 00355 } 00356 00357 for(kmi=km->items.first; kmi; kmi=kmi->next) 00358 keymap_item_free(kmi); 00359 00360 BLI_freelistN(&km->diff_items); 00361 BLI_freelistN(&km->items); 00362 } 00363 00364 BLI_freelistN(&U.uistyles); 00365 BLI_freelistN(&U.uifonts); 00366 BLI_freelistN(&U.themes); 00367 BLI_freelistN(&U.user_keymaps); 00368 BLI_freelistN(&U.addons); 00369 } 00370 00371 int BKE_read_file(bContext *C, const char *filepath, ReportList *reports) 00372 { 00373 BlendFileData *bfd; 00374 int retval= BKE_READ_FILE_OK; 00375 00376 if(strstr(filepath, BLENDER_STARTUP_FILE)==NULL) /* dont print user-pref loading */ 00377 printf("read blend: %s\n", filepath); 00378 00379 bfd= BLO_read_from_file(filepath, reports); 00380 if (bfd) { 00381 if(bfd->user) retval= BKE_READ_FILE_OK_USERPREFS; 00382 00383 if(0==handle_subversion_warning(bfd->main, reports)) { 00384 free_main(bfd->main); 00385 MEM_freeN(bfd); 00386 bfd= NULL; 00387 retval= BKE_READ_FILE_FAIL; 00388 } 00389 else 00390 setup_app_data(C, bfd, filepath); // frees BFD 00391 } 00392 else 00393 BKE_reports_prependf(reports, "Loading %s failed: ", filepath); 00394 00395 return (bfd?retval:BKE_READ_FILE_FAIL); 00396 } 00397 00398 int BKE_read_file_from_memory(bContext *C, char* filebuf, int filelength, ReportList *reports) 00399 { 00400 BlendFileData *bfd; 00401 00402 bfd= BLO_read_from_memory(filebuf, filelength, reports); 00403 if (bfd) 00404 setup_app_data(C, bfd, "<memory2>"); 00405 else 00406 BKE_reports_prepend(reports, "Loading failed: "); 00407 00408 return (bfd?1:0); 00409 } 00410 00411 /* memfile is the undo buffer */ 00412 int BKE_read_file_from_memfile(bContext *C, MemFile *memfile, ReportList *reports) 00413 { 00414 BlendFileData *bfd; 00415 00416 bfd= BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports); 00417 if (bfd) 00418 setup_app_data(C, bfd, "<memory1>"); 00419 else 00420 BKE_reports_prepend(reports, "Loading failed: "); 00421 00422 return (bfd?1:0); 00423 } 00424 00425 00426 /* ***************** testing for break ************* */ 00427 00428 static void (*blender_test_break_cb)(void)= NULL; 00429 00430 void set_blender_test_break_cb(void (*func)(void) ) 00431 { 00432 blender_test_break_cb= func; 00433 } 00434 00435 00436 int blender_test_break(void) 00437 { 00438 if (!G.background) { 00439 if (blender_test_break_cb) 00440 blender_test_break_cb(); 00441 } 00442 00443 return (G.afbreek==1); 00444 } 00445 00446 00447 /* ***************** GLOBAL UNDO *************** */ 00448 00449 #define UNDO_DISK 0 00450 00451 #define MAXUNDONAME 64 00452 typedef struct UndoElem { 00453 struct UndoElem *next, *prev; 00454 char str[FILE_MAX]; 00455 char name[MAXUNDONAME]; 00456 MemFile memfile; 00457 uintptr_t undosize; 00458 } UndoElem; 00459 00460 static ListBase undobase={NULL, NULL}; 00461 static UndoElem *curundo= NULL; 00462 00463 00464 static int read_undosave(bContext *C, UndoElem *uel) 00465 { 00466 char mainstr[sizeof(G.main->name)]; 00467 int success=0, fileflags; 00468 00469 /* This is needed so undoing/redoing doesnt crash with threaded previews going */ 00470 WM_jobs_stop_all(CTX_wm_manager(C)); 00471 00472 BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */ 00473 00474 fileflags= G.fileflags; 00475 G.fileflags |= G_FILE_NO_UI; 00476 00477 if(UNDO_DISK) 00478 success= (BKE_read_file(C, uel->str, NULL) != BKE_READ_FILE_FAIL); 00479 else 00480 success= BKE_read_file_from_memfile(C, &uel->memfile, NULL); 00481 00482 /* restore */ 00483 BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */ 00484 G.fileflags= fileflags; 00485 00486 if(success) { 00487 /* important not to update time here, else non keyed tranforms are lost */ 00488 DAG_on_visible_update(G.main, FALSE); 00489 } 00490 00491 return success; 00492 } 00493 00494 /* name can be a dynamic string */ 00495 void BKE_write_undo(bContext *C, const char *name) 00496 { 00497 uintptr_t maxmem, totmem, memused; 00498 int nr /*, success */ /* UNUSED */; 00499 UndoElem *uel; 00500 00501 if( (U.uiflag & USER_GLOBALUNDO)==0) return; 00502 if( U.undosteps==0) return; 00503 00504 /* remove all undos after (also when curundo==NULL) */ 00505 while(undobase.last != curundo) { 00506 uel= undobase.last; 00507 BLI_remlink(&undobase, uel); 00508 BLO_free_memfile(&uel->memfile); 00509 MEM_freeN(uel); 00510 } 00511 00512 /* make new */ 00513 curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file"); 00514 BLI_strncpy(uel->name, name, sizeof(uel->name)); 00515 BLI_addtail(&undobase, uel); 00516 00517 /* and limit amount to the maximum */ 00518 nr= 0; 00519 uel= undobase.last; 00520 while(uel) { 00521 nr++; 00522 if(nr==U.undosteps) break; 00523 uel= uel->prev; 00524 } 00525 if(uel) { 00526 while(undobase.first!=uel) { 00527 UndoElem *first= undobase.first; 00528 BLI_remlink(&undobase, first); 00529 /* the merge is because of compression */ 00530 BLO_merge_memfile(&first->memfile, &first->next->memfile); 00531 MEM_freeN(first); 00532 } 00533 } 00534 00535 00536 /* disk save version */ 00537 if(UNDO_DISK) { 00538 static int counter= 0; 00539 char filepath[FILE_MAX]; 00540 char numstr[32]; 00541 int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */ 00542 00543 /* calculate current filepath */ 00544 counter++; 00545 counter= counter % U.undosteps; 00546 00547 BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); 00548 BLI_make_file_string("/", filepath, BLI_temporary_dir(), numstr); 00549 00550 /* success= */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL); 00551 00552 BLI_strncpy(curundo->str, filepath, sizeof(curundo->str)); 00553 } 00554 else { 00555 MemFile *prevfile=NULL; 00556 00557 if(curundo->prev) prevfile= &(curundo->prev->memfile); 00558 00559 memused= MEM_get_memory_in_use(); 00560 /* success= */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags); 00561 curundo->undosize= MEM_get_memory_in_use() - memused; 00562 } 00563 00564 if(U.undomemory != 0) { 00565 /* limit to maximum memory (afterwards, we can't know in advance) */ 00566 totmem= 0; 00567 maxmem= ((uintptr_t)U.undomemory)*1024*1024; 00568 00569 /* keep at least two (original + other) */ 00570 uel= undobase.last; 00571 while(uel && uel->prev) { 00572 totmem+= uel->undosize; 00573 if(totmem>maxmem) break; 00574 uel= uel->prev; 00575 } 00576 00577 if(uel) { 00578 if(uel->prev && uel->prev->prev) 00579 uel= uel->prev; 00580 00581 while(undobase.first!=uel) { 00582 UndoElem *first= undobase.first; 00583 BLI_remlink(&undobase, first); 00584 /* the merge is because of compression */ 00585 BLO_merge_memfile(&first->memfile, &first->next->memfile); 00586 MEM_freeN(first); 00587 } 00588 } 00589 } 00590 } 00591 00592 /* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */ 00593 void BKE_undo_step(bContext *C, int step) 00594 { 00595 00596 if(step==0) { 00597 read_undosave(C, curundo); 00598 } 00599 else if(step==1) { 00600 /* curundo should never be NULL, after restart or load file it should call undo_save */ 00601 if(curundo==NULL || curundo->prev==NULL) ; // XXX error("No undo available"); 00602 else { 00603 if(G.f & G_DEBUG) printf("undo %s\n", curundo->name); 00604 curundo= curundo->prev; 00605 read_undosave(C, curundo); 00606 } 00607 } 00608 else { 00609 00610 /* curundo has to remain current situation! */ 00611 00612 if(curundo==NULL || curundo->next==NULL) ; // XXX error("No redo available"); 00613 else { 00614 read_undosave(C, curundo->next); 00615 curundo= curundo->next; 00616 if(G.f & G_DEBUG) printf("redo %s\n", curundo->name); 00617 } 00618 } 00619 } 00620 00621 void BKE_reset_undo(void) 00622 { 00623 UndoElem *uel; 00624 00625 uel= undobase.first; 00626 while(uel) { 00627 BLO_free_memfile(&uel->memfile); 00628 uel= uel->next; 00629 } 00630 00631 BLI_freelistN(&undobase); 00632 curundo= NULL; 00633 } 00634 00635 /* based on index nr it does a restore */ 00636 void BKE_undo_number(bContext *C, int nr) 00637 { 00638 curundo= BLI_findlink(&undobase, nr); 00639 BKE_undo_step(C, 0); 00640 } 00641 00642 /* go back to the last occurance of name in stack */ 00643 void BKE_undo_name(bContext *C, const char *name) 00644 { 00645 UndoElem *uel= BLI_rfindstring(&undobase, name, offsetof(UndoElem, name)); 00646 00647 if(uel && uel->prev) { 00648 curundo= uel->prev; 00649 BKE_undo_step(C, 0); 00650 } 00651 } 00652 00653 /* name optional */ 00654 int BKE_undo_valid(const char *name) 00655 { 00656 if(name) { 00657 UndoElem *uel= BLI_rfindstring(&undobase, name, offsetof(UndoElem, name)); 00658 return uel && uel->prev; 00659 } 00660 00661 return undobase.last != undobase.first; 00662 } 00663 00664 /* get name of undo item, return null if no item with this index */ 00665 /* if active pointer, set it to 1 if true */ 00666 const char *BKE_undo_get_name(int nr, int *active) 00667 { 00668 UndoElem *uel= BLI_findlink(&undobase, nr); 00669 00670 if(active) *active= 0; 00671 00672 if(uel) { 00673 if(active && uel==curundo) 00674 *active= 1; 00675 return uel->name; 00676 } 00677 return NULL; 00678 } 00679 00680 char *BKE_undo_menu_string(void) 00681 { 00682 UndoElem *uel; 00683 DynStr *ds= BLI_dynstr_new(); 00684 char *menu; 00685 00686 BLI_dynstr_append(ds, "Global Undo History %t"); 00687 00688 for(uel= undobase.first; uel; uel= uel->next) { 00689 BLI_dynstr_append(ds, "|"); 00690 BLI_dynstr_append(ds, uel->name); 00691 } 00692 00693 menu= BLI_dynstr_get_cstring(ds); 00694 BLI_dynstr_free(ds); 00695 00696 return menu; 00697 } 00698 00699 /* saves quit.blend */ 00700 void BKE_undo_save_quit(void) 00701 { 00702 UndoElem *uel; 00703 MemFileChunk *chunk; 00704 int file; 00705 char str[FILE_MAX]; 00706 00707 if( (U.uiflag & USER_GLOBALUNDO)==0) return; 00708 00709 uel= curundo; 00710 if(uel==NULL) { 00711 printf("No undo buffer to save recovery file\n"); 00712 return; 00713 } 00714 00715 /* no undo state to save */ 00716 if(undobase.first==undobase.last) return; 00717 00718 BLI_make_file_string("/", str, BLI_temporary_dir(), "quit.blend"); 00719 00720 file = open(str,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666); 00721 if(file == -1) { 00722 //XXX error("Unable to save %s, check you have permissions", str); 00723 return; 00724 } 00725 00726 chunk= uel->memfile.chunks.first; 00727 while(chunk) { 00728 if( write(file, chunk->buf, chunk->size) != chunk->size) break; 00729 chunk= chunk->next; 00730 } 00731 00732 close(file); 00733 00734 if(chunk) ; //XXX error("Unable to save %s, internal error", str); 00735 else printf("Saved session recovery to %s\n", str); 00736 } 00737 00738 /* sets curscene */ 00739 Main *BKE_undo_get_main(Scene **scene) 00740 { 00741 Main *mainp= NULL; 00742 BlendFileData *bfd= BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL); 00743 00744 if(bfd) { 00745 mainp= bfd->main; 00746 if(scene) 00747 *scene= bfd->curscene; 00748 00749 MEM_freeN(bfd); 00750 } 00751 00752 return mainp; 00753 } 00754