baf2d322db0a80d16ddb26c6e8d4188529101ef5
[blender.git] / source / blender / windowmanager / intern / wm_files.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation 2007
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/windowmanager/intern/wm_files.c
27  *  \ingroup wm
28  *
29  * User level access for blend file read/write, file-history and userprefs.
30  */
31
32
33 /* placed up here because of crappy
34  * winsock stuff.
35  */
36 #include <stddef.h>
37 #include <string.h>
38 #include <errno.h>
39
40 #include "zlib.h" /* wm_read_exotic() */
41
42 #ifdef WIN32
43 #  include <windows.h> /* need to include windows.h so _WIN32_IE is defined  */
44 #  ifndef _WIN32_IE
45 #    define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
46 #  endif
47 #  include <shlobj.h>  /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff
48                         * because 'near' is disabled through BLI_windstuff */
49 #  include "BLI_winstuff.h"
50 #endif
51
52 #include "MEM_guardedalloc.h"
53 #include "MEM_CacheLimiterC-Api.h"
54
55 #include "BLI_blenlib.h"
56 #include "BLI_linklist.h"
57 #include "BLI_utildefines.h"
58 #include "BLI_threads.h"
59 #include "BLI_callbacks.h"
60 #include "BLI_system.h"
61 #include BLI_SYSTEM_PID_H
62
63 #include "BLF_translation.h"
64
65 #include "DNA_object_types.h"
66 #include "DNA_space_types.h"
67 #include "DNA_userdef_types.h"
68 #include "DNA_scene_types.h"
69 #include "DNA_screen_types.h"
70 #include "DNA_windowmanager_types.h"
71
72 #include "BKE_appdir.h"
73 #include "BKE_utildefines.h"
74 #include "BKE_autoexec.h"
75 #include "BKE_blender.h"
76 #include "BKE_context.h"
77 #include "BKE_depsgraph.h"
78 #include "BKE_global.h"
79 #include "BKE_main.h"
80 #include "BKE_packedFile.h"
81 #include "BKE_report.h"
82 #include "BKE_sound.h"
83 #include "BKE_screen.h"
84
85 #include "BLO_readfile.h"
86 #include "BLO_writefile.h"
87
88 #include "RNA_access.h"
89
90 #include "IMB_imbuf.h"
91 #include "IMB_imbuf_types.h"
92 #include "IMB_thumbs.h"
93
94 #include "ED_datafiles.h"
95 #include "ED_fileselect.h"
96 #include "ED_screen.h"
97 #include "ED_view3d.h"
98 #include "ED_util.h"
99
100 #include "RE_pipeline.h" /* only to report missing engine */
101
102 #include "GHOST_C-api.h"
103 #include "GHOST_Path-api.h"
104
105 #include "UI_interface.h"
106 #include "UI_view2d.h"
107
108 #include "GPU_draw.h"
109
110 #ifdef WITH_PYTHON
111 #include "BPY_extern.h"
112 #endif
113
114 #include "WM_api.h"
115 #include "WM_types.h"
116 #include "wm.h"
117 #include "wm_files.h"
118 #include "wm_window.h"
119 #include "wm_event_system.h"
120
121 static void write_history(void);
122
123 /* To be able to read files without windows closing, opening, moving
124  * we try to prepare for worst case:
125  * - active window gets active screen from file
126  * - restoring the screens from non-active windows
127  * Best case is all screens match, in that case they get assigned to proper window
128  */
129 static void wm_window_match_init(bContext *C, ListBase *wmlist)
130 {
131         wmWindowManager *wm;
132         wmWindow *win, *active_win;
133         
134         *wmlist = G.main->wm;
135         BLI_listbase_clear(&G.main->wm);
136         
137         active_win = CTX_wm_window(C);
138
139         /* first wrap up running stuff */
140         /* code copied from wm_init_exit.c */
141         for (wm = wmlist->first; wm; wm = wm->id.next) {
142                 
143                 WM_jobs_kill_all(wm);
144                 
145                 for (win = wm->windows.first; win; win = win->next) {
146                 
147                         CTX_wm_window_set(C, win);  /* needed by operator close callbacks */
148                         WM_event_remove_handlers(C, &win->handlers);
149                         WM_event_remove_handlers(C, &win->modalhandlers);
150                         ED_screen_exit(C, win, win->screen);
151                 }
152         }
153         
154         /* reset active window */
155         CTX_wm_window_set(C, active_win);
156
157         ED_editors_exit(C);
158
159         /* just had return; here from r12991, this code could just get removed?*/
160 #if 0
161         if (wm == NULL) return;
162         if (G.fileflags & G_FILE_NO_UI) return;
163         
164         /* we take apart the used screens from non-active window */
165         for (win = wm->windows.first; win; win = win->next) {
166                 BLI_strncpy(win->screenname, win->screen->id.name, MAX_ID_NAME);
167                 if (win != wm->winactive) {
168                         BLI_remlink(&G.main->screen, win->screen);
169                         //BLI_addtail(screenbase, win->screen);
170                 }
171         }
172 #endif
173 }
174
175 static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
176 {
177         win->ghostwin = oldwin->ghostwin;
178         win->active = oldwin->active;
179         if (win->active)
180                 wm->winactive = win;
181
182         if (!G.background) /* file loading in background mode still calls this */
183                 GHOST_SetWindowUserData(win->ghostwin, win);    /* pointer back */
184
185         oldwin->ghostwin = NULL;
186
187         win->eventstate = oldwin->eventstate;
188         oldwin->eventstate = NULL;
189
190         /* ensure proper screen rescaling */
191         win->sizex = oldwin->sizex;
192         win->sizey = oldwin->sizey;
193         win->posx = oldwin->posx;
194         win->posy = oldwin->posy;
195 }
196
197 /* match old WM with new, 4 cases:
198  * 1- no current wm, no read wm: make new default
199  * 2- no current wm, but read wm: that's OK, do nothing
200  * 3- current wm, but not in file: try match screen names
201  * 4- current wm, and wm in file: try match ghostwin
202  */
203
204 static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
205 {
206         wmWindowManager *oldwm, *wm;
207         wmWindow *oldwin, *win;
208         
209         /* cases 1 and 2 */
210         if (BLI_listbase_is_empty(oldwmlist)) {
211                 if (G.main->wm.first) {
212                         /* nothing todo */
213                 }
214                 else {
215                         wm_add_default(C);
216                 }
217         }
218         else {
219                 /* cases 3 and 4 */
220                 
221                 /* we've read file without wm..., keep current one entirely alive */
222                 if (BLI_listbase_is_empty(&G.main->wm)) {
223                         bScreen *screen = NULL;
224
225                         /* when loading without UI, no matching needed */
226                         if (!(G.fileflags & G_FILE_NO_UI) && (screen = CTX_wm_screen(C))) {
227
228                                 /* match oldwm to new dbase, only old files */
229                                 for (wm = oldwmlist->first; wm; wm = wm->id.next) {
230                                         
231                                         for (win = wm->windows.first; win; win = win->next) {
232                                                 /* all windows get active screen from file */
233                                                 if (screen->winid == 0)
234                                                         win->screen = screen;
235                                                 else 
236                                                         win->screen = ED_screen_duplicate(win, screen);
237                                                 
238                                                 BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
239                                                 win->screen->winid = win->winid;
240                                         }
241                                 }
242                         }
243                         
244                         G.main->wm = *oldwmlist;
245                         
246                         /* screens were read from file! */
247                         ED_screens_initialize(G.main->wm.first);
248                 }
249                 else {
250                         bool has_match = false;
251
252                         /* what if old was 3, and loaded 1? */
253                         /* this code could move to setup_appdata */
254                         oldwm = oldwmlist->first;
255                         wm = G.main->wm.first;
256
257                         /* preserve key configurations in new wm, to preserve their keymaps */
258                         wm->keyconfigs = oldwm->keyconfigs;
259                         wm->addonconf = oldwm->addonconf;
260                         wm->defaultconf = oldwm->defaultconf;
261                         wm->userconf = oldwm->userconf;
262
263                         BLI_listbase_clear(&oldwm->keyconfigs);
264                         oldwm->addonconf = NULL;
265                         oldwm->defaultconf = NULL;
266                         oldwm->userconf = NULL;
267
268                         /* ensure making new keymaps and set space types */
269                         wm->initialized = 0;
270                         wm->winactive = NULL;
271
272                         /* only first wm in list has ghostwins */
273                         for (win = wm->windows.first; win; win = win->next) {
274                                 for (oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
275
276                                         if (oldwin->winid == win->winid) {
277                                                 has_match = true;
278
279                                                 wm_window_substitute_old(wm, oldwin, win);
280                                         }
281                                 }
282                         }
283
284                         /* make sure at least one window is kept open so we don't lose the context, check T42303 */
285                         if (!has_match) {
286                                 oldwin = oldwm->windows.first;
287                                 win = wm->windows.first;
288
289                                 wm_window_substitute_old(wm, oldwin, win);
290                         }
291
292                         wm_close_and_free_all(C, oldwmlist);
293                 }
294         }
295 }
296
297 /* in case UserDef was read, we re-initialize all, and do versioning */
298 static void wm_init_userdef(bContext *C, const bool from_memory)
299 {
300         Main *bmain = CTX_data_main(C);
301
302         /* versioning is here */
303         UI_init_userdef();
304         
305         MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024);
306         sound_init(bmain);
307
308         /* needed so loading a file from the command line respects user-pref [#26156] */
309         BKE_BIT_TEST_SET(G.fileflags, U.flag & USER_FILENOUI, G_FILE_NO_UI);
310
311         /* set the python auto-execute setting from user prefs */
312         /* enabled by default, unless explicitly enabled in the command line which overrides */
313         if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) {
314                 BKE_BIT_TEST_SET(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC);
315         }
316
317         /* avoid re-saving for every small change to our prefs, allow overrides */
318         if (from_memory) {
319                 BLO_update_defaults_userpref_blend();
320         }
321
322         /* update tempdir from user preferences */
323         BLI_temp_dir_init(U.tempdir);
324
325         BKE_userdef_state();
326 }
327
328
329
330 /* return codes */
331 #define BKE_READ_EXOTIC_FAIL_PATH       -3 /* file format is not supported */
332 #define BKE_READ_EXOTIC_FAIL_FORMAT     -2 /* file format is not supported */
333 #define BKE_READ_EXOTIC_FAIL_OPEN       -1 /* Can't open the file */
334 #define BKE_READ_EXOTIC_OK_BLEND         0 /* .blend file */
335 #define BKE_READ_EXOTIC_OK_OTHER         1 /* other supported formats */
336
337
338 /* intended to check for non-blender formats but for now it only reads blends */
339 static int wm_read_exotic(Scene *UNUSED(scene), const char *name)
340 {
341         int len;
342         gzFile gzfile;
343         char header[7];
344         int retval;
345
346         /* make sure we're not trying to read a directory.... */
347
348         len = strlen(name);
349         if (len > 0 && ELEM(name[len - 1], '/', '\\')) {
350                 retval = BKE_READ_EXOTIC_FAIL_PATH;
351         }
352         else {
353                 gzfile = BLI_gzopen(name, "rb");
354                 if (gzfile == NULL) {
355                         retval = BKE_READ_EXOTIC_FAIL_OPEN;
356                 }
357                 else {
358                         len = gzread(gzfile, header, sizeof(header));
359                         gzclose(gzfile);
360                         if (len == sizeof(header) && strncmp(header, "BLENDER", 7) == 0) {
361                                 retval = BKE_READ_EXOTIC_OK_BLEND;
362                         }
363                         else {
364 #if 0           /* historic stuff - no longer used */
365                                 WM_cursor_wait(true);
366
367                                 if (is_foo_format(name)) {
368                                         read_foo(name);
369                                         retval = BKE_READ_EXOTIC_OK_OTHER;
370                                 }
371                                 else
372 #endif
373                                 {
374                                         retval = BKE_READ_EXOTIC_FAIL_FORMAT;
375                                 }
376 #if 0
377                                 WM_cursor_wait(false);
378 #endif
379                         }
380                 }
381         }
382
383         return retval;
384 }
385
386 void WM_file_autoexec_init(const char *filepath)
387 {
388         if (G.f & G_SCRIPT_OVERRIDE_PREF) {
389                 return;
390         }
391
392         if (G.f & G_SCRIPT_AUTOEXEC) {
393                 char path[FILE_MAX];
394                 BLI_split_dir_part(filepath, path, sizeof(path));
395                 if (BKE_autoexec_match(path)) {
396                         G.f &= ~G_SCRIPT_AUTOEXEC;
397                 }
398         }
399 }
400
401 bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
402 {
403         bool success = false;
404         int retval;
405
406         /* so we can get the error message */
407         errno = 0;
408
409         WM_cursor_wait(1);
410
411         BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
412
413         UI_view2d_zoom_cache_reset();
414
415         /* first try to append data from exotic file formats... */
416         /* it throws error box when file doesn't exist and returns -1 */
417         /* note; it should set some error message somewhere... (ton) */
418         retval = wm_read_exotic(CTX_data_scene(C), filepath);
419         
420         /* we didn't succeed, now try to read Blender file */
421         if (retval == BKE_READ_EXOTIC_OK_BLEND) {
422                 int G_f = G.f;
423                 ListBase wmbase;
424
425                 /* assume automated tasks with background, don't write recent file list */
426                 const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0);
427
428                 /* put aside screens to match with persistent windows later */
429                 /* also exit screens and editors */
430                 wm_window_match_init(C, &wmbase); 
431                 
432                 /* confusing this global... */
433                 G.relbase_valid = 1;
434                 retval = BKE_read_file(C, filepath, reports);
435                 /* when loading startup.blend's, we can be left with a blank path */
436                 if (G.main->name[0]) {
437                         G.save_over = 1;
438                 }
439                 else {
440                         G.save_over = 0;
441                         G.relbase_valid = 0;
442                 }
443
444                 /* this flag is initialized by the operator but overwritten on read.
445                  * need to re-enable it here else drivers + registered scripts wont work. */
446                 if (G.f != G_f) {
447                         const int flags_keep = (G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF);
448                         G.f = (G.f & ~flags_keep) | (G_f & flags_keep);
449                 }
450
451                 /* match the read WM with current WM */
452                 wm_window_match_do(C, &wmbase);
453                 WM_check(C); /* opens window(s), checks keymaps */
454
455                 if (retval == BKE_READ_FILE_OK_USERPREFS) {
456                         /* in case a userdef is read from regular .blend */
457                         wm_init_userdef(C, false);
458                 }
459                 
460                 if (retval != BKE_READ_FILE_FAIL) {
461                         if (do_history) {
462                                 write_history();
463                         }
464                 }
465
466
467                 WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
468 //              refresh_interface_font();
469
470                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
471
472                 ED_editors_init(C);
473                 DAG_on_visible_update(CTX_data_main(C), true);
474
475 #ifdef WITH_PYTHON
476                 /* run any texts that were loaded in and flagged as modules */
477                 BPY_python_reset(C);
478 #endif
479
480                 WM_operatortype_last_properties_clear_all();
481
482                 /* important to do before NULL'ing the context */
483                 BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
484                 BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
485
486                 if (!G.background) {
487                         /* in background mode this makes it hard to load
488                          * a blend file and do anything since the screen
489                          * won't be set to a valid value again */
490                         CTX_wm_window_set(C, NULL); /* exits queues */
491                 }
492
493 #if 0
494                 /* gives popups on windows but not linux, bug in report API
495                  * but disable for now to stop users getting annoyed  */
496                 /* TODO, make this show in header info window */
497                 {
498                         Scene *sce;
499                         for (sce = G.main->scene.first; sce; sce = sce->id.next) {
500                                 if (sce->r.engine[0] &&
501                                     BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL)
502                                 {
503                                         BKE_reportf(reports, RPT_ERROR, "Engine '%s' not available for scene '%s' "
504                                                     "(an addon may need to be installed or enabled)",
505                                                     sce->r.engine, sce->id.name + 2);
506                                 }
507                         }
508                 }
509 #endif
510
511                 BKE_reset_undo();
512                 BKE_write_undo(C, "original");  /* save current state */
513
514                 success = true;
515         }
516         else if (retval == BKE_READ_EXOTIC_OK_OTHER)
517                 BKE_write_undo(C, "Import file");
518         else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
519                 BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
520                             errno ? strerror(errno) : TIP_("unable to open the file"));
521         }
522         else if (retval == BKE_READ_EXOTIC_FAIL_FORMAT) {
523                 BKE_reportf(reports, RPT_ERROR, "File format is not supported in file '%s'", filepath);
524         }
525         else if (retval == BKE_READ_EXOTIC_FAIL_PATH) {
526                 BKE_reportf(reports, RPT_ERROR, "File path '%s' invalid", filepath);
527         }
528         else {
529                 BKE_reportf(reports, RPT_ERROR, "Unknown error loading '%s'", filepath);
530                 BLI_assert(!"invalid 'retval'");
531         }
532
533         WM_cursor_wait(0);
534
535         return success;
536
537 }
538
539
540 /* called on startup,  (context entirely filled with NULLs) */
541 /* or called for 'New File' */
542 /* both startup.blend and userpref.blend are checked */
543 /* the optional paramater custom_file points to an alterntive startup page */
544 /* custom_file can be NULL */
545 int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const char *custom_file)
546 {
547         ListBase wmbase;
548         char startstr[FILE_MAX];
549         char prefstr[FILE_MAX];
550         int success = 0;
551
552         /* Indicates whether user preferences were really load from memory.
553          *
554          * This is used for versioning code, and for this we can not rely on from_memory
555          * passed via argument. This is because there might be configuration folder
556          * exists but it might not have userpref.blend and in this case we fallback to
557          * reading home file from memory.
558          *
559          * And in this case versioning code is to be run.
560          */
561         bool read_userdef_from_memory = true;
562
563         /* options exclude eachother */
564         BLI_assert((from_memory && custom_file) == 0);
565
566         BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
567
568         UI_view2d_zoom_cache_reset();
569
570         G.relbase_valid = 0;
571         if (!from_memory) {
572                 const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
573                 if (custom_file) {
574                         BLI_strncpy(startstr, custom_file, FILE_MAX);
575
576                         if (cfgdir) {
577                                 BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
578                         }
579                         else {
580                                 prefstr[0] = '\0';
581                         }
582                 }
583                 else if (cfgdir) {
584                         BLI_make_file_string(G.main->name, startstr, cfgdir, BLENDER_STARTUP_FILE);
585                         BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
586                 }
587                 else {
588                         startstr[0] = '\0';
589                         prefstr[0] = '\0';
590                         from_memory = 1;
591                 }
592         }
593         
594         /* put aside screens to match with persistent windows later */
595         wm_window_match_init(C, &wmbase);
596         
597         if (!from_memory) {
598                 if (BLI_access(startstr, R_OK) == 0) {
599                         success = (BKE_read_file(C, startstr, NULL) != BKE_READ_FILE_FAIL);
600                 }
601                 if (BLI_listbase_is_empty(&U.themes)) {
602                         if (G.debug & G_DEBUG)
603                                 printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", startstr);
604                         success = 0;
605                 }
606         }
607
608         if (success == 0 && custom_file && reports) {
609                 BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", custom_file);
610                 /*We can not return from here because wm is already reset*/
611         }
612
613         if (success == 0) {
614                 success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true);
615                 if (BLI_listbase_is_empty(&wmbase)) {
616                         wm_clear_default_size(C);
617                 }
618                 BLI_temp_dir_init(U.tempdir);
619
620 #ifdef WITH_PYTHON_SECURITY
621                 /* use alternative setting for security nuts
622                  * otherwise we'd need to patch the binary blob - startup.blend.c */
623                 U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
624 #endif
625         }
626         
627         /* check new prefs only after startup.blend was finished */
628         if (!from_memory && BLI_exists(prefstr)) {
629                 int done = BKE_read_file_userdef(prefstr, NULL);
630                 if (done != BKE_READ_FILE_FAIL) {
631                         read_userdef_from_memory = false;
632                         printf("Read new prefs: %s\n", prefstr);
633                 }
634         }
635         
636         /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
637          * can remove this eventually, only in a 2.53 and older, now its not written */
638         G.fileflags &= ~G_FILE_RELATIVE_REMAP;
639         
640         /* check userdef before open window, keymaps etc */
641         wm_init_userdef(C, read_userdef_from_memory);
642         
643         /* match the read WM with current WM */
644         wm_window_match_do(C, &wmbase); 
645         WM_check(C); /* opens window(s), checks keymaps */
646
647         G.main->name[0] = '\0';
648
649         /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
650         if (!G.background) GPU_default_lights();
651         
652         /* XXX */
653         G.save_over = 0;    // start with save preference untitled.blend
654         G.fileflags &= ~G_FILE_AUTOPLAY;    /*  disable autoplay in startup.blend... */
655
656 //      refresh_interface_font();
657         
658 //      undo_editmode_clear();
659         BKE_reset_undo();
660         BKE_write_undo(C, "original");  /* save current state */
661
662         ED_editors_init(C);
663         DAG_on_visible_update(CTX_data_main(C), true);
664
665 #ifdef WITH_PYTHON
666         if (CTX_py_init_get(C)) {
667                 /* sync addons, these may have changed from the defaults */
668                 BPY_string_exec(C, "__import__('addon_utils').reset_all()");
669
670                 BPY_python_reset(C);
671         }
672 #endif
673
674         WM_operatortype_last_properties_clear_all();
675
676         /* important to do before NULL'ing the context */
677         BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
678         BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
679
680         WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
681
682         /* in background mode the scene will stay NULL */
683         if (!G.background) {
684                 CTX_wm_window_set(C, NULL); /* exits queues */
685         }
686
687         return true;
688 }
689
690 int wm_history_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
691 {
692         ED_file_read_bookmarks();
693         wm_read_history();
694         return OPERATOR_FINISHED;
695 }
696
697 int wm_homefile_read_exec(bContext *C, wmOperator *op)
698 {
699         const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
700         char filepath_buf[FILE_MAX];
701         const char *filepath = NULL;
702
703         if (!from_memory) {
704                 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
705
706                 /* This can be used when loading of a start-up file should only change
707                  * the scene content but keep the blender UI as it is. */
708                 wm_open_init_load_ui(op, true);
709                 BKE_BIT_TEST_SET(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
710
711                 if (RNA_property_is_set(op->ptr, prop)) {
712                         RNA_property_string_get(op->ptr, prop, filepath_buf);
713                         filepath = filepath_buf;
714                         if (BLI_access(filepath, R_OK)) {
715                                 BKE_reportf(op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath);
716                                 return OPERATOR_CANCELLED;
717                         }
718                 }
719         }
720
721         return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
722 }
723
724 void wm_read_history(void)
725 {
726         char name[FILE_MAX];
727         LinkNode *l, *lines;
728         struct RecentFile *recent;
729         const char *line;
730         int num;
731         const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
732
733         if (!cfgdir) return;
734
735         BLI_make_file_string("/", name, cfgdir, BLENDER_HISTORY_FILE);
736
737         lines = BLI_file_read_as_lines(name);
738
739         BLI_listbase_clear(&G.recent_files);
740
741         /* read list of recent opened files from recent-files.txt to memory */
742         for (l = lines, num = 0; l && (num < U.recent_files); l = l->next) {
743                 line = l->link;
744                 if (line[0] && BLI_exists(line)) {
745                         recent = (RecentFile *)MEM_mallocN(sizeof(RecentFile), "RecentFile");
746                         BLI_addtail(&(G.recent_files), recent);
747                         recent->filepath = BLI_strdup(line);
748                         num++;
749                 }
750         }
751         
752         BLI_file_free_lines(lines);
753 }
754
755 static void write_history(void)
756 {
757         struct RecentFile *recent, *next_recent;
758         char name[FILE_MAX];
759         const char *user_config_dir;
760         FILE *fp;
761         int i;
762
763         /* no write history for recovered startup files */
764         if (G.main->name[0] == 0)
765                 return;
766         
767         /* will be NULL in background mode */
768         user_config_dir = BLI_get_folder_create(BLENDER_USER_CONFIG, NULL);
769         if (!user_config_dir)
770                 return;
771
772         BLI_make_file_string("/", name, user_config_dir, BLENDER_HISTORY_FILE);
773
774         recent = G.recent_files.first;
775         /* refresh recent-files.txt of recent opened files, when current file was changed */
776         if (!(recent) || (BLI_path_cmp(recent->filepath, G.main->name) != 0)) {
777                 fp = BLI_fopen(name, "w");
778                 if (fp) {
779                         /* add current file to the beginning of list */
780                         recent = (RecentFile *)MEM_mallocN(sizeof(RecentFile), "RecentFile");
781                         recent->filepath = BLI_strdup(G.main->name);
782                         BLI_addhead(&(G.recent_files), recent);
783                         /* write current file to recent-files.txt */
784                         fprintf(fp, "%s\n", recent->filepath);
785                         recent = recent->next;
786                         i = 1;
787                         /* write rest of recent opened files to recent-files.txt */
788                         while ((i < U.recent_files) && (recent)) {
789                                 /* this prevents to have duplicities in list */
790                                 if (BLI_path_cmp(recent->filepath, G.main->name) != 0) {
791                                         fprintf(fp, "%s\n", recent->filepath);
792                                         recent = recent->next;
793                                 }
794                                 else {
795                                         next_recent = recent->next;
796                                         MEM_freeN(recent->filepath);
797                                         BLI_freelinkN(&(G.recent_files), recent);
798                                         recent = next_recent;
799                                 }
800                                 i++;
801                         }
802                         fclose(fp);
803                 }
804
805                 /* also update most recent files on System */
806                 GHOST_addToSystemRecentFiles(G.main->name);
807         }
808 }
809
810 /* screen can be NULL */
811 static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
812 {
813         /* will be scaled down, but gives some nice oversampling */
814         ImBuf *ibuf;
815         int *thumb;
816         char err_out[256] = "unknown";
817
818         /* screen if no camera found */
819         ScrArea *sa = NULL;
820         ARegion *ar = NULL;
821         View3D *v3d = NULL;
822
823         *thumb_pt = NULL;
824
825         /* scene can be NULL if running a script at startup and calling the save operator */
826         if (G.background || scene == NULL)
827                 return NULL;
828
829         if ((scene->camera == NULL) && (screen != NULL)) {
830                 sa = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
831                 ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
832                 if (ar) {
833                         v3d = sa->spacedata.first;
834                 }
835         }
836
837         if (scene->camera == NULL && v3d == NULL) {
838                 return NULL;
839         }
840
841         /* gets scaled to BLEN_THUMB_SIZE */
842         if (scene->camera) {
843                 ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
844                                                              BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
845                                                              IB_rect, OB_SOLID, false, false, R_ADDSKY, err_out);
846         }
847         else {
848                 ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
849                                                       IB_rect, false, R_ADDSKY, err_out);
850         }
851
852         if (ibuf) {
853                 float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
854
855                 /* dirty oversampling */
856                 IMB_scaleImBuf(ibuf, BLEN_THUMB_SIZE, BLEN_THUMB_SIZE);
857
858                 /* add pretty overlay */
859                 IMB_overlayblend_thumb(ibuf->rect, ibuf->x, ibuf->y, aspect);
860                 
861                 /* first write into thumb buffer */
862                 thumb = MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb");
863
864                 thumb[0] = BLEN_THUMB_SIZE;
865                 thumb[1] = BLEN_THUMB_SIZE;
866
867                 memcpy(thumb + 2, ibuf->rect, BLEN_THUMB_SIZE * BLEN_THUMB_SIZE * sizeof(int));
868         }
869         else {
870                 /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */
871                 fprintf(stderr, "blend_file_thumb failed to create thumbnail: %s\n", err_out);
872                 thumb = NULL;
873         }
874         
875         /* must be freed by caller */
876         *thumb_pt = thumb;
877         
878         return ibuf;
879 }
880
881 /* easy access from gdb */
882 bool write_crash_blend(void)
883 {
884         char path[FILE_MAX];
885         int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on crash file */
886
887         BLI_strncpy(path, G.main->name, sizeof(path));
888         BLI_replace_extension(path, sizeof(path), "_crash.blend");
889         if (BLO_write_file(G.main, path, fileflags, NULL, NULL)) {
890                 printf("written: %s\n", path);
891                 return 1;
892         }
893         else {
894                 printf("failed: %s\n", path);
895                 return 0;
896         }
897 }
898
899 /**
900  * \see #wm_homefile_write_exec wraps #BLO_write_file in a similar way.
901  */
902 int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports)
903 {
904         Library *li;
905         int len;
906         int *thumb = NULL;
907         ImBuf *ibuf_thumb = NULL;
908
909         len = strlen(filepath);
910         
911         if (len == 0) {
912                 BKE_report(reports, RPT_ERROR, "Path is empty, cannot save");
913                 return -1;
914         }
915
916         if (len >= FILE_MAX) {
917                 BKE_report(reports, RPT_ERROR, "Path too long, cannot save");
918                 return -1;
919         }
920         
921         /* Check if file write permission is ok */
922         if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
923                 BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
924                 return -1;
925         }
926  
927         /* note: used to replace the file extension (to ensure '.blend'),
928          * no need to now because the operator ensures,
929          * its handy for scripts to save to a predefined name without blender editing it */
930         
931         /* send the OnSave event */
932         for (li = G.main->library.first; li; li = li->id.next) {
933                 if (BLI_path_cmp(li->filepath, filepath) == 0) {
934                         BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath);
935                         return -1;
936                 }
937         }
938
939         /* blend file thumbnail */
940         /* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */
941         if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
942                 ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_wm_screen(C), &thumb);
943         }
944
945         BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
946
947         /* operator now handles overwrite checks */
948
949         if (G.fileflags & G_AUTOPACK) {
950                 packAll(G.main, reports);
951         }
952
953         /* don't forget not to return without! */
954         WM_cursor_wait(1);
955         
956         ED_editors_flush_edits(C, false);
957
958         fileflags |= G_FILE_HISTORY; /* write file history */
959
960         /* first time saving */
961         /* XXX temp solution to solve bug, real fix coming (ton) */
962         if ((G.main->name[0] == '\0') && !(fileflags & G_FILE_SAVE_COPY)) {
963                 BLI_strncpy(G.main->name, filepath, sizeof(G.main->name));
964         }
965
966         /* XXX temp solution to solve bug, real fix coming (ton) */
967         G.main->recovered = 0;
968         
969         if (BLO_write_file(CTX_data_main(C), filepath, fileflags, reports, thumb)) {
970                 if (!(fileflags & G_FILE_SAVE_COPY)) {
971                         G.relbase_valid = 1;
972                         BLI_strncpy(G.main->name, filepath, sizeof(G.main->name));  /* is guaranteed current file */
973         
974                         G.save_over = 1; /* disable untitled.blend convention */
975                 }
976
977                 BKE_BIT_TEST_SET(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
978                 BKE_BIT_TEST_SET(G.fileflags, fileflags & G_FILE_AUTOPLAY, G_FILE_AUTOPLAY);
979
980                 /* prevent background mode scripts from clobbering history */
981                 if (!G.background) {
982                         write_history();
983                 }
984
985                 BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
986
987                 /* run this function after because the file cant be written before the blend is */
988                 if (ibuf_thumb) {
989                         IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */
990                         ibuf_thumb = IMB_thumb_create(filepath, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb);
991                         IMB_freeImBuf(ibuf_thumb);
992                 }
993
994                 if (thumb) MEM_freeN(thumb);
995         }
996         else {
997                 if (ibuf_thumb) IMB_freeImBuf(ibuf_thumb);
998                 if (thumb) MEM_freeN(thumb);
999                 
1000                 WM_cursor_wait(0);
1001                 return -1;
1002         }
1003
1004         WM_cursor_wait(0);
1005         
1006         return 0;
1007 }
1008
1009 /**
1010  * \see #wm_file_write wraps #BLO_write_file in a similar way.
1011  */
1012 int wm_homefile_write_exec(bContext *C, wmOperator *op)
1013 {
1014         wmWindowManager *wm = CTX_wm_manager(C);
1015         wmWindow *win = CTX_wm_window(C);
1016         char filepath[FILE_MAX];
1017         int fileflags;
1018
1019         BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
1020
1021         /* check current window and close it if temp */
1022         if (win && win->screen->temp)
1023                 wm_window_close(C, wm, win);
1024         
1025         /* update keymaps in user preferences */
1026         WM_keyconfig_update(wm);
1027         
1028         BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
1029         printf("trying to save homefile at %s ", filepath);
1030         
1031         ED_editors_flush_edits(C, false);
1032
1033         /*  force save as regular blend file */
1034         fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
1035
1036         if (BLO_write_file(CTX_data_main(C), filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
1037                 printf("fail\n");
1038                 return OPERATOR_CANCELLED;
1039         }
1040         
1041         printf("ok\n");
1042
1043         G.save_over = 0;
1044
1045         BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
1046
1047         return OPERATOR_FINISHED;
1048 }
1049
1050 /* Only save the prefs block. operator entry */
1051 int wm_userpref_write_exec(bContext *C, wmOperator *op)
1052 {
1053         wmWindowManager *wm = CTX_wm_manager(C);
1054         char filepath[FILE_MAX];
1055         
1056         /* update keymaps in user preferences */
1057         WM_keyconfig_update(wm);
1058         
1059         BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
1060         printf("trying to save userpref at %s ", filepath);
1061         
1062         if (BKE_write_file_userdef(filepath, op->reports) == 0) {
1063                 printf("fail\n");
1064                 return OPERATOR_CANCELLED;
1065         }
1066         
1067         printf("ok\n");
1068         
1069         return OPERATOR_FINISHED;
1070 }
1071
1072 /************************ autosave ****************************/
1073
1074 void wm_autosave_location(char *filepath)
1075 {
1076         const int pid = abs(getpid());
1077         char path[1024];
1078 #ifdef WIN32
1079         const char *savedir;
1080 #endif
1081
1082         if (G.main && G.relbase_valid) {
1083                 const char *basename = BLI_path_basename(G.main->name);
1084                 int len = strlen(basename) - 6;
1085                 BLI_snprintf(path, sizeof(path), "%.*s-%d.blend", len, basename, pid);
1086         }
1087         else {
1088                 BLI_snprintf(path, sizeof(path), "%d.blend", pid);
1089         }
1090
1091 #ifdef WIN32
1092         /* XXX Need to investigate how to handle default location of '/tmp/'
1093          * This is a relative directory on Windows, and it may be
1094          * found. Example:
1095          * Blender installed on D:\ drive, D:\ drive has D:\tmp\
1096          * Now, BLI_exists() will find '/tmp/' exists, but
1097          * BLI_make_file_string will create string that has it most likely on C:\
1098          * through get_default_root().
1099          * If there is no C:\tmp autosave fails. */
1100         if (!BLI_exists(BLI_temp_dir_base())) {
1101                 savedir = BLI_get_folder_create(BLENDER_USER_AUTOSAVE, NULL);
1102                 BLI_make_file_string("/", filepath, savedir, path);
1103                 return;
1104         }
1105 #endif
1106
1107         BLI_make_file_string("/", filepath, BLI_temp_dir_base(), path);
1108 }
1109
1110 void WM_autosave_init(wmWindowManager *wm)
1111 {
1112         wm_autosave_timer_ended(wm);
1113
1114         if (U.flag & USER_AUTOSAVE)
1115                 wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime * 60.0);
1116 }
1117
1118 void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(wt))
1119 {
1120         wmWindow *win;
1121         wmEventHandler *handler;
1122         char filepath[FILE_MAX];
1123         
1124         WM_event_remove_timer(wm, NULL, wm->autosavetimer);
1125
1126         /* if a modal operator is running, don't autosave, but try again in 10 seconds */
1127         for (win = wm->windows.first; win; win = win->next) {
1128                 for (handler = win->modalhandlers.first; handler; handler = handler->next) {
1129                         if (handler->op) {
1130                                 wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0);
1131                                 return;
1132                         }
1133                 }
1134         }
1135
1136         ED_editors_flush_edits(C, false);
1137
1138         wm_autosave_location(filepath);
1139
1140         if (U.uiflag & USER_GLOBALUNDO) {
1141                 /* fast save of last undobuffer, now with UI */
1142                 BKE_undo_save_file(filepath);
1143         }
1144         else {
1145                 /*  save as regular blend file */
1146                 int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
1147
1148                 /* no error reporting to console */
1149                 BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
1150         }
1151         /* do timer after file write, just in case file write takes a long time */
1152         wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime * 60.0);
1153 }
1154
1155 void wm_autosave_timer_ended(wmWindowManager *wm)
1156 {
1157         if (wm->autosavetimer) {
1158                 WM_event_remove_timer(wm, NULL, wm->autosavetimer);
1159                 wm->autosavetimer = NULL;
1160         }
1161 }
1162
1163 void wm_autosave_delete(void)
1164 {
1165         char filename[FILE_MAX];
1166         
1167         wm_autosave_location(filename);
1168
1169         if (BLI_exists(filename)) {
1170                 char str[FILE_MAX];
1171                 BLI_make_file_string("/", str, BLI_temp_dir_base(), BLENDER_QUIT_FILE);
1172
1173                 /* if global undo; remove tempsave, otherwise rename */
1174                 if (U.uiflag & USER_GLOBALUNDO) BLI_delete(filename, false, false);
1175                 else BLI_rename(filename, str);
1176         }
1177 }
1178
1179 void wm_autosave_read(bContext *C, ReportList *reports)
1180 {
1181         char filename[FILE_MAX];
1182
1183         wm_autosave_location(filename);
1184         WM_file_read(C, filename, reports);
1185 }
1186
1187
1188 /** \name Initialize WM_OT_open_xxx properties
1189  *
1190  * Check if load_ui was set by the caller.
1191  * Fall back to user preference when file flags not specified.
1192  *
1193  * \{ */
1194
1195 void wm_open_init_load_ui(wmOperator *op, bool use_prefs)
1196 {
1197         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "load_ui");
1198         if (!RNA_property_is_set(op->ptr, prop)) {
1199                 bool value = use_prefs ?
1200                              ((U.flag & USER_FILENOUI) == 0) :
1201                              ((G.fileflags & G_FILE_NO_UI) == 0);
1202
1203                 RNA_property_boolean_set(op->ptr, prop, value);
1204         }
1205 }
1206
1207 void wm_open_init_use_scripts(wmOperator *op, bool use_prefs)
1208 {
1209         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
1210         if (!RNA_property_is_set(op->ptr, prop)) {
1211                 /* use G_SCRIPT_AUTOEXEC rather than the userpref because this means if
1212                  * the flag has been disabled from the command line, then opening
1213                  * from the menu wont enable this setting. */
1214                 bool value = use_prefs ?
1215                              ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) :
1216                              ((G.f & G_SCRIPT_AUTOEXEC) != 0);
1217
1218                 RNA_property_boolean_set(op->ptr, prop, value);
1219         }
1220 }
1221
1222 /** \} */