2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation 2007
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/windowmanager/intern/wm_files.c
29 * User level access for blend file read/write, file-history and userprefs.
33 /* placed up here because of crappy
40 #include "zlib.h" /* wm_read_exotic() */
43 # include <windows.h> /* need to include windows.h so _WIN32_IE is defined */
45 # define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
47 # include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff
48 * because 'near' is disabled through BLI_windstuff */
49 # include <process.h> /* getpid */
50 # include "BLI_winstuff.h"
52 # include <unistd.h> /* getpid */
55 #include "MEM_guardedalloc.h"
56 #include "MEM_CacheLimiterC-Api.h"
58 #include "BLI_blenlib.h"
59 #include "BLI_linklist.h"
60 #include "BLI_utildefines.h"
61 #include "BLI_threads.h"
62 #include "BLI_callbacks.h"
64 #include "BLF_translation.h"
66 #include "DNA_anim_types.h"
67 #include "DNA_object_types.h"
68 #include "DNA_space_types.h"
69 #include "DNA_userdef_types.h"
70 #include "DNA_scene_types.h"
71 #include "DNA_screen_types.h"
72 #include "DNA_windowmanager_types.h"
74 #include "BKE_autoexec.h"
75 #include "BKE_blender.h"
76 #include "BKE_context.h"
77 #include "BKE_depsgraph.h"
78 #include "BKE_DerivedMesh.h"
80 #include "BKE_global.h"
81 #include "BKE_library.h"
83 #include "BKE_multires.h"
84 #include "BKE_packedFile.h"
85 #include "BKE_report.h"
86 #include "BKE_sound.h"
87 #include "BKE_screen.h"
88 #include "BKE_texture.h"
91 #include "BLO_readfile.h"
92 #include "BLO_writefile.h"
94 #include "RNA_access.h"
96 #include "IMB_imbuf.h"
97 #include "IMB_imbuf_types.h"
98 #include "IMB_thumbs.h"
100 #include "ED_datafiles.h"
101 #include "ED_fileselect.h"
102 #include "ED_object.h"
103 #include "ED_screen.h"
104 #include "ED_sculpt.h"
105 #include "ED_view3d.h"
108 #include "RE_pipeline.h" /* only to report missing engine */
110 #include "GHOST_C-api.h"
111 #include "GHOST_Path-api.h"
113 #include "UI_interface.h"
115 #include "GPU_draw.h"
118 #include "BPY_extern.h"
122 #include "WM_types.h"
124 #include "wm_files.h"
125 #include "wm_window.h"
126 #include "wm_event_system.h"
128 static void write_history(void);
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
136 static void wm_window_match_init(bContext *C, ListBase *wmlist)
139 wmWindow *win, *active_win;
141 *wmlist = G.main->wm;
142 G.main->wm.first = G.main->wm.last = NULL;
144 active_win = CTX_wm_window(C);
146 /* first wrap up running stuff */
147 /* code copied from wm_init_exit.c */
148 for (wm = wmlist->first; wm; wm = wm->id.next) {
150 WM_jobs_kill_all(wm);
152 for (win = wm->windows.first; win; win = win->next) {
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);
161 /* reset active window */
162 CTX_wm_window_set(C, active_win);
166 /* just had return; here from r12991, this code could just get removed?*/
168 if (wm == NULL) return;
169 if (G.fileflags & G_FILE_NO_UI) return;
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);
182 /* match old WM with new, 4 cases:
183 * 1- no current wm, no read wm: make new default
184 * 2- no current wm, but read wm: that's OK, do nothing
185 * 3- current wm, but not in file: try match screen names
186 * 4- current wm, and wm in file: try match ghostwin
189 static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
191 wmWindowManager *oldwm, *wm;
192 wmWindow *oldwin, *win;
195 if (oldwmlist->first == NULL) {
196 if (G.main->wm.first) {
206 /* we've read file without wm..., keep current one entirely alive */
207 if (G.main->wm.first == NULL) {
208 bScreen *screen = NULL;
210 /* when loading without UI, no matching needed */
211 if (!(G.fileflags & G_FILE_NO_UI) && (screen = CTX_wm_screen(C))) {
213 /* match oldwm to new dbase, only old files */
214 for (wm = oldwmlist->first; wm; wm = wm->id.next) {
216 for (win = wm->windows.first; win; win = win->next) {
217 /* all windows get active screen from file */
218 if (screen->winid == 0)
219 win->screen = screen;
221 win->screen = ED_screen_duplicate(win, screen);
223 BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
224 win->screen->winid = win->winid;
229 G.main->wm = *oldwmlist;
231 /* screens were read from file! */
232 ED_screens_initialize(G.main->wm.first);
235 /* what if old was 3, and loaded 1? */
236 /* this code could move to setup_appdata */
237 oldwm = oldwmlist->first;
238 wm = G.main->wm.first;
240 /* preserve key configurations in new wm, to preserve their keymaps */
241 wm->keyconfigs = oldwm->keyconfigs;
242 wm->addonconf = oldwm->addonconf;
243 wm->defaultconf = oldwm->defaultconf;
244 wm->userconf = oldwm->userconf;
246 oldwm->keyconfigs.first = oldwm->keyconfigs.last = NULL;
247 oldwm->addonconf = NULL;
248 oldwm->defaultconf = NULL;
249 oldwm->userconf = NULL;
251 /* ensure making new keymaps and set space types */
253 wm->winactive = NULL;
255 /* only first wm in list has ghostwins */
256 for (win = wm->windows.first; win; win = win->next) {
257 for (oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
259 if (oldwin->winid == win->winid) {
260 win->ghostwin = oldwin->ghostwin;
261 win->active = oldwin->active;
265 if (!G.background) /* file loading in background mode still calls this */
266 GHOST_SetWindowUserData(win->ghostwin, win); /* pointer back */
268 oldwin->ghostwin = NULL;
270 win->eventstate = oldwin->eventstate;
271 oldwin->eventstate = NULL;
273 /* ensure proper screen rescaling */
274 win->sizex = oldwin->sizex;
275 win->sizey = oldwin->sizey;
276 win->posx = oldwin->posx;
277 win->posy = oldwin->posy;
281 wm_close_and_free_all(C, oldwmlist);
286 /* in case UserDef was read, we re-initialize all, and do versioning */
287 static void wm_init_userdef(bContext *C, const bool from_memory)
289 /* versioning is here */
292 MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024);
293 sound_init(CTX_data_main(C));
295 /* needed so loading a file from the command line respects user-pref [#26156] */
296 if (U.flag & USER_FILENOUI) G.fileflags |= G_FILE_NO_UI;
297 else G.fileflags &= ~G_FILE_NO_UI;
299 /* set the python auto-execute setting from user prefs */
300 /* enabled by default, unless explicitly enabled in the command line which overrides */
301 if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) {
302 if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) G.f |= G_SCRIPT_AUTOEXEC;
303 else G.f &= ~G_SCRIPT_AUTOEXEC;
306 /* avoid re-saving for every small change to our prefs, allow overrides */
308 UI_init_userdef_factory();
311 /* update tempdir from user preferences */
312 BLI_init_temporary_dir(U.tempdir);
320 #define BKE_READ_EXOTIC_FAIL_PATH -3 /* file format is not supported */
321 #define BKE_READ_EXOTIC_FAIL_FORMAT -2 /* file format is not supported */
322 #define BKE_READ_EXOTIC_FAIL_OPEN -1 /* Can't open the file */
323 #define BKE_READ_EXOTIC_OK_BLEND 0 /* .blend file */
324 #define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */
327 /* intended to check for non-blender formats but for now it only reads blends */
328 static int wm_read_exotic(Scene *UNUSED(scene), const char *name)
335 /* make sure we're not trying to read a directory.... */
338 if (len > 0 && ELEM(name[len - 1], '/', '\\')) {
339 retval = BKE_READ_EXOTIC_FAIL_PATH;
342 gzfile = BLI_gzopen(name, "rb");
343 if (gzfile == NULL) {
344 retval = BKE_READ_EXOTIC_FAIL_OPEN;
347 len = gzread(gzfile, header, sizeof(header));
349 if (len == sizeof(header) && strncmp(header, "BLENDER", 7) == 0) {
350 retval = BKE_READ_EXOTIC_OK_BLEND;
353 #if 0 /* historic stuff - no longer used */
354 WM_cursor_wait(TRUE);
356 if (is_foo_format(name)) {
358 retval = BKE_READ_EXOTIC_OK_OTHER;
363 retval = BKE_READ_EXOTIC_FAIL_FORMAT;
366 WM_cursor_wait(FALSE);
375 void WM_file_autoexec_init(const char *filepath)
377 if (G.f & G_SCRIPT_OVERRIDE_PREF) {
381 if (G.f & G_SCRIPT_AUTOEXEC) {
383 BLI_split_dir_part(filepath, path, sizeof(path));
384 if (BKE_autoexec_match(path)) {
385 G.f &= ~G_SCRIPT_AUTOEXEC;
390 void WM_file_read(bContext *C, const char *filepath, ReportList *reports)
394 /* so we can get the error message */
399 BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
401 /* first try to append data from exotic file formats... */
402 /* it throws error box when file doesn't exist and returns -1 */
403 /* note; it should set some error message somewhere... (ton) */
404 retval = wm_read_exotic(CTX_data_scene(C), filepath);
406 /* we didn't succeed, now try to read Blender file */
407 if (retval == BKE_READ_EXOTIC_OK_BLEND) {
411 /* assume automated tasks with background, don't write recent file list */
412 const int do_history = (G.background == FALSE) && (CTX_wm_manager(C)->op_undo_depth == 0);
414 /* put aside screens to match with persistent windows later */
415 /* also exit screens and editors */
416 wm_window_match_init(C, &wmbase);
418 /* confusing this global... */
420 retval = BKE_read_file(C, filepath, reports);
421 /* when loading startup.blend's, we can be left with a blank path */
422 if (G.main->name[0]) {
430 /* this flag is initialized by the operator but overwritten on read.
431 * need to re-enable it here else drivers + registered scripts wont work. */
433 const int flags_keep = (G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF);
434 G.f = (G.f & ~flags_keep) | (G_f & flags_keep);
437 /* match the read WM with current WM */
438 wm_window_match_do(C, &wmbase);
439 WM_check(C); /* opens window(s), checks keymaps */
441 if (retval == BKE_READ_FILE_OK_USERPREFS) {
442 /* in case a userdef is read from regular .blend */
443 wm_init_userdef(C, false);
446 if (retval != BKE_READ_FILE_FAIL) {
453 WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
454 // refresh_interface_font();
456 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
459 DAG_on_visible_update(CTX_data_main(C), TRUE);
462 /* run any texts that were loaded in and flagged as modules */
466 /* important to do before NULL'ing the context */
467 BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
470 /* in background mode this makes it hard to load
471 * a blend file and do anything since the screen
472 * won't be set to a valid value again */
473 CTX_wm_window_set(C, NULL); /* exits queues */
477 /* gives popups on windows but not linux, bug in report API
478 * but disable for now to stop users getting annoyed */
479 /* TODO, make this show in header info window */
482 for (sce = G.main->scene.first; sce; sce = sce->id.next) {
483 if (sce->r.engine[0] &&
484 BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL)
486 BKE_reportf(reports, RPT_ERROR, "Engine '%s' not available for scene '%s' "
487 "(an addon may need to be installed or enabled)",
488 sce->r.engine, sce->id.name + 2);
495 BKE_write_undo(C, "original"); /* save current state */
497 else if (retval == BKE_READ_EXOTIC_OK_OTHER)
498 BKE_write_undo(C, "Import file");
499 else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
500 BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
501 errno ? strerror(errno) : TIP_("unable to open the file"));
503 else if (retval == BKE_READ_EXOTIC_FAIL_FORMAT) {
504 BKE_reportf(reports, RPT_ERROR, "File format is not supported in file '%s'", filepath);
506 else if (retval == BKE_READ_EXOTIC_FAIL_PATH) {
507 BKE_reportf(reports, RPT_ERROR, "File path '%s' invalid", filepath);
510 BKE_reportf(reports, RPT_ERROR, "Unknown error loading '%s'", filepath);
511 BLI_assert(!"invalid 'retval'");
519 /* called on startup, (context entirely filled with NULLs) */
520 /* or called for 'New File' */
521 /* both startup.blend and userpref.blend are checked */
522 /* the optional paramater custom_file points to an alterntive startup page */
523 /* custom_file can be NULL */
524 int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const char *custom_file)
527 char startstr[FILE_MAX];
528 char prefstr[FILE_MAX];
531 /* Indicates whether user prefereneces were really load from memory.
533 * This is used for versioning code, and for this we can not rely on from_memory
534 * passed via argument. This is because there might be configuration folder
535 * exists but it might not have userpref.blend and in this case we fallback to
536 * reading home file from memory.
538 * And in this case versioning code is to be run.
540 bool read_userdef_from_memory = true;
542 /* options exclude eachother */
543 BLI_assert((from_memory && custom_file) == 0);
545 BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
549 const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
551 BLI_strncpy(startstr, custom_file, FILE_MAX);
554 BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
561 BLI_make_file_string(G.main->name, startstr, cfgdir, BLENDER_STARTUP_FILE);
562 BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
571 /* prevent loading no UI */
572 G.fileflags &= ~G_FILE_NO_UI;
574 /* put aside screens to match with persistent windows later */
575 wm_window_match_init(C, &wmbase);
578 if (BLI_access(startstr, R_OK) == 0) {
579 success = (BKE_read_file(C, startstr, NULL) != BKE_READ_FILE_FAIL);
581 if (U.themes.first == NULL) {
582 if (G.debug & G_DEBUG)
583 printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", startstr);
588 if (success == 0 && custom_file && reports) {
589 BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", custom_file);
590 /*We can not return from here because wm is already reset*/
594 success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true);
595 if (wmbase.first == NULL) wm_clear_default_size(C);
596 BLI_init_temporary_dir(U.tempdir);
598 #ifdef WITH_PYTHON_SECURITY
599 /* use alternative setting for security nuts
600 * otherwise we'd need to patch the binary blob - startup.blend.c */
601 U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
605 /* check new prefs only after startup.blend was finished */
606 if (!from_memory && BLI_exists(prefstr)) {
607 int done = BKE_read_file_userdef(prefstr, NULL);
609 read_userdef_from_memory = false;
610 printf("Read new prefs: %s\n", prefstr);
614 /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
615 * can remove this eventually, only in a 2.53 and older, now its not written */
616 G.fileflags &= ~G_FILE_RELATIVE_REMAP;
618 /* check userdef before open window, keymaps etc */
619 wm_init_userdef(C, read_userdef_from_memory);
621 /* match the read WM with current WM */
622 wm_window_match_do(C, &wmbase);
623 WM_check(C); /* opens window(s), checks keymaps */
625 G.main->name[0] = '\0';
627 /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
628 if (!G.background) GPU_default_lights();
631 G.save_over = 0; // start with save preference untitled.blend
632 G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */
634 // refresh_interface_font();
636 // undo_editmode_clear();
638 BKE_write_undo(C, "original"); /* save current state */
641 DAG_on_visible_update(CTX_data_main(C), TRUE);
644 if (CTX_py_init_get(C)) {
645 /* sync addons, these may have changed from the defaults */
646 BPY_string_exec(C, "__import__('addon_utils').reset_all()");
652 /* important to do before NULL'ing the context */
653 BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
655 WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
657 /* in background mode the scene will stay NULL */
659 CTX_wm_window_set(C, NULL); /* exits queues */
665 int wm_history_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
667 ED_file_read_bookmarks();
669 return OPERATOR_FINISHED;
672 int wm_homefile_read_exec(bContext *C, wmOperator *op)
674 const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
675 char filepath_buf[FILE_MAX];
676 const char *filepath = NULL;
679 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
680 if (RNA_property_is_set(op->ptr, prop)) {
681 RNA_property_string_get(op->ptr, prop, filepath_buf);
682 filepath = filepath_buf;
683 if (BLI_access(filepath, R_OK)) {
684 BKE_reportf(op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath);
685 return OPERATOR_CANCELLED;
690 return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
693 void wm_read_history(void)
697 struct RecentFile *recent;
700 const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
704 BLI_make_file_string("/", name, cfgdir, BLENDER_HISTORY_FILE);
706 lines = BLI_file_read_as_lines(name);
708 G.recent_files.first = G.recent_files.last = NULL;
710 /* read list of recent opened files from recent-files.txt to memory */
711 for (l = lines, num = 0; l && (num < U.recent_files); l = l->next) {
713 if (line[0] && BLI_exists(line)) {
714 recent = (RecentFile *)MEM_mallocN(sizeof(RecentFile), "RecentFile");
715 BLI_addtail(&(G.recent_files), recent);
716 recent->filepath = BLI_strdup(line);
721 BLI_file_free_lines(lines);
724 static void write_history(void)
726 struct RecentFile *recent, *next_recent;
728 const char *user_config_dir;
732 /* no write history for recovered startup files */
733 if (G.main->name[0] == 0)
736 /* will be NULL in background mode */
737 user_config_dir = BLI_get_folder_create(BLENDER_USER_CONFIG, NULL);
738 if (!user_config_dir)
741 BLI_make_file_string("/", name, user_config_dir, BLENDER_HISTORY_FILE);
743 recent = G.recent_files.first;
744 /* refresh recent-files.txt of recent opened files, when current file was changed */
745 if (!(recent) || (BLI_path_cmp(recent->filepath, G.main->name) != 0)) {
746 fp = BLI_fopen(name, "w");
748 /* add current file to the beginning of list */
749 recent = (RecentFile *)MEM_mallocN(sizeof(RecentFile), "RecentFile");
750 recent->filepath = BLI_strdup(G.main->name);
751 BLI_addhead(&(G.recent_files), recent);
752 /* write current file to recent-files.txt */
753 fprintf(fp, "%s\n", recent->filepath);
754 recent = recent->next;
756 /* write rest of recent opened files to recent-files.txt */
757 while ((i < U.recent_files) && (recent)) {
758 /* this prevents to have duplicities in list */
759 if (BLI_path_cmp(recent->filepath, G.main->name) != 0) {
760 fprintf(fp, "%s\n", recent->filepath);
761 recent = recent->next;
764 next_recent = recent->next;
765 MEM_freeN(recent->filepath);
766 BLI_freelinkN(&(G.recent_files), recent);
767 recent = next_recent;
774 /* also update most recent files on System */
775 GHOST_addToSystemRecentFiles(G.main->name);
779 /* screen can be NULL */
780 static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
782 /* will be scaled down, but gives some nice oversampling */
785 char err_out[256] = "unknown";
787 /* screen if no camera found */
794 /* scene can be NULL if running a script at startup and calling the save operator */
795 if (G.background || scene == NULL)
798 if ((scene->camera == NULL) && (screen != NULL)) {
799 sa = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
800 ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
802 v3d = sa->spacedata.first;
806 if (scene->camera == NULL && v3d == NULL) {
810 /* gets scaled to BLEN_THUMB_SIZE */
812 ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
813 BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
814 IB_rect, OB_SOLID, FALSE, FALSE, R_ADDSKY, err_out);
817 ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
818 IB_rect, FALSE, R_ADDSKY, err_out);
822 float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
824 /* dirty oversampling */
825 IMB_scaleImBuf(ibuf, BLEN_THUMB_SIZE, BLEN_THUMB_SIZE);
827 /* add pretty overlay */
828 IMB_overlayblend_thumb(ibuf->rect, ibuf->x, ibuf->y, aspect);
830 /* first write into thumb buffer */
831 thumb = MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb");
833 thumb[0] = BLEN_THUMB_SIZE;
834 thumb[1] = BLEN_THUMB_SIZE;
836 memcpy(thumb + 2, ibuf->rect, BLEN_THUMB_SIZE * BLEN_THUMB_SIZE * sizeof(int));
839 /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */
840 fprintf(stderr, "blend_file_thumb failed to create thumbnail: %s\n", err_out);
844 /* must be freed by caller */
850 /* easy access from gdb */
851 bool write_crash_blend(void)
854 int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on crash file */
856 BLI_strncpy(path, G.main->name, sizeof(path));
857 BLI_replace_extension(path, sizeof(path), "_crash.blend");
858 if (BLO_write_file(G.main, path, fileflags, NULL, NULL)) {
859 printf("written: %s\n", path);
863 printf("failed: %s\n", path);
869 * Flush any temp data from object editing to DNA before writing the blend file to disk.
871 static void write_flush_editdata(bContext *C)
875 obedit = CTX_data_edit_object(C);
878 ED_object_editmode_load(obedit);
881 ED_sculpt_force_update(C);
885 * \see #wm_homefile_write_exec wraps #BLO_write_file in a similar way.
887 int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports)
892 ImBuf *ibuf_thumb = NULL;
894 len = strlen(filepath);
897 BKE_report(reports, RPT_ERROR, "Path is empty, cannot save");
901 if (len >= FILE_MAX) {
902 BKE_report(reports, RPT_ERROR, "Path too long, cannot save");
906 /* Check if file write permission is ok */
907 if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
908 BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
912 /* note: used to replace the file extension (to ensure '.blend'),
913 * no need to now because the operator ensures,
914 * its handy for scripts to save to a predefined name without blender editing it */
916 /* send the OnSave event */
917 for (li = G.main->library.first; li; li = li->id.next) {
918 if (BLI_path_cmp(li->filepath, filepath) == 0) {
919 BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath);
924 /* blend file thumbnail */
925 /* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */
926 if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
927 ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_wm_screen(C), &thumb);
930 BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
932 /* operator now handles overwrite checks */
934 if (G.fileflags & G_AUTOPACK) {
935 packAll(G.main, reports);
938 /* don't forget not to return without! */
941 write_flush_editdata(C);
943 fileflags |= G_FILE_HISTORY; /* write file history */
945 /* first time saving */
946 /* XXX temp solution to solve bug, real fix coming (ton) */
947 if ((G.main->name[0] == '\0') && !(fileflags & G_FILE_SAVE_COPY)) {
948 BLI_strncpy(G.main->name, filepath, sizeof(G.main->name));
951 /* XXX temp solution to solve bug, real fix coming (ton) */
952 G.main->recovered = 0;
954 if (BLO_write_file(CTX_data_main(C), filepath, fileflags, reports, thumb)) {
955 if (!(fileflags & G_FILE_SAVE_COPY)) {
957 BLI_strncpy(G.main->name, filepath, sizeof(G.main->name)); /* is guaranteed current file */
959 G.save_over = 1; /* disable untitled.blend convention */
962 if (fileflags & G_FILE_COMPRESS) G.fileflags |= G_FILE_COMPRESS;
963 else G.fileflags &= ~G_FILE_COMPRESS;
965 if (fileflags & G_FILE_AUTOPLAY) G.fileflags |= G_FILE_AUTOPLAY;
966 else G.fileflags &= ~G_FILE_AUTOPLAY;
968 /* prevent background mode scripts from clobbering history */
973 BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
975 /* run this function after because the file cant be written before the blend is */
977 IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */
978 ibuf_thumb = IMB_thumb_create(filepath, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb);
979 IMB_freeImBuf(ibuf_thumb);
982 if (thumb) MEM_freeN(thumb);
985 if (ibuf_thumb) IMB_freeImBuf(ibuf_thumb);
986 if (thumb) MEM_freeN(thumb);
998 * \see #wm_file_write wraps #BLO_write_file in a similar way.
1000 int wm_homefile_write_exec(bContext *C, wmOperator *op)
1002 wmWindowManager *wm = CTX_wm_manager(C);
1003 wmWindow *win = CTX_wm_window(C);
1004 char filepath[FILE_MAX];
1007 /* check current window and close it if temp */
1008 if (win && win->screen->temp)
1009 wm_window_close(C, wm, win);
1011 /* update keymaps in user preferences */
1012 WM_keyconfig_update(wm);
1014 BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
1015 printf("trying to save homefile at %s ", filepath);
1017 write_flush_editdata(C);
1019 /* force save as regular blend file */
1020 fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
1022 if (BLO_write_file(CTX_data_main(C), filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
1024 return OPERATOR_CANCELLED;
1031 return OPERATOR_FINISHED;
1034 /* Only save the prefs block. operator entry */
1035 int wm_userpref_write_exec(bContext *C, wmOperator *op)
1037 wmWindowManager *wm = CTX_wm_manager(C);
1038 char filepath[FILE_MAX];
1040 /* update keymaps in user preferences */
1041 WM_keyconfig_update(wm);
1043 BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
1044 printf("trying to save userpref at %s ", filepath);
1046 if (BKE_write_file_userdef(filepath, op->reports) == 0) {
1048 return OPERATOR_CANCELLED;
1053 return OPERATOR_FINISHED;
1056 /************************ autosave ****************************/
1058 void wm_autosave_location(char *filepath)
1062 const char *savedir;
1065 BLI_snprintf(pidstr, sizeof(pidstr), "%d.blend", abs(getpid()));
1068 /* XXX Need to investigate how to handle default location of '/tmp/'
1069 * This is a relative directory on Windows, and it may be
1071 * Blender installed on D:\ drive, D:\ drive has D:\tmp\
1072 * Now, BLI_exists() will find '/tmp/' exists, but
1073 * BLI_make_file_string will create string that has it most likely on C:\
1074 * through get_default_root().
1075 * If there is no C:\tmp autosave fails. */
1076 if (!BLI_exists(BLI_temporary_dir())) {
1077 savedir = BLI_get_folder_create(BLENDER_USER_AUTOSAVE, NULL);
1078 BLI_make_file_string("/", filepath, savedir, pidstr);
1083 BLI_make_file_string("/", filepath, BLI_temporary_dir(), pidstr);
1086 void WM_autosave_init(wmWindowManager *wm)
1088 wm_autosave_timer_ended(wm);
1090 if (U.flag & USER_AUTOSAVE)
1091 wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime * 60.0);
1094 void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(wt))
1097 wmEventHandler *handler;
1098 char filepath[FILE_MAX];
1100 Scene *scene = CTX_data_scene(C);
1102 WM_event_remove_timer(wm, NULL, wm->autosavetimer);
1104 /* if a modal operator is running, don't autosave, but try again in 10 seconds */
1105 for (win = wm->windows.first; win; win = win->next) {
1106 for (handler = win->modalhandlers.first; handler; handler = handler->next) {
1108 wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0);
1117 if (ob && ob->mode & OB_MODE_SCULPT)
1118 multires_force_update(ob);
1121 wm_autosave_location(filepath);
1123 if (U.uiflag & USER_GLOBALUNDO) {
1124 /* fast save of last undobuffer, now with UI */
1125 BKE_undo_save_file(filepath);
1128 /* save as regular blend file */
1129 int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
1131 /* no error reporting to console */
1132 BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
1134 /* do timer after file write, just in case file write takes a long time */
1135 wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, U.savetime * 60.0);
1138 void wm_autosave_timer_ended(wmWindowManager *wm)
1140 if (wm->autosavetimer) {
1141 WM_event_remove_timer(wm, NULL, wm->autosavetimer);
1142 wm->autosavetimer = NULL;
1146 void wm_autosave_delete(void)
1148 char filename[FILE_MAX];
1150 wm_autosave_location(filename);
1152 if (BLI_exists(filename)) {
1154 BLI_make_file_string("/", str, BLI_temporary_dir(), BLENDER_QUIT_FILE);
1156 /* if global undo; remove tempsave, otherwise rename */
1157 if (U.uiflag & USER_GLOBALUNDO) BLI_delete(filename, false, false);
1158 else BLI_rename(filename, str);
1162 void wm_autosave_read(bContext *C, ReportList *reports)
1164 char filename[FILE_MAX];
1166 wm_autosave_location(filename);
1167 WM_file_read(C, filename, reports);