Blender  V2.93
wm_files.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
27 /* placed up here because of crappy
28  * winsock stuff.
29  */
30 #include <errno.h>
31 #include <stddef.h>
32 #include <string.h>
33 
34 #include "zlib.h" /* wm_read_exotic() */
35 
36 #ifdef WIN32
37 /* Need to include windows.h so _WIN32_IE is defined. */
38 # include <windows.h>
39 # ifndef _WIN32_IE
40 /* Minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already. */
41 # define _WIN32_IE 0x0400
42 # endif
43 /* For SHGetSpecialFolderPath, has to be done before BLI_winstuff
44  * because 'near' is disabled through BLI_windstuff */
45 # include "BLI_winstuff.h"
46 # include <shlobj.h>
47 #endif
48 
49 #include "MEM_CacheLimiterC-Api.h"
50 #include "MEM_guardedalloc.h"
51 
52 #include "BLI_blenlib.h"
53 #include "BLI_fileops_types.h"
54 #include "BLI_linklist.h"
55 #include "BLI_system.h"
56 #include "BLI_threads.h"
57 #include "BLI_timer.h"
58 #include "BLI_utildefines.h"
59 #include BLI_SYSTEM_PID_H
60 
61 #include "BLT_translation.h"
62 
63 #include "BLF_api.h"
64 
65 #include "DNA_object_types.h"
66 #include "DNA_scene_types.h"
67 #include "DNA_screen_types.h"
68 #include "DNA_space_types.h"
69 #include "DNA_userdef_types.h"
71 #include "DNA_workspace_types.h"
72 
73 #include "BKE_addon.h"
74 #include "BKE_appdir.h"
75 #include "BKE_autoexec.h"
76 #include "BKE_blender.h"
77 #include "BKE_blendfile.h"
78 #include "BKE_callbacks.h"
79 #include "BKE_context.h"
80 #include "BKE_global.h"
81 #include "BKE_idprop.h"
82 #include "BKE_lib_id.h"
83 #include "BKE_lib_override.h"
84 #include "BKE_lib_remap.h"
85 #include "BKE_main.h"
86 #include "BKE_packedFile.h"
87 #include "BKE_report.h"
88 #include "BKE_scene.h"
89 #include "BKE_screen.h"
90 #include "BKE_sound.h"
91 #include "BKE_undo_system.h"
92 #include "BKE_workspace.h"
93 
94 #include "BLO_readfile.h"
95 #include "BLO_undofile.h" /* to save from an undo memfile */
96 #include "BLO_writefile.h"
97 
98 #include "RNA_access.h"
99 #include "RNA_define.h"
100 
101 #include "IMB_imbuf.h"
102 #include "IMB_imbuf_types.h"
103 #include "IMB_thumbs.h"
104 
105 #include "ED_datafiles.h"
106 #include "ED_fileselect.h"
107 #include "ED_image.h"
108 #include "ED_outliner.h"
109 #include "ED_screen.h"
110 #include "ED_undo.h"
111 #include "ED_util.h"
112 #include "ED_view3d.h"
113 #include "ED_view3d_offscreen.h"
114 
115 #include "GHOST_C-api.h"
116 #include "GHOST_Path-api.h"
117 
118 #include "UI_interface.h"
119 #include "UI_resources.h"
120 #include "UI_view2d.h"
121 
122 /* only to report a missing engine */
123 #include "RE_engine.h"
124 
125 #ifdef WITH_PYTHON
126 # include "BPY_extern_python.h"
127 # include "BPY_extern_run.h"
128 #endif
129 
130 #include "DEG_depsgraph.h"
131 
132 #include "WM_api.h"
133 #include "WM_message.h"
134 #include "WM_toolsystem.h"
135 #include "WM_types.h"
136 
137 #include "wm.h"
138 #include "wm_event_system.h"
139 #include "wm_files.h"
140 #include "wm_window.h"
141 
142 #include "CLG_log.h"
143 
144 static RecentFile *wm_file_history_find(const char *filepath);
145 static void wm_history_file_free(RecentFile *recent);
146 static void wm_history_files_free(void);
147 static void wm_history_file_update(void);
148 static void wm_history_file_write(void);
149 
151 
152 static CLG_LogRef LOG = {"wm.files"};
153 
154 /* -------------------------------------------------------------------- */
159 {
160  wmWindowManager *wm = G_MAIN->wm.first;
161  if (wm->file_saved) {
162  wm->file_saved = 0;
163  /* notifier that data changed, for save-over warning or header */
165  }
166 }
167 
168 bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm)
169 {
170  return !wm->file_saved || ED_image_should_save_modified(bmain);
171 }
172 
175 /* -------------------------------------------------------------------- */
186 static void wm_window_match_init(bContext *C, ListBase *wmlist)
187 {
188  *wmlist = G_MAIN->wm;
190 
191  wmWindow *active_win = CTX_wm_window(C);
192 
193  /* first wrap up running stuff */
194  /* code copied from wm_init_exit.c */
195  LISTBASE_FOREACH (wmWindowManager *, wm, wmlist) {
196  WM_jobs_kill_all(wm);
197 
198  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
199  CTX_wm_window_set(C, win); /* needed by operator close callbacks */
200  WM_event_remove_handlers(C, &win->handlers);
201  WM_event_remove_handlers(C, &win->modalhandlers);
203  }
204  }
205 
206  /* reset active window */
207  CTX_wm_window_set(C, active_win);
208 
209  /* XXX Hack! We have to clear context menu here, because removing all modalhandlers
210  * above frees the active menu (at least, in the 'startup splash' case),
211  * causing use-after-free error in later handling of the button callbacks in UI code
212  * (see ui_apply_but_funcs_after()).
213  * Tried solving this by always NULL-ing context's menu when setting wm/win/etc.,
214  * but it broke popups refreshing (see T47632),
215  * so for now just handling this specific case here. */
217 
218  ED_editors_exit(G_MAIN, true);
219 }
220 
222  wmWindowManager *wm,
223  wmWindow *oldwin,
224  wmWindow *win)
225 {
226  win->ghostwin = oldwin->ghostwin;
227  win->gpuctx = oldwin->gpuctx;
228  win->active = oldwin->active;
229  if (win->active) {
230  wm->winactive = win;
231  }
232  if (oldwm->windrawable == oldwin) {
233  oldwm->windrawable = NULL;
234  wm->windrawable = win;
235  }
236 
237  /* File loading in background mode still calls this. */
238  if (!G.background) {
239  /* Pointer back. */
241  }
242 
243  oldwin->ghostwin = NULL;
244  oldwin->gpuctx = NULL;
245 
246  win->eventstate = oldwin->eventstate;
247  oldwin->eventstate = NULL;
248 
249  /* ensure proper screen rescaling */
250  win->sizex = oldwin->sizex;
251  win->sizey = oldwin->sizey;
252  win->posx = oldwin->posx;
253  win->posy = oldwin->posy;
254 }
255 
257  ListBase *current_wm_list,
258  const bool load_ui,
259  ListBase *r_new_wm_list)
260 {
261  Main *bmain = CTX_data_main(C);
262  wmWindowManager *wm = current_wm_list->first;
263  bScreen *screen = NULL;
264 
265  /* match oldwm to new dbase, only old files */
267 
268  /* when loading without UI, no matching needed */
269  if (load_ui && (screen = CTX_wm_screen(C))) {
270  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
271  WorkSpace *workspace;
272 
273  BKE_workspace_layout_find_global(bmain, screen, &workspace);
274  BKE_workspace_active_set(win->workspace_hook, workspace);
275  win->scene = CTX_data_scene(C);
276 
277  /* all windows get active screen from file */
278  if (screen->winid == 0) {
279  WM_window_set_active_screen(win, workspace, screen);
280  }
281  else {
282  WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
284  bmain, workspace, layout_old, win);
285 
286  WM_window_set_active_layout(win, workspace, layout_new);
287  }
288 
289  bScreen *win_screen = WM_window_get_active_screen(win);
290  win_screen->winid = win->winid;
291  }
292  }
293 
294  *r_new_wm_list = *current_wm_list;
295 }
296 
298  ListBase *current_wm_list,
299  ListBase *readfile_wm_list,
300  ListBase *r_new_wm_list)
301 {
302  wmWindowManager *oldwm = current_wm_list->first;
303  wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */
304 
305  /* Support window-manager ID references being held between file load operations by keeping
306  * #Main.wm.first memory address in-place, while swapping all of it's contents.
307  *
308  * This is needed so items such as key-maps can be held by an add-on,
309  * without it pointing to invalid memory, see: T86431 */
310  {
311  /* Referencing the window-manager pointer from elsewhere in the file is highly unlikely
312  * however it's possible with ID-properties & animation-drivers.
313  * At some point we could check on disallowing this since it doesn't seem practical. */
314  Main *bmain = G_MAIN;
315  BLI_assert(bmain->relations == NULL);
317 
318  /* Maintain the undo-depth between file loads. Useful so Python can perform
319  * nested operator calls that exit with the proper undo-depth. */
320  wm->op_undo_depth = oldwm->op_undo_depth;
321 
322  /* Simple pointer swapping step. */
323  BLI_remlink(current_wm_list, oldwm);
324  BLI_remlink(readfile_wm_list, wm);
325  SWAP(wmWindowManager, *oldwm, *wm);
326  SWAP(wmWindowManager *, oldwm, wm);
327  BLI_addhead(current_wm_list, oldwm);
328  BLI_addhead(readfile_wm_list, wm);
329 
330  /* Don't leave the old pointer in the context. */
331  CTX_wm_manager_set(C, wm);
332  }
333 
334  bool has_match = false;
335 
336  /* this code could move to setup_appdata */
337 
338  /* preserve key configurations in new wm, to preserve their keymaps */
339  wm->keyconfigs = oldwm->keyconfigs;
340  wm->addonconf = oldwm->addonconf;
341  wm->defaultconf = oldwm->defaultconf;
342  wm->userconf = oldwm->userconf;
343 
345  oldwm->addonconf = NULL;
346  oldwm->defaultconf = NULL;
347  oldwm->userconf = NULL;
348 
349  /* ensure making new keymaps and set space types */
350  wm->initialized = 0;
351  wm->winactive = NULL;
352 
353  /* Clearing drawable of before deleting any context
354  * to avoid clearing the wrong wm. */
356 
357  /* only first wm in list has ghostwins */
358  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
359  LISTBASE_FOREACH (wmWindow *, oldwin, &oldwm->windows) {
360  if (oldwin->winid == win->winid) {
361  has_match = true;
362 
363  wm_window_substitute_old(oldwm, wm, oldwin, win);
364  }
365  }
366  }
367  /* make sure at least one window is kept open so we don't lose the context, check T42303 */
368  if (!has_match) {
369  wm_window_substitute_old(oldwm, wm, oldwm->windows.first, wm->windows.first);
370  }
371 
372  wm_close_and_free_all(C, current_wm_list);
373 
374  *r_new_wm_list = *readfile_wm_list;
375 }
376 
387  ListBase *current_wm_list,
388  ListBase *readfile_wm_list,
389  ListBase *r_new_wm_list)
390 {
391  if (BLI_listbase_is_empty(current_wm_list)) {
392  /* case 1 */
393  if (BLI_listbase_is_empty(readfile_wm_list)) {
394  Main *bmain = CTX_data_main(C);
395  /* Neither current, no newly read file have a WM -> add the default one. */
396  wm_add_default(bmain, C);
397  *r_new_wm_list = bmain->wm;
398  }
399  /* case 2 */
400  else {
401  *r_new_wm_list = *readfile_wm_list;
402  }
403  }
404  else {
405  /* case 3 */
406  if (BLI_listbase_is_empty(readfile_wm_list)) {
407  /* We've read file without wm, keep current one entirely alive.
408  * Happens when reading pre 2.5 files (no WM back then) */
410  C, current_wm_list, (G.fileflags & G_FILE_NO_UI) == 0, r_new_wm_list);
411  }
412  /* case 4 */
413  else {
414  wm_window_match_replace_by_file_wm(C, current_wm_list, readfile_wm_list, r_new_wm_list);
415  }
416  }
417 }
418 
421 /* -------------------------------------------------------------------- */
428 static void wm_init_userdef(Main *bmain)
429 {
430  /* Not versioning, just avoid errors. */
431 #ifndef WITH_CYCLES
432  BKE_addon_remove_safe(&U.addons, "cycles");
433 #else
435 #endif
436 
437  UI_init_userdef();
438 
439  /* needed so loading a file from the command line respects user-pref T26156. */
440  SET_FLAG_FROM_TEST(G.fileflags, U.flag & USER_FILENOUI, G_FILE_NO_UI);
441 
442  /* set the python auto-execute setting from user prefs */
443  /* enabled by default, unless explicitly enabled in the command line which overrides */
444  if ((G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) == 0) {
446  }
447 
448  MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024);
449  BKE_sound_init(bmain);
450 
451  /* Update the temporary directory from the preferences or fallback to the system default. */
452  BKE_tempdir_init(U.tempdir);
453 
454  /* Update tablet API preference. */
456 
458 }
459 
460 /* return codes */
461 #define BKE_READ_EXOTIC_FAIL_PATH -3 /* file format is not supported */
462 #define BKE_READ_EXOTIC_FAIL_FORMAT -2 /* file format is not supported */
463 #define BKE_READ_EXOTIC_FAIL_OPEN -1 /* Can't open the file */
464 #define BKE_READ_EXOTIC_OK_BLEND 0 /* .blend file */
465 #if 0
466 # define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */
467 #endif
468 
471 /* -------------------------------------------------------------------- */
478 /* intended to check for non-blender formats but for now it only reads blends */
479 static int wm_read_exotic(const char *name)
480 {
481  int len;
482  gzFile gzfile;
483  char header[7];
484  int retval;
485 
486  /* make sure we're not trying to read a directory.... */
487 
488  len = strlen(name);
489  if (len > 0 && ELEM(name[len - 1], '/', '\\')) {
490  retval = BKE_READ_EXOTIC_FAIL_PATH;
491  }
492  else {
493  gzfile = BLI_gzopen(name, "rb");
494  if (gzfile == NULL) {
495  retval = BKE_READ_EXOTIC_FAIL_OPEN;
496  }
497  else {
498  len = gzread(gzfile, header, sizeof(header));
499  gzclose(gzfile);
500  if (len == sizeof(header) && STREQLEN(header, "BLENDER", 7)) {
501  retval = BKE_READ_EXOTIC_OK_BLEND;
502  }
503  else {
504  /* We may want to support loading other file formats
505  * from their header bytes or file extension.
506  * This used to be supported in the code below and may be added
507  * back at some point. */
508 #if 0
509  WM_cursor_wait(true);
510 
511  if (is_foo_format(name)) {
512  read_foo(name);
513  retval = BKE_READ_EXOTIC_OK_OTHER;
514  }
515  else
516 #endif
517  {
519  }
520 #if 0
521  WM_cursor_wait(false);
522 #endif
523  }
524  }
525  }
526 
527  return retval;
528 }
529 
532 /* -------------------------------------------------------------------- */
536 void WM_file_autoexec_init(const char *filepath)
537 {
538  if (G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) {
539  return;
540  }
541 
542  if (G.f & G_FLAG_SCRIPT_AUTOEXEC) {
543  char path[FILE_MAX];
544  BLI_split_dir_part(filepath, path, sizeof(path));
545  if (BKE_autoexec_match(path)) {
547  }
548  }
549 }
550 
552 {
553  ReportList *reports = NULL;
554  LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
555  if (scene->r.engine[0] &&
556  BLI_findstring(&R_engines, scene->r.engine, offsetof(RenderEngineType, idname)) == NULL) {
557  if (reports == NULL) {
558  reports = CTX_wm_reports(C);
559  }
560 
561  BKE_reportf(reports,
562  RPT_ERROR,
563  "Engine '%s' not available for scene '%s' (an add-on may need to be installed "
564  "or enabled)",
565  scene->r.engine,
566  scene->id.name + 2);
567  }
568  }
569 
570  if (reports) {
571  if (!G.background) {
573  }
574  }
575 }
576 
583 static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef))
584 {
585  if (use_data) {
588  }
589 
590  /* Always do this as both startup and preferences may have loaded in many font's
591  * at a different zoom level to the file being loaded. */
593 }
594 
600  const bool is_startup_file,
601  const bool is_factory_startup,
602  const bool use_data,
603  const bool use_userdef,
604  const bool reset_app_template)
605 {
606  bool addons_loaded = false;
608 
609  if (use_data) {
610  if (!G.background) {
611  /* remove windows which failed to be added via WM_check */
613  }
615  }
616 
617 #ifdef WITH_PYTHON
618  if (is_startup_file) {
619  /* On startup (by default), Python won't have been initialized.
620  *
621  * The following block handles data & preferences being reloaded
622  * which requires resetting some internal variables. */
623  if (CTX_py_init_get(C)) {
624  bool reset_all = use_userdef;
625  if (use_userdef || reset_app_template) {
626  /* Only run when we have a template path found. */
629  C, (const char *[]){"bl_app_template_utils", NULL}, "bl_app_template_utils.reset()");
630  reset_all = true;
631  }
632  }
633  if (reset_all) {
635  C,
636  (const char *[]){"bpy", "addon_utils", NULL},
637  /* Refresh scripts as the preferences may have changed the user-scripts path.
638  *
639  * This is needed when loading settings from the previous version,
640  * otherwise the script path stored in the preferences would be ignored. */
641  "bpy.utils.refresh_script_paths()\n"
642  /* Sync add-ons, these may have changed from the defaults. */
643  "addon_utils.reset_all()");
644  }
645  if (use_data) {
647  }
648  addons_loaded = true;
649  }
650  }
651  else {
652  /* run any texts that were loaded in and flagged as modules */
653  if (use_data) {
655  }
656  addons_loaded = true;
657  }
658 #else
659  UNUSED_VARS(is_startup_file, reset_app_template);
660 #endif /* WITH_PYTHON */
661 
662  Main *bmain = CTX_data_main(C);
663 
664  if (use_userdef) {
665  if (is_factory_startup) {
667  }
668  }
669 
670  if (use_data) {
671  /* important to do before NULL'ing the context */
674  if (is_factory_startup) {
676  }
677  }
678 
679  if (use_data) {
681 
682  /* After load post, so for example the driver namespace can be filled
683  * before evaluating the depsgraph. */
684  wm_event_do_depsgraph(C, true);
685 
687 
688 #if 1
690 #else
692 #endif
693  }
694 
695  /* report any errors.
696  * currently disabled if addons aren't yet loaded */
697  if (addons_loaded) {
698  wm_file_read_report(C, bmain);
699  }
700 
701  if (use_data) {
702  if (!G.background) {
703  if (wm->undo_stack == NULL) {
705  }
706  else {
708  }
711  }
712  }
713 
714  if (use_data) {
715  if (!G.background) {
716  /* in background mode this makes it hard to load
717  * a blend file and do anything since the screen
718  * won't be set to a valid value again */
719  CTX_wm_window_set(C, NULL); /* exits queues */
720 
721  /* Ensure auto-run action is not used from a previous blend file load. */
723 
724  /* Ensure tools are registered. */
726  }
727  }
728 }
729 
732 /* -------------------------------------------------------------------- */
736 bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
737 {
738  /* assume automated tasks with background, don't write recent file list */
739  const bool do_history_file_update = (G.background == false) &&
740  (CTX_wm_manager(C)->op_undo_depth == 0);
741  bool success = false;
742 
743  const bool use_data = true;
744  const bool use_userdef = false;
745 
746  /* so we can get the error message */
747  errno = 0;
748 
749  WM_cursor_wait(true);
750 
751  /* first try to append data from exotic file formats... */
752  /* it throws error box when file doesn't exist and returns -1 */
753  /* note; it should set some error message somewhere... (ton) */
754  const int retval = wm_read_exotic(filepath);
755 
756  /* we didn't succeed, now try to read Blender file */
757  if (retval == BKE_READ_EXOTIC_OK_BLEND) {
758  const struct BlendFileReadParams params = {
759  .is_startup = false,
760  /* Loading preferences when the user intended to load a regular file is a security
761  * risk, because the excluded path list is also loaded. Further it's just confusing
762  * if a user loads a file and various preferences change. */
763  .skip_flags = BLO_READ_SKIP_USERDEF,
764  };
765 
766  struct BlendFileData *bfd = BKE_blendfile_read(filepath, &params, reports);
767  if (bfd != NULL) {
768  wm_file_read_pre(C, use_data, use_userdef);
769 
770  /* Put aside screens to match with persistent windows later,
771  * also exit screens and editors. */
772  ListBase wmbase;
773  wm_window_match_init(C, &wmbase);
774 
775  /* This flag is initialized by the operator but overwritten on read.
776  * need to re-enable it here else drivers + registered scripts wont work. */
777  const int G_f_orig = G.f;
778 
779  BKE_blendfile_read_setup(C, bfd, &params, reports);
780 
781  if (G.f != G_f_orig) {
782  const int flags_keep = G_FLAG_ALL_RUNTIME;
783  G.f &= G_FLAG_ALL_READFILE;
784  G.f = (G.f & ~flags_keep) | (G_f_orig & flags_keep);
785  }
786 
787  /* #BKE_blendfile_read_result_setup sets new Main into context. */
788  Main *bmain = CTX_data_main(C);
789 
790  /* When recovering a session from an unsaved file, this can have a blank path. */
791  if (BKE_main_blendfile_path(bmain)[0] != '\0') {
792  G.save_over = 1;
793  G.relbase_valid = 1;
794  }
795  else {
796  G.save_over = 0;
797  G.relbase_valid = 0;
798  }
799 
800  /* match the read WM with current WM */
801  wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
802  WM_check(C); /* opens window(s), checks keymaps */
803 
804  if (do_history_file_update) {
806  }
807 
808  wm_file_read_post(C, false, false, use_data, use_userdef, false);
809 
810  success = true;
811  }
812  }
813 #if 0
814  else if (retval == BKE_READ_EXOTIC_OK_OTHER) {
815  BKE_undo_write(C, "Import file");
816  }
817 #endif
818  else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
819  BKE_reportf(reports,
820  RPT_ERROR,
821  "Cannot read file '%s': %s",
822  filepath,
823  errno ? strerror(errno) : TIP_("unable to open the file"));
824  }
825  else if (retval == BKE_READ_EXOTIC_FAIL_FORMAT) {
826  BKE_reportf(reports, RPT_ERROR, "File format is not supported in file '%s'", filepath);
827  }
828  else if (retval == BKE_READ_EXOTIC_FAIL_PATH) {
829  BKE_reportf(reports, RPT_ERROR, "File path '%s' invalid", filepath);
830  }
831  else {
832  BKE_reportf(reports, RPT_ERROR, "Unknown error loading '%s'", filepath);
833  BLI_assert(!"invalid 'retval'");
834  }
835 
836  if (success == false) {
837  /* remove from recent files list */
838  if (do_history_file_update) {
839  RecentFile *recent = wm_file_history_find(filepath);
840  if (recent) {
841  wm_history_file_free(recent);
843  }
844  }
845  }
846 
847  WM_cursor_wait(false);
848 
849  return success;
850 }
851 
852 static struct {
853  char app_template[64];
854  bool override;
856 
864 {
865  if (app_template) {
867  wm_init_state_app_template.override = true;
868  }
869  else {
870  wm_init_state_app_template.app_template[0] = '\0';
871  wm_init_state_app_template.override = false;
872  }
873 }
874 
876 {
877  return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL;
878 }
879 
882 /* -------------------------------------------------------------------- */
905  ReportList *reports,
906  bool use_factory_settings,
907  bool use_empty_data,
908  bool use_data,
909  bool use_userdef,
910  const char *filepath_startup_override,
911  const char *app_template_override,
912  bool *r_is_factory_startup)
913 {
914  Main *bmain = G_MAIN; /* Context does not always have valid main pointer here... */
915  ListBase wmbase;
916  bool success = false;
917 
918  bool filepath_startup_is_factory = true;
919  char filepath_startup[FILE_MAX];
920  char filepath_userdef[FILE_MAX];
921 
922  /* When 'app_template' is set:
923  * '{BLENDER_USER_CONFIG}/{app_template}' */
924  char app_template_system[FILE_MAX];
925  /* When 'app_template' is set:
926  * '{BLENDER_SYSTEM_SCRIPTS}/startup/bl_app_templates_system/{app_template}' */
927  char app_template_config[FILE_MAX];
928 
929  eBLOReadSkip skip_flags = 0;
930 
931  if (use_data == false) {
932  skip_flags |= BLO_READ_SKIP_DATA;
933  }
934  if (use_userdef == false) {
935  skip_flags |= BLO_READ_SKIP_USERDEF;
936  }
937 
938  /* True if we load startup.blend from memory
939  * or use app-template startup.blend which the user hasn't saved. */
940  bool is_factory_startup = true;
941 
942  const char *app_template = NULL;
943  bool update_defaults = false;
944 
945  if (filepath_startup_override != NULL) {
946  /* pass */
947  }
948  else if (app_template_override) {
949  /* This may be clearing the current template by setting to an empty string. */
950  app_template = app_template_override;
951  }
952  else if (!use_factory_settings && U.app_template[0]) {
953  app_template = U.app_template;
954  }
955 
956  const bool reset_app_template = ((!app_template && U.app_template[0]) ||
957  (app_template && !STREQ(app_template, U.app_template)));
958 
959  /* options exclude eachother */
960  BLI_assert((use_factory_settings && filepath_startup_override) == 0);
961 
962  if ((G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) == 0) {
964  }
965 
966  if (use_data) {
967  if (reset_app_template) {
968  /* Always load UI when switching to another template. */
969  G.fileflags &= ~G_FILE_NO_UI;
970  }
971  }
972 
973  if (use_userdef || reset_app_template) {
974 #ifdef WITH_PYTHON
975  /* This only runs once Blender has already started. */
976  if (CTX_py_init_get(C)) {
977  /* This is restored by 'wm_file_read_post', disable before loading any preferences
978  * so an add-on can read their own preferences when un-registering,
979  * and use new preferences if/when re-registering, see T67577.
980  *
981  * Note that this fits into 'wm_file_read_pre' function but gets messy
982  * since we need to know if 'reset_app_template' is true. */
983  BPY_run_string_eval(C, (const char *[]){"addon_utils", NULL}, "addon_utils.disable_all()");
984  }
985 #endif /* WITH_PYTHON */
986  }
987 
988  /* For regular file loading this only runs after the file is successfully read.
989  * In the case of the startup file, the in-memory startup file is used as a fallback
990  * so we know this will work if all else fails. */
991  wm_file_read_pre(C, use_data, use_userdef);
992 
993  if (use_data) {
994  G.relbase_valid = 0;
995 
996  /* put aside screens to match with persistent windows later */
997  wm_window_match_init(C, &wmbase);
998  }
999 
1000  filepath_startup[0] = '\0';
1001  filepath_userdef[0] = '\0';
1002  app_template_system[0] = '\0';
1003  app_template_config[0] = '\0';
1004 
1005  const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
1006  if (!use_factory_settings) {
1007  if (cfgdir) {
1008  BLI_path_join(
1009  filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
1010  filepath_startup_is_factory = false;
1011  if (use_userdef) {
1012  BLI_path_join(
1013  filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
1014  }
1015  }
1016  else {
1017  use_factory_settings = true;
1018  }
1019 
1020  if (filepath_startup_override) {
1021  BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX);
1022  filepath_startup_is_factory = false;
1023  }
1024  }
1025 
1026  /* load preferences before startup.blend */
1027  if (use_userdef) {
1028  if (!use_factory_settings && BLI_exists(filepath_userdef)) {
1029  UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL);
1030  if (userdef != NULL) {
1032  userdef = NULL;
1033 
1034  skip_flags |= BLO_READ_SKIP_USERDEF;
1035  printf("Read prefs: %s\n", filepath_userdef);
1036  }
1037  }
1038  }
1039 
1040  if ((app_template != NULL) && (app_template[0] != '\0')) {
1042  app_template, app_template_system, sizeof(app_template_system))) {
1043  /* Can safely continue with code below, just warn it's not found. */
1044  BKE_reportf(reports, RPT_WARNING, "Application Template '%s' not found", app_template);
1045  }
1046 
1047  /* Insert template name into startup file. */
1048 
1049  /* note that the path is being set even when 'use_factory_settings == true'
1050  * this is done so we can load a templates factory-settings */
1051  if (!use_factory_settings) {
1052  BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
1053  BLI_path_join(filepath_startup,
1054  sizeof(filepath_startup),
1055  app_template_config,
1057  NULL);
1058  filepath_startup_is_factory = false;
1059  if (BLI_access(filepath_startup, R_OK) != 0) {
1060  filepath_startup[0] = '\0';
1061  }
1062  }
1063  else {
1064  filepath_startup[0] = '\0';
1065  }
1066 
1067  if (filepath_startup[0] == '\0') {
1068  BLI_path_join(filepath_startup,
1069  sizeof(filepath_startup),
1070  app_template_system,
1072  NULL);
1073  filepath_startup_is_factory = true;
1074 
1075  /* Update defaults only for system templates. */
1076  update_defaults = true;
1077  }
1078  }
1079 
1080  if (!use_factory_settings || (filepath_startup[0] != '\0')) {
1081  if (BLI_access(filepath_startup, R_OK) == 0) {
1082  const struct BlendFileReadParams params = {
1083  .is_startup = true,
1084  .skip_flags = skip_flags | BLO_READ_SKIP_USERDEF,
1085  };
1086 
1087  struct BlendFileData *bfd = BKE_blendfile_read(filepath_startup, &params, NULL);
1088  if (bfd != NULL) {
1090  C, bfd, &params, NULL, update_defaults && use_data, app_template);
1091  success = true;
1092  }
1093  }
1094  if (success) {
1095  is_factory_startup = filepath_startup_is_factory;
1096  }
1097  }
1098 
1099  if (use_userdef) {
1100  if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
1101  UserDef *userdef_default = BKE_blendfile_userdef_from_defaults();
1102  BKE_blender_userdef_data_set_and_free(userdef_default);
1103  skip_flags |= BLO_READ_SKIP_USERDEF;
1104  }
1105  }
1106 
1107  if (success == false && filepath_startup_override && reports) {
1108  /* We can not return from here because wm is already reset */
1109  BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override);
1110  }
1111 
1112  if (success == false) {
1113  const struct BlendFileReadParams params = {
1114  .is_startup = true,
1115  .skip_flags = skip_flags,
1116  };
1119  if (bfd != NULL) {
1120  BKE_blendfile_read_setup_ex(C, bfd, &params, NULL, true, NULL);
1121  success = true;
1122  }
1123 
1124  if (use_data && BLI_listbase_is_empty(&wmbase)) {
1126  }
1127  }
1128 
1129  if (use_empty_data) {
1131  }
1132 
1133  /* Load template preferences,
1134  * unlike regular preferences we only use some of the settings,
1135  * see: BKE_blender_userdef_set_app_template */
1136  if (app_template_system[0] != '\0') {
1137  char temp_path[FILE_MAX];
1138  temp_path[0] = '\0';
1139  if (!use_factory_settings) {
1140  BLI_path_join(
1141  temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL);
1142  if (BLI_access(temp_path, R_OK) != 0) {
1143  temp_path[0] = '\0';
1144  }
1145  }
1146 
1147  if (temp_path[0] == '\0') {
1148  BLI_path_join(
1149  temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL);
1150  }
1151 
1152  if (use_userdef) {
1153  UserDef *userdef_template = NULL;
1154  /* just avoids missing file warning */
1155  if (BLI_exists(temp_path)) {
1156  userdef_template = BKE_blendfile_userdef_read(temp_path, NULL);
1157  }
1158  if (userdef_template == NULL) {
1159  /* we need to have preferences load to overwrite preferences from previous template */
1160  userdef_template = BKE_blendfile_userdef_from_defaults();
1161  }
1162  if (userdef_template) {
1164  userdef_template = NULL;
1165  }
1166  }
1167  }
1168 
1169  if (app_template_override) {
1170  BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template));
1171  }
1172 
1173  bmain = CTX_data_main(C);
1174 
1175  if (use_userdef) {
1176  /* check userdef before open window, keymaps etc */
1177  wm_init_userdef(bmain);
1178  }
1179 
1180  if (use_data) {
1181  /* match the read WM with current WM */
1182  wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
1183  }
1184 
1185  if (use_userdef) {
1186  /* Clear keymaps because the current default keymap may have been initialized
1187  * from user preferences, which have been reset. */
1188  LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
1189  if (wm->defaultconf) {
1190  wm->defaultconf->flag &= ~KEYCONF_INIT_DEFAULT;
1191  }
1192  }
1193  }
1194 
1195  if (use_data) {
1196  WM_check(C); /* opens window(s), checks keymaps */
1197 
1198  bmain->name[0] = '\0';
1199 
1200  /* start with save preference untitled.blend */
1201  G.save_over = 0;
1202  }
1203 
1204  wm_file_read_post(C, true, is_factory_startup, use_data, use_userdef, reset_app_template);
1205 
1206  if (r_is_factory_startup) {
1207  *r_is_factory_startup = is_factory_startup;
1208  }
1209 }
1210 
1211 /* -------------------------------------------------------------------- */
1216 {
1217  char name[FILE_MAX];
1218  LinkNode *l, *lines;
1219  struct RecentFile *recent;
1220  const char *line;
1221  int num;
1222  const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
1223 
1224  if (!cfgdir) {
1225  return;
1226  }
1227 
1228  BLI_join_dirfile(name, sizeof(name), cfgdir, BLENDER_HISTORY_FILE);
1229 
1230  lines = BLI_file_read_as_lines(name);
1231 
1233 
1234  /* read list of recent opened files from recent-files.txt to memory */
1235  for (l = lines, num = 0; l && (num < U.recent_files); l = l->next) {
1236  line = l->link;
1237  /* don't check if files exist, causes slow startup for remote/external drives */
1238  if (line[0]) {
1239  recent = (RecentFile *)MEM_mallocN(sizeof(RecentFile), "RecentFile");
1240  BLI_addtail(&(G.recent_files), recent);
1241  recent->filepath = BLI_strdup(line);
1242  num++;
1243  }
1244  }
1245 
1246  BLI_file_free_lines(lines);
1247 }
1248 
1250 {
1251  RecentFile *recent = MEM_mallocN(sizeof(RecentFile), "RecentFile");
1252  recent->filepath = BLI_strdup(filepath);
1253  return recent;
1254 }
1255 
1256 static void wm_history_file_free(RecentFile *recent)
1257 {
1258  BLI_assert(BLI_findindex(&G.recent_files, recent) != -1);
1259  MEM_freeN(recent->filepath);
1260  BLI_freelinkN(&G.recent_files, recent);
1261 }
1262 
1263 static void wm_history_files_free(void)
1264 {
1265  LISTBASE_FOREACH_MUTABLE (RecentFile *, recent, &G.recent_files) {
1266  wm_history_file_free(recent);
1267  }
1268 }
1269 
1271 {
1272  return BLI_findstring_ptr(&G.recent_files, filepath, offsetof(RecentFile, filepath));
1273 }
1274 
1279 static void wm_history_file_write(void)
1280 {
1281  const char *user_config_dir;
1282  char name[FILE_MAX];
1283  FILE *fp;
1284 
1285  /* will be NULL in background mode */
1287  if (!user_config_dir) {
1288  return;
1289  }
1290 
1291  BLI_join_dirfile(name, sizeof(name), user_config_dir, BLENDER_HISTORY_FILE);
1292 
1293  fp = BLI_fopen(name, "w");
1294  if (fp) {
1295  LISTBASE_FOREACH (RecentFile *, recent, &G.recent_files) {
1296  fprintf(fp, "%s\n", recent->filepath);
1297  }
1298  fclose(fp);
1299  }
1300 }
1301 
1305 static void wm_history_file_update(void)
1306 {
1307  RecentFile *recent;
1308  const char *blendfile_name = BKE_main_blendfile_path_from_global();
1309 
1310  /* no write history for recovered startup files */
1311  if (blendfile_name[0] == '\0') {
1312  return;
1313  }
1314 
1315  recent = G.recent_files.first;
1316  /* refresh recent-files.txt of recent opened files, when current file was changed */
1317  if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_name) != 0)) {
1318 
1319  recent = wm_file_history_find(blendfile_name);
1320  if (recent) {
1321  BLI_remlink(&G.recent_files, recent);
1322  }
1323  else {
1324  RecentFile *recent_next;
1325  for (recent = BLI_findlink(&G.recent_files, U.recent_files - 1); recent;
1326  recent = recent_next) {
1327  recent_next = recent->next;
1328  wm_history_file_free(recent);
1329  }
1330  recent = wm_history_file_new(blendfile_name);
1331  }
1332 
1333  /* add current file to the beginning of list */
1334  BLI_addhead(&(G.recent_files), recent);
1335 
1336  /* write current file to recent-files.txt */
1338 
1339  /* also update most recent files on System */
1340  GHOST_addToSystemRecentFiles(blendfile_name);
1341  }
1342 }
1343 
1346 /* -------------------------------------------------------------------- */
1350 /* screen can be NULL */
1352  Scene *scene,
1353  bScreen *screen,
1354  BlendThumbnail **thumb_pt)
1355 {
1356  /* will be scaled down, but gives some nice oversampling */
1357  ImBuf *ibuf;
1358  BlendThumbnail *thumb;
1360  const float pixelsize_old = U.pixelsize;
1361  wmWindow *windrawable_old = wm->windrawable;
1362  char err_out[256] = "unknown";
1363 
1364  /* screen if no camera found */
1365  ScrArea *area = NULL;
1366  ARegion *region = NULL;
1367  View3D *v3d = NULL;
1368 
1369  /* In case we are given a valid thumbnail data, just generate image from it. */
1370  if (*thumb_pt) {
1371  thumb = *thumb_pt;
1372  return BKE_main_thumbnail_to_imbuf(NULL, thumb);
1373  }
1374 
1375  /* scene can be NULL if running a script at startup and calling the save operator */
1376  if (G.background || scene == NULL) {
1377  return NULL;
1378  }
1379 
1380  if ((scene->camera == NULL) && (screen != NULL)) {
1383  if (region) {
1384  v3d = area->spacedata.first;
1385  }
1386  }
1387 
1388  if (scene->camera == NULL && v3d == NULL) {
1389  return NULL;
1390  }
1391 
1392  /* gets scaled to BLEN_THUMB_SIZE */
1394 
1395  /* Note that with scaling, this ends up being 0.5,
1396  * as it's a thumbnail, we don't need object centers and friends to be 1:1 size. */
1397  U.pixelsize = 1.0f;
1398 
1399  if (scene->camera) {
1401  scene,
1402  NULL,
1403  OB_SOLID,
1404  scene->camera,
1405  BLEN_THUMB_SIZE * 2,
1406  BLEN_THUMB_SIZE * 2,
1407  IB_rect,
1409  R_ALPHAPREMUL,
1410  NULL,
1411  NULL,
1412  err_out);
1413  }
1414  else {
1416  scene,
1417  OB_SOLID,
1418  v3d,
1419  region,
1420  BLEN_THUMB_SIZE * 2,
1421  BLEN_THUMB_SIZE * 2,
1422  IB_rect,
1423  R_ALPHAPREMUL,
1424  NULL,
1425  true,
1426  NULL,
1427  err_out);
1428  }
1429 
1430  U.pixelsize = pixelsize_old;
1431 
1432  /* Reset to old drawable. */
1433  if (windrawable_old) {
1434  wm_window_make_drawable(wm, windrawable_old);
1435  }
1436  else {
1438  }
1439 
1440  if (ibuf) {
1441  /* dirty oversampling */
1443  thumb = BKE_main_thumbnail_from_imbuf(NULL, ibuf);
1444  }
1445  else {
1446  /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */
1447  CLOG_WARN(&LOG, "failed to create thumbnail: %s", err_out);
1448  thumb = NULL;
1449  }
1450 
1451  /* must be freed by caller */
1452  *thumb_pt = thumb;
1453 
1454  return ibuf;
1455 }
1456 
1457 /* easy access from gdb */
1459 {
1460  char path[FILE_MAX];
1461 
1462  BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
1463  BLI_path_extension_replace(path, sizeof(path), "_crash.blend");
1464  if (BLO_write_file(G_MAIN, path, G.fileflags, &(const struct BlendFileWriteParams){0}, NULL)) {
1465  printf("written: %s\n", path);
1466  return 1;
1467  }
1468  printf("failed: %s\n", path);
1469  return 0;
1470 }
1471 
1475 static bool wm_file_write(bContext *C,
1476  const char *filepath,
1477  int fileflags,
1478  eBLO_WritePathRemap remap_mode,
1479  bool use_save_as_copy,
1480  ReportList *reports)
1481 {
1482  Main *bmain = CTX_data_main(C);
1483  int len;
1484  int ok = false;
1485  BlendThumbnail *thumb, *main_thumb;
1486  ImBuf *ibuf_thumb = NULL;
1487 
1488  len = strlen(filepath);
1489 
1490  if (len == 0) {
1491  BKE_report(reports, RPT_ERROR, "Path is empty, cannot save");
1492  return ok;
1493  }
1494 
1495  if (len >= FILE_MAX) {
1496  BKE_report(reports, RPT_ERROR, "Path too long, cannot save");
1497  return ok;
1498  }
1499 
1500  /* Check if file write permission is ok */
1502  BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
1503  return ok;
1504  }
1505 
1506  /* note: used to replace the file extension (to ensure '.blend'),
1507  * no need to now because the operator ensures,
1508  * its handy for scripts to save to a predefined name without blender editing it */
1509 
1510  /* send the OnSave event */
1511  LISTBASE_FOREACH (Library *, li, &bmain->libraries) {
1512  if (BLI_path_cmp(li->filepath_abs, filepath) == 0) {
1513  BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath);
1514  return ok;
1515  }
1516  }
1517 
1518  /* Call pre-save callbacks before writing preview,
1519  * that way you can generate custom file thumbnail. */
1521 
1522  /* Enforce full override check/generation on file save. */
1524 
1525  /* blend file thumbnail */
1526  /* Save before exit_editmode, otherwise derivedmeshes for shared data corrupt T27765. */
1527  /* Main now can store a '.blend' thumbnail, useful for background mode
1528  * or thumbnail customization. */
1529  main_thumb = thumb = bmain->blen_thumb;
1530  if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
1531  ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
1532  }
1533 
1534  /* operator now handles overwrite checks */
1535 
1536  if (G.fileflags & G_FILE_AUTOPACK) {
1537  BKE_packedfile_pack_all(bmain, reports, false);
1538  }
1539 
1540  /* don't forget not to return without! */
1541  WM_cursor_wait(true);
1542 
1543  ED_editors_flush_edits(bmain);
1544 
1545  /* first time saving */
1546  /* XXX temp solution to solve bug, real fix coming (ton) */
1547  if ((BKE_main_blendfile_path(bmain)[0] == '\0') && (use_save_as_copy == false)) {
1548  BLI_strncpy(bmain->name, filepath, sizeof(bmain->name));
1549  }
1550 
1551  /* XXX temp solution to solve bug, real fix coming (ton) */
1552  bmain->recovered = 0;
1553 
1555  filepath,
1556  fileflags,
1557  &(const struct BlendFileWriteParams){
1558  .remap_mode = remap_mode,
1559  .use_save_versions = true,
1560  .use_save_as_copy = use_save_as_copy,
1561  .thumb = thumb,
1562  },
1563  reports)) {
1564  const bool do_history_file_update = (G.background == false) &&
1565  (CTX_wm_manager(C)->op_undo_depth == 0);
1566 
1567  if (use_save_as_copy == false) {
1568  G.relbase_valid = 1;
1569  BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); /* is guaranteed current file */
1570 
1571  G.save_over = 1; /* disable untitled.blend convention */
1572  }
1573 
1574  SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
1575 
1576  /* prevent background mode scripts from clobbering history */
1577  if (do_history_file_update) {
1579  }
1580 
1582 
1583  /* run this function after because the file cant be written before the blend is */
1584  if (ibuf_thumb) {
1585  IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */
1586  ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb);
1587  }
1588 
1589  /* Without this there is no feedback the file was saved. */
1590  BKE_reportf(reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(filepath));
1591 
1592  /* Success. */
1593  ok = true;
1594  }
1595 
1596  if (ibuf_thumb) {
1597  IMB_freeImBuf(ibuf_thumb);
1598  }
1599  if (thumb && thumb != main_thumb) {
1600  MEM_freeN(thumb);
1601  }
1602 
1603  WM_cursor_wait(false);
1604 
1605  return ok;
1606 }
1607 
1610 /* -------------------------------------------------------------------- */
1614 static void wm_autosave_location(char *filepath)
1615 {
1616  const int pid = abs(getpid());
1617  char path[1024];
1618 #ifdef WIN32
1619  const char *savedir;
1620 #endif
1621 
1622  if (G_MAIN && G.relbase_valid) {
1624  int len = strlen(basename) - 6;
1625  BLI_snprintf(path, sizeof(path), "%.*s_%d_autosave.blend", len, basename, pid);
1626  }
1627  else {
1628  BLI_snprintf(path, sizeof(path), "%d_autosave.blend", pid);
1629  }
1630 
1631 #ifdef WIN32
1632  /* XXX Need to investigate how to handle default location of '/tmp/'
1633  * This is a relative directory on Windows, and it may be
1634  * found. Example:
1635  * Blender installed on D:\ drive, D:\ drive has D:\tmp\
1636  * Now, BLI_exists() will find '/tmp/' exists, but
1637  * BLI_make_file_string will create string that has it most likely on C:\
1638  * through BLI_windows_get_default_root_dir().
1639  * If there is no C:\tmp autosave fails. */
1640  if (!BLI_exists(BKE_tempdir_base())) {
1642  BLI_make_file_string("/", filepath, savedir, path);
1643  return;
1644  }
1645 #endif
1646 
1648 }
1649 
1650 static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
1651 {
1652  char filepath[FILE_MAX];
1653 
1655 
1656  /* Fast save of last undo-buffer, now with UI. */
1657  const bool use_memfile = (U.uiflag & USER_GLOBALUNDO) != 0;
1658  MemFile *memfile = use_memfile ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : NULL;
1659  if (memfile != NULL) {
1660  BLO_memfile_write_file(memfile, filepath);
1661  }
1662  else {
1663  if (use_memfile) {
1664  /* This is very unlikely, alert developers of this unexpected case. */
1665  CLOG_WARN(&LOG, "undo-data not found for writing, fallback to regular file write!");
1666  }
1667 
1668  /* Save as regular blend file with recovery information. */
1669  const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE;
1670 
1671  ED_editors_flush_edits(bmain);
1672 
1673  /* Error reporting into console. */
1674  BLO_write_file(bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
1675  }
1676 }
1677 
1678 static void wm_autosave_timer_begin_ex(wmWindowManager *wm, double timestep)
1679 {
1681 
1682  if (U.flag & USER_AUTOSAVE) {
1683  wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, timestep);
1684  }
1685 }
1686 
1688 {
1689  wm_autosave_timer_begin_ex(wm, U.savetime * 60.0);
1690 }
1691 
1693 {
1694  if (wm->autosavetimer) {
1696  wm->autosavetimer = NULL;
1697  }
1698 }
1699 
1701 {
1703 }
1704 
1709 {
1711 
1712  /* If a modal operator is running, don't autosave because we might not be in
1713  * a valid state to save. But try again in 10ms. */
1714  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1715  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
1716  if (handler_base->type == WM_HANDLER_TYPE_OP) {
1717  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
1718  if (handler->op) {
1719  wm_autosave_timer_begin_ex(wm, 0.01);
1720  return;
1721  }
1722  }
1723  }
1724  }
1725 
1726  wm_autosave_write(bmain, wm);
1727 
1728  /* Restart the timer after file write, just in case file write takes a long time. */
1730 }
1731 
1733 {
1734  char filename[FILE_MAX];
1735 
1736  wm_autosave_location(filename);
1737 
1738  if (BLI_exists(filename)) {
1739  char str[FILE_MAX];
1741 
1742  /* if global undo; remove tempsave, otherwise rename */
1743  if (U.uiflag & USER_GLOBALUNDO) {
1744  BLI_delete(filename, false, false);
1745  }
1746  else {
1747  BLI_rename(filename, str);
1748  }
1749  }
1750 }
1751 
1754 /* -------------------------------------------------------------------- */
1762 void wm_open_init_load_ui(wmOperator *op, bool use_prefs)
1763 {
1764  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "load_ui");
1765  if (!RNA_property_is_set(op->ptr, prop)) {
1766  bool value = use_prefs ? ((U.flag & USER_FILENOUI) == 0) : ((G.fileflags & G_FILE_NO_UI) == 0);
1767 
1768  RNA_property_boolean_set(op->ptr, prop, value);
1769  }
1770 }
1771 
1772 void wm_open_init_use_scripts(wmOperator *op, bool use_prefs)
1773 {
1774  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
1775  if (!RNA_property_is_set(op->ptr, prop)) {
1776  /* use G_FLAG_SCRIPT_AUTOEXEC rather than the userpref because this means if
1777  * the flag has been disabled from the command line, then opening
1778  * from the menu wont enable this setting. */
1779  bool value = use_prefs ? ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) :
1780  ((G.f & G_FLAG_SCRIPT_AUTOEXEC) != 0);
1781 
1782  RNA_property_boolean_set(op->ptr, prop, value);
1783  }
1784 }
1785 
1788 /* -------------------------------------------------------------------- */
1797 {
1798  Main *bmain = CTX_data_main(C);
1800  wmWindow *win = CTX_wm_window(C);
1801  char filepath[FILE_MAX];
1802  int fileflags;
1803 
1804  const char *app_template = U.app_template[0] ? U.app_template : NULL;
1805  const char *const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
1806  if (cfgdir == NULL) {
1807  BKE_report(op->reports, RPT_ERROR, "Unable to create user config path");
1808  return OPERATOR_CANCELLED;
1809  }
1810 
1812 
1813  /* check current window and close it if temp */
1814  if (win && WM_window_is_temp_screen(win)) {
1815  wm_window_close(C, wm, win);
1816  }
1817 
1818  /* update keymaps in user preferences */
1819  WM_keyconfig_update(wm);
1820 
1822 
1823  printf("Writing homefile: '%s' ", filepath);
1824 
1825  ED_editors_flush_edits(bmain);
1826 
1827  /* Force save as regular blend file. */
1828  fileflags = G.fileflags & ~G_FILE_COMPRESS;
1829 
1830  if (BLO_write_file(bmain,
1831  filepath,
1832  fileflags,
1833  &(const struct BlendFileWriteParams){
1834  /* Make all paths absolute when saving the startup file.
1835  * On load the `G.relbase_valid` will be false so the paths
1836  * wont have a base for resolving the relative paths. */
1837  .remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE,
1838  /* Don't apply any path changes to the current blend file. */
1839  .use_save_as_copy = true,
1840  },
1841  op->reports) == 0) {
1842  printf("fail\n");
1843  return OPERATOR_CANCELLED;
1844  }
1845 
1846  printf("ok\n");
1847 
1848  G.save_over = 0;
1849 
1851 
1852  return OPERATOR_FINISHED;
1853 }
1854 
1856 {
1857  ot->name = "Save Startup File";
1858  ot->idname = "WM_OT_save_homefile";
1859  ot->description = "Make the current file the default .blend file";
1860 
1863 }
1864 
1867 /* -------------------------------------------------------------------- */
1871 /* Only save the prefs block. operator entry */
1873 {
1875 
1876  /* Update keymaps in user preferences. */
1877  WM_keyconfig_update(wm);
1878 
1879  const bool ok = BKE_blendfile_userdef_write_all(op->reports);
1880 
1881  return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1882 }
1883 
1885 {
1886  ot->name = "Save Preferences";
1887  ot->idname = "WM_OT_save_userpref";
1888  ot->description = "Make the current preferences default";
1889 
1892 }
1893 
1896 /* -------------------------------------------------------------------- */
1903 static void wm_userpref_read_exceptions(UserDef *userdef_curr, const UserDef *userdef_prev)
1904 {
1905 #define USERDEF_RESTORE(member) \
1906  { \
1907  userdef_curr->member = userdef_prev->member; \
1908  } \
1909  ((void)0)
1910 
1911  /* Current visible preferences category. */
1912  USERDEF_RESTORE(space_data.section_active);
1913 
1914 #undef USERDEF_RESTORE
1915 }
1916 
1918  Main *bmain,
1919  PointerRNA *ptr_a,
1920  PointerRNA *ptr_b)
1921 {
1923  PropertyRNA *iterprop = RNA_struct_iterator_property(ptr_a->type);
1924  BLI_assert(ptr_a->type == ptr_b->type);
1925  RNA_property_collection_begin(ptr_a, iterprop, &iter);
1926  for (; iter.valid; RNA_property_collection_next(&iter)) {
1927  PropertyRNA *prop = iter.ptr.data;
1928  if (STREQ(RNA_property_identifier(prop), "rna_type")) {
1929  continue;
1930  }
1931  switch (RNA_property_type(prop)) {
1932  case PROP_POINTER: {
1933  PointerRNA ptr_sub_a = RNA_property_pointer_get(ptr_a, prop);
1934  PointerRNA ptr_sub_b = RNA_property_pointer_get(ptr_b, prop);
1935  rna_struct_update_when_changed(C, bmain, &ptr_sub_a, &ptr_sub_b);
1936  break;
1937  }
1938  case PROP_COLLECTION:
1939  /* Don't handle collections. */
1940  break;
1941  default: {
1942  if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, RNA_EQ_STRICT)) {
1943  RNA_property_update(C, ptr_b, prop);
1944  }
1945  }
1946  }
1947  }
1949 }
1950 
1952  Main *bmain,
1953  UserDef *userdef_prev,
1954  UserDef *userdef_curr)
1955 {
1956  PointerRNA ptr_a, ptr_b;
1957  RNA_pointer_create(NULL, &RNA_Preferences, userdef_prev, &ptr_a);
1958  RNA_pointer_create(NULL, &RNA_Preferences, userdef_curr, &ptr_b);
1959  const bool is_dirty = userdef_curr->runtime.is_dirty;
1960 
1961  rna_struct_update_when_changed(C, bmain, &ptr_a, &ptr_b);
1962 
1963  WM_reinit_gizmomap_all(bmain);
1965 
1966  userdef_curr->runtime.is_dirty = is_dirty;
1967 }
1968 
1970 {
1971  const bool use_data = false;
1972  const bool use_userdef = true;
1973  const bool use_factory_settings = STREQ(op->type->idname, "WM_OT_read_factory_userpref");
1974 
1975  UserDef U_backup = U;
1976 
1978  op->reports,
1979  use_factory_settings,
1980  false,
1981  use_data,
1982  use_userdef,
1983  NULL,
1985  NULL);
1986 
1987  wm_userpref_read_exceptions(&U, &U_backup);
1988  SET_FLAG_FROM_TEST(G.f, use_factory_settings, G_FLAG_USERPREF_NO_SAVE_ON_EXIT);
1989 
1990  Main *bmain = CTX_data_main(C);
1991 
1992  wm_userpref_update_when_changed(C, bmain, &U_backup, &U);
1993 
1994  if (use_factory_settings) {
1995  U.runtime.is_dirty = true;
1996  }
1997 
1998  /* Needed to recalculate UI scaling values (eg, #UserDef.inv_dpi_fac). */
2000 
2002 
2003  return OPERATOR_FINISHED;
2004 }
2005 
2007 {
2008  ot->name = "Load Preferences";
2009  ot->idname = "WM_OT_read_userpref";
2010  ot->description = "Load last saved preferences";
2011 
2014 }
2015 
2017 {
2018  ot->name = "Load Factory Preferences";
2019  ot->idname = "WM_OT_read_factory_userpref";
2020  ot->description =
2021  "Load factory default preferences. "
2022  "To make changes to preferences permanent, use \"Save Preferences\"";
2023 
2026 }
2027 
2030 /* -------------------------------------------------------------------- */
2035 {
2038  return OPERATOR_FINISHED;
2039 }
2040 
2042 {
2043  ot->name = "Reload History File";
2044  ot->idname = "WM_OT_read_history";
2045  ot->description = "Reloads history and bookmarks";
2046 
2049 
2050  /* this operator is only used for loading settings from a previous blender install */
2051  ot->flag = OPTYPE_INTERNAL;
2052 }
2053 
2056 /* -------------------------------------------------------------------- */
2063 {
2064  const bool use_factory_startup_and_userdef = STREQ(op->type->idname,
2065  "WM_OT_read_factory_settings");
2066  const bool use_factory_settings = use_factory_startup_and_userdef ||
2067  RNA_boolean_get(op->ptr, "use_factory_startup");
2068  bool use_userdef = false;
2069  char filepath_buf[FILE_MAX];
2070  const char *filepath = NULL;
2071  UserDef U_backup = U;
2072 
2073  if (!use_factory_settings) {
2074  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
2075 
2076  /* This can be used when loading of a start-up file should only change
2077  * the scene content but keep the blender UI as it is. */
2078  wm_open_init_load_ui(op, true);
2079  SET_FLAG_FROM_TEST(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
2080 
2081  if (RNA_property_is_set(op->ptr, prop)) {
2082  RNA_property_string_get(op->ptr, prop, filepath_buf);
2083  filepath = filepath_buf;
2084  if (BLI_access(filepath, R_OK)) {
2085  BKE_reportf(
2086  op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath);
2087  return OPERATOR_CANCELLED;
2088  }
2089  }
2090  }
2091  else {
2092  if (use_factory_startup_and_userdef) {
2093  /* always load UI for factory settings (prefs will re-init) */
2094  G.fileflags &= ~G_FILE_NO_UI;
2095  /* Always load preferences with factory settings. */
2096  use_userdef = true;
2097  }
2098  }
2099 
2100  char app_template_buf[sizeof(U.app_template)];
2101  const char *app_template;
2102  PropertyRNA *prop_app_template = RNA_struct_find_property(op->ptr, "app_template");
2103  const bool use_splash = !use_factory_settings && RNA_boolean_get(op->ptr, "use_splash");
2104  const bool use_empty_data = RNA_boolean_get(op->ptr, "use_empty");
2105 
2106  if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) {
2107  RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
2108  app_template = app_template_buf;
2109 
2110  if (!use_factory_settings) {
2111  /* Always load preferences when switching templates with own preferences. */
2114  }
2115 
2116  /* Turn override off, since we're explicitly loading a different app-template. */
2118  }
2119  else {
2120  /* Normally NULL, only set when overriding from the command-line. */
2122  }
2123 
2124  bool use_data = true;
2126  op->reports,
2127  use_factory_settings,
2128  use_empty_data,
2129  use_data,
2130  use_userdef,
2131  filepath,
2132  app_template,
2133  NULL);
2134  if (use_splash) {
2135  WM_init_splash(C);
2136  }
2137 
2138  if (use_userdef) {
2139  wm_userpref_read_exceptions(&U, &U_backup);
2140  SET_FLAG_FROM_TEST(G.f, use_factory_settings, G_FLAG_USERPREF_NO_SAVE_ON_EXIT);
2141 
2142  if (use_factory_settings) {
2143  U.runtime.is_dirty = true;
2144  }
2145  }
2146 
2147  if (G.fileflags & G_FILE_NO_UI) {
2149  }
2150 
2151  return OPERATOR_FINISHED;
2152 }
2153 
2155 {
2157  C, "WM_OT_read_homefile", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data);
2158 }
2159 
2161 {
2162  IDProperty *properties = (IDProperty *)user_data;
2163  IDP_FreeProperty(properties);
2164 }
2165 
2166 static int wm_homefile_read_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2167 {
2168  if (U.uiflag & USER_SAVE_PROMPT &&
2170  wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
2172  callback->user_data = IDP_CopyProperty(op->properties);
2175  return OPERATOR_INTERFACE;
2176  }
2177  return wm_homefile_read_exec(C, op);
2178 }
2179 
2181 {
2182  PropertyRNA *prop;
2183 
2184  prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
2186 
2187  prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
2189 }
2190 
2192 {
2193  PropertyRNA *prop;
2194  ot->name = "Reload Start-Up File";
2195  ot->idname = "WM_OT_read_homefile";
2196  ot->description = "Open the default file (doesn't save the current file)";
2197 
2200 
2201  prop = RNA_def_string_file_path(
2202  ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to an alternative start-up file");
2204 
2205  /* So scripts can use an alternative start-up file without the UI */
2206  prop = RNA_def_boolean(
2207  ot->srna, "load_ui", true, "Load UI", "Load user interface setup from the .blend file");
2209 
2210  /* So the splash can be kept open after loading a file (for templates). */
2211  prop = RNA_def_boolean(ot->srna, "use_splash", false, "Splash", "");
2213 
2214  /* So scripts can load factory-startup without resetting preferences
2215  * (which has other implications such as reloading all add-ons).
2216  * Match naming for `--factory-startup` command line argument. */
2217  prop = RNA_def_boolean(ot->srna, "use_factory_startup", false, "Factory Startup", "");
2219 
2221 
2222  /* omit poll to run in background mode */
2223 }
2224 
2226 {
2227  ot->name = "Load Factory Settings";
2228  ot->idname = "WM_OT_read_factory_settings";
2229  ot->description =
2230  "Load factory default startup file and preferences. "
2231  "To make changes permanent, use \"Save Startup File\" and \"Save Preferences\"";
2232 
2235 
2237  /* omit poll to run in background mode */
2238 }
2239 
2242 /* -------------------------------------------------------------------- */
2249 static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports)
2250 {
2251  bool success;
2252 
2253  /* XXX wm in context is not set correctly after WM_file_read -> crash */
2254  /* do it before for now, but is this correct with multiple windows? */
2256 
2257  /* Set by the "use_scripts" property on file load. */
2258  if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) {
2260  }
2261 
2262  success = WM_file_read(C, filepath, reports);
2263 
2264  return success;
2265 }
2266 
2267 /* Generic operator state utilities */
2268 
2269 static void create_operator_state(wmOperatorType *ot, int first_state)
2270 {
2271  PropertyRNA *prop = RNA_def_int(
2272  ot->srna, "state", first_state, INT32_MIN, INT32_MAX, "State", "", INT32_MIN, INT32_MAX);
2275 }
2276 
2278 {
2279  return RNA_int_get(op->ptr, "state");
2280 }
2281 
2283 {
2284  RNA_int_set(op->ptr, "state", state);
2285 }
2286 
2287 typedef struct OperatorDispatchTarget {
2288  int state;
2289  int (*run)(bContext *C, wmOperator *op);
2291 
2293 {
2294  int state = get_operator_state(op);
2295  for (int i = 0; targets[i].run; i++) {
2296  OperatorDispatchTarget target = targets[i];
2297  if (target.state == state) {
2298  return target.run(C, op);
2299  }
2300  }
2302  return OPERATOR_CANCELLED;
2303 }
2304 
2307 /* -------------------------------------------------------------------- */
2311 enum {
2315 };
2316 
2318 
2320 {
2322  C, "WM_OT_open_mainfile", WM_OP_INVOKE_DEFAULT, (IDProperty *)user_data);
2323 }
2324 
2326 {
2327  if (RNA_boolean_get(op->ptr, "display_file_selector")) {
2329  }
2330  else {
2332  }
2333 
2334  if (U.uiflag & USER_SAVE_PROMPT &&
2336  wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
2338  callback->user_data = IDP_CopyProperty(op->properties);
2341  return OPERATOR_INTERFACE;
2342  }
2343  return wm_open_mainfile_dispatch(C, op);
2344 }
2345 
2347 {
2349 
2350  Main *bmain = CTX_data_main(C);
2351  const char *openname = BKE_main_blendfile_path(bmain);
2352 
2353  if (CTX_wm_window(C) == NULL) {
2354  /* in rare cases this could happen, when trying to invoke in background
2355  * mode on load for example. Don't use poll for this because exec()
2356  * can still run without a window */
2357  BKE_report(op->reports, RPT_ERROR, "Context window not set");
2358  return OPERATOR_CANCELLED;
2359  }
2360 
2361  /* if possible, get the name of the most recently used .blend file */
2362  if (G.recent_files.first) {
2363  struct RecentFile *recent = G.recent_files.first;
2364  openname = recent->filepath;
2365  }
2366 
2367  RNA_string_set(op->ptr, "filepath", openname);
2368  wm_open_init_load_ui(op, true);
2369  wm_open_init_use_scripts(op, true);
2370  op->customdata = NULL;
2371 
2373 
2374  return OPERATOR_RUNNING_MODAL;
2375 }
2376 
2378 {
2379  char filepath[FILE_MAX];
2380  bool success;
2381 
2382  RNA_string_get(op->ptr, "filepath", filepath);
2383 
2384  /* re-use last loaded setting so we can reload a file without changing */
2385  wm_open_init_load_ui(op, false);
2386  wm_open_init_use_scripts(op, false);
2387 
2388  SET_FLAG_FROM_TEST(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
2390  success = wm_file_read_opwrap(C, filepath, op->reports);
2391 
2392  /* for file open also popup for warnings, not only errors */
2394 
2395  if (success) {
2396  if (G.fileflags & G_FILE_NO_UI) {
2398  }
2399  ED_view3d_local_collections_reset(C, (G.fileflags & G_FILE_NO_UI) != 0);
2400  return OPERATOR_FINISHED;
2401  }
2402  return OPERATOR_CANCELLED;
2403 }
2404 
2409  {0, NULL},
2410 };
2411 
2413 {
2415 }
2416 
2417 static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2418 {
2419  return wm_open_mainfile_dispatch(C, op);
2420 }
2421 
2423 {
2424  return wm_open_mainfile__open(C, op);
2425 }
2426 
2428  struct wmOperatorType *UNUSED(op),
2429  struct PointerRNA *params)
2430 {
2431  if (!RNA_struct_property_is_set(params, "filepath")) {
2432  return NULL;
2433  }
2434 
2435  /* Filepath. */
2436  char path[FILE_MAX];
2437  RNA_string_get(params, "filepath", path);
2438 
2439  BLI_stat_t stats;
2440  if (BLI_stat(path, &stats) == -1) {
2441  return BLI_sprintfN("%s\n\n%s", path, N_("File Not Found"));
2442  }
2443 
2444  /* Date. */
2445  char date_st[FILELIST_DIRENTRY_DATE_LEN];
2446  char time_st[FILELIST_DIRENTRY_TIME_LEN];
2447  bool is_today, is_yesterday;
2449  NULL, (int64_t)stats.st_mtime, false, time_st, date_st, &is_today, &is_yesterday);
2450  if (is_today || is_yesterday) {
2451  BLI_strncpy(date_st, is_today ? N_("Today") : N_("Yesterday"), sizeof(date_st));
2452  }
2453 
2454  /* Size. */
2455  char size_str[FILELIST_DIRENTRY_SIZE_LEN];
2456  BLI_filelist_entry_size_to_string(NULL, (uint64_t)stats.st_size, false, size_str);
2457 
2458  return BLI_sprintfN(
2459  "%s\n\n%s: %s %s\n%s: %s", path, N_("Modified"), date_st, time_st, N_("Size"), size_str);
2460 }
2461 
2462 /* currently fits in a pointer */
2463 struct FileRuntime {
2465 };
2466 BLI_STATIC_ASSERT(sizeof(struct FileRuntime) <= sizeof(void *),
2467  "Struct must not exceed pointer size");
2468 
2470 {
2471  struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
2472  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
2473  bool is_untrusted = false;
2474  char path[FILE_MAX];
2475  char *lslash;
2476 
2477  RNA_string_get(op->ptr, "filepath", path);
2478 
2479  /* get the dir */
2480  lslash = (char *)BLI_path_slash_rfind(path);
2481  if (lslash) {
2482  *(lslash + 1) = '\0';
2483  }
2484 
2485  if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
2486  if (BKE_autoexec_match(path) == true) {
2487  RNA_property_boolean_set(op->ptr, prop, false);
2488  is_untrusted = true;
2489  }
2490  }
2491 
2492  if (file_info) {
2493  file_info->is_untrusted = is_untrusted;
2494  }
2495 
2496  return is_untrusted;
2497 }
2498 
2500 {
2501  struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
2502  uiLayout *layout = op->layout;
2503  uiLayout *col = op->layout;
2504  const char *autoexec_text;
2505 
2506  uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
2507 
2508  col = uiLayoutColumn(layout, false);
2509  if (file_info->is_untrusted) {
2510  autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
2511  uiLayoutSetActive(col, false);
2512  uiLayoutSetEnabled(col, false);
2513  }
2514  else {
2515  autoexec_text = IFACE_("Trusted Source");
2516  }
2517 
2518  uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
2519 }
2520 
2522 {
2524  "use_scripts",
2525  true,
2526  "Trusted Source",
2527  "Allow .blend file to execute scripts automatically, default available from "
2528  "system preferences");
2529 }
2530 
2532 {
2533  ot->name = "Open";
2534  ot->idname = "WM_OT_open_mainfile";
2535  ot->description = "Open a Blender file";
2537 
2542  /* omit window poll so this can work in background mode */
2543 
2546  FILE_BLENDER,
2547  FILE_OPENFILE,
2551 
2553  ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
2554 
2556 
2557  PropertyRNA *prop = RNA_def_boolean(
2558  ot->srna, "display_file_selector", true, "Display File Selector", "");
2560 
2562 }
2563 
2566 /* -------------------------------------------------------------------- */
2571 {
2572  Main *bmain = CTX_data_main(C);
2573  bool success;
2574  char filepath[FILE_MAX];
2575 
2576  wm_open_init_use_scripts(op, false);
2577 
2579 
2580  BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
2581  success = wm_file_read_opwrap(C, filepath, op->reports);
2582 
2583  if (success) {
2584  return OPERATOR_FINISHED;
2585  }
2586  return OPERATOR_CANCELLED;
2587 }
2588 
2590 {
2591  return G.relbase_valid;
2592 }
2593 
2595 {
2596  ot->name = "Revert";
2597  ot->idname = "WM_OT_revert_mainfile";
2598  ot->description = "Reload the saved file";
2599 
2603 
2605 }
2606 
2609 /* -------------------------------------------------------------------- */
2614 {
2615  char filepath[FILE_MAX];
2616  BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
2617  G.fileflags |= G_FILE_RECOVER_READ;
2618  const bool success = wm_file_read_opwrap(C, filepath, reports);
2619  G.fileflags &= ~G_FILE_RECOVER_READ;
2620  return success;
2621 }
2622 
2624 {
2625  wm_open_init_use_scripts(op, true);
2627  if (WM_recover_last_session(C, op->reports)) {
2628  if (!G.background) {
2629  wmOperatorType *ot = op->type;
2630  PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__);
2632  RNA_boolean_set(props_ptr, "use_scripts", true);
2634  }
2635  return OPERATOR_FINISHED;
2636  }
2637  return OPERATOR_CANCELLED;
2638 }
2639 
2641 {
2642  /* Keep the current setting instead of using the preferences since a file selector
2643  * doesn't give us the option to change the setting. */
2644  wm_open_init_use_scripts(op, false);
2645  return WM_operator_confirm(C, op, event);
2646 }
2647 
2649 {
2650  ot->name = "Recover Last Session";
2651  ot->idname = "WM_OT_recover_last_session";
2652  ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
2653 
2656 
2658 }
2659 
2662 /* -------------------------------------------------------------------- */
2667 {
2668  char filepath[FILE_MAX];
2669  bool success;
2670 
2671  RNA_string_get(op->ptr, "filepath", filepath);
2672 
2673  wm_open_init_use_scripts(op, true);
2675 
2676  G.fileflags |= G_FILE_RECOVER_READ;
2677 
2678  success = wm_file_read_opwrap(C, filepath, op->reports);
2679 
2680  G.fileflags &= ~G_FILE_RECOVER_READ;
2681 
2682  if (success) {
2683  if (!G.background) {
2684  wmOperatorType *ot = op->type;
2685  PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__);
2687  RNA_boolean_set(props_ptr, "use_scripts", true);
2689  }
2690  return OPERATOR_FINISHED;
2691  }
2692  return OPERATOR_CANCELLED;
2693 }
2694 
2696 {
2697  char filename[FILE_MAX];
2698 
2699  wm_autosave_location(filename);
2700  RNA_string_set(op->ptr, "filepath", filename);
2701  wm_open_init_use_scripts(op, true);
2703 
2704  return OPERATOR_RUNNING_MODAL;
2705 }
2706 
2708 {
2709  ot->name = "Recover Auto Save";
2710  ot->idname = "WM_OT_recover_auto_save";
2711  ot->description = "Open an automatically saved file to recover it";
2712 
2715 
2718  FILE_BLENDER,
2719  FILE_OPENFILE,
2722  FILE_SORT_TIME);
2723 
2725 }
2726 
2729 /* -------------------------------------------------------------------- */
2735 static void wm_filepath_default(char *filepath)
2736 {
2737  if (G.save_over == false) {
2738  BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend");
2739  }
2740 }
2741 
2743 {
2744  PropertyRNA *prop;
2745 
2746  prop = RNA_struct_find_property(op->ptr, "compress");
2747  if (!RNA_property_is_set(op->ptr, prop)) {
2748  if (G.save_over) { /* keep flag for existing file */
2749  RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
2750  }
2751  else { /* use userdef for new file */
2752  RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
2753  }
2754  }
2755 }
2756 
2758 {
2759  Main *bmain = CTX_data_main(C);
2760  PropertyRNA *prop;
2761  char name[FILE_MAX];
2762 
2763  prop = RNA_struct_find_property(op->ptr, "filepath");
2764  if (!RNA_property_is_set(op->ptr, prop)) {
2765  /* if not saved before, get the name of the most recently used .blend file */
2766  if (BKE_main_blendfile_path(bmain)[0] == '\0' && G.recent_files.first) {
2767  struct RecentFile *recent = G.recent_files.first;
2768  BLI_strncpy(name, recent->filepath, FILE_MAX);
2769  }
2770  else {
2771  BLI_strncpy(name, bmain->name, FILE_MAX);
2772  }
2773 
2774  wm_filepath_default(name);
2775  RNA_property_string_set(op->ptr, prop, name);
2776  }
2777 }
2778 
2780 {
2781 
2782  save_set_compress(op);
2783  save_set_filepath(C, op);
2784 
2786 
2787  return OPERATOR_RUNNING_MODAL;
2788 }
2789 
2790 /* function used for WM_OT_save_mainfile too */
2792 {
2793  Main *bmain = CTX_data_main(C);
2794  char path[FILE_MAX];
2795  const bool is_save_as = (op->type->invoke == wm_save_as_mainfile_invoke);
2796  const bool use_save_as_copy = (RNA_struct_property_is_set(op->ptr, "copy") &&
2797  RNA_boolean_get(op->ptr, "copy"));
2798 
2799  /* We could expose all options to the users however in most cases remapping
2800  * existing relative paths is a good default.
2801  * Users can manually make their paths relative & absolute if they wish. */
2802  const eBLO_WritePathRemap remap_mode = RNA_boolean_get(op->ptr, "relative_remap") ?
2805  save_set_compress(op);
2806 
2807  if (RNA_struct_property_is_set(op->ptr, "filepath")) {
2808  RNA_string_get(op->ptr, "filepath", path);
2809  }
2810  else {
2812  wm_filepath_default(path);
2813  }
2814 
2815  const int fileflags_orig = G.fileflags;
2816  int fileflags = G.fileflags;
2817 
2818  /* set compression flag */
2819  SET_FLAG_FROM_TEST(fileflags, RNA_boolean_get(op->ptr, "compress"), G_FILE_COMPRESS);
2820 
2821  const bool ok = wm_file_write(C, path, fileflags, remap_mode, use_save_as_copy, op->reports);
2822 
2823  if ((op->flag & OP_IS_INVOKE) == 0) {
2824  /* OP_IS_INVOKE is set when the operator is called from the GUI.
2825  * If it is not set, the operator is called from a script and
2826  * shouldn't influence G.fileflags. */
2827  G.fileflags = fileflags_orig;
2828  }
2829 
2830  if (ok == false) {
2831  return OPERATOR_CANCELLED;
2832  }
2833 
2835 
2836  if (!is_save_as && RNA_boolean_get(op->ptr, "exit")) {
2838  }
2839 
2840  return OPERATOR_FINISHED;
2841 }
2842 
2843 /* function used for WM_OT_save_mainfile too */
2845 {
2846  char filepath[FILE_MAX];
2847  RNA_string_get(op->ptr, "filepath", filepath);
2849  /* some users would prefer BLI_path_extension_replace(),
2850  * we keep getting nitpicking bug reports about this - campbell */
2852  RNA_string_set(op->ptr, "filepath", filepath);
2853  return true;
2854  }
2855  return false;
2856 }
2857 
2859 {
2860  if (RNA_boolean_get(ptr, "copy")) {
2861  return CTX_IFACE_(ot->translation_context, "Save Copy");
2862  }
2863  return NULL;
2864 }
2865 
2868  PointerRNA *ptr)
2869 {
2870  if (RNA_boolean_get(ptr, "copy")) {
2871  return BLI_strdup(
2872  "Save the current file in the desired location but do not make the saved file active");
2873  }
2874  return NULL;
2875 }
2876 
2878 {
2879  PropertyRNA *prop;
2880 
2881  ot->name = "Save As";
2882  ot->idname = "WM_OT_save_as_mainfile";
2883  ot->description = "Save the current file in the desired location";
2884 
2890  /* omit window poll so this can work in background mode */
2891 
2894  FILE_BLENDER,
2895  FILE_SAVE,
2899  RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
2901  "relative_remap",
2902  true,
2903  "Remap Relative",
2904  "Remap relative paths when saving to a different directory");
2905  prop = RNA_def_boolean(
2906  ot->srna,
2907  "copy",
2908  false,
2909  "Save Copy",
2910  "Save a copy of the actual working state but does not make saved file active");
2912 }
2913 
2914 static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2915 {
2916  int ret;
2917 
2918  /* cancel if no active window */
2919  if (CTX_wm_window(C) == NULL) {
2920  return OPERATOR_CANCELLED;
2921  }
2922 
2923  save_set_compress(op);
2924  save_set_filepath(C, op);
2925 
2926  /* if we're saving for the first time and prefer relative paths -
2927  * any existing paths will be absolute,
2928  * enable the option to remap paths to avoid confusion T37240. */
2929  if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
2930  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
2931  if (!RNA_property_is_set(op->ptr, prop)) {
2932  RNA_property_boolean_set(op->ptr, prop, true);
2933  }
2934  }
2935 
2936  if (G.save_over) {
2937  char path[FILE_MAX];
2938 
2939  RNA_string_get(op->ptr, "filepath", path);
2941  }
2942  else {
2945  }
2946 
2947  return ret;
2948 }
2949 
2951 {
2952  ot->name = "Save Blender File";
2953  ot->idname = "WM_OT_save_mainfile";
2954  ot->description = "Save the current Blender file";
2955 
2959  /* omit window poll so this can work in background mode */
2960 
2961  PropertyRNA *prop;
2964  FILE_BLENDER,
2965  FILE_SAVE,
2969  RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
2971  "relative_remap",
2972  false,
2973  "Remap Relative",
2974  "Remap relative paths when saving to a different directory");
2975 
2976  prop = RNA_def_boolean(ot->srna, "exit", false, "Exit", "Exit Blender after saving");
2978 }
2979 
2982 /* -------------------------------------------------------------------- */
2986 static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *UNUSED(arg))
2987 {
2988  wmWindow *win = CTX_wm_window(C);
2989  UI_popup_block_close(C, win, arg_block);
2990 
2991  /* Free the data as it's no longer needed. */
2993 }
2994 
2996  void *arg_block,
2997  void *UNUSED(arg))
2998 {
2999  wmWindow *win = CTX_wm_window(C);
3000 
3001  UI_popup_block_close(C, win, arg_block);
3002 
3003  /* Save user preferences for permanent execution. */
3004  if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
3005  WM_operator_name_call(C, "WM_OT_save_userpref", WM_OP_EXEC_DEFAULT, NULL);
3006  }
3007 
3008  /* Load file again with scripts enabled.
3009  * The reload is necessary to allow scripts to run when the files loads. */
3011 }
3012 
3014  void *arg_block,
3015  void *UNUSED(arg))
3016 {
3017  wmWindow *win = CTX_wm_window(C);
3018  Main *bmain = CTX_data_main(C);
3019 
3020  UI_popup_block_close(C, win, arg_block);
3021 
3022  /* Save user preferences for permanent execution. */
3023  if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
3024  WM_operator_name_call(C, "WM_OT_save_userpref", WM_OP_EXEC_DEFAULT, NULL);
3025  }
3026 
3027  /* Force a full refresh, but without reloading the file. */
3028  LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
3030  }
3031 }
3032 
3033 /* Build the autorun warning dialog UI */
3035  struct ARegion *region,
3036  void *UNUSED(arg1))
3037 {
3039 
3040  uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS);
3045 
3046  uiLayout *layout = uiItemsAlertBox(block, 44, ALERT_ICON_ERROR);
3047 
3048  /* Title and explanation text. */
3049  uiLayout *col = uiLayoutColumn(layout, true);
3050  uiItemL_ex(col,
3051  TIP_("For security reasons, automatic execution of Python scripts "
3052  "in this file was disabled:"),
3053  ICON_NONE,
3054  true,
3055  false);
3056  uiItemL_ex(col, G.autoexec_fail, ICON_NONE, false, true);
3057  uiItemL(col, TIP_("This may lead to unexpected behavior"), ICON_NONE);
3058 
3059  uiItemS(layout);
3060 
3061  PointerRNA pref_ptr;
3063  uiItemR(layout,
3064  &pref_ptr,
3065  "use_scripts_auto_execute",
3066  0,
3067  TIP_("Permanently allow execution of scripts"),
3068  ICON_NONE);
3069 
3070  uiItemS_ex(layout, 3.0f);
3071 
3072  /* Buttons */
3073  uiBut *but;
3074  uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
3075  uiLayoutSetScaleY(split, 1.2f);
3076 
3077  /* empty space */
3078  col = uiLayoutColumn(split, false);
3079  uiItemS(col);
3080 
3081  col = uiLayoutColumn(split, false);
3082 
3083  /* Allow reload if we have a saved file.
3084  * Otherwise just enable scripts and reset the depsgraphs. */
3085  if (G.relbase_valid && wm->file_saved) {
3086  but = uiDefIconTextBut(block,
3087  UI_BTYPE_BUT,
3088  0,
3089  ICON_NONE,
3090  IFACE_("Allow Execution"),
3091  0,
3092  0,
3093  50,
3094  UI_UNIT_Y,
3095  NULL,
3096  0,
3097  0,
3098  0,
3099  0,
3100  TIP_("Reload file with execution of Python scripts enabled"));
3102  }
3103  else {
3104  but = uiDefIconTextBut(block,
3105  UI_BTYPE_BUT,
3106  0,
3107  ICON_NONE,
3108  IFACE_("Allow Execution"),
3109  0,
3110  0,
3111  50,
3112  UI_UNIT_Y,
3113  NULL,
3114  0,
3115  0,
3116  0,
3117  0,
3118  TIP_("Enable scripts"));
3120  }
3122 
3123  col = uiLayoutColumn(split, false);
3124  but = uiDefIconTextBut(block,
3125  UI_BTYPE_BUT,
3126  0,
3127  ICON_NONE,
3128  IFACE_("Ignore"),
3129  0,
3130  0,
3131  50,
3132  UI_UNIT_Y,
3133  NULL,
3134  0,
3135  0,
3136  0,
3137  0,
3138  TIP_("Continue using file without Python scripts"));
3142 
3143  UI_block_bounds_set_centered(block, 14 * U.dpi_fac);
3144 
3145  return block;
3146 }
3147 
3155 static struct {
3159  .ot = NULL,
3160  .ptr = NULL,
3161 };
3162 
3164 {
3165  BLI_assert(!G.background);
3171  }
3174 }
3175 
3177 {
3180 
3181  /* Use regular revert. */
3182  if (ot == NULL) {
3183  ot = WM_operatortype_find("WM_OT_revert_mainfile", false);
3184  ptr = MEM_callocN(sizeof(PointerRNA), __func__);
3186  RNA_boolean_set(ptr, "use_scripts", true);
3187 
3188  /* Set state, so it's freed correctly */
3190  }
3191 
3194 }
3195 
3197 {
3198  /* Test if any auto-execution of scripts failed. */
3199  if ((G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL) == 0) {
3200  return;
3201  }
3202 
3203  /* Only show the warning once. */
3205  return;
3206  }
3207 
3209 
3211  wmWindow *win = (wm->winactive) ? wm->winactive : wm->windows.first;
3212 
3213  if (win) {
3214  wmWindow *prevwin = CTX_wm_window(C);
3215  CTX_wm_window_set(C, win);
3217  CTX_wm_window_set(C, prevwin);
3218  }
3219 }
3220 
3223 /* -------------------------------------------------------------------- */
3228 
3229 static void wm_block_file_close_cancel(bContext *C, void *arg_block, void *UNUSED(arg_data))
3230 {
3231  wmWindow *win = CTX_wm_window(C);
3232  UI_popup_block_close(C, win, arg_block);
3233 }
3234 
3235 static void wm_block_file_close_discard(bContext *C, void *arg_block, void *arg_data)
3236 {
3238 
3239  /* Close the popup before executing the callback. Otherwise
3240  * the popup might be closed by the callback, which will lead
3241  * to a crash. */
3242  wmWindow *win = CTX_wm_window(C);
3243  UI_popup_block_close(C, win, arg_block);
3244 
3245  callback->exec(C, callback->user_data);
3247 }
3248 
3249 static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_data)
3250 {
3251  const Main *bmain = CTX_data_main(C);
3253  bool execute_callback = true;
3254 
3255  wmWindow *win = CTX_wm_window(C);
3256  UI_popup_block_close(C, win, arg_block);
3257 
3258  int modified_images_count = ED_image_save_all_modified_info(CTX_data_main(C), NULL);
3259  if (modified_images_count > 0 && save_images_when_file_is_closed) {
3260  if (ED_image_should_save_modified(bmain)) {
3261  ReportList *reports = CTX_wm_reports(C);
3262  ED_image_save_all_modified(C, reports);
3264  }
3265  else {
3266  execute_callback = false;
3267  }
3268  }
3269 
3270  bool file_has_been_saved_before = BKE_main_blendfile_path(bmain)[0] != '\0';
3271 
3272  if (file_has_been_saved_before) {
3273  WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL);
3274  }
3275  else {
3276  WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_INVOKE_DEFAULT, NULL);
3277  execute_callback = false;
3278  }
3279 
3280  if (execute_callback) {
3281  callback->exec(C, callback->user_data);
3282  }
3284 }
3285 
3287 {
3288  uiBut *but = uiDefIconTextBut(
3289  block, UI_BTYPE_BUT, 0, 0, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, "");
3290  UI_but_func_set(but, wm_block_file_close_cancel, block, post_action);
3292 }
3293 
3295 {
3296  uiBut *but = uiDefIconTextBut(
3297  block, UI_BTYPE_BUT, 0, 0, IFACE_("Don't Save"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, "");
3298  UI_but_func_set(but, wm_block_file_close_discard, block, post_action);
3300 }
3301 
3303 {
3304  uiBut *but = uiDefIconTextBut(
3305  block, UI_BTYPE_BUT, 0, 0, IFACE_("Save"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, "");
3306  UI_but_func_set(but, wm_block_file_close_save, block, post_action);
3309 }
3310 
3311 static const char *close_file_dialog_name = "file_close_popup";
3312 
3314  struct ARegion *region,
3315  void *arg1)
3316 {
3317  wmGenericCallback *post_action = (wmGenericCallback *)arg1;
3318  Main *bmain = CTX_data_main(C);
3319 
3324 
3325  uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_QUESTION);
3326 
3327  /* Title. */
3328  uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false);
3329 
3330  /* Filename. */
3331  const char *blendfile_pathpath = BKE_main_blendfile_path(CTX_data_main(C));
3332  char filename[FILE_MAX];
3333  if (blendfile_pathpath[0] != '\0') {
3334  BLI_split_file_part(blendfile_pathpath, filename, sizeof(filename));
3335  }
3336  else {
3337  STRNCPY(filename, IFACE_("untitled.blend"));
3338  }
3339  uiItemL(layout, filename, ICON_NONE);
3340 
3341  /* Image Saving Warnings. */
3342  ReportList reports;
3343  BKE_reports_init(&reports, RPT_STORE);
3344  uint modified_images_count = ED_image_save_all_modified_info(bmain, &reports);
3345 
3346  LISTBASE_FOREACH (Report *, report, &reports.list) {
3347  uiLayout *row = uiLayoutColumn(layout, false);
3348  uiLayoutSetScaleY(row, 0.6f);
3349  uiItemS(row);
3350 
3351  /* Error messages created in ED_image_save_all_modified_info() can be long,
3352  * but are made to separate into two parts at first colon between text and paths.
3353  */
3354  char *message = BLI_strdupn(report->message, report->len);
3355  char *path_info = strstr(message, ": ");
3356  if (path_info) {
3357  /* Terminate message string at colon. */
3358  path_info[1] = '\0';
3359  /* Skip over the ": " */
3360  path_info += 2;
3361  }
3362  uiItemL_ex(row, message, ICON_NONE, false, true);
3363  if (path_info) {
3364  uiItemL_ex(row, path_info, ICON_NONE, false, true);
3365  }
3366  MEM_freeN(message);
3367  }
3368 
3369  /* Modified Images Checkbox. */
3370  if (modified_images_count > 0) {
3371  char message[64];
3372  BLI_snprintf(message, sizeof(message), "Save %u modified image(s)", modified_images_count);
3373  uiItemS(layout);
3374  uiDefButBitC(block,
3376  1,
3377  0,
3378  message,
3379  0,
3380  0,
3381  0,
3382  UI_UNIT_Y,
3384  0,
3385  0,
3386  0,
3387  0,
3388  "");
3389  }
3390 
3391  BKE_reports_clear(&reports);
3392 
3393  uiItemS_ex(layout, modified_images_count > 0 ? 2.0f : 4.0f);
3394 
3395  /* Buttons. */
3396 #ifdef _WIN32
3397  const bool windows_layout = true;
3398 #else
3399  const bool windows_layout = false;
3400 #endif
3401 
3402  if (windows_layout) {
3403  /* Windows standard layout. */
3404 
3405  uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
3406  uiLayoutSetScaleY(split, 1.2f);
3407 
3408  uiLayoutColumn(split, false);
3409  wm_block_file_close_save_button(block, post_action);
3410 
3411  uiLayoutColumn(split, false);
3412  wm_block_file_close_discard_button(block, post_action);
3413 
3414  uiLayoutColumn(split, false);
3415  wm_block_file_close_cancel_button(block, post_action);
3416  }
3417  else {
3418  /* Non-Windows layout (macOS and Linux). */
3419 
3420  uiLayout *split = uiLayoutSplit(layout, 0.3f, true);
3421  uiLayoutSetScaleY(split, 1.2f);
3422 
3423  uiLayoutColumn(split, false);
3424  wm_block_file_close_discard_button(block, post_action);
3425 
3426  uiLayout *split_right = uiLayoutSplit(split, 0.1f, true);
3427 
3428  uiLayoutColumn(split_right, false);
3429  /* Empty space. */
3430 
3431  uiLayoutColumn(split_right, false);
3432  wm_block_file_close_cancel_button(block, post_action);
3433 
3434  uiLayoutColumn(split_right, false);
3435  wm_block_file_close_save_button(block, post_action);
3436  }
3437 
3438  UI_block_bounds_set_centered(block, 14 * U.dpi_fac);
3439  return block;
3440 }
3441 
3442 static void free_post_file_close_action(void *arg)
3443 {
3444  wmGenericCallback *action = (wmGenericCallback *)arg;
3445  WM_generic_callback_free(action);
3446 }
3447 
3449 {
3453  }
3454  else {
3455  WM_generic_callback_free(post_action);
3456  }
3457 }
3458 
bool BKE_addon_remove_safe(struct ListBase *addon_list, const char *module)
Definition: addon.c:69
bool BKE_appdir_app_template_any(void)
Definition: appdir.c:987
@ BLENDER_USER_AUTOSAVE
Definition: BKE_appdir.h:84
@ BLENDER_USER_CONFIG
Definition: BKE_appdir.h:81
const char * BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
Definition: appdir.c:735
void BKE_tempdir_init(const char *userdir)
Definition: appdir.c:1160
#define BLENDER_USERPREF_FILE
Definition: BKE_appdir.h:100
bool BKE_appdir_app_template_has_userpref(const char *app_template)
Definition: appdir.c:1013
const char * BKE_appdir_folder_id(const int folder_id, const char *subfolder)
Definition: appdir.c:674
#define BLENDER_HISTORY_FILE
Definition: BKE_appdir.h:103
#define BLENDER_STARTUP_FILE
Definition: BKE_appdir.h:99
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len)
Definition: appdir.c:1001
#define BLENDER_QUIT_FILE
Definition: BKE_appdir.h:101
const char * BKE_tempdir_base(void)
Definition: appdir.c:1182
bool BKE_autoexec_match(const char *path)
Definition: autoexec.c:43
Blender util stuff.
void BKE_blender_userdef_data_set_and_free(struct UserDef *userdef)
Definition: blender.c:214
void BKE_blender_userdef_app_template_data_set_and_free(struct UserDef *userdef)
Definition: blender.c:379
void BKE_blendfile_read_setup(struct bContext *C, struct BlendFileData *bfd, const struct BlendFileReadParams *params, struct ReportList *reports)
Definition: blendfile.c:459
struct UserDef * BKE_blendfile_userdef_read(const char *filepath, struct ReportList *reports)
Definition: blendfile.c:556
struct BlendFileData * BKE_blendfile_read_from_memory(const void *filebuf, int filelength, const struct BlendFileReadParams *params, struct ReportList *reports)
Definition: blendfile.c:492
struct UserDef * BKE_blendfile_userdef_from_defaults(void)
Definition: blendfile.c:596
void BKE_blendfile_read_make_empty(struct bContext *C)
Definition: blendfile.c:537
struct BlendFileData * BKE_blendfile_read(const char *filepath, const struct BlendFileReadParams *params, struct ReportList *reports)
Definition: blendfile.c:470
bool BKE_blendfile_userdef_write_all(struct ReportList *reports)
Definition: blendfile.c:716
void BKE_blendfile_read_setup_ex(struct bContext *C, struct BlendFileData *bfd, const struct BlendFileReadParams *params, struct ReportList *reports, const bool startup_update_defaults, const char *startup_app_template)
Definition: blendfile.c:442
void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt)
Definition: callbacks.c:46
@ BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST
Definition: BKE_callbacks.h:61
@ BKE_CB_EVT_LOAD_FACTORY_USERDEF_POST
Definition: BKE_callbacks.h:60
@ BKE_CB_EVT_SAVE_PRE
Definition: BKE_callbacks.h:51
@ BKE_CB_EVT_VERSION_UPDATE
Definition: BKE_callbacks.h:59
@ BKE_CB_EVT_SAVE_POST
Definition: BKE_callbacks.h:52
@ BKE_CB_EVT_LOAD_POST
Definition: BKE_callbacks.h:50
@ BKE_CB_EVT_LOAD_PRE
Definition: BKE_callbacks.h:49
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
bool CTX_py_init_get(bContext *C)
Definition: context.c:215
void CTX_wm_menu_set(bContext *C, struct ARegion *menu)
Definition: context.c:996
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
void CTX_wm_window_set(bContext *C, struct wmWindow *win)
Definition: context.c:942
struct ReportList * CTX_wm_reports(const bContext *C)
Definition: context.c:751
struct wmMsgBus * CTX_wm_message_bus(const bContext *C)
Definition: context.c:746
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm)
Definition: context.c:926
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
@ G_FILE_RECOVER_READ
Definition: BKE_global.h:182
@ G_FILE_AUTOPACK
Definition: BKE_global.h:166
@ G_FILE_RECOVER_WRITE
Definition: BKE_global.h:190
@ G_FILE_NO_UI
Definition: BKE_global.h:170
@ G_FILE_COMPRESS
Definition: BKE_global.h:167
#define G_FLAG_ALL_READFILE
Definition: BKE_global.h:129
#define G_MAIN
Definition: BKE_global.h:232
@ G_FLAG_SCRIPT_OVERRIDE_PREF
Definition: BKE_global.h:118
@ G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET
Definition: BKE_global.h:120
@ G_FLAG_USERPREF_NO_SAVE_ON_EXIT
Definition: BKE_global.h:114
@ G_FLAG_SCRIPT_AUTOEXEC_FAIL
Definition: BKE_global.h:119
@ G_FLAG_SCRIPT_AUTOEXEC
Definition: BKE_global.h:116
#define G_FLAG_ALL_RUNTIME
Definition: BKE_global.h:124
void IDP_FreeProperty(struct IDProperty *prop)
Definition: idprop.c:1040
struct IDProperty * IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto)
void void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, const short remap_flags) ATTR_NONNULL(1
@ ID_REMAP_SKIP_USER_CLEAR
Definition: BKE_lib_remap.h:80
@ ID_REMAP_SKIP_INDIRECT_USAGE
Definition: BKE_lib_remap.h:46
struct ImBuf * BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data)
Definition: main.c:394
#define BLEN_THUMB_SIZE
Definition: BKE_main.h:277
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
struct BlendThumbnail * BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img)
Definition: main.c:363
const char * BKE_main_blendfile_path_from_global(void)
Definition: main.c:439
void BKE_packedfile_pack_all(struct Main *bmain, struct ReportList *reports, bool verbose)
Definition: packedFile.c:246
void BKE_report_print_level_set(ReportList *reports, ReportType level)
Definition: report.c:227
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reports_clear(ReportList *reports)
Definition: report.c:84
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_reports_init(ReportList *reports, int flag)
Definition: report.c:66
void BKE_scene_free_depsgraph_hash(struct Scene *scene)
Definition: scene.c:3422
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
struct ScrArea struct ScrArea * BKE_screen_find_big_area(struct bScreen *screen, const int spacetype, const short min)
Definition: screen.c:983
void BKE_sound_init(struct Main *main)
UndoStack * BKE_undosys_stack_create(void)
Definition: undo_system.c:265
void BKE_undosys_stack_init_from_context(UndoStack *ustack, struct bContext *C)
Definition: undo_system.c:362
void BKE_undosys_stack_clear(UndoStack *ustack)
Definition: undo_system.c:277
void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
Definition: undo_system.c:355
void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace) SETTER_ATTRS
Definition: workspace.c:539
struct WorkSpaceLayout * BKE_workspace_layout_find_global(const struct Main *bmain, const struct bScreen *screen, struct WorkSpace **r_workspace) ATTR_NONNULL(1
#define BLI_assert_unreachable()
Definition: BLI_assert.h:96
#define BLI_assert(a)
Definition: BLI_assert.h:58
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:349
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1024
bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:265
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL()
Definition: fileops.c:1037
int BLI_rename(const char *from, const char *to) ATTR_NONNULL()
Definition: fileops.c:1381
void BLI_file_free_lines(struct LinkNode *lines)
Definition: storage.c:639
struct stat BLI_stat_t
Definition: BLI_fileops.h:67
struct LinkNode * BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:590
void BLI_filelist_entry_size_to_string(const struct stat *st, const uint64_t sz, const bool compact, char r_size[])
void * BLI_gzopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1010
void BLI_filelist_entry_datetime_to_string(const struct stat *st, const int64_t ts, const bool compact, char r_time[], char r_date[], bool *r_is_today, bool *r_is_yesterday)
FILE * BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1003
Some types for dealing with directories.
#define FILELIST_DIRENTRY_SIZE_LEN
#define FILELIST_DIRENTRY_DATE_LEN
#define FILELIST_DIRENTRY_TIME_LEN
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void * BLI_findstring_ptr(const struct ListBase *listbase, const char *id, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void * BLI_findstring(const struct ListBase *listbase, const char *id, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
const char * BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1868
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
Definition: path_util.c:1682
bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL()
Definition: path_util.c:1633
#define FILE_MAX
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL()
Definition: path_util.c:1601
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
Definition: path_util.c:1365
void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1737
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL()
Definition: path_util.c:1571
const char * BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1962
void BLI_split_file_part(const char *string, char *file, const size_t filelen)
Definition: path_util.c:1690
#define BLI_path_cmp
size_t size_t char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
#define STRNCPY(dst, src)
Definition: BLI_string.h:163
char * BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:54
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:70
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
unsigned int uint
Definition: BLI_sys_types.h:83
int BLI_thread_is_main(void)
Definition: threads.cc:234
void BLI_timer_on_file_load(void)
Definition: BLI_timer.c:157
#define UNUSED_VARS(...)
#define SWAP(type, a, b)
#define STREQLEN(a, b, n)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define STREQ(a, b)
Compatibility-like things for windows.
external readfile function prototypes.
void BLO_sanitize_experimental_features_userpref_blend(struct UserDef *userdef)
eBLOReadSkip
Definition: BLO_readfile.h:93
@ BLO_READ_SKIP_DATA
Definition: BLO_readfile.h:96
@ BLO_READ_SKIP_USERDEF
Definition: BLO_readfile.h:95
bool BLO_has_bfile_extension(const char *str)
Definition: readfile.c:1684
bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
Definition: undofile.c:223
external writefile function prototypes.
bool BLO_write_file(struct Main *mainvar, const char *filepath, const int write_flags, const struct BlendFileWriteParams *params, struct ReportList *reports)
Definition: writefile.c:1128
eBLO_WritePathRemap
Definition: BLO_writefile.h:41
@ BLO_WRITE_PATH_REMAP_NONE
Definition: BLO_writefile.h:43
@ BLO_WRITE_PATH_REMAP_ABSOLUTE
Definition: BLO_writefile.h:49
@ BLO_WRITE_PATH_REMAP_RELATIVE
Definition: BLO_writefile.h:45
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define N_(msgid)
void BPY_python_reset(struct bContext *C)
bool BPY_run_string_eval(struct bContext *C, const char *imports[], const char *expr)
bool BPY_run_string_exec(struct bContext *C, const char *imports[], const char *expr)
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:203
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
@ OB_SOLID
Object is a sort of wrapper for general info.
@ R_ALPHAPREMUL
@ RGN_TYPE_WINDOW
@ FILE_SORT_DEFAULT
@ FILE_SORT_TIME
@ FILE_BLENDER
@ FILE_TYPE_BLENDER
@ FILE_TYPE_FOLDER
@ SPACE_VIEW3D
@ FILE_OPENFILE
@ FILE_SAVE
@ FILE_VERTICALDISPLAY
@ FILE_DEFAULTDISPLAY
@ USER_SAVE_PROMPT
@ USER_GLOBALUNDO
@ USER_RELPATHS
@ USER_FILENOUI
@ USER_FILECOMPRESS
@ USER_SCRIPT_AUTOEXEC_DISABLE
@ USER_AUTOSAVE
@ USER_SAVE_PREVIEWS
@ V3D_OFSDRAW_NONE
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ KEYCONF_INIT_DEFAULT
@ WM_WINDOW_IS_INIT
char datatoc_startup_blend[]
int datatoc_startup_blend_size
void ED_file_read_bookmarks(void)
Definition: space_file.c:1020
bool ED_image_should_save_modified(const struct Main *bmain)
bool ED_image_save_all_modified(const struct bContext *C, struct ReportList *reports)
int ED_image_save_all_modified_info(const struct Main *bmain, struct ReportList *reports)
void ED_outliner_select_sync_from_all_tag(struct bContext *C)
Definition: outliner_sync.c:80
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen)
Definition: screen_edit.c:625
struct WorkSpaceLayout * ED_workspace_layout_duplicate(struct Main *bmain, struct WorkSpace *workspace, const struct WorkSpaceLayout *layout_old, struct wmWindow *win) ATTR_NONNULL()
struct MemFile * ED_undosys_stack_memfile_get_active(struct UndoStack *ustack)
Definition: memfile_undo.c:304
void ED_editors_exit(struct Main *bmain, bool do_undo_system)
Definition: ed_util.c:181
void ED_editors_init(struct bContext *C)
Definition: ed_util.c:86
bool ED_editors_flush_edits(struct Main *bmain)
Definition: ed_util.c:295
void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all)
Definition: view3d_view.c:1661
struct ImBuf * ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph, struct Scene *scene, eDrawType drawtype, struct View3D *v3d, struct ARegion *region, int sizex, int sizey, eImBufFlags imbuf_flag, int alpha_mode, const char *viewname, const bool restore_rv3d_mats, struct GPUOffScreen *ofs, char err_out[256])
Definition: view3d_draw.c:1834
struct ImBuf * ED_view3d_draw_offscreen_imbuf_simple(struct Depsgraph *depsgraph, struct Scene *scene, struct View3DShading *shading_override, eDrawType drawtype, struct Object *camera, int width, int height, eImBufFlags imbuf_flags, eV3DOffscreenDrawFlag draw_flags, int alpha_mode, const char *viewname, struct GPUOffScreen *ofs, char err_out[256])
Definition: view3d_draw.c:1991
GHOST C-API function and type declarations.
void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata)
void GHOST_addToSystemRecentFiles(const char *filename)
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
Definition: scaling.c:1667
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
Contains defines and structs used throughout the imbuf module.
@ IB_rect
@ THB_FAIL
Definition: IMB_thumbs.h:41
@ THB_LARGE
Definition: IMB_thumbs.h:40
@ THB_SOURCE_BLEND
Definition: IMB_thumbs.h:47
void IMB_thumb_delete(const char *path, ThumbSize size)
Definition: thumbs.c:544
struct ImBuf * IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, struct ImBuf *img)
Definition: thumbs.c:512
void MEM_CacheLimiter_set_maximum(size_t m)
Read Guarded memory(de)allocation.
StructRNA RNA_PreferencesFilePaths
StructRNA RNA_Preferences
@ RNA_EQ_STRICT
Definition: RNA_access.h:1451
@ PROP_POINTER
Definition: RNA_types.h:78
@ PROP_COLLECTION
Definition: RNA_types.h:79
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
void uiItemS_ex(uiLayout *layout, float factor)
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.c:5603
#define UI_UNIT_Y
void uiItemL_ex(uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert)
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_BUT_TEXT_LEFT
Definition: UI_interface.h:259
@ UI_EMBOSS
Definition: UI_interface.h:107
void UI_block_theme_style_set(uiBlock *block, char theme_style)
Definition: interface.c:3547
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block)
@ UI_BUT_ACTIVE_DEFAULT
Definition: UI_interface.h:215
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetScaleY(uiLayout *layout, float scale)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemS(uiLayout *layout)
void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg, void(*arg_free)(void *arg))
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
Definition: interface.c:3542
void UI_but_drawflag_disable(uiBut *but, int flag)
Definition: interface.c:6097
@ UI_BLOCK_NUMSELECT
Definition: UI_interface.h:143
@ UI_BLOCK_LOOP
Definition: UI_interface.h:140
@ UI_BLOCK_KEEP_OPEN
Definition: UI_interface.h:149
@ UI_BLOCK_NO_WIN_CLIP
Definition: UI_interface.h:145
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
Definition: interface.c:6294
uiBlock * UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, eUIEmbossType emboss)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
void UI_block_bounds_set_centered(uiBlock *block, int addval)
Definition: interface.c:626
uiBut * uiDefButBitC(uiBlock *block, int type, int bit, int retval, const char *str, int x, int y, short width, short height, char *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.c:5112
void UI_block_flag_enable(uiBlock *block, int flag)
Definition: interface.c:6067
@ UI_BTYPE_BUT
Definition: UI_interface.h:334
@ UI_BTYPE_CHECKBOX
Definition: UI_interface.h:351
@ UI_BLOCK_THEME_STYLE_POPUP
Definition: UI_interface.h:671
bool UI_popup_block_name_exists(const struct bScreen *screen, const char *name)
void UI_init_userdef(void)
Definition: interface.c:7117
void UI_but_flag_enable(uiBut *but, int flag)
Definition: interface.c:6077
uiLayout * uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
@ ALERT_ICON_QUESTION
@ ALERT_ICON_ERROR
void UI_view2d_zoom_cache_reset(void)
Definition: view2d.c:1057
#define WM_FILESEL_FILEPATH
Definition: WM_api.h:537
#define NC_WINDOW
Definition: WM_types.h:277
#define ND_FILEREAD
Definition: WM_types.h:311
@ OPTYPE_INTERNAL
Definition: WM_types.h:175
#define NC_WM
Definition: WM_types.h:276
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:197
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:204
#define ND_DATACHANGED
Definition: WM_types.h:313
#define ND_FILESAVE
Definition: WM_types.h:312
#define U
ATTR_WARN_UNUSED_RESULT const BMLoop * l
unsigned int U
Definition: btGjkEpa3.h:78
static char * basename(char *string)
Definition: datatoc.c:33
Scene scene
const Depsgraph * depsgraph
void * user_data
DEGForeachIDComponentCallback callback
ListBase R_engines
Definition: engine.c:72
#define str(s)
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong state[N]
static void area(int d1, int d2, int e1, int e2, float weights[2])
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
return ret
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:6550
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1145
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:6272
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:6655
void RNA_property_collection_begin(PointerRNA *ptr, PropertyRNA *prop, CollectionPropertyIterator *iter)
Definition: rna_access.c:3816
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1155
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3641
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2317
void RNA_property_collection_next(CollectionPropertyIterator *iter)
Definition: rna_access.c:3850
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:6514
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
void RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop, char *value)
Definition: rna_access.c:3310
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2358
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_property_collection_end(CollectionPropertyIterator *iter)
Definition: rna_access.c:3891
PropertyRNA * RNA_struct_iterator_property(StructRNA *type)
Definition: rna_access.c:771
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
Definition: rna_access.c:3401
bool RNA_property_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_string_file_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3699
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3675
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
#define INT32_MAX
Definition: stdint.h:140
__int64 int64_t
Definition: stdint.h:92
#define INT32_MIN
Definition: stdint.h:139
unsigned __int64 uint64_t
Definition: stdint.h:93
struct BMLoop * next
Definition: bmesh_class.h:245
bool is_untrusted
Definition: wm_files.c:2464
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
char recovered
Definition: BKE_main.h:123
ListBase scenes
Definition: BKE_main.h:146
ListBase wm
Definition: BKE_main.h:175
BlendThumbnail * blen_thumb
Definition: BKE_main.h:143
ListBase libraries
Definition: BKE_main.h:147
char name[1024]
Definition: BKE_main.h:118
struct MainIDRelations * relations
Definition: BKE_main.h:192
int(* run)(bContext *C, wmOperator *op)
Definition: wm_files.c:2289
struct StructRNA * type
Definition: RNA_types.h:51
void * data
Definition: RNA_types.h:52
struct RecentFile * next
Definition: WM_types.h:990
char * filepath
Definition: WM_types.h:991
char engine[32]
struct RenderData r
struct Object * camera
UserDef_Runtime runtime
Wrapper for bScreen.
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:799
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * translation_context
Definition: WM_types.h:724
const char * description
Definition: WM_types.h:726
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:787
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:744
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
const char *(* get_name)(struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:793
struct ReportList * reports
IDProperty * properties
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
struct wmKeyConfig * defaultconf
struct UndoStack * undo_stack
struct wmKeyConfig * userconf
struct wmTimer * autosavetimer
struct wmWindow * windrawable
struct wmKeyConfig * addonconf
struct wmWindow * winactive
struct wmEvent * eventstate
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186
#define G(x, y, z)
uint len
void wm_clear_default_size(bContext *C)
Definition: wm.c:526
void wm_close_and_free_all(bContext *C, ListBase *wmlist)
Definition: wm.c:624
void WM_check(bContext *C)
Definition: wm.c:487
void WM_keyconfig_reload(bContext *C)
Definition: wm.c:439
void wm_add_default(Main *bmain, bContext *C)
Definition: wm.c:549
void WM_cursor_wait(bool val)
Definition: wm_cursors.c:226
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_fileselect(bContext *C, wmOperator *op)
int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, short context, struct IDProperty *properties)
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
void WM_report_banner_show(void)
int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties)
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
@ WM_HANDLER_TYPE_OP
@ TIMERAUTOSAVE
static void wm_history_file_update(void)
Definition: wm_files.c:1305
static void free_post_file_close_action(void *arg)
Definition: wm_files.c:3442
static uiBlock * block_create__close_file_dialog(struct bContext *C, struct ARegion *region, void *arg1)
Definition: wm_files.c:3313
static const char * wm_save_as_mainfile_get_name(wmOperatorType *ot, PointerRNA *ptr)
Definition: wm_files.c:2858
static void wm_autosave_location(char *filepath)
Definition: wm_files.c:1614
void wm_autosave_timer_end(wmWindowManager *wm)
Definition: wm_files.c:1692
static void create_operator_state(wmOperatorType *ot, int first_state)
Definition: wm_files.c:2269
#define BKE_READ_EXOTIC_OK_BLEND
Definition: wm_files.c:464
static void wm_window_match_do(bContext *C, ListBase *current_wm_list, ListBase *readfile_wm_list, ListBase *r_new_wm_list)
Definition: wm_files.c:386
static void wm_block_autorun_warning_enable_scripts(bContext *C, void *arg_block, void *UNUSED(arg))
Definition: wm_files.c:3013
static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
Definition: wm_files.c:2499
static void wm_init_userdef(Main *bmain)
Definition: wm_files.c:428
bool write_crash_blend(void)
Definition: wm_files.c:1458
static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool is_factory_startup, const bool use_data, const bool use_userdef, const bool reset_app_template)
Definition: wm_files.c:599
static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2623
static void wm_history_files_free(void)
Definition: wm_files.c:1263
static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
Definition: wm_files.c:2469
static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *UNUSED(arg))
Definition: wm_files.c:2986
static int operator_state_dispatch(bContext *C, wmOperator *op, OperatorDispatchTarget *targets)
Definition: wm_files.c:2292
static bool blend_save_check(bContext *UNUSED(C), wmOperator *op)
Definition: wm_files.c:2844
static void wm_filepath_default(char *filepath)
Definition: wm_files.c:2735
void WM_OT_read_history(wmOperatorType *ot)
Definition: wm_files.c:2041
bool WM_recover_last_session(bContext *C, ReportList *reports)
Definition: wm_files.c:2613
static void wm_open_mainfile_after_dialog_callback(bContext *C, void *user_data)
Definition: wm_files.c:2319
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs)
Definition: wm_files.c:1772
static int wm_homefile_read_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2062
static int wm_open_mainfile__discard_changes(bContext *C, wmOperator *op)
Definition: wm_files.c:2325
static bool wm_revert_mainfile_poll(bContext *UNUSED(C))
Definition: wm_files.c:2589
#define BKE_READ_EXOTIC_FAIL_FORMAT
Definition: wm_files.c:462
void wm_test_autorun_revert_action_set(wmOperatorType *ot, PointerRNA *ptr)
Definition: wm_files.c:3163
#define BKE_READ_EXOTIC_FAIL_OPEN
Definition: wm_files.c:463
void wm_homefile_read(bContext *C, ReportList *reports, bool use_factory_settings, bool use_empty_data, bool use_data, bool use_userdef, const char *filepath_startup_override, const char *app_template_override, bool *r_is_factory_startup)
Definition: wm_files.c:904
void WM_OT_save_as_mainfile(wmOperatorType *ot)
Definition: wm_files.c:2877
void wm_autosave_delete(void)
Definition: wm_files.c:1732
void WM_OT_open_mainfile(wmOperatorType *ot)
Definition: wm_files.c:2531
const char * WM_init_state_app_template_get(void)
Definition: wm_files.c:875
static void wm_block_file_close_cancel_button(uiBlock *block, wmGenericCallback *post_action)
Definition: wm_files.c:3286
static RecentFile * wm_file_history_find(const char *filepath)
Definition: wm_files.c:1270
static ImBuf * blend_file_thumb(const bContext *C, Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
Definition: wm_files.c:1351
PointerRNA * ptr
Definition: wm_files.c:3157
void wm_autosave_timer_begin(wmWindowManager *wm)
Definition: wm_files.c:1687
static void rna_struct_update_when_changed(bContext *C, Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b)
Definition: wm_files.c:1917
void WM_OT_recover_last_session(wmOperatorType *ot)
Definition: wm_files.c:2648
void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
Definition: wm_files.c:1708
static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2417
static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2570
static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
Definition: wm_files.c:1650
static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports)
Definition: wm_files.c:2249
BLI_STATIC_ASSERT(sizeof(struct FileRuntime)<=sizeof(void *), "Struct must not exceed pointer size")
static void wm_homefile_read_after_dialog_callback(bContext *C, void *user_data)
Definition: wm_files.c:2154
static OperatorDispatchTarget wm_open_mainfile_dispatch_targets[]
Definition: wm_files.c:2405
#define USERDEF_RESTORE(member)
static void wm_userpref_read_exceptions(UserDef *userdef_curr, const UserDef *userdef_prev)
Definition: wm_files.c:1903
static char * wm_open_mainfile_description(struct bContext *UNUSED(C), struct wmOperatorType *UNUSED(op), struct PointerRNA *params)
Definition: wm_files.c:2427
@ OPEN_MAINFILE_STATE_OPEN
Definition: wm_files.c:2314
@ OPEN_MAINFILE_STATE_DISCARD_CHANGES
Definition: wm_files.c:2312
@ OPEN_MAINFILE_STATE_SELECT_FILE_PATH
Definition: wm_files.c:2313
static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2695
void WM_OT_read_userpref(wmOperatorType *ot)
Definition: wm_files.c:2006
static void wm_test_autorun_revert_action_exec(bContext *C)
Definition: wm_files.c:3176
static char save_images_when_file_is_closed
Definition: wm_files.c:3227
static void wm_block_file_close_cancel(bContext *C, void *arg_block, void *UNUSED(arg_data))
Definition: wm_files.c:3229
void wm_file_read_report(bContext *C, Main *bmain)
Definition: wm_files.c:551
struct OperatorDispatchTarget OperatorDispatchTarget
static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2779
static void wm_block_file_close_save_button(uiBlock *block, wmGenericCallback *post_action)
Definition: wm_files.c:3302
void WM_OT_save_homefile(wmOperatorType *ot)
Definition: wm_files.c:1855
void WM_OT_read_factory_userpref(wmOperatorType *ot)
Definition: wm_files.c:2016
static int wm_userpref_write_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:1872
static int get_operator_state(wmOperator *op)
Definition: wm_files.c:2277
void WM_init_state_app_template_set(const char *app_template)
Definition: wm_files.c:863
static void save_set_compress(wmOperator *op)
Definition: wm_files.c:2742
bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
Definition: wm_files.c:736
static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2791
static void wm_window_match_init(bContext *C, ListBase *wmlist)
Definition: wm_files.c:186
static int wm_read_exotic(const char *name)
Definition: wm_files.c:479
static char * wm_save_as_mainfile_get_description(bContext *UNUSED(C), wmOperatorType *UNUSED(ot), PointerRNA *ptr)
Definition: wm_files.c:2866
void WM_OT_save_mainfile(wmOperatorType *ot)
Definition: wm_files.c:2950
void WM_OT_recover_auto_save(wmOperatorType *ot)
Definition: wm_files.c:2707
bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm)
Definition: wm_files.c:168
void wm_history_file_read(void)
Definition: wm_files.c:1215
static void wm_window_substitute_old(wmWindowManager *oldwm, wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
Definition: wm_files.c:221
char app_template[64]
Definition: wm_files.c:853
static void wm_window_match_keep_current_wm(const bContext *C, ListBase *current_wm_list, const bool load_ui, ListBase *r_new_wm_list)
Definition: wm_files.c:256
static uiBlock * block_create_autorun_warning(struct bContext *C, struct ARegion *region, void *UNUSED(arg1))
Definition: wm_files.c:3034
static void wm_block_file_close_discard(bContext *C, void *arg_block, void *arg_data)
Definition: wm_files.c:3235
static RecentFile * wm_history_file_new(const char *filepath)
Definition: wm_files.c:1249
static struct @1156 wm_test_autorun_revert_action_data
static void set_next_operator_state(wmOperator *op, int state)
Definition: wm_files.c:2282
void WM_file_tag_modified(void)
Definition: wm_files.c:158
void WM_file_autoexec_init(const char *filepath)
Definition: wm_files.c:536
static int wm_open_mainfile_dispatch(bContext *C, wmOperator *op)
Definition: wm_files.c:2412
static void wm_window_match_replace_by_file_wm(bContext *C, ListBase *current_wm_list, ListBase *readfile_wm_list, ListBase *r_new_wm_list)
Definition: wm_files.c:297
static int wm_homefile_read_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2166
static void wm_userpref_update_when_changed(bContext *C, Main *bmain, UserDef *userdef_prev, UserDef *userdef_curr)
Definition: wm_files.c:1951
static const char * close_file_dialog_name
Definition: wm_files.c:3311
void WM_OT_read_factory_settings(wmOperatorType *ot)
Definition: wm_files.c:2225
static int wm_userpref_read_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:1969
static int wm_open_mainfile__open(bContext *C, wmOperator *op)
Definition: wm_files.c:2377
static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
Definition: wm_files.c:2034
void wm_test_autorun_warning(bContext *C)
Definition: wm_files.c:3196
static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2914
wmOperatorType * ot
Definition: wm_files.c:3156
static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef))
Definition: wm_files.c:583
void wm_open_init_load_ui(wmOperator *op, bool use_prefs)
Definition: wm_files.c:1762
static CLG_LogRef LOG
Definition: wm_files.c:152
static struct @1154 wm_init_state_app_template
static void wm_history_file_free(RecentFile *recent)
Definition: wm_files.c:1256
static void wm_autosave_timer_begin_ex(wmWindowManager *wm, double timestep)
Definition: wm_files.c:1678
static void wm_open_mainfile_def_property_use_scripts(wmOperatorType *ot)
Definition: wm_files.c:2521
#define BKE_READ_EXOTIC_FAIL_PATH
Definition: wm_files.c:461
static bool wm_file_write(bContext *C, const char *filepath, int fileflags, eBLO_WritePathRemap remap_mode, bool use_save_as_copy, ReportList *reports)
Definition: wm_files.c:1475
static void wm_free_operator_properties_callback(void *user_data)
Definition: wm_files.c:2160
static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_data)
Definition: wm_files.c:3249
static void save_set_filepath(bContext *C, wmOperator *op)
Definition: wm_files.c:2757
static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2666
void WM_OT_read_homefile(wmOperatorType *ot)
Definition: wm_files.c:2191
static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2422
static void wm_block_file_close_discard_button(uiBlock *block, wmGenericCallback *post_action)
Definition: wm_files.c:3294
static int wm_homefile_write_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:1796
void WM_OT_save_userpref(wmOperatorType *ot)
Definition: wm_files.c:1884
static void wm_block_autorun_warning_reload_with_scripts(bContext *C, void *arg_block, void *UNUSED(arg))
Definition: wm_files.c:2995
static void wm_history_file_write(void)
Definition: wm_files.c:1279
static int wm_recover_last_session_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: wm_files.c:2640
static void read_homefile_props(wmOperatorType *ot)
Definition: wm_files.c:2180
static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
Definition: wm_files.c:2346
void WM_OT_revert_mainfile(wmOperatorType *ot)
Definition: wm_files.c:2594
void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action)
Definition: wm_files.c:3448
void WM_autosave_init(wmWindowManager *wm)
Definition: wm_files.c:1700
void WM_reinit_gizmomap_all(Main *bmain)
void WM_init_splash(bContext *C)
Definition: wm_init_exit.c:398
void wm_exit_schedule_delayed(const bContext *C)
Definition: wm_init_exit.c:457
void WM_jobs_kill_all(wmWindowManager *wm)
Definition: wm_jobs.c:550
void WM_keyconfig_update(wmWindowManager *wm)
Definition: wm_keymap.c:1781
@ WM_MSG_STATICTYPE_FILE_READ
void WM_msg_publish_static(struct wmMsgBus *mbus, int event)
void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, short action, short flag, short display, short sort)
void WM_operatortype_last_properties_clear_all(void)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:584
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:711
void WM_toolsystem_init(bContext *C)
wmGenericCallback * WM_generic_callback_steal(wmGenericCallback *callback)
Definition: wm_utils.c:44
void WM_generic_callback_free(wmGenericCallback *callback)
Definition: wm_utils.c:32
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1669
WorkSpaceLayout * WM_window_get_active_layout(const wmWindow *win)
Definition: wm_window.c:2359
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:389
void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
Definition: wm_window.c:2378
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
Definition: wm_window.c:720
void wm_window_clear_drawable(wmWindowManager *wm)
Definition: wm_window.c:1047
bScreen * WM_window_get_active_screen(const wmWindow *win)
Definition: wm_window.c:2372
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:1054
void WM_init_tablet_api(void)
Definition: wm_window.c:2072
bool WM_window_is_temp_screen(const wmWindow *win)
Definition: wm_window.c:2383
void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
Definition: wm_window.c:2364
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1632