passepartout overlay wasnt written into thumbnails
[blender.git] / source / blender / windowmanager / intern / wm_files.c
index ffaa315f04e2ad6208a764947af6fffeb2946cee..44768116c7ce6c4acb2784afbb84a9a131f917cd 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.
@@ -37,8 +37,8 @@
 #define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
 #endif
 #include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */
-#include "BLI_winstuff.h"
 #include <process.h> /* getpid */
+#include "BLI_winstuff.h"
 #else
 #include <unistd.h> /* getpid */
 #endif
@@ -68,6 +68,7 @@
 #include "BKE_main.h"
 #include "BKE_packedFile.h"
 #include "BKE_report.h"
+#include "BKE_sound.h"
 #include "BKE_texture.h"
 #include "BKE_utildefines.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"
+#include "BPY_extern.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
 #include "wm.h"
 #include "wm_window.h"
+#include "wm_event_system.h"
 
+static void writeBlog(void);
 
 /* To be able to read files without windows closing, opening, moving 
    we try to prepare for worst case:
 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) {
@@ -119,10 +129,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;        
@@ -193,6 +208,7 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
 
                        /* ensure making new keymaps and set space types */
                        wm->initialized= 0;
+                       wm->winactive= NULL;
                        
                        /* only first wm in list has ghostwins */
                        for(win= wm->windows.first; win; win= win->next) {
@@ -200,6 +216,10 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
                                        
                                        if(oldwin->winid == win->winid ) {
                                                win->ghostwin= oldwin->ghostwin;
+                                               win->active= oldwin->active;
+                                               if(win->active)
+                                                       wm->winactive= win;
+
                                                GHOST_SetWindowUserData(win->ghostwin, win);    /* pointer back */
                                                oldwin->ghostwin= NULL;
                                                
@@ -220,11 +240,19 @@ 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(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]) strncpy(btempdir, U.tempdir, FILE_MAXDIR+FILE_MAXFILE);
 }
 
 void WM_read_file(bContext *C, char *name, ReportList *reports)
@@ -238,6 +266,7 @@ 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 */
@@ -247,16 +276,24 @@ void WM_read_file(bContext *C, char *name, ReportList *reports)
                retval= BKE_read_file(C, name, NULL, 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);
-// XXX         sound_initialize_sounds();
 
-               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;
+               if (retval!=0) {
+                       G.relbase_valid = 1;
+                       if(!G.background) /* assume automated tasks with background, dont write recent file list */
+                               writeBlog();
+               }
 
 // XXX         undo_editmode_clear();
                BKE_reset_undo();
@@ -264,20 +301,27 @@ 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);
+
+#ifndef DISABLE_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\".", name);
        }
 }
 
 
 /* called on startup,  (context entirely filled with NULLs) */
-/* or called for 'Erase All' */
+/* or called for 'New File' */
 /* op can be NULL */
 int WM_read_homefile(bContext *C, wmOperator *op)
 {
@@ -312,14 +356,14 @@ int WM_read_homefile(bContext *C, wmOperator *op)
        
        /* 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();
+       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
@@ -331,6 +375,8 @@ int WM_read_homefile(bContext *C, wmOperator *op)
 //     undo_editmode_clear();
        BKE_reset_undo();
        BKE_write_undo(C, "original");  /* save current state */
+
+       ED_editors_init(C);
        
        WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL);
        CTX_wm_window_set(C, NULL); /* exits queues */
@@ -339,52 +385,9 @@ int WM_read_homefile(bContext *C, wmOperator *op)
 }
 
 
-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;
-       }
-#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);
-
-       save_over = G.save_over;
-       BKE_read_file(C, tstr, NULL, NULL);
-       G.save_over = save_over;
-       BLI_strncpy(G.sce, scestr, FILE_MAX);
-}
-
-
 void read_Blog(void)
 {
-       char name[FILE_MAX], filename[FILE_MAX];
+       char name[FILE_MAX];
        LinkNode *l, *lines;
        struct RecentFile *recent;
        char *line;
@@ -396,11 +399,11 @@ void read_Blog(void)
        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++) {
+       for (l= lines, num= 0; l && (num<U.recent_files); l= l->next) {
                line = l->link;
-               if (!BLI_streq(line, "")) {
+               if (line[0] && BLI_exists(line)) {
                        if (num==0) 
-                               strcpy(G.sce, line);
+                               strcpy(G.sce, line); /* note: this seems highly dodgy since the file isnt actually read. please explain. - campbell */
                        
                        recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
                        BLI_addtail(&(G.recent_files), recent);
@@ -408,6 +411,7 @@ void read_Blog(void)
                        recent->filename[0] = '\0';
                        
                        strcpy(recent->filename, line);
+                       num++;
                }
        }
 
@@ -416,58 +420,6 @@ void read_Blog(void)
        
        BLI_free_file_lines(lines);
 
-#ifdef WIN32
-       /* Add the drive names to the listing */
-       {
-               __int64 tmp;
-               char folder[MAX_PATH];
-               char tmps[4];
-               int i;
-                       
-               tmp= GetLogicalDrives();
-               
-               for (i=2; i < 26; i++) {
-                       if ((tmp>>i) & 1) {
-                               tmps[0]='a'+i;
-                               tmps[1]=':';
-                               tmps[2]='\\';
-                               tmps[3]=0;
-                               
-// XX                          fsmenu_insert_entry(tmps, 0, 0);
-                       }
-               }
-
-               /* Adding Desktop and My Documents */
-// XXX         fsmenu_append_separator();
-
-               SHGetSpecialFolderPath(0, folder, CSIDL_PERSONAL, 0);
-// XXX         fsmenu_insert_entry(folder, 0, 0);
-               SHGetSpecialFolderPath(0, folder, CSIDL_DESKTOPDIRECTORY, 0);
-// XXX         fsmenu_insert_entry(folder, 0, 0);
-
-// XXX         fsmenu_append_separator();
-       }
-#endif
-
-       BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
-       lines= BLI_read_file_as_lines(name);
-
-       for (l= lines; l; l= l->next) {
-               char *line= l->link;
-                       
-               if (!BLI_streq(line, "")) {
-// XXX                 fsmenu_insert_entry(line, 0, 1);
-               }
-       }
-
-// XXX fsmenu_append_separator();
-       
-       /* add last saved file */
-       BLI_split_dirfile(G.sce, name, filename); /* G.sce shouldn't be relative */
-       
-// XXX fsmenu_insert_entry(name, 0, 0);
-       
-       BLI_free_file_lines(lines);
 }
 
 static void writeBlog(void)
@@ -539,25 +491,74 @@ 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(const char *path, 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, 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;
+}
+
+int WM_write_file(bContext *C, char *target, int fileflags, ReportList *reports)
 {
        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;
        }
  
        /* 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;
+                       return -1;
                }
        }
        
@@ -576,85 +577,168 @@ void WM_write_file(bContext *C, char *target, int compress, ReportList *reports)
                packAll(G.main, reports);
        }
        
-       ED_object_exit_editmode(C, 0);
+       ED_object_exit_editmode(C, EM_DO_UNDO);
+       ED_sculpt_force_update(C);
 
        do_history(di, reports);
        
-       writeflags= G.fileflags;
+       /* blend file thumbnail */
+       ibuf_thumb= blend_file_thumb(di, CTX_data_scene(C), &thumb);
 
-       /* set compression flag */
-       if(compress) writeflags |= G_FILE_COMPRESS;
-       else writeflags &= ~G_FILE_COMPRESS;
-       
-       if (BLO_write_file(CTX_data_main(C), di, writeflags, reports)) {
+       if (BLO_write_file(CTX_data_main(C), di, fileflags, reports, thumb)) {
                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 */
 
-               if(compress) G.fileflags |= G_FILE_COMPRESS;
+               if(fileflags & G_FILE_COMPRESS) G.fileflags |= G_FILE_COMPRESS;
                else G.fileflags &= ~G_FILE_COMPRESS;
                
+               if(fileflags & G_FILE_AUTOPLAY) G.fileflags |= G_FILE_AUTOPLAY;
+               else G.fileflags &= ~G_FILE_AUTOPLAY;
+
                writeBlog();
+
+               /* 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");
        
        /*  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);
+       BLO_write_file(CTX_data_main(C), tstr, fileflags, op->reports, NULL);
        
        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 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("/", 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 *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);
+}