Blender V2.61 - r43446

wm_files.c

Go to the documentation of this file.
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  * Contributor(s): Blender Foundation 2007
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031     /* placed up here because of crappy
00032      * winsock stuff.
00033      */
00034 #include <stddef.h>
00035 #include <string.h>
00036 #include <errno.h>
00037 
00038 #include "zlib.h" /* wm_read_exotic() */
00039 
00040 #ifdef WIN32
00041 #include <windows.h> /* need to include windows.h so _WIN32_IE is defined  */
00042 #ifndef _WIN32_IE
00043 #define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
00044 #endif
00045 #include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */
00046 #include <process.h> /* getpid */
00047 #include "BLI_winstuff.h"
00048 #else
00049 #include <unistd.h> /* getpid */
00050 #endif
00051 
00052 #include "MEM_guardedalloc.h"
00053 #include "MEM_CacheLimiterC-Api.h"
00054 
00055 #include "BLI_blenlib.h"
00056 #include "BLI_linklist.h"
00057 #include "BLI_utildefines.h"
00058 #include "BLI_callbacks.h"
00059 
00060 #include "BLF_translation.h"
00061 
00062 #include "DNA_anim_types.h"
00063 #include "DNA_ipo_types.h" // XXX old animation system
00064 #include "DNA_object_types.h"
00065 #include "DNA_space_types.h"
00066 #include "DNA_userdef_types.h"
00067 #include "DNA_scene_types.h"
00068 #include "DNA_screen_types.h"
00069 #include "DNA_windowmanager_types.h"
00070 
00071 #include "BKE_blender.h"
00072 #include "BKE_context.h"
00073 #include "BKE_depsgraph.h"
00074 #include "BKE_DerivedMesh.h"
00075 #include "BKE_font.h"
00076 #include "BKE_global.h"
00077 #include "BKE_library.h"
00078 #include "BKE_main.h"
00079 #include "BKE_packedFile.h"
00080 #include "BKE_report.h"
00081 #include "BKE_sound.h"
00082 #include "BKE_texture.h"
00083 
00084 
00085 #include "BLO_readfile.h"
00086 #include "BLO_writefile.h"
00087 
00088 #include "RNA_access.h"
00089 
00090 #include "IMB_imbuf.h"
00091 #include "IMB_imbuf_types.h"
00092 #include "IMB_thumbs.h"
00093 
00094 #include "ED_datafiles.h"
00095 #include "ED_object.h"
00096 #include "ED_screen.h"
00097 #include "ED_sculpt.h"
00098 #include "ED_view3d.h"
00099 #include "ED_util.h"
00100 
00101 #include "RE_pipeline.h" /* only to report missing engine */
00102 
00103 #include "GHOST_C-api.h"
00104 #include "GHOST_Path-api.h"
00105 
00106 #include "UI_interface.h"
00107 
00108 #include "GPU_draw.h"
00109 
00110 #ifdef WITH_PYTHON
00111 #include "BPY_extern.h"
00112 #endif
00113 
00114 #include "WM_api.h"
00115 #include "WM_types.h"
00116 #include "wm.h"
00117 #include "wm_files.h"
00118 #include "wm_window.h"
00119 #include "wm_event_system.h"
00120 
00121 static void write_history(void);
00122 
00123 /* To be able to read files without windows closing, opening, moving 
00124    we try to prepare for worst case:
00125    - active window gets active screen from file 
00126    - restoring the screens from non-active windows 
00127    Best case is all screens match, in that case they get assigned to proper window  
00128 */
00129 static void wm_window_match_init(bContext *C, ListBase *wmlist)
00130 {
00131     wmWindowManager *wm;
00132     wmWindow *win, *active_win;
00133     
00134     *wmlist= G.main->wm;
00135     G.main->wm.first= G.main->wm.last= NULL;
00136     
00137     active_win = CTX_wm_window(C);
00138 
00139     /* first wrap up running stuff */
00140     /* code copied from wm_init_exit.c */
00141     for(wm= wmlist->first; wm; wm= wm->id.next) {
00142         
00143         WM_jobs_stop_all(wm);
00144         
00145         for(win= wm->windows.first; win; win= win->next) {
00146         
00147             CTX_wm_window_set(C, win);  /* needed by operator close callbacks */
00148             WM_event_remove_handlers(C, &win->handlers);
00149             WM_event_remove_handlers(C, &win->modalhandlers);
00150             ED_screen_exit(C, win, win->screen);
00151         }
00152     }
00153     
00154     /* reset active window */
00155     CTX_wm_window_set(C, active_win);
00156 
00157     ED_editors_exit(C);
00158 
00159     /* just had return; here from r12991, this code could just get removed?*/
00160 #if 0
00161     if(wm==NULL) return;
00162     if(G.fileflags & G_FILE_NO_UI) return;
00163     
00164     /* we take apart the used screens from non-active window */
00165     for(win= wm->windows.first; win; win= win->next) {
00166         BLI_strncpy(win->screenname, win->screen->id.name, MAX_ID_NAME);
00167         if(win!=wm->winactive) {
00168             BLI_remlink(&G.main->screen, win->screen);
00169             //BLI_addtail(screenbase, win->screen);
00170         }
00171     }
00172 #endif
00173 }
00174 
00175 /* match old WM with new, 4 cases:
00176   1- no current wm, no read wm: make new default
00177   2- no current wm, but read wm: that's OK, do nothing
00178   3- current wm, but not in file: try match screen names
00179   4- current wm, and wm in file: try match ghostwin 
00180 */
00181 
00182 static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
00183 {
00184     wmWindowManager *oldwm, *wm;
00185     wmWindow *oldwin, *win;
00186     
00187     /* cases 1 and 2 */
00188     if(oldwmlist->first==NULL) {
00189         if(G.main->wm.first); /* nothing todo */
00190         else
00191             wm_add_default(C);
00192     }
00193     else {
00194         /* cases 3 and 4 */
00195         
00196         /* we've read file without wm..., keep current one entirely alive */
00197         if(G.main->wm.first==NULL) {
00198             bScreen *screen= NULL;
00199 
00200             /* when loading without UI, no matching needed */
00201             if(!(G.fileflags & G_FILE_NO_UI) && (screen= CTX_wm_screen(C))) {
00202 
00203                 /* match oldwm to new dbase, only old files */
00204                 for(wm= oldwmlist->first; wm; wm= wm->id.next) {
00205                     
00206                     for(win= wm->windows.first; win; win= win->next) {
00207                         /* all windows get active screen from file */
00208                         if(screen->winid==0)
00209                             win->screen= screen;
00210                         else 
00211                             win->screen= ED_screen_duplicate(win, screen);
00212                         
00213                         BLI_strncpy(win->screenname, win->screen->id.name+2, sizeof(win->screenname));
00214                         win->screen->winid= win->winid;
00215                     }
00216                 }
00217             }
00218             
00219             G.main->wm= *oldwmlist;
00220             
00221             /* screens were read from file! */
00222             ED_screens_initialize(G.main->wm.first);
00223         }
00224         else {
00225             /* what if old was 3, and loaded 1? */
00226             /* this code could move to setup_appdata */
00227             oldwm= oldwmlist->first;
00228             wm= G.main->wm.first;
00229 
00230             /* preserve key configurations in new wm, to preserve their keymaps */
00231             wm->keyconfigs= oldwm->keyconfigs;
00232             wm->addonconf= oldwm->addonconf;
00233             wm->defaultconf= oldwm->defaultconf;
00234             wm->userconf= oldwm->userconf;
00235 
00236             oldwm->keyconfigs.first= oldwm->keyconfigs.last= NULL;
00237             oldwm->addonconf= NULL;
00238             oldwm->defaultconf= NULL;
00239             oldwm->userconf= NULL;
00240 
00241             /* ensure making new keymaps and set space types */
00242             wm->initialized= 0;
00243             wm->winactive= NULL;
00244             
00245             /* only first wm in list has ghostwins */
00246             for(win= wm->windows.first; win; win= win->next) {
00247                 for(oldwin= oldwm->windows.first; oldwin; oldwin= oldwin->next) {
00248                     
00249                     if(oldwin->winid == win->winid ) {
00250                         win->ghostwin= oldwin->ghostwin;
00251                         win->active= oldwin->active;
00252                         if(win->active)
00253                             wm->winactive= win;
00254 
00255                         if(!G.background) /* file loading in background mode still calls this */
00256                             GHOST_SetWindowUserData(win->ghostwin, win);    /* pointer back */
00257 
00258                         oldwin->ghostwin= NULL;
00259                         
00260                         win->eventstate= oldwin->eventstate;
00261                         oldwin->eventstate= NULL;
00262                         
00263                         /* ensure proper screen rescaling */
00264                         win->sizex= oldwin->sizex;
00265                         win->sizey= oldwin->sizey;
00266                         win->posx= oldwin->posx;
00267                         win->posy= oldwin->posy;
00268                     }
00269                 }
00270             }
00271             wm_close_and_free_all(C, oldwmlist);
00272         }
00273     }
00274 }
00275 
00276 /* in case UserDef was read, we re-initialize all, and do versioning */
00277 static void wm_init_userdef(bContext *C)
00278 {
00279     UI_init_userdef();
00280     MEM_CacheLimiter_set_maximum(U.memcachelimit * 1024 * 1024);
00281     sound_init(CTX_data_main(C));
00282 
00283     /* needed so loading a file from the command line respects user-pref [#26156] */
00284     if(U.flag & USER_FILENOUI)  G.fileflags |= G_FILE_NO_UI;
00285     else                        G.fileflags &= ~G_FILE_NO_UI;
00286 
00287     /* set the python auto-execute setting from user prefs */
00288     /* enabled by default, unless explicitly enabled in the command line which overrides */
00289     if((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) {
00290         if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) G.f |=  G_SCRIPT_AUTOEXEC;
00291         else                                              G.f &= ~G_SCRIPT_AUTOEXEC;
00292     }
00293 
00294     /* update tempdir from user preferences */
00295     BLI_init_temporary_dir(U.tempdir);
00296 }
00297 
00298 
00299 
00300 /* return codes */
00301 #define BKE_READ_EXOTIC_FAIL_PATH       -3 /* file format is not supported */
00302 #define BKE_READ_EXOTIC_FAIL_FORMAT     -2 /* file format is not supported */
00303 #define BKE_READ_EXOTIC_FAIL_OPEN       -1 /* Can't open the file */
00304 #define BKE_READ_EXOTIC_OK_BLEND         0 /* .blend file */
00305 #define BKE_READ_EXOTIC_OK_OTHER         1 /* other supported formats */
00306 
00307 /* intended to check for non-blender formats but for now it only reads blends */
00308 static int wm_read_exotic(Scene *UNUSED(scene), const char *name)
00309 {
00310     int len;
00311     gzFile gzfile;
00312     char header[7];
00313     int retval;
00314 
00315     // make sure we're not trying to read a directory....
00316 
00317     len= strlen(name);
00318     if (ELEM(name[len-1], '/', '\\')) {
00319         retval= BKE_READ_EXOTIC_FAIL_PATH;
00320     }
00321     else {
00322         gzfile = gzopen(name,"rb");
00323 
00324         if (gzfile == NULL) {
00325             retval= BKE_READ_EXOTIC_FAIL_OPEN;
00326         }
00327         else {
00328             len= gzread(gzfile, header, sizeof(header));
00329             gzclose(gzfile);
00330             if (len == sizeof(header) && strncmp(header, "BLENDER", 7) == 0) {
00331                 retval= BKE_READ_EXOTIC_OK_BLEND;
00332             }
00333             else {
00334                 //XXX waitcursor(1);
00335                 /*
00336                 if(is_foo_format(name)) {
00337                     read_foo(name);
00338                     retval= BKE_READ_EXOTIC_OK_OTHER;
00339                 }
00340                 else
00341                  */
00342                 {
00343                     retval= BKE_READ_EXOTIC_FAIL_FORMAT;
00344                 }
00345                 //XXX waitcursor(0);
00346             }
00347         }
00348     }
00349 
00350     return retval;
00351 }
00352 
00353 void WM_read_file(bContext *C, const char *filepath, ReportList *reports)
00354 {
00355     int retval;
00356 
00357     /* so we can get the error message */
00358     errno = 0;
00359 
00360     WM_cursor_wait(1);
00361 
00362     BLI_exec_cb(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
00363 
00364     /* first try to append data from exotic file formats... */
00365     /* it throws error box when file doesn't exist and returns -1 */
00366     /* note; it should set some error message somewhere... (ton) */
00367     retval= wm_read_exotic(CTX_data_scene(C), filepath);
00368     
00369     /* we didn't succeed, now try to read Blender file */
00370     if (retval == BKE_READ_EXOTIC_OK_BLEND) {
00371         int G_f= G.f;
00372         ListBase wmbase;
00373 
00374         /* put aside screens to match with persistent windows later */
00375         /* also exit screens and editors */
00376         wm_window_match_init(C, &wmbase); 
00377         
00378         retval= BKE_read_file(C, filepath, reports);
00379         G.save_over = 1;
00380 
00381         /* this flag is initialized by the operator but overwritten on read.
00382          * need to re-enable it here else drivers + registered scripts wont work. */
00383         if(G.f != G_f) {
00384             const int flags_keep= (G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF);
00385             G.f= (G.f & ~flags_keep) | (G_f & flags_keep);
00386         }
00387 
00388         /* match the read WM with current WM */
00389         wm_window_match_do(C, &wmbase);
00390         WM_check(C); /* opens window(s), checks keymaps */
00391         
00392 // XXX      mainwindow_set_filename_to_title(G.main->name);
00393 
00394         if(retval == BKE_READ_FILE_OK_USERPREFS) wm_init_userdef(C);    // in case a userdef is read from regular .blend
00395         
00396         if (retval != BKE_READ_FILE_FAIL) {
00397             G.relbase_valid = 1;
00398             if(!G.background) /* assume automated tasks with background, dont write recent file list */
00399                 write_history();
00400         }
00401 
00402 
00403         WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL);
00404 //      refresh_interface_font();
00405 
00406         CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
00407 
00408         ED_editors_init(C);
00409         DAG_on_visible_update(CTX_data_main(C), TRUE);
00410 
00411 #ifdef WITH_PYTHON
00412         /* run any texts that were loaded in and flagged as modules */
00413         BPY_driver_reset();
00414         BPY_app_handlers_reset(FALSE);
00415         BPY_modules_load_user(C);
00416 #endif
00417 
00418         /* important to do before NULL'ing the context */
00419         BLI_exec_cb(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
00420 
00421         CTX_wm_window_set(C, NULL); /* exits queues */
00422 
00423 #if 0   /* gives popups on windows but not linux, bug in report API but disable for now to stop users getting annoyed  */
00424         /* TODO, make this show in header info window */
00425         {
00426             Scene *sce;
00427             for(sce= G.main->scene.first; sce; sce= sce->id.next) {
00428                 if(sce->r.engine[0] && BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL) {
00429                     BKE_reportf(reports, RPT_WARNING, "Engine not available: '%s' for scene: %s, an addon may need to be installed or enabled", sce->r.engine, sce->id.name+2);
00430                 }
00431             }
00432         }
00433 #endif
00434 
00435         // XXX      undo_editmode_clear();
00436         BKE_reset_undo();
00437         BKE_write_undo(C, "original");  /* save current state */
00438     }
00439     else if(retval == BKE_READ_EXOTIC_OK_OTHER)
00440         BKE_write_undo(C, "Import file");
00441     else if(retval == BKE_READ_EXOTIC_FAIL_OPEN) {
00442         BKE_reportf(reports, RPT_ERROR, IFACE_("Can't read file: \"%s\", %s."), filepath,
00443                 errno ? strerror(errno) : IFACE_("Unable to open the file"));
00444     }
00445     else if(retval == BKE_READ_EXOTIC_FAIL_FORMAT) {
00446         BKE_reportf(reports, RPT_ERROR, IFACE_("File format is not supported in file: \"%s\"."), filepath);
00447     }
00448     else if(retval == BKE_READ_EXOTIC_FAIL_PATH) {
00449         BKE_reportf(reports, RPT_ERROR, IFACE_("File path invalid: \"%s\"."), filepath);
00450     }
00451     else {
00452         BKE_reportf(reports, RPT_ERROR, IFACE_("Unknown error loading: \"%s\"."), filepath);
00453         BLI_assert(!"invalid 'retval'");
00454     }
00455 
00456     WM_cursor_wait(0);
00457 
00458 }
00459 
00460 
00461 /* called on startup,  (context entirely filled with NULLs) */
00462 /* or called for 'New File' */
00463 /* op can be NULL */
00464 int WM_read_homefile(bContext *C, ReportList *UNUSED(reports), short from_memory)
00465 {
00466     ListBase wmbase;
00467     char tstr[FILE_MAX];
00468     int success= 0;
00469     
00470     free_ttfont(); /* still weird... what does it here? */
00471         
00472     G.relbase_valid = 0;
00473     if (!from_memory) {
00474         char *cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
00475         if (cfgdir) {
00476             BLI_make_file_string(G.main->name, tstr, cfgdir, BLENDER_STARTUP_FILE);
00477         } else {
00478             tstr[0] = '\0';
00479             from_memory = 1;
00480         }
00481     }
00482     
00483     /* prevent loading no UI */
00484     G.fileflags &= ~G_FILE_NO_UI;
00485     
00486     /* put aside screens to match with persistent windows later */
00487     wm_window_match_init(C, &wmbase); 
00488     
00489     if (!from_memory && BLI_exists(tstr)) {
00490         success = (BKE_read_file(C, tstr, NULL) != BKE_READ_FILE_FAIL);
00491         
00492         if(U.themes.first==NULL) {
00493             printf("\nError: No valid "STRINGIFY(BLENDER_STARTUP_FILE)", fall back to built-in default.\n\n");
00494             success = 0;
00495         }
00496     }
00497     if(success==0) {
00498         success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL);
00499         if (wmbase.first == NULL) wm_clear_default_size(C);
00500 
00501 #ifdef WITH_PYTHON_SECURITY /* not default */
00502         /* use alternative setting for security nuts
00503          * otherwise we'd need to patch the binary blob - startup.blend.c */
00504         U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
00505 #endif
00506     }
00507     
00508     /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
00509      * can remove this eventually, only in a 2.53 and older, now its not written */
00510     G.fileflags &= ~G_FILE_RELATIVE_REMAP;
00511     
00512     /* check userdef before open window, keymaps etc */
00513     wm_init_userdef(C);
00514     
00515     /* match the read WM with current WM */
00516     wm_window_match_do(C, &wmbase); 
00517     WM_check(C); /* opens window(s), checks keymaps */
00518 
00519     G.main->name[0]= '\0';
00520 
00521     /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
00522     if (!G.background) GPU_default_lights();
00523     
00524     /* XXX */
00525     G.save_over = 0;    // start with save preference untitled.blend
00526     G.fileflags &= ~G_FILE_AUTOPLAY;    /*  disable autoplay in startup.blend... */
00527 //  mainwindow_set_filename_to_title("");   // empty string re-initializes title to "Blender"
00528     
00529 //  refresh_interface_font();
00530     
00531 //  undo_editmode_clear();
00532     BKE_reset_undo();
00533     BKE_write_undo(C, "original");  /* save current state */
00534 
00535     ED_editors_init(C);
00536     DAG_on_visible_update(CTX_data_main(C), TRUE);
00537 
00538 #ifdef WITH_PYTHON
00539     if(CTX_py_init_get(C)) {
00540         /* sync addons, these may have changed from the defaults */
00541         BPY_string_exec(C, "__import__('addon_utils').reset_all()");
00542 
00543         BPY_driver_reset();
00544         BPY_app_handlers_reset(FALSE);
00545         BPY_modules_load_user(C);
00546     }
00547 #endif
00548 
00549     WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL);
00550 
00551     /* in background mode the scene will stay NULL */
00552     if(!G.background) {
00553         CTX_wm_window_set(C, NULL); /* exits queues */
00554     }
00555 
00556     return TRUE;
00557 }
00558 
00559 int WM_read_homefile_exec(bContext *C, wmOperator *op)
00560 {
00561     int from_memory= strcmp(op->type->idname, "WM_OT_read_factory_settings") == 0;
00562     return WM_read_homefile(C, op->reports, from_memory) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
00563 }
00564 
00565 void WM_read_history(void)
00566 {
00567     char name[FILE_MAX];
00568     LinkNode *l, *lines;
00569     struct RecentFile *recent;
00570     char *line;
00571     int num;
00572     char *cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
00573 
00574     if (!cfgdir) return;
00575 
00576     BLI_make_file_string("/", name, cfgdir, BLENDER_HISTORY_FILE);
00577 
00578     lines= BLI_file_read_as_lines(name);
00579 
00580     G.recent_files.first = G.recent_files.last = NULL;
00581 
00582     /* read list of recent opened files from recent-files.txt to memory */
00583     for (l= lines, num= 0; l && (num<U.recent_files); l= l->next) {
00584         line = l->link;
00585         if (line[0] && BLI_exists(line)) {
00586             recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
00587             BLI_addtail(&(G.recent_files), recent);
00588             recent->filepath = BLI_strdup(line);
00589             num++;
00590         }
00591     }
00592     
00593     BLI_file_free_lines(lines);
00594 
00595 }
00596 
00597 static void write_history(void)
00598 {
00599     struct RecentFile *recent, *next_recent;
00600     char name[FILE_MAX];
00601     char *user_config_dir;
00602     FILE *fp;
00603     int i;
00604 
00605     /* will be NULL in background mode */
00606     user_config_dir = BLI_get_folder_create(BLENDER_USER_CONFIG, NULL);
00607     if(!user_config_dir)
00608         return;
00609 
00610     BLI_make_file_string("/", name, user_config_dir, BLENDER_HISTORY_FILE);
00611 
00612     recent = G.recent_files.first;
00613     /* refresh recent-files.txt of recent opened files, when current file was changed */
00614     if(!(recent) || (BLI_path_cmp(recent->filepath, G.main->name)!=0)) {
00615         fp= fopen(name, "w");
00616         if (fp) {
00617             /* add current file to the beginning of list */
00618             recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
00619             recent->filepath = BLI_strdup(G.main->name);
00620             BLI_addhead(&(G.recent_files), recent);
00621             /* write current file to recent-files.txt */
00622             fprintf(fp, "%s\n", recent->filepath);
00623             recent = recent->next;
00624             i=1;
00625             /* write rest of recent opened files to recent-files.txt */
00626             while((i<U.recent_files) && (recent)){
00627                 /* this prevents to have duplicities in list */
00628                 if (BLI_path_cmp(recent->filepath, G.main->name)!=0) {
00629                     fprintf(fp, "%s\n", recent->filepath);
00630                     recent = recent->next;
00631                 }
00632                 else {
00633                     next_recent = recent->next;
00634                     MEM_freeN(recent->filepath);
00635                     BLI_freelinkN(&(G.recent_files), recent);
00636                     recent = next_recent;
00637                 }
00638                 i++;
00639             }
00640             fclose(fp);
00641         }
00642 
00643         /* also update most recent files on System */
00644         GHOST_addToSystemRecentFiles(G.main->name);
00645     }
00646 }
00647 
00648 static ImBuf *blend_file_thumb(Scene *scene, int **thumb_pt)
00649 {
00650     /* will be scaled down, but gives some nice oversampling */
00651     ImBuf *ibuf;
00652     int *thumb;
00653     char err_out[256]= "unknown";
00654 
00655     *thumb_pt= NULL;
00656 
00657     /* scene can be NULL if running a script at startup and calling the save operator */
00658     if(G.background || scene==NULL || scene->camera==NULL)
00659         return NULL;
00660 
00661     /* gets scaled to BLEN_THUMB_SIZE */
00662     ibuf= ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, IB_rect, OB_SOLID, err_out);
00663     
00664     if(ibuf) {      
00665         float aspect= (scene->r.xsch*scene->r.xasp) / (scene->r.ysch*scene->r.yasp);
00666 
00667         /* dirty oversampling */
00668         IMB_scaleImBuf(ibuf, BLEN_THUMB_SIZE, BLEN_THUMB_SIZE);
00669 
00670         /* add pretty overlay */
00671         IMB_overlayblend_thumb(ibuf->rect, ibuf->x, ibuf->y, aspect);
00672         
00673         /* first write into thumb buffer */
00674         thumb= MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb");
00675 
00676         thumb[0] = BLEN_THUMB_SIZE;
00677         thumb[1] = BLEN_THUMB_SIZE;
00678 
00679         memcpy(thumb + 2, ibuf->rect, BLEN_THUMB_SIZE * BLEN_THUMB_SIZE * sizeof(int));
00680     }
00681     else {
00682         /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */
00683         fprintf(stderr, "blend_file_thumb failed to create thumbnail: %s\n", err_out);
00684         thumb= NULL;
00685     }
00686     
00687     /* must be freed by caller */
00688     *thumb_pt= thumb;
00689     
00690     return ibuf;
00691 }
00692 
00693 /* easy access from gdb */
00694 int write_crash_blend(void)
00695 {
00696     char path[FILE_MAX];
00697     int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on crash file */
00698 
00699     BLI_strncpy(path, G.main->name, sizeof(path));
00700     BLI_replace_extension(path, sizeof(path), "_crash.blend");
00701     if(BLO_write_file(G.main, path, fileflags, NULL, NULL)) {
00702         printf("written: %s\n", path);
00703         return 1;
00704     }
00705     else {
00706         printf("failed: %s\n", path);
00707         return 0;
00708     }
00709 }
00710 
00711 int WM_write_file(bContext *C, const char *target, int fileflags, ReportList *reports, int copy)
00712 {
00713     Library *li;
00714     int len;
00715     char filepath[FILE_MAX];
00716 
00717     int *thumb= NULL;
00718     ImBuf *ibuf_thumb= NULL;
00719 
00720     len = strlen(target);
00721     
00722     if (len == 0) {
00723         BKE_report(reports, RPT_ERROR, "Path is empty, cannot save");
00724         return -1;
00725     }
00726 
00727     if (len >= FILE_MAX) {
00728         BKE_report(reports, RPT_ERROR, "Path too long, cannot save");
00729         return -1;
00730     }
00731  
00732     BLI_strncpy(filepath, target, FILE_MAX);
00733     BLI_replace_extension(filepath, FILE_MAX, ".blend");
00734     /* dont use 'target' anymore */
00735     
00736     /* send the OnSave event */
00737     for (li= G.main->library.first; li; li= li->id.next) {
00738         if (BLI_path_cmp(li->filepath, filepath) == 0) {
00739             BKE_reportf(reports, RPT_ERROR, "Can't overwrite used library '%.240s'", filepath);
00740             return -1;
00741         }
00742     }
00743 
00744     /* blend file thumbnail */
00745     /* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */
00746     if(U.flag & USER_SAVE_PREVIEWS) {
00747         ibuf_thumb= blend_file_thumb(CTX_data_scene(C), &thumb);
00748     }
00749 
00750     BLI_exec_cb(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
00751 
00752     /* operator now handles overwrite checks */
00753 
00754     if (G.fileflags & G_AUTOPACK) {
00755         packAll(G.main, reports);
00756     }
00757     
00758     ED_object_exit_editmode(C, EM_DO_UNDO);
00759     ED_sculpt_force_update(C);
00760 
00761     /* don't forget not to return without! */
00762     WM_cursor_wait(1);
00763     
00764     fileflags |= G_FILE_HISTORY; /* write file history */
00765 
00766     if (BLO_write_file(CTX_data_main(C), filepath, fileflags, reports, thumb)) {
00767         if(!copy) {
00768             G.relbase_valid = 1;
00769             BLI_strncpy(G.main->name, filepath, sizeof(G.main->name));  /* is guaranteed current file */
00770     
00771             G.save_over = 1; /* disable untitled.blend convention */
00772         }
00773 
00774         if(fileflags & G_FILE_COMPRESS) G.fileflags |= G_FILE_COMPRESS;
00775         else G.fileflags &= ~G_FILE_COMPRESS;
00776         
00777         if(fileflags & G_FILE_AUTOPLAY) G.fileflags |= G_FILE_AUTOPLAY;
00778         else G.fileflags &= ~G_FILE_AUTOPLAY;
00779 
00780         /* prevent background mode scripts from clobbering history */
00781         if(!G.background) {
00782             write_history();
00783         }
00784 
00785         BLI_exec_cb(G.main, NULL, BLI_CB_EVT_SAVE_POST);
00786 
00787         /* run this function after because the file cant be written before the blend is */
00788         if (ibuf_thumb) {
00789             ibuf_thumb= IMB_thumb_create(filepath, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb);
00790             IMB_freeImBuf(ibuf_thumb);
00791         }
00792 
00793         if(thumb) MEM_freeN(thumb);
00794     }
00795     else {
00796         if(ibuf_thumb) IMB_freeImBuf(ibuf_thumb);
00797         if(thumb) MEM_freeN(thumb);
00798         
00799         WM_cursor_wait(0);
00800         return -1;
00801     }
00802 
00803     WM_cursor_wait(0);
00804     
00805     return 0;
00806 }
00807 
00808 /* operator entry */
00809 int WM_write_homefile(bContext *C, wmOperator *op)
00810 {
00811     wmWindowManager *wm= CTX_wm_manager(C);
00812     wmWindow *win= CTX_wm_window(C);
00813     char filepath[FILE_MAX];
00814     int fileflags;
00815 
00816     /* check current window and close it if temp */
00817     if(win->screen->temp)
00818         wm_window_close(C, wm, win);
00819     
00820     /* update keymaps in user preferences */
00821     WM_keyconfig_update(wm);
00822     
00823     BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
00824     printf("trying to save homefile at %s ", filepath);
00825     
00826     /*  force save as regular blend file */
00827     fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
00828 
00829     if(BLO_write_file(CTX_data_main(C), filepath, fileflags, op->reports, NULL) == 0) {
00830         printf("fail\n");
00831         return OPERATOR_CANCELLED;
00832     }
00833     
00834     printf("ok\n");
00835 
00836     G.save_over= 0;
00837 
00838     return OPERATOR_FINISHED;
00839 }
00840 
00841 /************************ autosave ****************************/
00842 
00843 void wm_autosave_location(char *filepath)
00844 {
00845     char pidstr[32];
00846 #ifdef WIN32
00847     char *savedir;
00848 #endif
00849 
00850     BLI_snprintf(pidstr, sizeof(pidstr), "%d.blend", abs(getpid()));
00851 
00852 #ifdef WIN32
00853     /* XXX Need to investigate how to handle default location of '/tmp/'
00854      * This is a relative directory on Windows, and it may be
00855      * found. Example:
00856      * Blender installed on D:\ drive, D:\ drive has D:\tmp\
00857      * Now, BLI_exists() will find '/tmp/' exists, but
00858      * BLI_make_file_string will create string that has it most likely on C:\
00859      * through get_default_root().
00860      * If there is no C:\tmp autosave fails. */
00861     if (!BLI_exists(BLI_temporary_dir())) {
00862         savedir = BLI_get_folder_create(BLENDER_USER_AUTOSAVE, NULL);
00863         BLI_make_file_string("/", filepath, savedir, pidstr);
00864         return;
00865     }
00866 #endif
00867 
00868     BLI_make_file_string("/", filepath, BLI_temporary_dir(), pidstr);
00869 }
00870 
00871 void WM_autosave_init(wmWindowManager *wm)
00872 {
00873     wm_autosave_timer_ended(wm);
00874 
00875     if(U.flag & USER_AUTOSAVE)
00876         wm->autosavetimer= WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime*60.0);
00877 }
00878 
00879 void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(wt))
00880 {
00881     wmWindow *win;
00882     wmEventHandler *handler;
00883     char filepath[FILE_MAX];
00884     int fileflags;
00885 
00886     WM_event_remove_timer(wm, NULL, wm->autosavetimer);
00887 
00888     /* if a modal operator is running, don't autosave, but try again in 10 seconds */
00889     for(win=wm->windows.first; win; win=win->next) {
00890         for(handler=win->modalhandlers.first; handler; handler=handler->next) {
00891             if(handler->op) {
00892                 wm->autosavetimer= WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0);
00893                 return;
00894             }
00895         }
00896     }
00897     
00898     wm_autosave_location(filepath);
00899 
00900     /*  force save as regular blend file */
00901     fileflags = G.fileflags & ~(G_FILE_COMPRESS|G_FILE_AUTOPLAY |G_FILE_LOCK|G_FILE_SIGN|G_FILE_HISTORY);
00902 
00903     /* no error reporting to console */
00904     BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
00905 
00906     /* do timer after file write, just in case file write takes a long time */
00907     wm->autosavetimer= WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime*60.0);
00908 }
00909 
00910 void wm_autosave_timer_ended(wmWindowManager *wm)
00911 {
00912     if(wm->autosavetimer) {
00913         WM_event_remove_timer(wm, NULL, wm->autosavetimer);
00914         wm->autosavetimer= NULL;
00915     }
00916 }
00917 
00918 void wm_autosave_delete(void)
00919 {
00920     char filename[FILE_MAX];
00921     
00922     wm_autosave_location(filename);
00923 
00924     if(BLI_exists(filename)) {
00925         char str[FILE_MAX];
00926         BLI_make_file_string("/", str, BLI_temporary_dir(), "quit.blend");
00927 
00928         /* if global undo; remove tempsave, otherwise rename */
00929         if(U.uiflag & USER_GLOBALUNDO) BLI_delete(filename, 0, 0);
00930         else BLI_rename(filename, str);
00931     }
00932 }
00933 
00934 void wm_autosave_read(bContext *C, ReportList *reports)
00935 {
00936     char filename[FILE_MAX];
00937 
00938     wm_autosave_location(filename);
00939     WM_read_file(C, filename, reports);
00940 }
00941