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