rename and negate DISABLE_PYTHON --> WITH_PYTHON
[blender.git] / source / blender / windowmanager / intern / wm_files.c
index 1aca9a66e579d90b851a9b8af7e7a86d1aca9ba5..aa99e8fcb1c18fbd3e9f17963da240220766c928 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * $Id: wm_files.c
+ * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
@@ -30,6 +30,7 @@
         */
 #include <stdio.h>
 #include <string.h>
+#include <errno.h>
 
 #ifdef WIN32
 #include <windows.h> /* need to include windows.h so _WIN32_IE is defined  */
@@ -60,6 +61,7 @@
 
 #include "BKE_blender.h"
 #include "BKE_context.h"
+#include "BKE_depsgraph.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_exotic.h"
 #include "BKE_font.h"
 #include "BLO_writefile.h"
 
 #include "RNA_access.h"
-#include "RNA_define.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
 
 #include "ED_datafiles.h"
 #include "ED_object.h"
 #include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
 #include "ED_util.h"
 
 #include "GHOST_C-api.h"
 
 #include "GPU_draw.h"
 
-// XXX #include "BPY_extern.h"
+#ifdef WITH_PYTHON
+#include "BPY_extern.h"
+#endif
 
 #include "WM_api.h"
 #include "WM_types.h"
 #include "wm.h"
 #include "wm_window.h"
+#include "wm_event_system.h"
 
-static void writeBlog(void);
+static void write_history(void);
 
 /* To be able to read files without windows closing, opening, moving 
    we try to prepare for worst case:
@@ -107,11 +117,13 @@ static void writeBlog(void);
 static void wm_window_match_init(bContext *C, ListBase *wmlist)
 {
        wmWindowManager *wm= G.main->wm.first;
-       wmWindow *win;
+       wmWindow *win, *active_win;
        
        *wmlist= G.main->wm;
        G.main->wm.first= G.main->wm.last= NULL;
        
+       active_win = CTX_wm_window(C);
+
        /* first wrap up running stuff */
        /* code copied from wm_init_exit.c */
        for(wm= wmlist->first; wm; wm= wm->id.next) {
@@ -121,10 +133,15 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
                for(win= wm->windows.first; win; win= win->next) {
                
                        CTX_wm_window_set(C, win);      /* needed by operator close callbacks */
+                       WM_event_remove_handlers(C, &win->handlers);
+                       WM_event_remove_handlers(C, &win->modalhandlers);
                        ED_screen_exit(C, win, win->screen);
                }
        }
        
+       /* reset active window */
+       CTX_wm_window_set(C, active_win);
+
        ED_editors_exit(C);
        
 return;        
@@ -164,21 +181,23 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
                
                /* we've read file without wm..., keep current one entirely alive */
                if(G.main->wm.first==NULL) {
-                       bScreen *screen= CTX_wm_screen(C);
-                       
-                       /* match oldwm to new dbase, only old files */
-                       
-                       for(wm= oldwmlist->first; wm; wm= wm->id.next) {
-                               
-                               for(win= wm->windows.first; win; win= win->next) {
-                                       /* all windows get active screen from file */
-                                       if(screen->winid==0)
-                                               win->screen= screen;
-                                       else 
-                                               win->screen= ED_screen_duplicate(win, screen);
+                       /* when loading without UI, no matching needed */
+                       if(!(G.fileflags & G_FILE_NO_UI)) {
+                               bScreen *screen= CTX_wm_screen(C);
+
+                               /* match oldwm to new dbase, only old files */
+                               for(wm= oldwmlist->first; wm; wm= wm->id.next) {
                                        
-                                       BLI_strncpy(win->screenname, win->screen->id.name+2, 21);
-                                       win->screen->winid= win->winid;
+                                       for(win= wm->windows.first; win; win= win->next) {
+                                               /* all windows get active screen from file */
+                                               if(screen->winid==0)
+                                                       win->screen= screen;
+                                               else 
+                                                       win->screen= ED_screen_duplicate(win, screen);
+                                               
+                                               BLI_strncpy(win->screenname, win->screen->id.name+2, 21);
+                                               win->screen->winid= win->winid;
+                                       }
                                }
                        }
                        
@@ -207,7 +226,9 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
                                                if(win->active)
                                                        wm->winactive= win;
 
-                                               GHOST_SetWindowUserData(win->ghostwin, win);    /* pointer back */
+                                               if(!G.background) /* file loading in background mode still calls this */
+                                                       GHOST_SetWindowUserData(win->ghostwin, win);    /* pointer back */
+
                                                oldwin->ghostwin= NULL;
                                                
                                                win->eventstate= oldwin->eventstate;
@@ -227,17 +248,27 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
 }
 
 /* in case UserDef was read, we re-initialize all, and do versioning */
-static void wm_init_userdef()
+static void wm_init_userdef(bContext *C)
 {
+       extern char btempdir[];
+
        UI_init_userdef();
        MEM_CacheLimiter_set_maximum(U.memcachelimit * 1024 * 1024);
-       sound_init();
+       sound_init(CTX_data_main(C));
+
+       /* set the python auto-execute setting from user prefs */
+       /* disabled by default, unless explicitly enabled in the command line */
+       if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) G.f |=  G_SCRIPT_AUTOEXEC;
+       if(U.tempdir[0]) BLI_where_is_temp(btempdir, 1);
 }
 
 void WM_read_file(bContext *C, char *name, ReportList *reports)
 {
        int retval;
 
+       /* so we can get the error message */
+       errno = 0;
+
        /* first try to append data from exotic file formats... */
        /* it throws error box when file doesnt exist and returns -1 */
        /* note; it should set some error message somewhere... (ton) */
@@ -245,26 +276,33 @@ void WM_read_file(bContext *C, char *name, ReportList *reports)
        
        /* we didn't succeed, now try to read Blender file */
        if (retval== 0) {
+               int G_f= G.f;
                ListBase wmbase;
 
                /* put aside screens to match with persistant windows later */
                /* also exit screens and editors */
                wm_window_match_init(C, &wmbase); 
                
-               retval= BKE_read_file(C, name, NULL, reports);
+               retval= BKE_read_file(C, name, reports);
                G.save_over = 1;
 
+               /* this flag is initialized by the operator but overwritten on read.
+                * need to re-enable it here else drivers + registered scripts wont work. */
+               if(G_f & G_SCRIPT_AUTOEXEC) G.f |= G_SCRIPT_AUTOEXEC;
+               else                                            G.f &= ~G_SCRIPT_AUTOEXEC;
+
                /* match the read WM with current WM */
-               wm_window_match_do(C, &wmbase); 
-               wm_check(C); /* opens window(s), checks keymaps */
+               wm_window_match_do(C, &wmbase);
+               WM_check(C); /* opens window(s), checks keymaps */
                
 // XXX         mainwindow_set_filename_to_title(G.main->name);
 
-               if(retval==2) wm_init_userdef();        // in case a userdef is read from regular .blend
+               if(retval==2) wm_init_userdef(C);       // in case a userdef is read from regular .blend
                
                if (retval!=0) {
                        G.relbase_valid = 1;
-                       writeBlog();
+                       if(!G.background) /* assume automated tasks with background, dont write recent file list */
+                               write_history();
                }
 
 // XXX         undo_editmode_clear();
@@ -273,14 +311,23 @@ void WM_read_file(bContext *C, char *name, ReportList *reports)
 
                WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL);
 //             refresh_interface_font();
-                                          
+
+               CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+
+               ED_editors_init(C);
+               DAG_on_load_update(CTX_data_main(C));
+
+#ifdef WITH_PYTHON
+               /* run any texts that were loaded in and flagged as modules */
+               BPY_load_user_modules(C);
+#endif
                CTX_wm_window_set(C, NULL); /* exits queues */
        }
        else if(retval==1)
                BKE_write_undo(C, "Import file");
        else if(retval == -1) {
-               if(reports && reports->list.first == NULL)
-                       BKE_report(reports, RPT_ERROR, "Cannot read file.");
+               if(reports)
+                       BKE_reportf(reports, RPT_ERROR, "Can't read file: \"%s\", %s.", name, errno ? strerror(errno) : "Incompatible file format");
        }
 }
 
@@ -291,20 +338,25 @@ void WM_read_file(bContext *C, char *name, ReportList *reports)
 int WM_read_homefile(bContext *C, wmOperator *op)
 {
        ListBase wmbase;
-       char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR];
-       char *home= BLI_gethome();
-       int from_memory= op?RNA_boolean_get(op->ptr, "factory"):0;
+       char tstr[FILE_MAXDIR+FILE_MAXFILE];
+       int from_memory= op && strcmp(op->type->idname, "WM_OT_read_factory_settings")==0;
        int success;
-               
-       BLI_clean(home);
        
        free_ttfont(); /* still weird... what does it here? */
                
        G.relbase_valid = 0;
        if (!from_memory) {
-               BLI_make_file_string(G.sce, tstr, home, ".B25.blend");
+               char *cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
+               if (cfgdir) {
+                       BLI_make_file_string(G.main->name, tstr, cfgdir, BLENDER_STARTUP_FILE);
+               } else {
+                       tstr[0] = '\0';
+                       from_memory = 1;
+                       if (op) {
+                               BKE_report(op->reports, RPT_INFO, "Config directory with startup.blend file found."); 
+                       }
+               }
        }
-       strcpy(scestr, G.sce);  /* temporary store */
        
        /* prevent loading no UI */
        G.fileflags &= ~G_FILE_NO_UI;
@@ -313,26 +365,30 @@ int WM_read_homefile(bContext *C, wmOperator *op)
        wm_window_match_init(C, &wmbase); 
        
        if (!from_memory && BLI_exists(tstr)) {
-               success = BKE_read_file(C, tstr, NULL, NULL);
+               success = BKE_read_file(C, tstr, NULL);
        } else {
-               success = BKE_read_file_from_memory(C, datatoc_B_blend, datatoc_B_blend_size, NULL, NULL);
+               success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL);
                if (wmbase.first == NULL) wm_clear_default_size(C);
        }
        
+       /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
+        * can remove this eventually, only in a 2.53 and older, now its not written */
+       G.fileflags &= ~G_FILE_RELATIVE_REMAP;
+
        /* match the read WM with current WM */
        wm_window_match_do(C, &wmbase); 
-       wm_check(C); /* opens window(s), checks keymaps */
+       WM_check(C); /* opens window(s), checks keymaps */
 
-       strcpy(G.sce, scestr); /* restore */
-       
-       wm_init_userdef();
+       G.main->name[0]= '\0';
+
+       wm_init_userdef(C);
        
        /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
-       GPU_default_lights();
+       if (!G.background) GPU_default_lights();
        
        /* XXX */
        G.save_over = 0;        // start with save preference untitled.blend
-       G.fileflags &= ~G_FILE_AUTOPLAY;        /*  disable autoplay in .B.blend... */
+       G.fileflags &= ~G_FILE_AUTOPLAY;        /*  disable autoplay in startup.blend... */
 //     mainwindow_set_filename_to_title("");   // empty string re-initializes title to "Blender"
        
 //     refresh_interface_font();
@@ -340,127 +396,99 @@ int WM_read_homefile(bContext *C, wmOperator *op)
 //     undo_editmode_clear();
        BKE_reset_undo();
        BKE_write_undo(C, "original");  /* save current state */
-       
-       WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL);
-       CTX_wm_window_set(C, NULL); /* exits queues */
-
-       return OPERATOR_FINISHED;
-}
 
+       ED_editors_init(C);
+       DAG_on_load_update(CTX_data_main(C));
 
-static void get_autosave_location(char buf[FILE_MAXDIR+FILE_MAXFILE])
-{
-       char pidstr[32];
-#ifdef WIN32
-       char subdir[9];
-       char savedir[FILE_MAXDIR];
-#endif
-
-       sprintf(pidstr, "%d.blend", abs(getpid()));
-       
-#ifdef WIN32
-       if (!BLI_exists(U.tempdir)) {
-               BLI_strncpy(subdir, "autosave", sizeof(subdir));
-               BLI_make_file_string("/", savedir, BLI_gethome(), subdir);
-               
-               /* create a new autosave dir
-                * function already checks for existence or not */
-               BLI_recurdir_fileops(savedir);
-       
-               BLI_make_file_string("/", buf, savedir, pidstr);
-               return;
+#ifdef WITH_PYTHON
+       if(CTX_py_init_get(C)) {
+               /* sync addons, these may have changed from the defaults */
+               BPY_eval_string(C, "__import__('bpy').utils.addon_reset_all()");
        }
 #endif
        
-       BLI_make_file_string("/", buf, U.tempdir, pidstr);
-}
-
-void WM_read_autosavefile(bContext *C)
-{
-       char tstr[FILE_MAX], scestr[FILE_MAX];
-       int save_over;
-
-       BLI_strncpy(scestr, G.sce, FILE_MAX);   /* temporal store */
-       
-       get_autosave_location(tstr);
+       WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL);
+       CTX_wm_window_set(C, NULL); /* exits queues */
 
-       save_over = G.save_over;
-       BKE_read_file(C, tstr, NULL, NULL);
-       G.save_over = save_over;
-       BLI_strncpy(G.sce, scestr, FILE_MAX);
+       return OPERATOR_FINISHED;
 }
 
 
-void read_Blog(void)
+void read_history(void)
 {
        char name[FILE_MAX];
        LinkNode *l, *lines;
        struct RecentFile *recent;
        char *line;
        int num;
+       char *cfgdir = BLI_get_folder(BLENDER_CONFIG, NULL);
+
+       if (!cfgdir) return;
+
+       BLI_make_file_string("/", name, cfgdir, BLENDER_HISTORY_FILE);
 
-       BLI_make_file_string("/", name, BLI_gethome(), ".Blog");
        lines= BLI_read_file_as_lines(name);
 
        G.recent_files.first = G.recent_files.last = NULL;
 
-       /* read list of recent opend files from .Blog to memory */
-       for (l= lines, num= 0; l && (num<U.recent_files); l= l->next, num++) {
+       /* read list of recent opend files from recent-files.txt to memory */
+       for (l= lines, num= 0; l && (num<U.recent_files); l= l->next) {
                line = l->link;
-               if (!BLI_streq(line, "")) {
-                       if (num==0) 
-                               strcpy(G.sce, line);
-                       
+               if (line[0] && BLI_exists(line)) {
                        recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
                        BLI_addtail(&(G.recent_files), recent);
-                       recent->filename = (char*)MEM_mallocN(sizeof(char)*(strlen(line)+1), "name of file");
-                       recent->filename[0] = '\0';
+                       recent->filepath = (char*)MEM_mallocN(sizeof(char)*(strlen(line)+1), "name of file");
+                       recent->filepath[0] = '\0';
                        
-                       strcpy(recent->filename, line);
+                       strcpy(recent->filepath, line);
+                       num++;
                }
        }
-
-       if(G.sce[0] == 0)
-               BLI_make_file_string("/", G.sce, BLI_gethome(), "untitled.blend");
        
        BLI_free_file_lines(lines);
 
 }
 
-static void writeBlog(void)
+static void write_history(void)
 {
        struct RecentFile *recent, *next_recent;
        char name[FILE_MAXDIR+FILE_MAXFILE];
+       char *user_config_dir;
        FILE *fp;
        int i;
 
-       BLI_make_file_string("/", name, BLI_gethome(), ".Blog");
+       /* will be NULL in background mode */
+       user_config_dir = BLI_get_folder_create(BLENDER_USER_CONFIG, NULL);
+       if(!user_config_dir)
+               return;
+
+       BLI_make_file_string("/", name, user_config_dir, BLENDER_HISTORY_FILE);
 
        recent = G.recent_files.first;
-       /* refresh .Blog of recent opened files, when current file was changed */
-       if(!(recent) || (strcmp(recent->filename, G.sce)!=0)) {
+       /* refresh recent-files.txt of recent opened files, when current file was changed */
+       if(!(recent) || (strcmp(recent->filepath, G.main->name)!=0)) {
                fp= fopen(name, "w");
                if (fp) {
                        /* add current file to the beginning of list */
                        recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
-                       recent->filename = (char*)MEM_mallocN(sizeof(char)*(strlen(G.sce)+1), "name of file");
-                       recent->filename[0] = '\0';
-                       strcpy(recent->filename, G.sce);
+                       recent->filepath = (char*)MEM_mallocN(sizeof(char)*(strlen(G.main->name)+1), "name of file");
+                       recent->filepath[0] = '\0';
+                       strcpy(recent->filepath, G.main->name);
                        BLI_addhead(&(G.recent_files), recent);
-                       /* write current file to .Blog */
-                       fprintf(fp, "%s\n", recent->filename);
+                       /* write current file to recent-files.txt */
+                       fprintf(fp, "%s\n", recent->filepath);
                        recent = recent->next;
                        i=1;
-                       /* write rest of recent opened files to .Blog */
+                       /* write rest of recent opened files to recent-files.txt */
                        while((i<U.recent_files) && (recent)){
                                /* this prevents to have duplicities in list */
-                               if (strcmp(recent->filename, G.sce)!=0) {
-                                       fprintf(fp, "%s\n", recent->filename);
+                               if (strcmp(recent->filepath, G.main->name)!=0) {
+                                       fprintf(fp, "%s\n", recent->filepath);
                                        recent = recent->next;
                                }
                                else {
                                        next_recent = recent->next;
-                                       MEM_freeN(recent->filename);
+                                       MEM_freeN(recent->filepath);
                                        BLI_freelinkN(&(G.recent_files), recent);
                                        recent = next_recent;
                                }
@@ -496,122 +524,274 @@ static void do_history(char *name, ReportList *reports)
                BKE_report(reports, RPT_ERROR, "Unable to make version backup");
 }
 
-void WM_write_file(bContext *C, char *target, int compress, ReportList *reports)
+static ImBuf *blend_file_thumb(Scene *scene, int **thumb_pt)
+{
+       /* will be scaled down, but gives some nice oversampling */
+       ImBuf *ibuf;
+       int *thumb;
+
+       *thumb_pt= NULL;
+       
+       if(G.background || scene->camera==NULL)
+               return NULL;
+
+       /* gets scaled to BLEN_THUMB_SIZE */
+       ibuf= ED_view3d_draw_offscreen_imbuf_simple(scene, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, IB_rect, OB_SOLID);
+       
+       if(ibuf) {              
+               float aspect= (scene->r.xsch*scene->r.xasp) / (scene->r.ysch*scene->r.yasp);
+
+               /* dirty oversampling */
+               IMB_scaleImBuf(ibuf, BLEN_THUMB_SIZE, BLEN_THUMB_SIZE);
+
+               /* add pretty overlay */
+               IMB_overlayblend_thumb(ibuf->rect, ibuf->x, ibuf->y, aspect);
+               
+               /* first write into thumb buffer */
+               thumb= MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb");
+
+               thumb[0] = BLEN_THUMB_SIZE;
+               thumb[1] = BLEN_THUMB_SIZE;
+
+               memcpy(thumb + 2, ibuf->rect, BLEN_THUMB_SIZE * BLEN_THUMB_SIZE * sizeof(int));
+       }
+       else {
+               /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */
+               thumb= NULL;
+       }
+       
+       /* must be freed by caller */
+       *thumb_pt= thumb;
+       
+       return ibuf;
+}
+
+/* easy access from gdb */
+int write_crash_blend(void)
+{
+       char path[FILE_MAX];
+       BLI_strncpy(path, G.main->name, sizeof(path));
+       BLI_replace_extension(path, sizeof(path), "_crash.blend");
+       if(BLO_write_file(G.main, path, G.fileflags, NULL, NULL)) {
+               printf("written: %s\n", path);
+               return 1;
+       }
+       else {
+               printf("failed: %s\n", path);
+               return 0;
+       }
+}
+
+int WM_write_file(bContext *C, const char *target, int fileflags, ReportList *reports, int copy)
 {
        Library *li;
-       int writeflags, len;
+       int len;
        char di[FILE_MAX];
-       
+
+       int *thumb= NULL;
+       ImBuf *ibuf_thumb= NULL;
+
        len = strlen(target);
        
-       if (len == 0) return;
+       if (len == 0) {
+               BKE_report(reports, RPT_ERROR, "Path is empty, cannot save");
+               return -1;
+       }
+
        if (len >= FILE_MAX) {
                BKE_report(reports, RPT_ERROR, "Path too long, cannot save");
-               return;
+               return -1;
        }
  
+       BLI_strncpy(di, target, FILE_MAX);
+       BLI_replace_extension(di, FILE_MAX, ".blend");
+       /* dont use 'target' anymore */
+       
        /* send the OnSave event */
        for (li= G.main->library.first; li; li= li->id.next) {
-               if (BLI_streq(li->name, target)) {
-                       BKE_report(reports, RPT_ERROR, "Cannot overwrite used library");
-                       return;
+               if (strcmp(li->filepath, di) == 0) {
+                       BKE_reportf(reports, RPT_ERROR, "Can't overwrite used library '%f'", di);
+                       return -1;
                }
        }
-       
-       if (!BLO_has_bfile_extension(target) && (len+6 < FILE_MAX)) {
-               sprintf(di, "%s.blend", target);
-       } else {
-               strcpy(di, target);
-       }
 
-//     if (BLI_exists(di)) {
-// XXX         if(!saveover(di))
-// XXX                 return; 
-//     }
-       
+       /* operator now handles overwrite checks */
+
        if (G.fileflags & G_AUTOPACK) {
                packAll(G.main, reports);
        }
        
-       ED_object_exit_editmode(C, 0);
+       ED_object_exit_editmode(C, EM_DO_UNDO);
+       ED_sculpt_force_update(C);
 
+       /* blend file thumbnail */
+       ibuf_thumb= blend_file_thumb(CTX_data_scene(C), &thumb);
+
+       /* rename to .blend1, do this as last before write */
        do_history(di, reports);
-       
-       writeflags= G.fileflags;
 
-       /* set compression flag */
-       if(compress) writeflags |= G_FILE_COMPRESS;
-       else writeflags &= ~G_FILE_COMPRESS;
+       if (BLO_write_file(CTX_data_main(C), di, fileflags, reports, thumb)) {
+               if(!copy) {
+                       G.relbase_valid = 1;
+                       strcpy(G.main->name, di);       /* is guaranteed current file */
        
-       if (BLO_write_file(CTX_data_main(C), di, writeflags, reports)) {
-               strcpy(G.sce, di);
-               G.relbase_valid = 1;
-               strcpy(G.main->name, di);       /* is guaranteed current file */
-
-               G.save_over = 1; /* disable untitled.blend convention */
+                       G.save_over = 1; /* disable untitled.blend convention */
+               }
 
-               if(compress) G.fileflags |= G_FILE_COMPRESS;
+               if(fileflags & G_FILE_COMPRESS) G.fileflags |= G_FILE_COMPRESS;
                else G.fileflags &= ~G_FILE_COMPRESS;
                
-               writeBlog();
+               if(fileflags & G_FILE_AUTOPLAY) G.fileflags |= G_FILE_AUTOPLAY;
+               else G.fileflags &= ~G_FILE_AUTOPLAY;
+
+               write_history();
+
+               /* run this function after because the file cant be written before the blend is */
+               if (ibuf_thumb) {
+                       ibuf_thumb= IMB_thumb_create(di, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb);
+                       IMB_freeImBuf(ibuf_thumb);
+               }
+
+               if(thumb) MEM_freeN(thumb);
+       }
+       else {
+               if(ibuf_thumb) IMB_freeImBuf(ibuf_thumb);
+               if(thumb) MEM_freeN(thumb);
+               return -1;
        }
 
 // XXX waitcursor(0);
+       return 0;
 }
 
 /* operator entry */
 int WM_write_homefile(bContext *C, wmOperator *op)
 {
+       wmWindowManager *wm= CTX_wm_manager(C);
        wmWindow *win= CTX_wm_window(C);
        char tstr[FILE_MAXDIR+FILE_MAXFILE];
-       int write_flags;
+       int fileflags;
        
        /* check current window and close it if temp */
-       if(win->screen->full == SCREENTEMP) {
-               wm_window_close(C, win);
-       }
+       if(win->screen->full == SCREENTEMP)
+               wm_window_close(C, wm, win);
        
-       BLI_make_file_string("/", tstr, BLI_gethome(), ".B25.blend");
+       BLI_make_file_string("/", tstr, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
+       printf("trying to save homefile at %s ", tstr);
        
        /*  force save as regular blend file */
-       write_flags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_LOCK | G_FILE_SIGN);
+       fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN);
 
-       BLO_write_file(CTX_data_main(C), tstr, write_flags, op->reports);
+       if(BLO_write_file(CTX_data_main(C), tstr, fileflags, op->reports, NULL) == 0) {
+               printf("fail\n");
+               return OPERATOR_CANCELLED;
+       }
        
+       printf("ok\n");
+
        G.save_over= 0;
-       
+
        return OPERATOR_FINISHED;
 }
 
-void WM_write_autosave(bContext *C)
+/************************ autosave ****************************/
+
+void wm_autosave_location(char *filename)
 {
-       char tstr[FILE_MAXDIR+FILE_MAXFILE];
-       int write_flags;
+       char pidstr[32];
+#ifdef WIN32
+       char *savedir;
+#endif
+
+       sprintf(pidstr, "%d.blend", abs(getpid()));
+       
+#ifdef WIN32
+       /* XXX Need to investigate how to handle default location of '/tmp/'
+        * This is a relative directory on Windows, and it may be
+        * found. Example:
+        * Blender installed on D:\ drive, D:\ drive has D:\tmp\
+        * Now, BLI_exists() will find '/tmp/' exists, but
+        * BLI_make_file_string will create string that has it most likely on C:\
+        * through get_default_root().
+        * If there is no C:\tmp autosave fails. */
+       if (!BLI_exists(U.tempdir)) {
+               savedir = BLI_get_folder_create(BLENDER_USER_AUTOSAVE, NULL);
+               BLI_make_file_string("/", filename, savedir, pidstr);
+               return;
+       }
+#endif
        
-       get_autosave_location(tstr);
+       BLI_make_file_string("/", filename, U.tempdir, pidstr);
+}
 
-               /*  force save as regular blend file */
-       write_flags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_LOCK | G_FILE_SIGN);
+void WM_autosave_init(wmWindowManager *wm)
+{
+       wm_autosave_timer_ended(wm);
 
-               /* error reporting to console */
-       BLO_write_file(CTX_data_main(C), tstr, write_flags, NULL);
+       if(U.flag & USER_AUTOSAVE)
+               wm->autosavetimer= WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime*60.0);
 }
 
-/* if global undo; remove tempsave, otherwise rename */
-void delete_autosave(void)
+void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(wt))
 {
-       char tstr[FILE_MAXDIR+FILE_MAXFILE];
+       wmWindow *win;
+       wmEventHandler *handler;
+       char filename[FILE_MAX];
+       int fileflags;
+
+       WM_event_remove_timer(wm, NULL, wm->autosavetimer);
+
+       /* if a modal operator is running, don't autosave, but try again in 10 seconds */
+       for(win=wm->windows.first; win; win=win->next) {
+               for(handler=win->modalhandlers.first; handler; handler=handler->next) {
+                       if(handler->op) {
+                               wm->autosavetimer= WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0);
+                               return;
+                       }
+               }
+       }
+       
+       wm_autosave_location(filename);
+
+       /*  force save as regular blend file */
+       fileflags = G.fileflags & ~(G_FILE_COMPRESS|G_FILE_AUTOPLAY |G_FILE_LOCK|G_FILE_SIGN);
+
+       /* no error reporting to console */
+       BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL);
+
+       /* do timer after file write, just in case file write takes a long time */
+       wm->autosavetimer= WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime*60.0);
+}
+
+void wm_autosave_timer_ended(wmWindowManager *wm)
+{
+       if(wm->autosavetimer) {
+               WM_event_remove_timer(wm, NULL, wm->autosavetimer);
+               wm->autosavetimer= NULL;
+       }
+}
+
+void wm_autosave_delete(void)
+{
+       char filename[FILE_MAX];
        
-       get_autosave_location(tstr);
+       wm_autosave_location(filename);
 
-       if (BLI_exists(tstr)) {
+       if(BLI_exists(filename)) {
                char str[FILE_MAXDIR+FILE_MAXFILE];
                BLI_make_file_string("/", str, U.tempdir, "quit.blend");
 
-               if(U.uiflag & USER_GLOBALUNDO) BLI_delete(tstr, 0, 0);
-               else BLI_rename(tstr, str);
+               /* if global undo; remove tempsave, otherwise rename */
+               if(U.uiflag & USER_GLOBALUNDO) BLI_delete(filename, 0, 0);
+               else BLI_rename(filename, str);
        }
 }
 
-/***/
+void wm_autosave_read(bContext *C, ReportList *reports)
+{
+       char filename[FILE_MAX];
+
+       wm_autosave_location(filename);
+       WM_read_file(C, filename, reports);
+}