Blender  V2.59
blender.c
Go to the documentation of this file.
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