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