Blender  V3.3
wm_files.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
11 /* placed up here because of crappy
12  * winsock stuff.
13  */
14 #include <errno.h>
15 #include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */
16 #include <stddef.h>
17 #include <string.h>
18 
19 #ifdef WIN32
20 /* Need to include windows.h so _WIN32_IE is defined. */
21 # include <windows.h>
22 # ifndef _WIN32_IE
23 /* Minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already. */
24 # define _WIN32_IE 0x0400
25 # endif
26 /* For SHGetSpecialFolderPath, has to be done before BLI_winstuff
27  * because 'near' is disabled through BLI_windstuff */
28 # include "BLI_winstuff.h"
29 # include <shlobj.h>
30 #endif
31 
32 #include "MEM_CacheLimiterC-Api.h"
33 #include "MEM_guardedalloc.h"
34 
35 #include "BLI_blenlib.h"
36 #include "BLI_fileops_types.h"
37 #include "BLI_filereader.h"
38 #include "BLI_linklist.h"
39 #include "BLI_math.h"
40 #include "BLI_system.h"
41 #include "BLI_threads.h"
42 #include "BLI_timer.h"
43 #include "BLI_utildefines.h"
44 #include BLI_SYSTEM_PID_H
45 
46 #include "PIL_time.h"
47 
48 #include "BLT_translation.h"
49 
50 #include "BLF_api.h"
51 
52 #include "DNA_object_types.h"
53 #include "DNA_scene_types.h"
54 #include "DNA_screen_types.h"
55 #include "DNA_space_types.h"
56 #include "DNA_userdef_types.h"
58 #include "DNA_workspace_types.h"
59 
60 #include "BKE_addon.h"
61 #include "BKE_appdir.h"
62 #include "BKE_asset_library.h"
63 #include "BKE_autoexec.h"
64 #include "BKE_blender.h"
65 #include "BKE_blender_version.h"
66 #include "BKE_blendfile.h"
67 #include "BKE_callbacks.h"
68 #include "BKE_context.h"
69 #include "BKE_global.h"
70 #include "BKE_idprop.h"
71 #include "BKE_lib_id.h"
72 #include "BKE_lib_override.h"
73 #include "BKE_lib_remap.h"
74 #include "BKE_main.h"
75 #include "BKE_main_namemap.h"
76 #include "BKE_packedFile.h"
77 #include "BKE_report.h"
78 #include "BKE_scene.h"
79 #include "BKE_screen.h"
80 #include "BKE_sound.h"
81 #include "BKE_undo_system.h"
82 #include "BKE_workspace.h"
83 
84 #include "BLO_readfile.h"
85 #include "BLO_undofile.h" /* to save from an undo memfile */
86 #include "BLO_writefile.h"
87 
88 #include "RNA_access.h"
89 #include "RNA_define.h"
90 
91 #include "IMB_imbuf.h"
92 #include "IMB_imbuf_types.h"
93 #include "IMB_thumbs.h"
94 
95 #include "ED_asset.h"
96 #include "ED_datafiles.h"
97 #include "ED_fileselect.h"
98 #include "ED_image.h"
99 #include "ED_outliner.h"
100 #include "ED_render.h"
101 #include "ED_screen.h"
102 #include "ED_undo.h"
103 #include "ED_util.h"
104 #include "ED_view3d.h"
105 #include "ED_view3d_offscreen.h"
106 
107 #include "GHOST_C-api.h"
108 #include "GHOST_Path-api.h"
109 
110 #include "UI_interface.h"
111 #include "UI_resources.h"
112 #include "UI_view2d.h"
113 
114 /* only to report a missing engine */
115 #include "RE_engine.h"
116 
117 #ifdef WITH_PYTHON
118 # include "BPY_extern_python.h"
119 # include "BPY_extern_run.h"
120 #endif
121 
122 #include "DEG_depsgraph.h"
123 
124 #include "WM_api.h"
125 #include "WM_message.h"
126 #include "WM_toolsystem.h"
127 #include "WM_types.h"
128 
129 #include "wm.h"
130 #include "wm_event_system.h"
131 #include "wm_files.h"
132 #include "wm_window.h"
133 
134 #include "CLG_log.h"
135 
136 static RecentFile *wm_file_history_find(const char *filepath);
137 static void wm_history_file_free(RecentFile *recent);
138 static void wm_history_files_free(void);
139 static void wm_history_file_update(void);
140 static void wm_history_file_write(void);
141 
143 
144 static CLG_LogRef LOG = {"wm.files"};
145 
146 /* -------------------------------------------------------------------- */
151 {
152  wmWindowManager *wm = G_MAIN->wm.first;
153  if (wm->file_saved) {
154  wm->file_saved = 0;
155  /* notifier that data changed, for save-over warning or header */
157  }
158 }
159 
161 {
162  return !wm->file_saved || ED_image_should_save_modified(bmain) ||
164 }
165 
168 /* -------------------------------------------------------------------- */
179 static void wm_window_match_init(bContext *C, ListBase *wmlist)
180 {
181  *wmlist = G_MAIN->wm;
182 
183  wmWindow *active_win = CTX_wm_window(C);
184 
185  /* first wrap up running stuff */
186  /* code copied from wm_init_exit.c */
187  LISTBASE_FOREACH (wmWindowManager *, wm, wmlist) {
188  WM_jobs_kill_all(wm);
189 
190  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
191  CTX_wm_window_set(C, win); /* needed by operator close callbacks */
192  WM_event_remove_handlers(C, &win->handlers);
193  WM_event_remove_handlers(C, &win->modalhandlers);
195  }
196 
197  /* NOTE(@campbellbarton): Clear the message bus so it's always cleared on file load.
198  * Otherwise it's cleared when "Load UI" is set (see #USER_FILENOUI & #wm_close_and_free).
199  * However it's _not_ cleared when the UI is kept. This complicates use from add-ons
200  * which can re-register subscribers on file-load. To support this use case,
201  * it's best to have predictable behavior - always clear. */
202  if (wm->message_bus != NULL) {
203  WM_msgbus_destroy(wm->message_bus);
204  wm->message_bus = NULL;
205  }
206  }
207 
209 
210  /* reset active window */
211  CTX_wm_window_set(C, active_win);
212 
213  /* XXX Hack! We have to clear context menu here, because removing all modalhandlers
214  * above frees the active menu (at least, in the 'startup splash' case),
215  * causing use-after-free error in later handling of the button callbacks in UI code
216  * (see ui_apply_but_funcs_after()).
217  * Tried solving this by always NULL-ing context's menu when setting wm/win/etc.,
218  * but it broke popups refreshing (see T47632),
219  * so for now just handling this specific case here. */
221 
222  ED_editors_exit(G_MAIN, true);
223 }
224 
226  wmWindowManager *wm,
227  wmWindow *oldwin,
228  wmWindow *win)
229 {
230  win->ghostwin = oldwin->ghostwin;
231  win->gpuctx = oldwin->gpuctx;
232  win->active = oldwin->active;
233  if (win->active) {
234  wm->winactive = win;
235  }
236  if (oldwm->windrawable == oldwin) {
237  oldwm->windrawable = NULL;
238  wm->windrawable = win;
239  }
240 
241  /* File loading in background mode still calls this. */
242  if (!G.background) {
243  /* Pointer back. */
245  }
246 
247  oldwin->ghostwin = NULL;
248  oldwin->gpuctx = NULL;
249 
250  win->eventstate = oldwin->eventstate;
251  win->event_last_handled = oldwin->event_last_handled;
252  oldwin->eventstate = NULL;
253  oldwin->event_last_handled = NULL;
254 
255  /* Ensure proper screen re-scaling. */
256  win->sizex = oldwin->sizex;
257  win->sizey = oldwin->sizey;
258  win->posx = oldwin->posx;
259  win->posy = oldwin->posy;
260 }
261 
263  ListBase *current_wm_list,
264  const bool load_ui,
265  ListBase *r_new_wm_list)
266 {
267  Main *bmain = CTX_data_main(C);
268  wmWindowManager *wm = current_wm_list->first;
269  bScreen *screen = NULL;
270 
271  /* match oldwm to new dbase, only old files */
273 
274  /* when loading without UI, no matching needed */
275  if (load_ui && (screen = CTX_wm_screen(C))) {
276  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
277  WorkSpace *workspace;
278 
279  BKE_workspace_layout_find_global(bmain, screen, &workspace);
280  BKE_workspace_active_set(win->workspace_hook, workspace);
281  win->scene = CTX_data_scene(C);
282 
283  /* all windows get active screen from file */
284  if (screen->winid == 0) {
285  WM_window_set_active_screen(win, workspace, screen);
286  }
287  else {
288  WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
290  bmain, workspace, layout_old, win);
291 
292  WM_window_set_active_layout(win, workspace, layout_new);
293  }
294 
295  bScreen *win_screen = WM_window_get_active_screen(win);
296  win_screen->winid = win->winid;
297  }
298  }
299 
300  /* we'll be using the current wm list directly; make sure
301  * the names are validated and in the name map. */
302  LISTBASE_FOREACH (wmWindowManager *, wm_item, current_wm_list) {
303  BKE_main_namemap_get_name(bmain, &wm_item->id, wm_item->id.name + 2);
304  }
305 
306  *r_new_wm_list = *current_wm_list;
307 }
308 
310  ListBase *current_wm_list,
311  ListBase *readfile_wm_list,
312  ListBase *r_new_wm_list)
313 {
314  wmWindowManager *oldwm = current_wm_list->first;
315  wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */
316 
317  /* Support window-manager ID references being held between file load operations by keeping
318  * #Main.wm.first memory address in-place, while swapping all of it's contents.
319  *
320  * This is needed so items such as key-maps can be held by an add-on,
321  * without it pointing to invalid memory, see: T86431 */
322  {
323  /* Referencing the window-manager pointer from elsewhere in the file is highly unlikely
324  * however it's possible with ID-properties & animation-drivers.
325  * At some point we could check on disallowing this since it doesn't seem practical. */
326  Main *bmain = G_MAIN;
327  BLI_assert(bmain->relations == NULL);
329 
330  /* Maintain the undo-depth between file loads. Useful so Python can perform
331  * nested operator calls that exit with the proper undo-depth. */
332  wm->op_undo_depth = oldwm->op_undo_depth;
333 
334  /* Simple pointer swapping step. */
335  BLI_remlink(current_wm_list, oldwm);
336  BLI_remlink(readfile_wm_list, wm);
337  SWAP(wmWindowManager, *oldwm, *wm);
338  SWAP(wmWindowManager *, oldwm, wm);
339  BLI_addhead(current_wm_list, oldwm);
340  BLI_addhead(readfile_wm_list, wm);
341 
342  /* Don't leave the old pointer in the context. */
343  CTX_wm_manager_set(C, wm);
344  }
345 
346  bool has_match = false;
347 
348  /* this code could move to setup_appdata */
349 
350  /* preserve key configurations in new wm, to preserve their keymaps */
351  wm->keyconfigs = oldwm->keyconfigs;
352  wm->addonconf = oldwm->addonconf;
353  wm->defaultconf = oldwm->defaultconf;
354  wm->userconf = oldwm->userconf;
355 
357  oldwm->addonconf = NULL;
358  oldwm->defaultconf = NULL;
359  oldwm->userconf = NULL;
360 
361  /* ensure making new keymaps and set space types */
362  wm->initialized = 0;
363  wm->winactive = NULL;
364 
365  /* Clearing drawable of before deleting any context
366  * to avoid clearing the wrong wm. */
368 
369  /* only first wm in list has ghostwins */
370  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
371  LISTBASE_FOREACH (wmWindow *, oldwin, &oldwm->windows) {
372  if (oldwin->winid == win->winid) {
373  has_match = true;
374 
375  wm_window_substitute_old(oldwm, wm, oldwin, win);
376  }
377  }
378  }
379  /* make sure at least one window is kept open so we don't lose the context, check T42303 */
380  if (!has_match) {
381  wm_window_substitute_old(oldwm, wm, oldwm->windows.first, wm->windows.first);
382  }
383 
384  wm_close_and_free_all(C, current_wm_list);
385 
386  *r_new_wm_list = *readfile_wm_list;
387 }
388 
399  ListBase *current_wm_list,
400  ListBase *readfile_wm_list,
401  ListBase *r_new_wm_list)
402 {
403  if (BLI_listbase_is_empty(current_wm_list)) {
404  /* case 1 */
405  if (BLI_listbase_is_empty(readfile_wm_list)) {
406  Main *bmain = CTX_data_main(C);
407  /* Neither current, no newly read file have a WM -> add the default one. */
408  wm_add_default(bmain, C);
409  *r_new_wm_list = bmain->wm;
410  }
411  /* case 2 */
412  else {
413  *r_new_wm_list = *readfile_wm_list;
414  }
415  }
416  else {
417  /* case 3 */
418  if (BLI_listbase_is_empty(readfile_wm_list)) {
419  /* We've read file without wm, keep current one entirely alive.
420  * Happens when reading pre 2.5 files (no WM back then) */
422  C, current_wm_list, (G.fileflags & G_FILE_NO_UI) == 0, r_new_wm_list);
423  }
424  /* case 4 */
425  else {
426  wm_window_match_replace_by_file_wm(C, current_wm_list, readfile_wm_list, r_new_wm_list);
427  }
428  }
429 }
430 
433 /* -------------------------------------------------------------------- */
440 static void wm_init_userdef(Main *bmain)
441 {
442  /* Not versioning, just avoid errors. */
443 #ifndef WITH_CYCLES
444  BKE_addon_remove_safe(&U.addons, "cycles");
445 #else
447 #endif
448 
449  UI_init_userdef();
450 
451  /* needed so loading a file from the command line respects user-pref T26156. */
452  SET_FLAG_FROM_TEST(G.fileflags, U.flag & USER_FILENOUI, G_FILE_NO_UI);
453 
454  /* set the python auto-execute setting from user prefs */
455  /* enabled by default, unless explicitly enabled in the command line which overrides */
456  if ((G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) == 0) {
458  }
459 
460  MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024);
461  BKE_sound_init(bmain);
462 
463  /* Update the temporary directory from the preferences or fallback to the system default. */
464  BKE_tempdir_init(U.tempdir);
465 
466  /* Update input device preference. */
468 
470 }
471 
472 /* return codes */
473 #define BKE_READ_EXOTIC_FAIL_PATH -3 /* file format is not supported */
474 #define BKE_READ_EXOTIC_FAIL_FORMAT -2 /* file format is not supported */
475 #define BKE_READ_EXOTIC_FAIL_OPEN -1 /* Can't open the file */
476 #define BKE_READ_EXOTIC_OK_BLEND 0 /* .blend file */
477 #if 0
478 # define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */
479 #endif
480 
483 /* -------------------------------------------------------------------- */
490 /* intended to check for non-blender formats but for now it only reads blends */
491 static int wm_read_exotic(const char *name)
492 {
493  /* make sure we're not trying to read a directory.... */
494 
495  int namelen = strlen(name);
496  if (namelen > 0 && ELEM(name[namelen - 1], '/', '\\')) {
498  }
499 
500  /* open the file. */
501  const int filedes = BLI_open(name, O_BINARY | O_RDONLY, 0);
502  if (filedes == -1) {
504  }
505 
506  FileReader *rawfile = BLI_filereader_new_file(filedes);
507  if (rawfile == NULL) {
509  }
510 
511  /* read the header (7 bytes are enough to identify all known types). */
512  char header[7];
513  if (rawfile->read(rawfile, header, sizeof(header)) != sizeof(header)) {
514  rawfile->close(rawfile);
516  }
517  rawfile->seek(rawfile, 0, SEEK_SET);
518 
519  /* check for uncompressed .blend */
520  if (STREQLEN(header, "BLENDER", 7)) {
521  rawfile->close(rawfile);
523  }
524 
525  /* check for compressed .blend */
526  FileReader *compressed_file = NULL;
527  if (BLI_file_magic_is_gzip(header)) {
528  /* In earlier versions of Blender (before 3.0), compressed files used `Gzip` instead of `Zstd`.
529  * While these files will no longer be written, there still needs to be reading support. */
530  compressed_file = BLI_filereader_new_gzip(rawfile);
531  }
532  else if (BLI_file_magic_is_zstd(header)) {
533  compressed_file = BLI_filereader_new_zstd(rawfile);
534  }
535 
536  /* If a compression signature matches, try decompressing the start and check if it's a .blend */
537  if (compressed_file != NULL) {
538  size_t len = compressed_file->read(compressed_file, header, sizeof(header));
539  compressed_file->close(compressed_file);
540  if (len == sizeof(header) && STREQLEN(header, "BLENDER", 7)) {
542  }
543  }
544  else {
545  rawfile->close(rawfile);
546  }
547 
548  /* Add check for future file formats here. */
549 
551 }
552 
555 /* -------------------------------------------------------------------- */
559 void WM_file_autoexec_init(const char *filepath)
560 {
561  if (G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) {
562  return;
563  }
564 
565  if (G.f & G_FLAG_SCRIPT_AUTOEXEC) {
566  char path[FILE_MAX];
567  BLI_split_dir_part(filepath, path, sizeof(path));
568  if (BKE_autoexec_match(path)) {
570  }
571  }
572 }
573 
575 {
576  ReportList *reports = NULL;
577  LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
578  if (scene->r.engine[0] &&
579  BLI_findstring(&R_engines, scene->r.engine, offsetof(RenderEngineType, idname)) == NULL) {
580  if (reports == NULL) {
581  reports = CTX_wm_reports(C);
582  }
583 
584  BKE_reportf(reports,
585  RPT_ERROR,
586  "Engine '%s' not available for scene '%s' (an add-on may need to be installed "
587  "or enabled)",
588  scene->r.engine,
589  scene->id.name + 2);
590  }
591  }
592 
593  if (reports) {
594  if (!G.background) {
596  }
597  }
598 }
599 
606 static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef))
607 {
608  if (use_data) {
611  }
612 
613  /* Always do this as both startup and preferences may have loaded in many font's
614  * at a different zoom level to the file being loaded. */
616 
618 }
619 
626 
630 };
631 
637 {
639 
640  const bool use_data = params->use_data;
641  const bool use_userdef = params->use_userdef;
642  const bool is_startup_file = params->is_startup_file;
643  const bool is_factory_startup = params->is_factory_startup;
644  const bool reset_app_template = params->reset_app_template;
645 
646  bool addons_loaded = false;
647 
648  if (use_data) {
649  if (!G.background) {
650  /* remove windows which failed to be added via WM_check */
652  }
654  }
655 
656 #ifdef WITH_PYTHON
657  if (is_startup_file) {
658  /* On startup (by default), Python won't have been initialized.
659  *
660  * The following block handles data & preferences being reloaded
661  * which requires resetting some internal variables. */
662  if (CTX_py_init_get(C)) {
663  bool reset_all = use_userdef;
664  if (use_userdef || reset_app_template) {
665  /* Only run when we have a template path found. */
668  C, (const char *[]){"bl_app_template_utils", NULL}, "bl_app_template_utils.reset()");
669  reset_all = true;
670  }
671  }
672  if (reset_all) {
674  C,
675  (const char *[]){"bpy", "addon_utils", NULL},
676  /* Refresh scripts as the preferences may have changed the user-scripts path.
677  *
678  * This is needed when loading settings from the previous version,
679  * otherwise the script path stored in the preferences would be ignored. */
680  "bpy.utils.refresh_script_paths()\n"
681  /* Sync add-ons, these may have changed from the defaults. */
682  "addon_utils.reset_all()");
683  }
684  if (use_data) {
686  }
687  addons_loaded = true;
688  }
689  }
690  else {
691  /* run any texts that were loaded in and flagged as modules */
692  if (use_data) {
694  }
695  addons_loaded = true;
696  }
697 #else
698  UNUSED_VARS(is_startup_file, reset_app_template);
699 #endif /* WITH_PYTHON */
700 
701  Main *bmain = CTX_data_main(C);
702 
703  if (use_userdef) {
704  if (is_factory_startup) {
706  }
707  }
708 
709  if (use_data) {
710  /* important to do before NULL'ing the context */
713  if (is_factory_startup) {
715  }
716  }
717 
718  if (use_data) {
720 
721  /* After load post, so for example the driver namespace can be filled
722  * before evaluating the depsgraph. */
723  wm_event_do_depsgraph(C, true);
724 
726 
727 #if 1
729 #else
731 #endif
732  }
733 
734  /* report any errors.
735  * currently disabled if addons aren't yet loaded */
736  if (addons_loaded) {
737  wm_file_read_report(C, bmain);
738  }
739 
740  if (use_data) {
741  if (!G.background) {
742  if (wm->undo_stack == NULL) {
744  }
745  else {
747  }
750  }
751  }
752 
753  if (use_data) {
754  if (!G.background) {
755  /* in background mode this makes it hard to load
756  * a blend file and do anything since the screen
757  * won't be set to a valid value again */
758  CTX_wm_window_set(C, NULL); /* exits queues */
759 
760  /* Ensure auto-run action is not used from a previous blend file load. */
762 
763  /* Ensure tools are registered. */
765  }
766  }
767 }
768 
771 /* -------------------------------------------------------------------- */
776 {
777  double duration_whole_minutes, duration_whole_seconds;
778  double duration_libraries_minutes, duration_libraries_seconds;
779  double duration_lib_override_minutes, duration_lib_override_seconds;
780  double duration_lib_override_resync_minutes, duration_lib_override_resync_seconds;
781  double duration_lib_override_recursive_resync_minutes,
782  duration_lib_override_recursive_resync_seconds;
783 
785  NULL,
786  NULL,
787  &duration_whole_minutes,
788  &duration_whole_seconds,
789  NULL);
791  NULL,
792  NULL,
793  &duration_libraries_minutes,
794  &duration_libraries_seconds,
795  NULL);
797  NULL,
798  NULL,
799  &duration_lib_override_minutes,
800  &duration_lib_override_seconds,
801  NULL);
803  NULL,
804  NULL,
805  &duration_lib_override_resync_minutes,
806  &duration_lib_override_resync_seconds,
807  NULL);
809  NULL,
810  NULL,
811  &duration_lib_override_recursive_resync_minutes,
812  &duration_lib_override_recursive_resync_seconds,
813  NULL);
814 
815  CLOG_INFO(
816  &LOG, 0, "Blender file read in %.0fm%.2fs", duration_whole_minutes, duration_whole_seconds);
817  CLOG_INFO(&LOG,
818  0,
819  " * Loading libraries: %.0fm%.2fs",
820  duration_libraries_minutes,
821  duration_libraries_seconds);
822  CLOG_INFO(&LOG,
823  0,
824  " * Applying overrides: %.0fm%.2fs",
825  duration_lib_override_minutes,
826  duration_lib_override_seconds);
827  CLOG_INFO(&LOG,
828  0,
829  " * Resyncing overrides: %.0fm%.2fs (%d root overrides), including recursive "
830  "resyncs: %.0fm%.2fs)",
831  duration_lib_override_resync_minutes,
832  duration_lib_override_resync_seconds,
833  bf_reports->count.resynced_lib_overrides,
834  duration_lib_override_recursive_resync_minutes,
835  duration_lib_override_recursive_resync_seconds);
836 
837  if (bf_reports->resynced_lib_overrides_libraries_count != 0) {
838  for (LinkNode *node_lib = bf_reports->resynced_lib_overrides_libraries; node_lib != NULL;
839  node_lib = node_lib->next) {
840  Library *library = node_lib->link;
841  BKE_reportf(
842  bf_reports->reports, RPT_INFO, "Library %s needs overrides resync", library->filepath);
843  }
844  }
845 
846  if (bf_reports->count.missing_libraries != 0 || bf_reports->count.missing_linked_id != 0) {
847  BKE_reportf(bf_reports->reports,
848  RPT_WARNING,
849  "%d libraries and %d linked data-blocks are missing (including %d ObjectData and "
850  "%d Proxies), please check the Info and Outliner editors for details",
851  bf_reports->count.missing_libraries,
852  bf_reports->count.missing_linked_id,
853  bf_reports->count.missing_obdata,
854  bf_reports->count.missing_obproxies);
855  }
856  else {
857  if (bf_reports->count.missing_obdata != 0 || bf_reports->count.missing_obproxies != 0) {
858  CLOG_ERROR(&LOG,
859  "%d local ObjectData and %d local Object proxies are reported to be missing, "
860  "this should never happen",
861  bf_reports->count.missing_obdata,
862  bf_reports->count.missing_obproxies);
863  }
864  }
865 
866  if (bf_reports->resynced_lib_overrides_libraries_count != 0) {
867  BKE_reportf(bf_reports->reports,
868  RPT_WARNING,
869  "%d libraries have overrides needing resync (auto resynced in %.0fm%.2fs), "
870  "please check the Info editor for details",
872  duration_lib_override_recursive_resync_minutes,
873  duration_lib_override_recursive_resync_seconds);
874  }
875 
876  if (bf_reports->count.proxies_to_lib_overrides_success != 0 ||
877  bf_reports->count.proxies_to_lib_overrides_failures != 0) {
878  BKE_reportf(
879  bf_reports->reports,
880  RPT_WARNING,
881  "Proxies have been removed from Blender (%d proxies were automatically converted "
882  "to library overrides, %d proxies could not be converted and were cleared). "
883  "Please also consider re-saving any library .blend file with the newest Blender version",
886  }
887 
888  if (bf_reports->count.sequence_strips_skipped != 0) {
889  BKE_reportf(bf_reports->reports,
890  RPT_ERROR,
891  "%d sequence strips were not read because they were in a channel larger than %d",
892  bf_reports->count.sequence_strips_skipped,
893  MAXSEQ);
894  }
895 
898 }
899 
900 bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
901 {
902  /* assume automated tasks with background, don't write recent file list */
903  const bool do_history_file_update = (G.background == false) &&
904  (CTX_wm_manager(C)->op_undo_depth == 0);
905  bool success = false;
906 
907  const bool use_data = true;
908  const bool use_userdef = false;
909 
910  /* so we can get the error message */
911  errno = 0;
912 
913  WM_cursor_wait(true);
914 
915  /* first try to append data from exotic file formats... */
916  /* it throws error box when file doesn't exist and returns -1 */
917  /* NOTE(ton): it should set some error message somewhere. */
918  const int retval = wm_read_exotic(filepath);
919 
920  /* we didn't succeed, now try to read Blender file */
921  if (retval == BKE_READ_EXOTIC_OK_BLEND) {
922  const struct BlendFileReadParams params = {
923  .is_startup = false,
924  /* Loading preferences when the user intended to load a regular file is a security
925  * risk, because the excluded path list is also loaded. Further it's just confusing
926  * if a user loads a file and various preferences change. */
927  .skip_flags = BLO_READ_SKIP_USERDEF,
928  };
929 
930  BlendFileReadReport bf_reports = {.reports = reports,
931  .duration.whole = PIL_check_seconds_timer()};
932  struct BlendFileData *bfd = BKE_blendfile_read(filepath, &params, &bf_reports);
933  if (bfd != NULL) {
934  wm_file_read_pre(C, use_data, use_userdef);
935 
936  /* Put aside screens to match with persistent windows later,
937  * also exit screens and editors. */
938  ListBase wmbase;
939  wm_window_match_init(C, &wmbase);
940 
941  /* This flag is initialized by the operator but overwritten on read.
942  * need to re-enable it here else drivers and registered scripts won't work. */
943  const int G_f_orig = G.f;
944 
945  BKE_blendfile_read_setup(C, bfd, &params, &bf_reports);
946 
947  if (G.f != G_f_orig) {
948  const int flags_keep = G_FLAG_ALL_RUNTIME;
949  G.f &= G_FLAG_ALL_READFILE;
950  G.f = (G.f & ~flags_keep) | (G_f_orig & flags_keep);
951  }
952 
953  /* #BKE_blendfile_read_result_setup sets new Main into context. */
954  Main *bmain = CTX_data_main(C);
955 
956  /* match the read WM with current WM */
957  wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
958  WM_check(C); /* opens window(s), checks keymaps */
959 
960  if (do_history_file_update) {
962  }
963 
965  &(const struct wmFileReadPost_Params){
966  .use_data = use_data,
967  .use_userdef = use_userdef,
968  .is_startup_file = false,
969  .is_factory_startup = false,
970  .reset_app_template = false,
971  });
972 
973  bf_reports.duration.whole = PIL_check_seconds_timer() - bf_reports.duration.whole;
974  file_read_reports_finalize(&bf_reports);
975 
976  success = true;
977  }
978  }
979 #if 0
980  else if (retval == BKE_READ_EXOTIC_OK_OTHER) {
981  BKE_undo_write(C, "Import file");
982  }
983 #endif
984  else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
985  BKE_reportf(reports,
986  RPT_ERROR,
987  "Cannot read file '%s': %s",
988  filepath,
989  errno ? strerror(errno) : TIP_("unable to open the file"));
990  }
991  else if (retval == BKE_READ_EXOTIC_FAIL_FORMAT) {
992  BKE_reportf(reports, RPT_ERROR, "File format is not supported in file '%s'", filepath);
993  }
994  else if (retval == BKE_READ_EXOTIC_FAIL_PATH) {
995  BKE_reportf(reports, RPT_ERROR, "File path '%s' invalid", filepath);
996  }
997  else {
998  BKE_reportf(reports, RPT_ERROR, "Unknown error loading '%s'", filepath);
999  BLI_assert_msg(0, "invalid 'retval'");
1000  }
1001 
1002  if (success == false) {
1003  /* remove from recent files list */
1004  if (do_history_file_update) {
1006  if (recent) {
1007  wm_history_file_free(recent);
1009  }
1010  }
1011  }
1012 
1013  WM_cursor_wait(false);
1014 
1016 
1017  return success;
1018 }
1019 
1020 static struct {
1021  char app_template[64];
1022  bool override;
1024 
1026 {
1027  if (app_template) {
1029  wm_init_state_app_template.override = true;
1030  }
1031  else {
1032  wm_init_state_app_template.app_template[0] = '\0';
1033  wm_init_state_app_template.override = false;
1034  }
1035 }
1036 
1038 {
1039  return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL;
1040 }
1041 
1044 /* -------------------------------------------------------------------- */
1049  const struct wmHomeFileRead_Params *params_homefile,
1050  ReportList *reports,
1051  struct wmFileReadPost_Params **r_params_file_read_post)
1052 {
1053 #if 0 /* UNUSED, keep as this may be needed later & the comment below isn't self evident. */
1054  /* Context does not always have valid main pointer here. */
1055  Main *bmain = G_MAIN;
1056 #endif
1057  ListBase wmbase;
1058  bool success = false;
1059 
1060  /* May be enabled, when the user configuration doesn't exist. */
1061  const bool use_data = params_homefile->use_data;
1062  const bool use_userdef = params_homefile->use_userdef;
1063  bool use_factory_settings = params_homefile->use_factory_settings;
1064  const bool use_empty_data = params_homefile->use_empty_data;
1065  const char *filepath_startup_override = params_homefile->filepath_startup_override;
1066  const char *app_template_override = params_homefile->app_template_override;
1067 
1068  bool filepath_startup_is_factory = true;
1069  char filepath_startup[FILE_MAX];
1070  char filepath_userdef[FILE_MAX];
1071 
1072  /* When 'app_template' is set:
1073  * '{BLENDER_USER_CONFIG}/{app_template}' */
1074  char app_template_system[FILE_MAX];
1075  /* When 'app_template' is set:
1076  * '{BLENDER_SYSTEM_SCRIPTS}/startup/bl_app_templates_system/{app_template}' */
1077  char app_template_config[FILE_MAX];
1078 
1079  eBLOReadSkip skip_flags = 0;
1080 
1081  if (use_data == false) {
1082  skip_flags |= BLO_READ_SKIP_DATA;
1083  }
1084  if (use_userdef == false) {
1085  skip_flags |= BLO_READ_SKIP_USERDEF;
1086  }
1087 
1088  /* True if we load startup.blend from memory
1089  * or use app-template startup.blend which the user hasn't saved. */
1090  bool is_factory_startup = true;
1091 
1092  const char *app_template = NULL;
1093  bool update_defaults = false;
1094 
1095  if (filepath_startup_override != NULL) {
1096  /* pass */
1097  }
1098  else if (app_template_override) {
1099  /* This may be clearing the current template by setting to an empty string. */
1100  app_template = app_template_override;
1101  }
1102  else if (!use_factory_settings && U.app_template[0]) {
1103  app_template = U.app_template;
1104  }
1105 
1106  const bool reset_app_template = ((!app_template && U.app_template[0]) ||
1107  (app_template && !STREQ(app_template, U.app_template)));
1108 
1109  /* Options exclude each other. */
1110  BLI_assert((use_factory_settings && filepath_startup_override) == 0);
1111 
1112  if ((G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) == 0) {
1114  }
1115 
1116  if (use_data) {
1117  if (reset_app_template) {
1118  /* Always load UI when switching to another template. */
1119  G.fileflags &= ~G_FILE_NO_UI;
1120  }
1121  }
1122 
1123  if (use_userdef || reset_app_template) {
1124 #ifdef WITH_PYTHON
1125  /* This only runs once Blender has already started. */
1126  if (CTX_py_init_get(C)) {
1127  /* This is restored by 'wm_file_read_post', disable before loading any preferences
1128  * so an add-on can read their own preferences when un-registering,
1129  * and use new preferences if/when re-registering, see T67577.
1130  *
1131  * Note that this fits into 'wm_file_read_pre' function but gets messy
1132  * since we need to know if 'reset_app_template' is true. */
1133  BPY_run_string_eval(C, (const char *[]){"addon_utils", NULL}, "addon_utils.disable_all()");
1134  }
1135 #endif /* WITH_PYTHON */
1136  }
1137 
1138  /* For regular file loading this only runs after the file is successfully read.
1139  * In the case of the startup file, the in-memory startup file is used as a fallback
1140  * so we know this will work if all else fails. */
1141  wm_file_read_pre(C, use_data, use_userdef);
1142 
1143  if (use_data) {
1144  /* put aside screens to match with persistent windows later */
1145  wm_window_match_init(C, &wmbase);
1146  }
1147 
1148  filepath_startup[0] = '\0';
1149  filepath_userdef[0] = '\0';
1150  app_template_system[0] = '\0';
1151  app_template_config[0] = '\0';
1152 
1153  const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
1154  if (!use_factory_settings) {
1155  if (cfgdir) {
1156  BLI_path_join(
1157  filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
1158  filepath_startup_is_factory = false;
1159  if (use_userdef) {
1160  BLI_path_join(
1161  filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
1162  }
1163  }
1164  else {
1165  use_factory_settings = true;
1166  }
1167 
1168  if (filepath_startup_override) {
1169  BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX);
1170  filepath_startup_is_factory = false;
1171  }
1172  }
1173 
1174  /* load preferences before startup.blend */
1175  if (use_userdef) {
1176  if (!use_factory_settings && BLI_exists(filepath_userdef)) {
1177  UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL);
1178  if (userdef != NULL) {
1180  userdef = NULL;
1181 
1182  skip_flags |= BLO_READ_SKIP_USERDEF;
1183  printf("Read prefs: %s\n", filepath_userdef);
1184  }
1185  }
1186  }
1187 
1188  if ((app_template != NULL) && (app_template[0] != '\0')) {
1190  app_template, app_template_system, sizeof(app_template_system))) {
1191  /* Can safely continue with code below, just warn it's not found. */
1192  BKE_reportf(reports, RPT_WARNING, "Application Template '%s' not found", app_template);
1193  }
1194 
1195  /* Insert template name into startup file. */
1196 
1197  /* note that the path is being set even when 'use_factory_settings == true'
1198  * this is done so we can load a templates factory-settings */
1199  if (!use_factory_settings) {
1200  BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
1201  BLI_path_join(filepath_startup,
1202  sizeof(filepath_startup),
1203  app_template_config,
1205  NULL);
1206  filepath_startup_is_factory = false;
1207  if (BLI_access(filepath_startup, R_OK) != 0) {
1208  filepath_startup[0] = '\0';
1209  }
1210  }
1211  else {
1212  filepath_startup[0] = '\0';
1213  }
1214 
1215  if (filepath_startup[0] == '\0') {
1216  BLI_path_join(filepath_startup,
1217  sizeof(filepath_startup),
1218  app_template_system,
1220  NULL);
1221  filepath_startup_is_factory = true;
1222 
1223  /* Update defaults only for system templates. */
1224  update_defaults = true;
1225  }
1226  }
1227 
1228  if (!use_factory_settings || (filepath_startup[0] != '\0')) {
1229  if (BLI_access(filepath_startup, R_OK) == 0) {
1230  const struct BlendFileReadParams params = {
1231  .is_startup = true,
1232  .skip_flags = skip_flags | BLO_READ_SKIP_USERDEF,
1233  };
1234  BlendFileReadReport bf_reports = {.reports = reports};
1235  struct BlendFileData *bfd = BKE_blendfile_read(filepath_startup, &params, &bf_reports);
1236 
1237  if (bfd != NULL) {
1239  C, bfd, &params, &bf_reports, update_defaults && use_data, app_template);
1240  success = true;
1241  }
1242  }
1243  if (success) {
1244  is_factory_startup = filepath_startup_is_factory;
1245  }
1246  }
1247 
1248  if (use_userdef) {
1249  if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
1250  UserDef *userdef_default = BKE_blendfile_userdef_from_defaults();
1251  BKE_blender_userdef_data_set_and_free(userdef_default);
1252  skip_flags |= BLO_READ_SKIP_USERDEF;
1253  }
1254  }
1255 
1256  if (success == false && filepath_startup_override && reports) {
1257  /* We can not return from here because wm is already reset */
1258  BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override);
1259  }
1260 
1261  if (success == false) {
1262  const struct BlendFileReadParams params = {
1263  .is_startup = true,
1264  .skip_flags = skip_flags,
1265  };
1268  if (bfd != NULL) {
1270  success = true;
1271  }
1272 
1273  if (use_data && BLI_listbase_is_empty(&wmbase)) {
1275  }
1276  }
1277 
1278  if (use_empty_data) {
1280  }
1281 
1282  /* Load template preferences,
1283  * unlike regular preferences we only use some of the settings,
1284  * see: BKE_blender_userdef_set_app_template */
1285  if (app_template_system[0] != '\0') {
1286  char temp_path[FILE_MAX];
1287  temp_path[0] = '\0';
1288  if (!use_factory_settings) {
1289  BLI_path_join(
1290  temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL);
1291  if (BLI_access(temp_path, R_OK) != 0) {
1292  temp_path[0] = '\0';
1293  }
1294  }
1295 
1296  if (temp_path[0] == '\0') {
1297  BLI_path_join(
1298  temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL);
1299  }
1300 
1301  if (use_userdef) {
1302  UserDef *userdef_template = NULL;
1303  /* just avoids missing file warning */
1304  if (BLI_exists(temp_path)) {
1305  userdef_template = BKE_blendfile_userdef_read(temp_path, NULL);
1306  }
1307  if (userdef_template == NULL) {
1308  /* we need to have preferences load to overwrite preferences from previous template */
1309  userdef_template = BKE_blendfile_userdef_from_defaults();
1310  }
1311  if (userdef_template) {
1313  userdef_template = NULL;
1314  }
1315  }
1316  }
1317 
1318  if (app_template_override) {
1319  BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template));
1320  }
1321 
1322  Main *bmain = CTX_data_main(C);
1323 
1324  if (use_userdef) {
1325  /* check userdef before open window, keymaps etc */
1326  wm_init_userdef(bmain);
1327  }
1328 
1329  if (use_data) {
1330  /* match the read WM with current WM */
1331  wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
1332  }
1333 
1334  if (use_userdef) {
1335  /* Clear keymaps because the current default keymap may have been initialized
1336  * from user preferences, which have been reset. */
1337  LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
1338  if (wm->defaultconf) {
1339  wm->defaultconf->flag &= ~KEYCONF_INIT_DEFAULT;
1340  }
1341  }
1342  }
1343 
1344  if (use_data) {
1345  WM_check(C); /* opens window(s), checks keymaps */
1346 
1347  bmain->filepath[0] = '\0';
1348  }
1349 
1350  {
1351  const struct wmFileReadPost_Params params_file_read_post = {
1352  .use_data = use_data,
1353  .use_userdef = use_userdef,
1354  .is_startup_file = true,
1355  .is_factory_startup = is_factory_startup,
1356  .reset_app_template = reset_app_template,
1357  };
1358  if (r_params_file_read_post == NULL) {
1359  wm_file_read_post(C, &params_file_read_post);
1360  }
1361  else {
1362  *r_params_file_read_post = MEM_mallocN(sizeof(struct wmFileReadPost_Params), __func__);
1363  **r_params_file_read_post = params_file_read_post;
1364 
1365  /* Match #wm_file_read_post which leaves the window cleared too. */
1367  }
1368  }
1369 }
1370 
1372  const struct wmHomeFileRead_Params *params_homefile,
1373  ReportList *reports)
1374 {
1375  wm_homefile_read_ex(C, params_homefile, reports, NULL);
1376 }
1377 
1379  const struct wmFileReadPost_Params *params_file_read_post)
1380 {
1381  wm_file_read_post(C, params_file_read_post);
1382  MEM_freeN((void *)params_file_read_post);
1383 }
1384 
1387 /* -------------------------------------------------------------------- */
1392 {
1393  char name[FILE_MAX];
1394  LinkNode *l, *lines;
1395  struct RecentFile *recent;
1396  const char *line;
1397  int num;
1398  const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
1399 
1400  if (!cfgdir) {
1401  return;
1402  }
1403 
1404  BLI_join_dirfile(name, sizeof(name), cfgdir, BLENDER_HISTORY_FILE);
1405 
1406  lines = BLI_file_read_as_lines(name);
1407 
1409 
1410  /* read list of recent opened files from recent-files.txt to memory */
1411  for (l = lines, num = 0; l && (num < U.recent_files); l = l->next) {
1412  line = l->link;
1413  /* don't check if files exist, causes slow startup for remote/external drives */
1414  if (line[0]) {
1415  recent = (RecentFile *)MEM_mallocN(sizeof(RecentFile), "RecentFile");
1416  BLI_addtail(&(G.recent_files), recent);
1417  recent->filepath = BLI_strdup(line);
1418  num++;
1419  }
1420  }
1421 
1422  BLI_file_free_lines(lines);
1423 }
1424 
1426 {
1427  RecentFile *recent = MEM_mallocN(sizeof(RecentFile), "RecentFile");
1428  recent->filepath = BLI_strdup(filepath);
1429  return recent;
1430 }
1431 
1432 static void wm_history_file_free(RecentFile *recent)
1433 {
1434  BLI_assert(BLI_findindex(&G.recent_files, recent) != -1);
1435  MEM_freeN(recent->filepath);
1436  BLI_freelinkN(&G.recent_files, recent);
1437 }
1438 
1439 static void wm_history_files_free(void)
1440 {
1441  LISTBASE_FOREACH_MUTABLE (RecentFile *, recent, &G.recent_files) {
1442  wm_history_file_free(recent);
1443  }
1444 }
1445 
1447 {
1448  return BLI_findstring_ptr(&G.recent_files, filepath, offsetof(RecentFile, filepath));
1449 }
1450 
1455 static void wm_history_file_write(void)
1456 {
1457  const char *user_config_dir;
1458  char name[FILE_MAX];
1459  FILE *fp;
1460 
1461  /* will be NULL in background mode */
1463  if (!user_config_dir) {
1464  return;
1465  }
1466 
1467  BLI_join_dirfile(name, sizeof(name), user_config_dir, BLENDER_HISTORY_FILE);
1468 
1469  fp = BLI_fopen(name, "w");
1470  if (fp) {
1471  LISTBASE_FOREACH (RecentFile *, recent, &G.recent_files) {
1472  fprintf(fp, "%s\n", recent->filepath);
1473  }
1474  fclose(fp);
1475  }
1476 }
1477 
1481 static void wm_history_file_update(void)
1482 {
1483  RecentFile *recent;
1484  const char *blendfile_path = BKE_main_blendfile_path_from_global();
1485 
1486  /* No write history for recovered startup files. */
1487  if (blendfile_path[0] == '\0') {
1488  return;
1489  }
1490 
1491  recent = G.recent_files.first;
1492  /* refresh recent-files.txt of recent opened files, when current file was changed */
1493  if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_path) != 0)) {
1494 
1495  recent = wm_file_history_find(blendfile_path);
1496  if (recent) {
1497  BLI_remlink(&G.recent_files, recent);
1498  }
1499  else {
1500  RecentFile *recent_next;
1501  for (recent = BLI_findlink(&G.recent_files, U.recent_files - 1); recent;
1502  recent = recent_next) {
1503  recent_next = recent->next;
1504  wm_history_file_free(recent);
1505  }
1506  recent = wm_history_file_new(blendfile_path);
1507  }
1508 
1509  /* add current file to the beginning of list */
1510  BLI_addhead(&(G.recent_files), recent);
1511 
1512  /* write current file to recent-files.txt */
1514 
1515  /* also update most recent files on System */
1516  GHOST_addToSystemRecentFiles(blendfile_path);
1517  }
1518 }
1519 
1522 /* -------------------------------------------------------------------- */
1547 {
1548  *r_thumb = NULL;
1549 
1550  wmWindow *win = CTX_wm_window(C);
1551  if (G.background || (win == NULL)) {
1552  return NULL;
1553  }
1554 
1555  /* The window to capture should be a main window (without parent). */
1556  while (win && win->parent) {
1557  win = win->parent;
1558  }
1559 
1560  int win_size[2];
1561  uint *buffer = WM_window_pixels_read(CTX_wm_manager(C), win, win_size);
1562  ImBuf *ibuf = IMB_allocFromBufferOwn(buffer, NULL, win_size[0], win_size[1], 24);
1563 
1564  if (ibuf) {
1565  int ex, ey;
1566  if (ibuf->x > ibuf->y) {
1567  ex = BLEN_THUMB_SIZE;
1568  ey = max_ii(1, (int)(((float)ibuf->y / (float)ibuf->x) * BLEN_THUMB_SIZE));
1569  }
1570  else {
1571  ex = max_ii(1, (int)(((float)ibuf->x / (float)ibuf->y) * BLEN_THUMB_SIZE));
1572  ey = BLEN_THUMB_SIZE;
1573  }
1574 
1575  /* File-system thumbnail image can be 256x256. */
1576  IMB_scaleImBuf(ibuf, ex * 2, ey * 2);
1577 
1578  /* Thumbnail inside blend should be 128x128. */
1579  ImBuf *thumb_ibuf = IMB_dupImBuf(ibuf);
1580  IMB_scaleImBuf(thumb_ibuf, ex, ey);
1581 
1582  BlendThumbnail *thumb = BKE_main_thumbnail_from_imbuf(NULL, thumb_ibuf);
1583  IMB_freeImBuf(thumb_ibuf);
1584  *r_thumb = thumb;
1585  }
1586 
1587  /* Must be freed by caller. */
1588  return ibuf;
1589 }
1590 
1597  Scene *scene,
1598  bScreen *screen,
1599  BlendThumbnail **r_thumb)
1600 {
1601  *r_thumb = NULL;
1602 
1603  /* Scene can be NULL if running a script at startup and calling the save operator. */
1604  if (G.background || scene == NULL) {
1605  return NULL;
1606  }
1607 
1608  /* will be scaled down, but gives some nice oversampling */
1609  ImBuf *ibuf;
1610  BlendThumbnail *thumb;
1612  const float pixelsize_old = U.pixelsize;
1613  wmWindow *windrawable_old = wm->windrawable;
1614  char err_out[256] = "unknown";
1615 
1616  /* screen if no camera found */
1617  ScrArea *area = NULL;
1618  ARegion *region = NULL;
1619  View3D *v3d = NULL;
1620 
1621  if (screen != NULL) {
1623  if (area) {
1624  v3d = area->spacedata.first;
1626  }
1627  }
1628 
1629  if (scene->camera == NULL && v3d == NULL) {
1630  return NULL;
1631  }
1632 
1634 
1635  /* Note that with scaling, this ends up being 0.5,
1636  * as it's a thumbnail, we don't need object centers and friends to be 1:1 size. */
1637  U.pixelsize = 1.0f;
1638 
1639  if (scene->camera) {
1641  scene,
1642  (v3d) ? &v3d->shading : NULL,
1643  (v3d) ? v3d->shading.type : OB_SOLID,
1644  scene->camera,
1647  IB_rect,
1650  R_ALPHAPREMUL,
1651  NULL,
1652  NULL,
1653  err_out);
1654  }
1655  else {
1657  scene,
1658  OB_SOLID,
1659  v3d,
1660  region,
1663  IB_rect,
1664  R_ALPHAPREMUL,
1665  NULL,
1666  true,
1667  NULL,
1668  err_out);
1669  }
1670 
1671  U.pixelsize = pixelsize_old;
1672 
1673  /* Reset to old drawable. */
1674  if (windrawable_old) {
1675  wm_window_make_drawable(wm, windrawable_old);
1676  }
1677  else {
1679  }
1680 
1681  if (ibuf) {
1682  /* dirty oversampling */
1683  ImBuf *thumb_ibuf;
1684  thumb_ibuf = IMB_dupImBuf(ibuf);
1685  /* BLEN_THUMB_SIZE is size of thumbnail inside blend file: 128x128. */
1687  thumb = BKE_main_thumbnail_from_imbuf(NULL, thumb_ibuf);
1688  IMB_freeImBuf(thumb_ibuf);
1689  /* Thumbnail saved to file-system should be 256x256. */
1691  }
1692  else {
1693  /* '*r_thumb' needs to stay NULL to prevent a bad thumbnail from being handled. */
1694  CLOG_WARN(&LOG, "failed to create thumbnail: %s", err_out);
1695  thumb = NULL;
1696  }
1697 
1698  /* must be freed by caller */
1699  *r_thumb = thumb;
1700 
1701  return ibuf;
1702 }
1703 
1706 /* -------------------------------------------------------------------- */
1711 {
1712  char path[FILE_MAX];
1713 
1714  BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
1715  BLI_path_extension_replace(path, sizeof(path), "_crash.blend");
1716  if (BLO_write_file(G_MAIN, path, G.fileflags, &(const struct BlendFileWriteParams){0}, NULL)) {
1717  printf("written: %s\n", path);
1718  return 1;
1719  }
1720  printf("failed: %s\n", path);
1721  return 0;
1722 }
1723 
1727 static bool wm_file_write(bContext *C,
1728  const char *filepath,
1729  int fileflags,
1730  eBLO_WritePathRemap remap_mode,
1731  bool use_save_as_copy,
1732  ReportList *reports)
1733 {
1734  Main *bmain = CTX_data_main(C);
1735  int len;
1736  int ok = false;
1737  BlendThumbnail *thumb = NULL, *main_thumb = NULL;
1738  ImBuf *ibuf_thumb = NULL;
1739 
1740  len = strlen(filepath);
1741 
1742  if (len == 0) {
1743  BKE_report(reports, RPT_ERROR, "Path is empty, cannot save");
1744  return ok;
1745  }
1746 
1747  if (len >= FILE_MAX) {
1748  BKE_report(reports, RPT_ERROR, "Path too long, cannot save");
1749  return ok;
1750  }
1751 
1752  /* Check if file write permission is ok */
1754  BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
1755  return ok;
1756  }
1757 
1758  /* NOTE: used to replace the file extension (to ensure '.blend'),
1759  * no need to now because the operator ensures,
1760  * its handy for scripts to save to a predefined name without blender editing it */
1761 
1762  /* send the OnSave event */
1763  LISTBASE_FOREACH (Library *, li, &bmain->libraries) {
1764  if (BLI_path_cmp(li->filepath_abs, filepath) == 0) {
1765  BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath);
1766  return ok;
1767  }
1768  }
1769 
1770  /* Call pre-save callbacks before writing preview,
1771  * that way you can generate custom file thumbnail. */
1773  ED_assets_pre_save(bmain);
1774 
1775  /* Enforce full override check/generation on file save. */
1777 
1778  /* NOTE: Ideally we would call `WM_redraw_windows` here to remove any open menus. But we
1779  * can crash if saving from a script, see T92704 & T97627. Just checking `!G.background
1780  * && BLI_thread_is_main()` is not sufficient to fix this. */
1781 
1782  /* don't forget not to return without! */
1783  WM_cursor_wait(true);
1784 
1785  if (U.file_preview_type != USER_FILE_PREVIEW_NONE) {
1786  /* Blend file thumbnail.
1787  *
1788  * - Save before exiting edit-mode, otherwise evaluated-mesh for shared data gets corrupted.
1789  * See T27765.
1790  * - Main can store a '.blend' thumbnail,
1791  * useful for background-mode or thumbnail customization.
1792  */
1793  main_thumb = thumb = bmain->blen_thumb;
1794  if (thumb != NULL) {
1795  /* In case we are given a valid thumbnail data, just generate image from it. */
1796  ibuf_thumb = BKE_main_thumbnail_to_imbuf(NULL, thumb);
1797  }
1798  else if (BLI_thread_is_main()) {
1799  int file_preview_type = U.file_preview_type;
1800 
1801  if (file_preview_type == USER_FILE_PREVIEW_AUTO) {
1803  bScreen *screen = CTX_wm_screen(C);
1804  bool do_render = (scene != NULL && scene->camera != NULL && screen != NULL &&
1805  (BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0) != NULL));
1806  file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT;
1807  }
1808 
1809  switch (file_preview_type) {
1811  ibuf_thumb = blend_file_thumb_from_screenshot(C, &thumb);
1812  break;
1813  }
1814  case USER_FILE_PREVIEW_CAMERA: {
1815  ibuf_thumb = blend_file_thumb_from_camera(
1816  C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
1817  break;
1818  }
1819  default:
1821  }
1822  }
1823  }
1824 
1825  /* operator now handles overwrite checks */
1826 
1827  if (G.fileflags & G_FILE_AUTOPACK) {
1828  BKE_packedfile_pack_all(bmain, reports, false);
1829  }
1830 
1831  ED_editors_flush_edits(bmain);
1832 
1833  /* XXX(ton): temp solution to solve bug, real fix coming. */
1834  bmain->recovered = 0;
1835 
1836  if (BLO_write_file(bmain,
1837  filepath,
1838  fileflags,
1839  &(const struct BlendFileWriteParams){
1840  .remap_mode = remap_mode,
1841  .use_save_versions = true,
1842  .use_save_as_copy = use_save_as_copy,
1843  .thumb = thumb,
1844  },
1845  reports)) {
1846  const bool do_history_file_update = (G.background == false) &&
1847  (CTX_wm_manager(C)->op_undo_depth == 0);
1848 
1849  if (use_save_as_copy == false) {
1850  STRNCPY(bmain->filepath, filepath); /* is guaranteed current file */
1851  }
1852 
1853  SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
1854 
1855  /* prevent background mode scripts from clobbering history */
1856  if (do_history_file_update) {
1858  }
1859 
1861 
1862  /* run this function after because the file can't be written before the blend is */
1863  if (ibuf_thumb) {
1864  IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */
1865  ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb);
1866  }
1867 
1868  /* Without this there is no feedback the file was saved. */
1869  BKE_reportf(reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(filepath));
1870 
1871  /* Success. */
1872  ok = true;
1873  }
1874 
1875  if (ibuf_thumb) {
1876  IMB_freeImBuf(ibuf_thumb);
1877  }
1878  if (thumb && thumb != main_thumb) {
1879  MEM_freeN(thumb);
1880  }
1881 
1882  WM_cursor_wait(false);
1883 
1884  return ok;
1885 }
1886 
1889 /* -------------------------------------------------------------------- */
1893 static void wm_autosave_location(char *filepath)
1894 {
1895  const int pid = abs(getpid());
1896  char path[1024];
1897 #ifdef WIN32
1898  const char *savedir;
1899 #endif
1900 
1901  /* Normally there is no need to check for this to be NULL,
1902  * however this runs on exit when it may be cleared. */
1903  Main *bmain = G_MAIN;
1904  const char *blendfile_path = bmain ? BKE_main_blendfile_path(bmain) : NULL;
1905 
1906  if (blendfile_path && (blendfile_path[0] != '\0')) {
1907  const char *basename = BLI_path_basename(blendfile_path);
1908  int len = strlen(basename) - 6;
1909  BLI_snprintf(path, sizeof(path), "%.*s_%d_autosave.blend", len, basename, pid);
1910  }
1911  else {
1912  BLI_snprintf(path, sizeof(path), "%d_autosave.blend", pid);
1913  }
1914 
1915 #ifdef WIN32
1916  /* XXX Need to investigate how to handle default location of '/tmp/'
1917  * This is a relative directory on Windows, and it may be
1918  * found. Example:
1919  * Blender installed on D:\ drive, D:\ drive has D:\tmp\
1920  * Now, BLI_exists() will find '/tmp/' exists, but
1921  * BLI_make_file_string will create string that has it most likely on C:\
1922  * through BLI_windows_get_default_root_dir().
1923  * If there is no C:\tmp autosave fails. */
1924  if (!BLI_exists(BKE_tempdir_base())) {
1926  BLI_make_file_string("/", filepath, savedir, path);
1927  return;
1928  }
1929 #endif
1930 
1932 }
1933 
1934 static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
1935 {
1936  char filepath[FILE_MAX];
1937 
1939 
1940  /* Fast save of last undo-buffer, now with UI. */
1941  const bool use_memfile = (U.uiflag & USER_GLOBALUNDO) != 0;
1942  MemFile *memfile = use_memfile ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : NULL;
1943  if (memfile != NULL) {
1944  BLO_memfile_write_file(memfile, filepath);
1945  }
1946  else {
1947  if (use_memfile) {
1948  /* This is very unlikely, alert developers of this unexpected case. */
1949  CLOG_WARN(&LOG, "undo-data not found for writing, fallback to regular file write!");
1950  }
1951 
1952  /* Save as regular blend file with recovery information. */
1953  const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE;
1954 
1955  ED_editors_flush_edits(bmain);
1956 
1957  /* Error reporting into console. */
1958  BLO_write_file(bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
1959  }
1960 }
1961 
1962 static void wm_autosave_timer_begin_ex(wmWindowManager *wm, double timestep)
1963 {
1965 
1966  if (U.flag & USER_AUTOSAVE) {
1967  wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, timestep);
1968  }
1969 }
1970 
1972 {
1973  wm_autosave_timer_begin_ex(wm, U.savetime * 60.0);
1974 }
1975 
1977 {
1978  if (wm->autosavetimer) {
1980  wm->autosavetimer = NULL;
1981  }
1982 }
1983 
1985 {
1987 }
1988 
1990 {
1992 
1993  /* If a modal operator is running, don't autosave because we might not be in
1994  * a valid state to save. But try again in 10ms. */
1995  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1996  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
1997  if (handler_base->type == WM_HANDLER_TYPE_OP) {
1998  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
1999  if (handler->op) {
2000  wm_autosave_timer_begin_ex(wm, 0.01);
2001  return;
2002  }
2003  }
2004  }
2005  }
2006 
2007  wm_autosave_write(bmain, wm);
2008 
2009  /* Restart the timer after file write, just in case file write takes a long time. */
2011 }
2012 
2014 {
2015  char filepath[FILE_MAX];
2016 
2018 
2019  if (BLI_exists(filepath)) {
2020  char str[FILE_MAX];
2022 
2023  /* if global undo; remove tempsave, otherwise rename */
2024  if (U.uiflag & USER_GLOBALUNDO) {
2025  BLI_delete(filepath, false, false);
2026  }
2027  else {
2029  }
2030  }
2031 }
2032 
2035 /* -------------------------------------------------------------------- */
2043 void wm_open_init_load_ui(wmOperator *op, bool use_prefs)
2044 {
2045  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "load_ui");
2046  if (!RNA_property_is_set(op->ptr, prop)) {
2047  bool value = use_prefs ? ((U.flag & USER_FILENOUI) == 0) : ((G.fileflags & G_FILE_NO_UI) == 0);
2048 
2049  RNA_property_boolean_set(op->ptr, prop, value);
2050  }
2051 }
2052 
2053 void wm_open_init_use_scripts(wmOperator *op, bool use_prefs)
2054 {
2055  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
2056  if (!RNA_property_is_set(op->ptr, prop)) {
2057  /* use G_FLAG_SCRIPT_AUTOEXEC rather than the userpref because this means if
2058  * the flag has been disabled from the command line, then opening
2059  * from the menu won't enable this setting. */
2060  bool value = use_prefs ? ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) :
2061  ((G.f & G_FLAG_SCRIPT_AUTOEXEC) != 0);
2062 
2063  RNA_property_boolean_set(op->ptr, prop, value);
2064  }
2065 }
2066 
2069 /* -------------------------------------------------------------------- */
2078 {
2079  Main *bmain = CTX_data_main(C);
2081  wmWindow *win = CTX_wm_window(C);
2082  char filepath[FILE_MAX];
2083  int fileflags;
2084 
2085  const char *app_template = U.app_template[0] ? U.app_template : NULL;
2086  const char *const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
2087  if (cfgdir == NULL) {
2088  BKE_report(op->reports, RPT_ERROR, "Unable to create user config path");
2089  return OPERATOR_CANCELLED;
2090  }
2091 
2093  ED_assets_pre_save(bmain);
2094 
2095  /* check current window and close it if temp */
2096  if (win && WM_window_is_temp_screen(win)) {
2097  wm_window_close(C, wm, win);
2098  }
2099 
2100  /* update keymaps in user preferences */
2101  WM_keyconfig_update(wm);
2102 
2104 
2105  printf("Writing homefile: '%s' ", filepath);
2106 
2107  ED_editors_flush_edits(bmain);
2108 
2109  /* Force save as regular blend file. */
2110  fileflags = G.fileflags & ~G_FILE_COMPRESS;
2111 
2112  if (BLO_write_file(bmain,
2113  filepath,
2114  fileflags,
2115  &(const struct BlendFileWriteParams){
2116  /* Make all paths absolute when saving the startup file.
2117  * On load the `G.main->filepath` will be empty so the paths
2118  * won't have a base for resolving the relative paths. */
2119  .remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE,
2120  /* Don't apply any path changes to the current blend file. */
2121  .use_save_as_copy = true,
2122  },
2123  op->reports) == 0) {
2124  printf("fail\n");
2125  return OPERATOR_CANCELLED;
2126  }
2127 
2128  printf("ok\n");
2129  BKE_report(op->reports, RPT_INFO, "Startup file saved");
2130 
2132 
2133  return OPERATOR_FINISHED;
2134 }
2135 
2137 {
2138  ot->name = "Save Startup File";
2139  ot->idname = "WM_OT_save_homefile";
2140  ot->description = "Make the current file the default .blend file";
2141 
2144 }
2145 
2148 /* -------------------------------------------------------------------- */
2152 /* Only save the prefs block. operator entry */
2154 {
2156 
2157  /* Update keymaps in user preferences. */
2158  WM_keyconfig_update(wm);
2159 
2160  const bool ok = BKE_blendfile_userdef_write_all(op->reports);
2161 
2162  return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2163 }
2164 
2166 {
2167  ot->name = "Save Preferences";
2168  ot->idname = "WM_OT_save_userpref";
2169  ot->description = "Make the current preferences default";
2170 
2173 }
2174 
2177 /* -------------------------------------------------------------------- */
2184 static void wm_userpref_read_exceptions(UserDef *userdef_curr, const UserDef *userdef_prev)
2185 {
2186 #define USERDEF_RESTORE(member) \
2187  { \
2188  userdef_curr->member = userdef_prev->member; \
2189  } \
2190  ((void)0)
2191 
2192  /* Current visible preferences category. */
2193  USERDEF_RESTORE(space_data.section_active);
2194 
2195 #undef USERDEF_RESTORE
2196 }
2197 
2199  Main *bmain,
2200  PointerRNA *ptr_a,
2201  PointerRNA *ptr_b)
2202 {
2204  PropertyRNA *iterprop = RNA_struct_iterator_property(ptr_a->type);
2205  BLI_assert(ptr_a->type == ptr_b->type);
2206  RNA_property_collection_begin(ptr_a, iterprop, &iter);
2207  for (; iter.valid; RNA_property_collection_next(&iter)) {
2208  PropertyRNA *prop = iter.ptr.data;
2209  if (STREQ(RNA_property_identifier(prop), "rna_type")) {
2210  continue;
2211  }
2212  switch (RNA_property_type(prop)) {
2213  case PROP_POINTER: {
2214  PointerRNA ptr_sub_a = RNA_property_pointer_get(ptr_a, prop);
2215  PointerRNA ptr_sub_b = RNA_property_pointer_get(ptr_b, prop);
2216  rna_struct_update_when_changed(C, bmain, &ptr_sub_a, &ptr_sub_b);
2217  break;
2218  }
2219  case PROP_COLLECTION:
2220  /* Don't handle collections. */
2221  break;
2222  default: {
2223  if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, RNA_EQ_STRICT)) {
2224  RNA_property_update(C, ptr_b, prop);
2225  }
2226  }
2227  }
2228  }
2230 }
2231 
2233  Main *bmain,
2234  UserDef *userdef_prev,
2235  UserDef *userdef_curr)
2236 {
2237  PointerRNA ptr_a, ptr_b;
2238  RNA_pointer_create(NULL, &RNA_Preferences, userdef_prev, &ptr_a);
2239  RNA_pointer_create(NULL, &RNA_Preferences, userdef_curr, &ptr_b);
2240  const bool is_dirty = userdef_curr->runtime.is_dirty;
2241 
2242  rna_struct_update_when_changed(C, bmain, &ptr_a, &ptr_b);
2243 
2244  WM_reinit_gizmomap_all(bmain);
2246 
2247  userdef_curr->runtime.is_dirty = is_dirty;
2248 }
2249 
2251 {
2252  const bool use_data = false;
2253  const bool use_userdef = true;
2254  const bool use_factory_settings = STREQ(op->type->idname, "WM_OT_read_factory_userpref");
2255 
2256  UserDef U_backup = U;
2257 
2259  &(const struct wmHomeFileRead_Params){
2260  .use_data = use_data,
2261  .use_userdef = use_userdef,
2262  .use_factory_settings = use_factory_settings,
2263  .use_empty_data = false,
2264  .filepath_startup_override = NULL,
2265  .app_template_override = WM_init_state_app_template_get(),
2266  },
2267  op->reports);
2268 
2269  wm_userpref_read_exceptions(&U, &U_backup);
2270  SET_FLAG_FROM_TEST(G.f, use_factory_settings, G_FLAG_USERPREF_NO_SAVE_ON_EXIT);
2271 
2272  Main *bmain = CTX_data_main(C);
2273 
2274  wm_userpref_update_when_changed(C, bmain, &U_backup, &U);
2275 
2276  if (use_factory_settings) {
2277  U.runtime.is_dirty = true;
2278  }
2279 
2280  /* Ensure the correct icon textures are loaded. When the current theme didn't had an
2281  * #icon_border_intensity, but the loaded theme has, the icon with border intensity needs to be
2282  * loaded. */
2284 
2285  /* Needed to recalculate UI scaling values (eg, #UserDef.inv_dpi_fac). */
2287 
2289 
2290  return OPERATOR_FINISHED;
2291 }
2292 
2294 {
2295  ot->name = "Load Preferences";
2296  ot->idname = "WM_OT_read_userpref";
2297  ot->description = "Load last saved preferences";
2298 
2301 }
2302 
2304 {
2305  ot->name = "Load Factory Preferences";
2306  ot->idname = "WM_OT_read_factory_userpref";
2307  ot->description =
2308  "Load factory default preferences. "
2309  "To make changes to preferences permanent, use \"Save Preferences\"";
2310 
2313 }
2314 
2317 /* -------------------------------------------------------------------- */
2322 {
2325  return OPERATOR_FINISHED;
2326 }
2327 
2329 {
2330  ot->name = "Reload History File";
2331  ot->idname = "WM_OT_read_history";
2332  ot->description = "Reloads history and bookmarks";
2333 
2336 
2337  /* this operator is only used for loading settings from a previous blender install */
2338  ot->flag = OPTYPE_INTERNAL;
2339 }
2340 
2343 /* -------------------------------------------------------------------- */
2350 {
2351  const bool use_factory_startup_and_userdef = STREQ(op->type->idname,
2352  "WM_OT_read_factory_settings");
2353  const bool use_factory_settings = use_factory_startup_and_userdef ||
2354  RNA_boolean_get(op->ptr, "use_factory_startup");
2355  bool use_userdef = false;
2356  char filepath_buf[FILE_MAX];
2357  const char *filepath = NULL;
2358  UserDef U_backup = U;
2359 
2360  if (!use_factory_settings) {
2361  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
2362 
2363  /* This can be used when loading of a start-up file should only change
2364  * the scene content but keep the blender UI as it is. */
2365  wm_open_init_load_ui(op, true);
2366  SET_FLAG_FROM_TEST(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
2367 
2368  if (RNA_property_is_set(op->ptr, prop)) {
2369  RNA_property_string_get(op->ptr, prop, filepath_buf);
2370  filepath = filepath_buf;
2371  if (BLI_access(filepath, R_OK)) {
2372  BKE_reportf(
2373  op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath);
2374  return OPERATOR_CANCELLED;
2375  }
2376  }
2377  }
2378  else {
2379  if (use_factory_startup_and_userdef) {
2380  /* always load UI for factory settings (prefs will re-init) */
2381  G.fileflags &= ~G_FILE_NO_UI;
2382  /* Always load preferences with factory settings. */
2383  use_userdef = true;
2384  }
2385  }
2386 
2387  char app_template_buf[sizeof(U.app_template)];
2388  const char *app_template;
2389  PropertyRNA *prop_app_template = RNA_struct_find_property(op->ptr, "app_template");
2390  const bool use_splash = !use_factory_settings && RNA_boolean_get(op->ptr, "use_splash");
2391  const bool use_empty_data = RNA_boolean_get(op->ptr, "use_empty");
2392 
2393  if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) {
2394  RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
2395  app_template = app_template_buf;
2396 
2397  if (!use_factory_settings) {
2398  /* Always load preferences when switching templates with own preferences. */
2401  }
2402 
2403  /* Turn override off, since we're explicitly loading a different app-template. */
2405  }
2406  else {
2407  /* Normally NULL, only set when overriding from the command-line. */
2409  }
2410 
2412  &(const struct wmHomeFileRead_Params){
2413  .use_data = true,
2414  .use_userdef = use_userdef,
2415  .use_factory_settings = use_factory_settings,
2416  .use_empty_data = use_empty_data,
2417  .filepath_startup_override = filepath,
2418  .app_template_override = app_template,
2419  },
2420  op->reports);
2421 
2422  if (use_splash) {
2423  WM_init_splash(C);
2424  }
2425 
2426  if (use_userdef) {
2427  wm_userpref_read_exceptions(&U, &U_backup);
2428  SET_FLAG_FROM_TEST(G.f, use_factory_settings, G_FLAG_USERPREF_NO_SAVE_ON_EXIT);
2429 
2430  if (use_factory_settings) {
2431  U.runtime.is_dirty = true;
2432  }
2433  }
2434 
2435  if (G.fileflags & G_FILE_NO_UI) {
2437  }
2438 
2439  return OPERATOR_FINISHED;
2440 }
2441 
2443 {
2445  C, "WM_OT_read_homefile", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data, NULL);
2446 }
2447 
2448 static int wm_homefile_read_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2449 {
2451  return OPERATOR_INTERFACE;
2452  }
2453  return wm_homefile_read_exec(C, op);
2454 }
2455 
2457 {
2458  PropertyRNA *prop;
2459 
2460  prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
2462 
2463  prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
2465 }
2466 
2468 {
2469  PropertyRNA *prop;
2470  ot->name = "Reload Start-Up File";
2471  ot->idname = "WM_OT_read_homefile";
2472  ot->description = "Open the default file (doesn't save the current file)";
2473 
2476 
2477  prop = RNA_def_string_file_path(
2478  ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to an alternative start-up file");
2480 
2481  /* So scripts can use an alternative start-up file without the UI */
2482  prop = RNA_def_boolean(
2483  ot->srna, "load_ui", true, "Load UI", "Load user interface setup from the .blend file");
2485 
2486  /* So the splash can be kept open after loading a file (for templates). */
2487  prop = RNA_def_boolean(ot->srna, "use_splash", false, "Splash", "");
2489 
2490  /* So scripts can load factory-startup without resetting preferences
2491  * (which has other implications such as reloading all add-ons).
2492  * Match naming for `--factory-startup` command line argument. */
2493  prop = RNA_def_boolean(ot->srna, "use_factory_startup", false, "Factory Startup", "");
2495 
2497 
2498  /* omit poll to run in background mode */
2499 }
2500 
2502 {
2503  ot->name = "Load Factory Settings";
2504  ot->idname = "WM_OT_read_factory_settings";
2505  ot->description =
2506  "Load factory default startup file and preferences. "
2507  "To make changes permanent, use \"Save Startup File\" and \"Save Preferences\"";
2508 
2511 
2513  /* omit poll to run in background mode */
2514 }
2515 
2518 /* -------------------------------------------------------------------- */
2525 static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports)
2526 {
2527  bool success;
2528 
2529  /* XXX wm in context is not set correctly after WM_file_read -> crash */
2530  /* do it before for now, but is this correct with multiple windows? */
2532 
2533  /* Set by the "use_scripts" property on file load. */
2534  if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) {
2536  }
2537 
2538  success = WM_file_read(C, filepath, reports);
2539 
2540  return success;
2541 }
2542 
2543 /* Generic operator state utilities */
2544 
2545 static void create_operator_state(wmOperatorType *ot, int first_state)
2546 {
2547  PropertyRNA *prop = RNA_def_int(
2548  ot->srna, "state", first_state, INT32_MIN, INT32_MAX, "State", "", INT32_MIN, INT32_MAX);
2551 }
2552 
2554 {
2555  return RNA_int_get(op->ptr, "state");
2556 }
2557 
2559 {
2560  RNA_int_set(op->ptr, "state", state);
2561 }
2562 
2563 typedef struct OperatorDispatchTarget {
2564  int state;
2565  int (*run)(bContext *C, wmOperator *op);
2567 
2569 {
2570  int state = get_operator_state(op);
2571  for (int i = 0; targets[i].run; i++) {
2572  OperatorDispatchTarget target = targets[i];
2573  if (target.state == state) {
2574  return target.run(C, op);
2575  }
2576  }
2578  return OPERATOR_CANCELLED;
2579 }
2580 
2583 /* -------------------------------------------------------------------- */
2587 enum {
2591 };
2592 
2594 
2596 {
2598  C, "WM_OT_open_mainfile", WM_OP_INVOKE_DEFAULT, (IDProperty *)user_data, NULL);
2599 }
2600 
2602 {
2603  if (RNA_boolean_get(op->ptr, "display_file_selector")) {
2605  }
2606  else {
2608  }
2609 
2611  return OPERATOR_INTERFACE;
2612  }
2613  return wm_open_mainfile_dispatch(C, op);
2614 }
2615 
2617 {
2619 
2620  Main *bmain = CTX_data_main(C);
2621  const char *blendfile_path = BKE_main_blendfile_path(bmain);
2622 
2623  if (CTX_wm_window(C) == NULL) {
2624  /* in rare cases this could happen, when trying to invoke in background
2625  * mode on load for example. Don't use poll for this because exec()
2626  * can still run without a window */
2627  BKE_report(op->reports, RPT_ERROR, "Context window not set");
2628  return OPERATOR_CANCELLED;
2629  }
2630 
2631  /* if possible, get the name of the most recently used .blend file */
2632  if (G.recent_files.first) {
2633  struct RecentFile *recent = G.recent_files.first;
2634  blendfile_path = recent->filepath;
2635  }
2636 
2637  RNA_string_set(op->ptr, "filepath", blendfile_path);
2638  wm_open_init_load_ui(op, true);
2639  wm_open_init_use_scripts(op, true);
2640  op->customdata = NULL;
2641 
2643 
2644  return OPERATOR_RUNNING_MODAL;
2645 }
2646 
2648 {
2649  char filepath[FILE_MAX];
2650  bool success;
2651 
2652  RNA_string_get(op->ptr, "filepath", filepath);
2653 
2654  /* For file opening, also print in console for warnings, not only errors. */
2656 
2657  /* re-use last loaded setting so we can reload a file without changing */
2658  wm_open_init_load_ui(op, false);
2659  wm_open_init_use_scripts(op, false);
2660 
2661  SET_FLAG_FROM_TEST(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
2663  success = wm_file_read_opwrap(C, filepath, op->reports);
2664 
2665  if (success) {
2666  if (G.fileflags & G_FILE_NO_UI) {
2668  }
2669  ED_view3d_local_collections_reset(C, (G.fileflags & G_FILE_NO_UI) != 0);
2670  return OPERATOR_FINISHED;
2671  }
2672  return OPERATOR_CANCELLED;
2673 }
2674 
2679  {0, NULL},
2680 };
2681 
2683 {
2685 }
2686 
2687 static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2688 {
2689  return wm_open_mainfile_dispatch(C, op);
2690 }
2691 
2693 {
2694  return wm_open_mainfile__open(C, op);
2695 }
2696 
2698  struct wmOperatorType *UNUSED(op),
2699  struct PointerRNA *params)
2700 {
2701  if (!RNA_struct_property_is_set(params, "filepath")) {
2702  return NULL;
2703  }
2704 
2705  /* Filepath. */
2706  char path[FILE_MAX];
2707  RNA_string_get(params, "filepath", path);
2708 
2709  BLI_stat_t stats;
2710  if (BLI_stat(path, &stats) == -1) {
2711  return BLI_sprintfN("%s\n\n%s", path, TIP_("File Not Found"));
2712  }
2713 
2714  /* Date. */
2715  char date_st[FILELIST_DIRENTRY_DATE_LEN];
2716  char time_st[FILELIST_DIRENTRY_TIME_LEN];
2717  bool is_today, is_yesterday;
2719  NULL, (int64_t)stats.st_mtime, false, time_st, date_st, &is_today, &is_yesterday);
2720  if (is_today || is_yesterday) {
2721  BLI_strncpy(date_st, is_today ? TIP_("Today") : TIP_("Yesterday"), sizeof(date_st));
2722  }
2723 
2724  /* Size. */
2725  char size_str[FILELIST_DIRENTRY_SIZE_LEN];
2726  BLI_filelist_entry_size_to_string(NULL, (uint64_t)stats.st_size, false, size_str);
2727 
2728  return BLI_sprintfN(
2729  "%s\n\n%s: %s %s\n%s: %s", path, TIP_("Modified"), date_st, time_st, TIP_("Size"), size_str);
2730 }
2731 
2732 /* currently fits in a pointer */
2733 struct FileRuntime {
2735 };
2736 BLI_STATIC_ASSERT(sizeof(struct FileRuntime) <= sizeof(void *),
2737  "Struct must not exceed pointer size");
2738 
2740 {
2741  struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
2742  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
2743  bool is_untrusted = false;
2744  char path[FILE_MAX];
2745  char *lslash;
2746 
2747  RNA_string_get(op->ptr, "filepath", path);
2748 
2749  /* get the dir */
2750  lslash = (char *)BLI_path_slash_rfind(path);
2751  if (lslash) {
2752  *(lslash + 1) = '\0';
2753  }
2754 
2755  if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
2756  if (BKE_autoexec_match(path) == true) {
2757  RNA_property_boolean_set(op->ptr, prop, false);
2758  is_untrusted = true;
2759  }
2760  }
2761 
2762  if (file_info) {
2763  file_info->is_untrusted = is_untrusted;
2764  }
2765 
2766  return is_untrusted;
2767 }
2768 
2770 {
2771  struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
2772  uiLayout *layout = op->layout;
2773  const char *autoexec_text;
2774 
2775  uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
2776 
2777  uiLayout *col = uiLayoutColumn(layout, false);
2778  if (file_info->is_untrusted) {
2779  autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
2780  uiLayoutSetActive(col, false);
2781  uiLayoutSetEnabled(col, false);
2782  }
2783  else {
2784  autoexec_text = IFACE_("Trusted Source");
2785  }
2786 
2787  uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
2788 }
2789 
2791 {
2793  "use_scripts",
2794  true,
2795  "Trusted Source",
2796  "Allow .blend file to execute scripts automatically, default available from "
2797  "system preferences");
2798 }
2799 
2801 {
2802  ot->name = "Open";
2803  ot->idname = "WM_OT_open_mainfile";
2804  ot->description = "Open a Blender file";
2806 
2811  /* omit window poll so this can work in background mode */
2812 
2815  FILE_BLENDER,
2816  FILE_OPENFILE,
2820 
2822  ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
2823 
2825 
2826  PropertyRNA *prop = RNA_def_boolean(
2827  ot->srna, "display_file_selector", true, "Display File Selector", "");
2829 
2831 }
2832 
2835 /* -------------------------------------------------------------------- */
2840 {
2841  Main *bmain = CTX_data_main(C);
2842  bool success;
2843  char filepath[FILE_MAX];
2844 
2845  wm_open_init_use_scripts(op, false);
2846 
2848 
2849  BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
2850  success = wm_file_read_opwrap(C, filepath, op->reports);
2851 
2852  if (success) {
2853  return OPERATOR_FINISHED;
2854  }
2855  return OPERATOR_CANCELLED;
2856 }
2857 
2859 {
2860  const char *blendfile_path = BKE_main_blendfile_path_from_global();
2861  return (blendfile_path[0] != '\0');
2862 }
2863 
2865 {
2866  ot->name = "Revert";
2867  ot->idname = "WM_OT_revert_mainfile";
2868  ot->description = "Reload the saved file";
2869 
2873 
2875 }
2876 
2879 /* -------------------------------------------------------------------- */
2884 {
2885  char filepath[FILE_MAX];
2886  BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
2887  G.fileflags |= G_FILE_RECOVER_READ;
2888  const bool success = wm_file_read_opwrap(C, filepath, reports);
2889  G.fileflags &= ~G_FILE_RECOVER_READ;
2890  return success;
2891 }
2892 
2894 {
2895  wm_open_init_use_scripts(op, true);
2898  if (!G.background) {
2899  wmOperatorType *ot = op->type;
2900  PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__);
2902  RNA_boolean_set(props_ptr, "use_scripts", true);
2904  }
2905  return OPERATOR_FINISHED;
2906  }
2907  return OPERATOR_CANCELLED;
2908 }
2909 
2911 {
2913  C, "WM_OT_recover_last_session", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data, NULL);
2914 }
2915 
2917  wmOperator *op,
2918  const wmEvent *UNUSED(event))
2919 {
2920  /* Keep the current setting instead of using the preferences since a file selector
2921  * doesn't give us the option to change the setting. */
2922  wm_open_init_use_scripts(op, false);
2923 
2926  return OPERATOR_INTERFACE;
2927  }
2928  return wm_recover_last_session_exec(C, op);
2929 }
2930 
2932 {
2933  ot->name = "Recover Last Session";
2934  ot->idname = "WM_OT_recover_last_session";
2935  ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
2936 
2939 
2941 }
2942 
2945 /* -------------------------------------------------------------------- */
2950 {
2951  char filepath[FILE_MAX];
2952  bool success;
2953 
2954  RNA_string_get(op->ptr, "filepath", filepath);
2955 
2956  wm_open_init_use_scripts(op, true);
2958 
2959  G.fileflags |= G_FILE_RECOVER_READ;
2960 
2961  success = wm_file_read_opwrap(C, filepath, op->reports);
2962 
2963  G.fileflags &= ~G_FILE_RECOVER_READ;
2964 
2965  if (success) {
2966  if (!G.background) {
2967  wmOperatorType *ot = op->type;
2968  PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__);
2970  RNA_boolean_set(props_ptr, "use_scripts", true);
2972  }
2973  return OPERATOR_FINISHED;
2974  }
2975  return OPERATOR_CANCELLED;
2976 }
2977 
2979 {
2980  char filepath[FILE_MAX];
2981 
2982  wm_autosave_location(filepath);
2983  RNA_string_set(op->ptr, "filepath", filepath);
2984  wm_open_init_use_scripts(op, true);
2986 
2987  return OPERATOR_RUNNING_MODAL;
2988 }
2989 
2991 {
2992  ot->name = "Recover Auto Save";
2993  ot->idname = "WM_OT_recover_auto_save";
2994  ot->description = "Open an automatically saved file to recover it";
2995 
2998 
3001  FILE_BLENDER,
3002  FILE_OPENFILE,
3005  FILE_SORT_TIME);
3006 
3008 }
3009 
3012 /* -------------------------------------------------------------------- */
3018 static void wm_filepath_default(const Main *bmain, char *filepath)
3019 {
3020  if (bmain->filepath[0] == '\0') {
3021  BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend");
3022  }
3023 }
3024 
3026 {
3027  PropertyRNA *prop;
3028 
3029  prop = RNA_struct_find_property(op->ptr, "compress");
3030  if (!RNA_property_is_set(op->ptr, prop)) {
3031  const char *blendfile_path = BKE_main_blendfile_path_from_global();
3032  if (blendfile_path[0] != '\0') { /* Keep flag for existing file. */
3033  RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
3034  }
3035  else { /* use userdef for new file */
3036  RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
3037  }
3038  }
3039 }
3040 
3042 {
3043  Main *bmain = CTX_data_main(C);
3044  PropertyRNA *prop;
3045  char filepath[FILE_MAX];
3046 
3047  prop = RNA_struct_find_property(op->ptr, "filepath");
3048  if (!RNA_property_is_set(op->ptr, prop)) {
3049  const char *blendfile_path = BKE_main_blendfile_path(bmain);
3050  /* if not saved before, get the name of the most recently used .blend file */
3051  if ((blendfile_path[0] == '\0') && G.recent_files.first) {
3052  struct RecentFile *recent = G.recent_files.first;
3053  STRNCPY(filepath, recent->filepath);
3054  }
3055  else {
3056  STRNCPY(filepath, blendfile_path);
3057  }
3058 
3059  wm_filepath_default(bmain, filepath);
3060  RNA_property_string_set(op->ptr, prop, filepath);
3061  }
3062 }
3063 
3065 {
3066 
3067  save_set_compress(op);
3068  save_set_filepath(C, op);
3069 
3070  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
3071  if (!RNA_property_is_set(op->ptr, prop)) {
3072  RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_RELPATHS));
3073  }
3074 
3076 
3077  return OPERATOR_RUNNING_MODAL;
3078 }
3079 
3080 /* function used for WM_OT_save_mainfile too */
3082 {
3083  Main *bmain = CTX_data_main(C);
3084  char path[FILE_MAX];
3085  const bool is_save_as = (op->type->invoke == wm_save_as_mainfile_invoke);
3086  const bool use_save_as_copy = is_save_as && RNA_boolean_get(op->ptr, "copy");
3087 
3088  /* We could expose all options to the users however in most cases remapping
3089  * existing relative paths is a good default.
3090  * Users can manually make their paths relative & absolute if they wish. */
3091  const eBLO_WritePathRemap remap_mode = RNA_boolean_get(op->ptr, "relative_remap") ?
3094  save_set_compress(op);
3095 
3096  const bool is_filepath_set = RNA_struct_property_is_set(op->ptr, "filepath");
3097  if (is_filepath_set) {
3098  RNA_string_get(op->ptr, "filepath", path);
3099  }
3100  else {
3101  STRNCPY(path, BKE_main_blendfile_path(bmain));
3102  }
3103 
3104  if (path[0] == '\0') {
3105  BKE_report(op->reports,
3106  RPT_ERROR,
3107  "Unable to save an unsaved file with an empty or unset \"filepath\" property");
3108  return OPERATOR_CANCELLED;
3109  }
3110 
3111  /* NOTE(@campbellbarton): only check this for file-path properties so saving an already
3112  * saved file never fails with an error.
3113  * Even though this should never happen, there may be some corner case where a malformed
3114  * path is stored in `G.main->filepath`: when the file path is initialized from recovering
3115  * a blend file - for example, so in this case failing to save isn't ideal. */
3116  if (is_filepath_set && !BLI_path_is_abs_from_cwd(path)) {
3117  BKE_reportf(op->reports,
3118  RPT_ERROR,
3119  "The \"filepath\" property was not an absolute path: \"%s\"",
3120  path);
3121  return OPERATOR_CANCELLED;
3122  }
3123 
3124  const int fileflags_orig = G.fileflags;
3125  int fileflags = G.fileflags;
3126 
3127  /* set compression flag */
3128  SET_FLAG_FROM_TEST(fileflags, RNA_boolean_get(op->ptr, "compress"), G_FILE_COMPRESS);
3129 
3130  const bool ok = wm_file_write(C, path, fileflags, remap_mode, use_save_as_copy, op->reports);
3131 
3132  if ((op->flag & OP_IS_INVOKE) == 0) {
3133  /* OP_IS_INVOKE is set when the operator is called from the GUI.
3134  * If it is not set, the operator is called from a script and
3135  * shouldn't influence G.fileflags. */
3136  G.fileflags = fileflags_orig;
3137  }
3138 
3139  if (ok == false) {
3140  return OPERATOR_CANCELLED;
3141  }
3142 
3143  if (!is_save_as) {
3144  /* If saved as current file, there are technically no more compatibility issues, the file on
3145  * disk now matches the currently opened data version-wise. */
3146  bmain->has_forward_compatibility_issues = false;
3147  }
3148 
3150 
3151  if (!is_save_as && RNA_boolean_get(op->ptr, "exit")) {
3153  }
3154 
3155  return OPERATOR_FINISHED;
3156 }
3157 
3158 /* function used for WM_OT_save_mainfile too */
3160 {
3161  char filepath[FILE_MAX];
3162  RNA_string_get(op->ptr, "filepath", filepath);
3164  /* some users would prefer BLI_path_extension_replace(),
3165  * we keep getting nitpicking bug reports about this - campbell */
3167  RNA_string_set(op->ptr, "filepath", filepath);
3168  return true;
3169  }
3170  return false;
3171 }
3172 
3174 {
3175  if (RNA_boolean_get(ptr, "copy")) {
3176  return CTX_IFACE_(ot->translation_context, "Save Copy");
3177  }
3178  return NULL;
3179 }
3180 
3183  PointerRNA *ptr)
3184 {
3185  if (RNA_boolean_get(ptr, "copy")) {
3186  return BLI_strdup(TIP_(
3187  "Save the current file in the desired location but do not make the saved file active"));
3188  }
3189  return NULL;
3190 }
3191 
3193 {
3194  PropertyRNA *prop;
3195 
3196  ot->name = "Save As";
3197  ot->idname = "WM_OT_save_as_mainfile";
3198  ot->description = "Save the current file in the desired location";
3199 
3205  /* omit window poll so this can work in background mode */
3206 
3209  FILE_BLENDER,
3210  FILE_SAVE,
3214  RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
3216  "relative_remap",
3217  true,
3218  "Remap Relative",
3219  "Remap relative paths when saving to a different directory");
3220  prop = RNA_def_boolean(
3221  ot->srna,
3222  "copy",
3223  false,
3224  "Save Copy",
3225  "Save a copy of the actual working state but does not make saved file active");
3227 }
3228 
3229 static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
3230 {
3231  int ret;
3232 
3233  /* cancel if no active window */
3234  if (CTX_wm_window(C) == NULL) {
3235  return OPERATOR_CANCELLED;
3236  }
3237 
3238  save_set_compress(op);
3239  save_set_filepath(C, op);
3240 
3241  /* if we're saving for the first time and prefer relative paths -
3242  * any existing paths will be absolute,
3243  * enable the option to remap paths to avoid confusion T37240. */
3244  const char *blendfile_path = BKE_main_blendfile_path_from_global();
3245  if ((blendfile_path[0] == '\0') && (U.flag & USER_RELPATHS)) {
3246  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
3247  if (!RNA_property_is_set(op->ptr, prop)) {
3248  RNA_property_boolean_set(op->ptr, prop, true);
3249  }
3250  }
3251 
3252  if (blendfile_path[0] != '\0') {
3253  if (CTX_data_main(C)->has_forward_compatibility_issues) {
3256  }
3257  else {
3258  char path[FILE_MAX];
3259 
3260  RNA_string_get(op->ptr, "filepath", path);
3262  }
3263  }
3264  else {
3267  }
3268 
3269  return ret;
3270 }
3271 
3273 {
3274  ot->name = "Save Blender File";
3275  ot->idname = "WM_OT_save_mainfile";
3276  ot->description = "Save the current Blender file";
3277 
3281  /* omit window poll so this can work in background mode */
3282 
3283  PropertyRNA *prop;
3286  FILE_BLENDER,
3287  FILE_SAVE,
3291  RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
3293  "relative_remap",
3294  false,
3295  "Remap Relative",
3296  "Remap relative paths when saving to a different directory");
3297 
3298  prop = RNA_def_boolean(ot->srna, "exit", false, "Exit", "Exit Blender after saving");
3300 }
3301 
3304 /* -------------------------------------------------------------------- */
3308 static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *UNUSED(arg))
3309 {
3310  wmWindow *win = CTX_wm_window(C);
3311  UI_popup_block_close(C, win, arg_block);
3312 
3313  /* Free the data as it's no longer needed. */
3315 }
3316 
3318  void *arg_block,
3319  void *UNUSED(arg))
3320 {
3321  wmWindow *win = CTX_wm_window(C);
3322 
3323  UI_popup_block_close(C, win, arg_block);
3324 
3325  /* Save user preferences for permanent execution. */
3326  if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
3327  WM_operator_name_call(C, "WM_OT_save_userpref", WM_OP_EXEC_DEFAULT, NULL, NULL);
3328  }
3329 
3330  /* Load file again with scripts enabled.
3331  * The reload is necessary to allow scripts to run when the files loads. */
3333 }
3334 
3336  void *arg_block,
3337  void *UNUSED(arg))
3338 {
3339  wmWindow *win = CTX_wm_window(C);
3340  Main *bmain = CTX_data_main(C);
3341 
3342  UI_popup_block_close(C, win, arg_block);
3343 
3344  /* Save user preferences for permanent execution. */
3345  if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
3346  WM_operator_name_call(C, "WM_OT_save_userpref", WM_OP_EXEC_DEFAULT, NULL, NULL);
3347  }
3348 
3349  /* Force a full refresh, but without reloading the file. */
3350  LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
3352  }
3353 }
3354 
3355 /* Build the autorun warning dialog UI */
3357  struct ARegion *region,
3358  void *UNUSED(arg1))
3359 {
3360  const char *blendfile_path = BKE_main_blendfile_path_from_global();
3362 
3363  uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS);
3368 
3369  uiLayout *layout = uiItemsAlertBox(block, 44, ALERT_ICON_ERROR);
3370 
3371  /* Title and explanation text. */
3372  uiLayout *col = uiLayoutColumn(layout, true);
3373  uiItemL_ex(col,
3374  TIP_("For security reasons, automatic execution of Python scripts "
3375  "in this file was disabled:"),
3376  ICON_NONE,
3377  true,
3378  false);
3379  uiItemL_ex(col, G.autoexec_fail, ICON_NONE, false, true);
3380  uiItemL(col, TIP_("This may lead to unexpected behavior"), ICON_NONE);
3381 
3382  uiItemS(layout);
3383 
3384  PointerRNA pref_ptr;
3385  RNA_pointer_create(NULL, &RNA_PreferencesFilePaths, &U, &pref_ptr);
3386  uiItemR(layout,
3387  &pref_ptr,
3388  "use_scripts_auto_execute",
3389  0,
3390  TIP_("Permanently allow execution of scripts"),
3391  ICON_NONE);
3392 
3393  uiItemS_ex(layout, 3.0f);
3394 
3395  /* Buttons */
3396  uiBut *but;
3397  uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
3398  uiLayoutSetScaleY(split, 1.2f);
3399 
3400  /* empty space */
3401  col = uiLayoutColumn(split, false);
3402  uiItemS(col);
3403 
3404  col = uiLayoutColumn(split, false);
3405 
3406  /* Allow reload if we have a saved file.
3407  * Otherwise just enable scripts and reset the depsgraphs. */
3408  if ((blendfile_path[0] != '\0') && wm->file_saved) {
3409  but = uiDefIconTextBut(block,
3410  UI_BTYPE_BUT,
3411  0,
3412  ICON_NONE,
3413  IFACE_("Allow Execution"),
3414  0,
3415  0,
3416  50,
3417  UI_UNIT_Y,
3418  NULL,
3419  0,
3420  0,
3421  0,
3422  0,
3423  TIP_("Reload file with execution of Python scripts enabled"));
3425  }
3426  else {
3427  but = uiDefIconTextBut(block,
3428  UI_BTYPE_BUT,
3429  0,
3430  ICON_NONE,
3431  IFACE_("Allow Execution"),
3432  0,
3433  0,
3434  50,
3435  UI_UNIT_Y,
3436  NULL,
3437  0,
3438  0,
3439  0,
3440  0,
3441  TIP_("Enable scripts"));
3443  }
3445 
3446  col = uiLayoutColumn(split, false);
3447  but = uiDefIconTextBut(block,
3448  UI_BTYPE_BUT,
3449  0,
3450  ICON_NONE,
3451  IFACE_("Ignore"),
3452  0,
3453  0,
3454  50,
3455  UI_UNIT_Y,
3456  NULL,
3457  0,
3458  0,
3459  0,
3460  0,
3461  TIP_("Continue using file without Python scripts"));
3465 
3466  UI_block_bounds_set_centered(block, 14 * U.dpi_fac);
3467 
3468  return block;
3469 }
3470 
3478 static struct {
3482  .ot = NULL,
3483  .ptr = NULL,
3484 };
3485 
3487 {
3488  BLI_assert(!G.background);
3494  }
3497 }
3498 
3500 {
3503 
3504  /* Use regular revert. */
3505  if (ot == NULL) {
3506  ot = WM_operatortype_find("WM_OT_revert_mainfile", false);
3507  ptr = MEM_callocN(sizeof(PointerRNA), __func__);
3509  RNA_boolean_set(ptr, "use_scripts", true);
3510 
3511  /* Set state, so it's freed correctly */
3513  }
3514 
3517 }
3518 
3520 {
3521  /* Test if any auto-execution of scripts failed. */
3522  if ((G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL) == 0) {
3523  return;
3524  }
3525 
3526  /* Only show the warning once. */
3528  return;
3529  }
3530 
3532 
3534  wmWindow *win = (wm->winactive) ? wm->winactive : wm->windows.first;
3535 
3536  if (win) {
3537  wmWindow *prevwin = CTX_wm_window(C);
3538  CTX_wm_window_set(C, win);
3540  CTX_wm_window_set(C, prevwin);
3541  }
3542 }
3543 
3546 /* -------------------------------------------------------------------- */
3550 static void free_post_file_close_action(void *arg)
3551 {
3552  wmGenericCallback *action = (wmGenericCallback *)arg;
3553  WM_generic_callback_free(action);
3554 }
3555 
3557 {
3558  IDProperty *properties = (IDProperty *)user_data;
3559  IDP_FreeProperty(properties);
3560 }
3561 
3562 static const char *save_file_forwardcompat_dialog_name = "save_file_forwardcompat_popup";
3563 
3564 static void file_forwardcompat_detailed_info_show(uiLayout *parent_layout, Main *bmain)
3565 {
3566  uiLayout *layout = uiLayoutColumn(parent_layout, true);
3567  /* Trick to make both lines of text below close enough to look like they are part of a same
3568  * block. */
3569  uiLayoutSetScaleY(layout, 0.70f);
3570 
3571  char writer_ver_str[16];
3572  char current_ver_str[16];
3573  if (bmain->versionfile == BLENDER_VERSION) {
3575  writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, bmain->subversionfile);
3577  current_ver_str, sizeof(current_ver_str), BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION);
3578  }
3579  else {
3581  writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
3583  current_ver_str, sizeof(current_ver_str), BLENDER_VERSION, -1);
3584  }
3585 
3586  char message_line1[256];
3587  char message_line2[256];
3588  SNPRINTF(message_line1,
3589  TIP_("This file was saved by a newer version of Blender (%s)"),
3590  writer_ver_str);
3591  SNPRINTF(message_line2,
3592  TIP_("Saving it with this Blender (%s) may cause loss of data"),
3593  current_ver_str);
3594  uiItemL(layout, message_line1, ICON_NONE);
3595  uiItemL(layout, message_line2, ICON_NONE);
3596 }
3597 
3598 static void save_file_forwardcompat_cancel(bContext *C, void *arg_block, void *UNUSED(arg_data))
3599 {
3600  wmWindow *win = CTX_wm_window(C);
3601  UI_popup_block_close(C, win, arg_block);
3602 }
3603 
3605 {
3606  uiBut *but = uiDefIconTextBut(
3607  block, UI_BTYPE_BUT, 0, 0, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
3608  UI_but_func_set(but, save_file_forwardcompat_cancel, block, post_action);
3610 }
3611 
3612 static void save_file_forwardcompat_overwrite(bContext *C, void *arg_block, void *arg_data)
3613 {
3614  wmWindow *win = CTX_wm_window(C);
3615 
3616  /* Re-use operator properties as defined for the initial 'save' operator, which triggered this
3617  * 'forward compat' popup. */
3619 
3620  /* Needs to be done after stealing the callback data above, otherwise it would cause a
3621  * use-after-free. */
3622  UI_popup_block_close(C, win, arg_block);
3623 
3624  PointerRNA operator_propptr = {0};
3625  PointerRNA *operator_propptr_p = &operator_propptr;
3626  IDProperty *operator_idproperties = callback->user_data;
3627  WM_operator_properties_alloc(&operator_propptr_p, &operator_idproperties, "WM_OT_save_mainfile");
3628 
3629  WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, operator_propptr_p, NULL);
3630 
3632 }
3633 
3635  wmGenericCallback *post_action)
3636 {
3637  uiBut *but = uiDefIconTextBut(
3638  block, UI_BTYPE_BUT, 0, 0, IFACE_("Overwrite"), 0, 0, 0, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
3639  UI_but_func_set(but, save_file_forwardcompat_overwrite, block, post_action);
3642 }
3643 
3644 static void save_file_forwardcompat_saveas(bContext *C, void *arg_block, void *UNUSED(arg_data))
3645 {
3646  wmWindow *win = CTX_wm_window(C);
3647  UI_popup_block_close(C, win, arg_block);
3648 
3649  WM_operator_name_call(C, "WM_OT_save_as_mainfile", WM_OP_INVOKE_DEFAULT, NULL, NULL);
3650 }
3651 
3653 {
3654  uiBut *but = uiDefIconTextBut(
3655  block, UI_BTYPE_BUT, 0, 0, IFACE_("Save As..."), 0, 0, 0, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
3656  UI_but_func_set(but, save_file_forwardcompat_saveas, block, post_action);
3659 }
3660 
3662  ARegion *region,
3663  void *arg1)
3664 {
3665  wmGenericCallback *post_action = arg1;
3666  Main *bmain = CTX_data_main(C);
3667 
3672 
3673  uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_WARNING);
3674 
3675  /* Title. */
3676  uiItemL_ex(
3677  layout, TIP_("Overwrite file with an older Blender version?"), ICON_NONE, true, false);
3678 
3679  /* Filename. */
3680  const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C));
3681  char filename[FILE_MAX];
3682  if (blendfile_path[0] != '\0') {
3683  BLI_split_file_part(blendfile_path, filename, sizeof(filename));
3684  }
3685  else {
3686  SNPRINTF(filename, "%s.blend", DATA_("untitled"));
3687  /* Since this dialog should only be shown when re-saving an existing file, current filepath
3688  * should never be empty. */
3690  }
3691  uiItemL(layout, filename, ICON_NONE);
3692 
3693  /* Detailed message info. */
3695 
3696  uiItemS_ex(layout, 4.0f);
3697 
3698  /* Buttons. */
3699 
3700  uiLayout *split = uiLayoutSplit(layout, 0.3f, true);
3701  uiLayoutSetScaleY(split, 1.2f);
3702 
3703  uiLayoutColumn(split, false);
3704  save_file_forwardcompat_overwrite_button(block, post_action);
3705 
3706  uiLayout *split_right = uiLayoutSplit(split, 0.1f, true);
3707 
3708  uiLayoutColumn(split_right, false);
3709  /* Empty space. */
3710 
3711  uiLayoutColumn(split_right, false);
3712  save_file_forwardcompat_cancel_button(block, post_action);
3713 
3714  uiLayoutColumn(split_right, false);
3715  save_file_forwardcompat_saveas_button(block, post_action);
3716 
3718  return block;
3719 }
3720 
3722 {
3724  wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
3725  callback->exec = NULL;
3726  callback->user_data = IDP_CopyProperty(op->properties);
3728 
3731  }
3732 }
3733 
3736 /* -------------------------------------------------------------------- */
3741 
3742 static void wm_block_file_close_cancel(bContext *C, void *arg_block, void *UNUSED(arg_data))
3743 {
3744  wmWindow *win = CTX_wm_window(C);
3745  UI_popup_block_close(C, win, arg_block);
3746 }
3747 
3748 static void wm_block_file_close_discard(bContext *C, void *arg_block, void *arg_data)
3749 {
3751 
3752  /* Close the popup before executing the callback. Otherwise
3753  * the popup might be closed by the callback, which will lead
3754  * to a crash. */
3755  wmWindow *win = CTX_wm_window(C);
3756  UI_popup_block_close(C, win, arg_block);
3757 
3758  callback->exec(C, callback->user_data);
3760 }
3761 
3762 static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_data)
3763 {
3764  const Main *bmain = CTX_data_main(C);
3766  bool execute_callback = true;
3767 
3768  wmWindow *win = CTX_wm_window(C);
3769  UI_popup_block_close(C, win, arg_block);
3770 
3771  int modified_images_count = ED_image_save_all_modified_info(CTX_data_main(C), NULL);
3772  if (modified_images_count > 0 && save_images_when_file_is_closed) {
3773  if (ED_image_should_save_modified(bmain)) {
3774  ReportList *reports = CTX_wm_reports(C);
3775  ED_image_save_all_modified(C, reports);
3777  }
3778  else {
3779  execute_callback = false;
3780  }
3781  }
3782 
3783  bool file_has_been_saved_before = BKE_main_blendfile_path(bmain)[0] != '\0';
3784 
3785  if (file_has_been_saved_before) {
3786  if (bmain->has_forward_compatibility_issues) {
3787  /* Need to invoke to get the filebrowser and choose where to save the new file.
3788  * This also makes it impossible to keep on going with current operation, which is why
3789  * callback cannot be executed anymore.
3790  *
3791  * This is the same situation as what happens when the file has never been saved before
3792  * (outer `else` statement, below). */
3793  WM_operator_name_call(C, "WM_OT_save_as_mainfile", WM_OP_INVOKE_DEFAULT, NULL, NULL);
3794  execute_callback = false;
3795  }
3796  else {
3797  if (WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL, NULL) &
3799  execute_callback = false;
3800  }
3801  }
3802  }
3803  else {
3804  WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_INVOKE_DEFAULT, NULL, NULL);
3805  execute_callback = false;
3806  }
3807 
3808  if (execute_callback) {
3809  callback->exec(C, callback->user_data);
3810  }
3812 }
3813 
3815 {
3816  uiBut *but = uiDefIconTextBut(
3817  block, UI_BTYPE_BUT, 0, 0, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, "");
3818  UI_but_func_set(but, wm_block_file_close_cancel, block, post_action);
3820 }
3821 
3823 {
3824  uiBut *but = uiDefIconTextBut(
3825  block, UI_BTYPE_BUT, 0, 0, IFACE_("Don't Save"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, "");
3826  UI_but_func_set(but, wm_block_file_close_discard, block, post_action);
3828 }
3829 
3831  wmGenericCallback *post_action,
3832  const bool has_forwardcompat_issues)
3833 {
3834  uiBut *but = uiDefIconTextBut(
3835  block,
3836  UI_BTYPE_BUT,
3837  0,
3838  0,
3839  /* Forward compatibility issues force using 'save as' operator instead of 'save' one. */
3840  has_forwardcompat_issues ? IFACE_("Save As...") : IFACE_("Save"),
3841  0,
3842  0,
3843  0,
3844  UI_UNIT_Y,
3845  NULL,
3846  0,
3847  0,
3848  0,
3849  0,
3850  "");
3851  UI_but_func_set(but, wm_block_file_close_save, block, post_action);
3854 }
3855 
3856 static const char *close_file_dialog_name = "file_close_popup";
3857 
3859  void *arg1,
3860  void *UNUSED(arg2))
3861 {
3862  char *save_catalogs_when_file_is_closed = arg1;
3863  ED_asset_catalogs_set_save_catalogs_when_file_is_saved(*save_catalogs_when_file_is_closed != 0);
3864 }
3865 
3867  struct ARegion *region,
3868  void *arg1)
3869 {
3870  wmGenericCallback *post_action = (wmGenericCallback *)arg1;
3871  Main *bmain = CTX_data_main(C);
3872 
3877 
3878  uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_QUESTION);
3879 
3880  const bool has_forwardcompat_issues = bmain->has_forward_compatibility_issues;
3881 
3882  /* Title. */
3883  uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false);
3884 
3885  /* Filename. */
3886  const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C));
3887  char filename[FILE_MAX];
3888  if (blendfile_path[0] != '\0') {
3889  BLI_split_file_part(blendfile_path, filename, sizeof(filename));
3890  }
3891  else {
3892  STRNCPY(filename, "untitled.blend");
3893  }
3894  uiItemL(layout, filename, ICON_NONE);
3895 
3896  /* Potential forward compatibility issues message. */
3897  if (has_forwardcompat_issues) {
3899  }
3900 
3901  /* Image Saving Warnings. */
3902  ReportList reports;
3903  BKE_reports_init(&reports, RPT_STORE);
3904  uint modified_images_count = ED_image_save_all_modified_info(bmain, &reports);
3905 
3906  LISTBASE_FOREACH (Report *, report, &reports.list) {
3907  uiLayout *row = uiLayoutColumn(layout, false);
3908  uiLayoutSetScaleY(row, 0.6f);
3909  uiItemS(row);
3910 
3911  /* Error messages created in ED_image_save_all_modified_info() can be long,
3912  * but are made to separate into two parts at first colon between text and paths.
3913  */
3914  char *message = BLI_strdupn(report->message, report->len);
3915  char *path_info = strstr(message, ": ");
3916  if (path_info) {
3917  /* Terminate message string at colon. */
3918  path_info[1] = '\0';
3919  /* Skip over the ": " */
3920  path_info += 2;
3921  }
3922  uiItemL_ex(row, message, ICON_NONE, false, true);
3923  if (path_info) {
3924  uiItemL_ex(row, path_info, ICON_NONE, false, true);
3925  }
3926  MEM_freeN(message);
3927  }
3928 
3929  /* Used to determine if extra separators are needed. */
3930  bool has_extra_checkboxes = false;
3931 
3932  /* Modified Images Checkbox. */
3933  if (modified_images_count > 0) {
3934  char message[64];
3935  BLI_snprintf(message, sizeof(message), "Save %u modified image(s)", modified_images_count);
3936  /* Only the first checkbox should get extra separation. */
3937  if (!has_extra_checkboxes) {
3938  uiItemS(layout);
3939  }
3940  uiDefButBitC(block,
3942  1,
3943  0,
3944  message,
3945  0,
3946  0,
3947  0,
3948  UI_UNIT_Y,
3950  0,
3951  0,
3952  0,
3953  0,
3954  "");
3955  has_extra_checkboxes = true;
3956  }
3957 
3959  static char save_catalogs_when_file_is_closed;
3960 
3961  save_catalogs_when_file_is_closed = ED_asset_catalogs_get_save_catalogs_when_file_is_saved();
3962 
3963  /* Only the first checkbox should get extra separation. */
3964  if (!has_extra_checkboxes) {
3965  uiItemS(layout);
3966  }
3967  uiBut *but = uiDefButBitC(block,
3969  1,
3970  0,
3971  "Save modified asset catalogs",
3972  0,
3973  0,
3974  0,
3975  UI_UNIT_Y,
3976  &save_catalogs_when_file_is_closed,
3977  0,
3978  0,
3979  0,
3980  0,
3981  "");
3983  but, save_catalogs_when_file_is_closed_set_fn, &save_catalogs_when_file_is_closed, NULL);
3984  has_extra_checkboxes = true;
3985  }
3986 
3987  BKE_reports_clear(&reports);
3988 
3989  uiItemS_ex(layout, has_extra_checkboxes ? 2.0f : 4.0f);
3990 
3991  /* Buttons. */
3992 #ifdef _WIN32
3993  const bool windows_layout = true;
3994 #else
3995  const bool windows_layout = false;
3996 #endif
3997 
3998  if (windows_layout) {
3999  /* Windows standard layout. */
4000 
4001  uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
4002  uiLayoutSetScaleY(split, 1.2f);
4003 
4004  uiLayoutColumn(split, false);
4005  wm_block_file_close_save_button(block, post_action, has_forwardcompat_issues);
4006 
4007  uiLayoutColumn(split, false);
4008  wm_block_file_close_discard_button(block, post_action);
4009 
4010  uiLayoutColumn(split, false);
4011  wm_block_file_close_cancel_button(block, post_action);
4012  }
4013  else {
4014  /* Non-Windows layout (macOS and Linux). */
4015 
4016  uiLayout *split = uiLayoutSplit(layout, 0.3f, true);
4017  uiLayoutSetScaleY(split, 1.2f);
4018 
4019  uiLayoutColumn(split, false);
4020  wm_block_file_close_discard_button(block, post_action);
4021 
4022  uiLayout *split_right = uiLayoutSplit(split, 0.1f, true);
4023 
4024  uiLayoutColumn(split_right, false);
4025  /* Empty space. */
4026 
4027  uiLayoutColumn(split_right, false);
4028  wm_block_file_close_cancel_button(block, post_action);
4029 
4030  uiLayoutColumn(split_right, false);
4031  wm_block_file_close_save_button(block, post_action, has_forwardcompat_issues);
4032  }
4033 
4034  UI_block_bounds_set_centered(block, 14 * U.dpi_fac);
4035  return block;
4036 }
4037 
4039 {
4043  }
4044  else {
4045  WM_generic_callback_free(post_action);
4046  }
4047 }
4048 
4050  wmOperator *op,
4051  wmGenericCallbackFn post_action_fn)
4052 {
4053  if (U.uiflag & USER_SAVE_PROMPT &&
4055  wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
4056  callback->exec = post_action_fn;
4057  callback->user_data = IDP_CopyProperty(op->properties);
4060  return true;
4061  }
4062 
4063  return false;
4064 }
4065 
bool BKE_addon_remove_safe(struct ListBase *addon_list, const char *module)
Definition: addon.c:55
bool BKE_appdir_app_template_any(void)
Definition: appdir.c:966
void BKE_tempdir_init(const char *userdir)
Definition: appdir.c:1133
const char * BKE_appdir_folder_id_create(int folder_id, const char *subfolder)
Definition: appdir.c:727
#define BLENDER_USERPREF_FILE
Definition: BKE_appdir.h:176
const char * BKE_appdir_folder_id(int folder_id, const char *subfolder)
Definition: appdir.c:672
bool BKE_appdir_app_template_has_userpref(const char *app_template)
Definition: appdir.c:992
#define BLENDER_HISTORY_FILE
Definition: BKE_appdir.h:179
#define BLENDER_STARTUP_FILE
Definition: BKE_appdir.h:175
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len)
Definition: appdir.c:980
#define BLENDER_QUIT_FILE
Definition: BKE_appdir.h:177
const char * BKE_tempdir_base(void)
Definition: appdir.c:1154
@ BLENDER_USER_AUTOSAVE
Definition: BKE_appdir.h:160
@ BLENDER_USER_CONFIG
Definition: BKE_appdir.h:157
bool BKE_asset_library_has_any_unsaved_catalogs(void)
bool BKE_autoexec_match(const char *path)
Definition: autoexec.c:25
Blender util stuff.
void BKE_blender_userdef_data_set_and_free(struct UserDef *userdef)
Definition: blender.c:216
void BKE_blender_userdef_app_template_data_set_and_free(struct UserDef *userdef)
Definition: blender.c:375
void BKE_blender_version_blendfile_string_from_values(char *str_buff, const size_t str_buff_len, const short file_version, const short file_subversion)
Definition: blender.c:129
#define BLENDER_FILE_SUBVERSION
#define BLENDER_VERSION
#define BLENDER_FILE_VERSION
struct UserDef * BKE_blendfile_userdef_read(const char *filepath, struct ReportList *reports)
Definition: blendfile.c:600
struct BlendFileData * BKE_blendfile_read(const char *filepath, const struct BlendFileReadParams *params, struct BlendFileReadReport *reports)
Definition: blendfile.c:514
struct BlendFileData * BKE_blendfile_read_from_memory(const void *filebuf, int filelength, const struct BlendFileReadParams *params, struct ReportList *reports)
Definition: blendfile.c:537
struct UserDef * BKE_blendfile_userdef_from_defaults(void)
Definition: blendfile.c:642
void BKE_blendfile_read_setup_ex(struct bContext *C, struct BlendFileData *bfd, const struct BlendFileReadParams *params, struct BlendFileReadReport *reports, bool startup_update_defaults, const char *startup_app_template)
Definition: blendfile.c:482
void BKE_blendfile_read_setup(struct bContext *C, struct BlendFileData *bfd, const struct BlendFileReadParams *params, struct BlendFileReadReport *reports)
Definition: blendfile.c:506
void BKE_blendfile_read_make_empty(struct bContext *C)
Definition: blendfile.c:582
bool BKE_blendfile_userdef_write_all(struct ReportList *reports)
Definition: blendfile.c:748
void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt)
Definition: callbacks.c:41
@ BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST
Definition: BKE_callbacks.h:96
@ BKE_CB_EVT_LOAD_FACTORY_USERDEF_POST
Definition: BKE_callbacks.h:95
@ BKE_CB_EVT_SAVE_PRE
Definition: BKE_callbacks.h:86
@ BKE_CB_EVT_VERSION_UPDATE
Definition: BKE_callbacks.h:94
@ BKE_CB_EVT_SAVE_POST
Definition: BKE_callbacks.h:87
@ BKE_CB_EVT_LOAD_POST
Definition: BKE_callbacks.h:85
@ BKE_CB_EVT_LOAD_PRE
Definition: BKE_callbacks.h:84
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
bool CTX_py_init_get(bContext *C)
Definition: context.c:233
void CTX_wm_menu_set(bContext *C, struct ARegion *menu)
Definition: context.c:1020
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
void CTX_wm_window_set(bContext *C, struct wmWindow *win)
Definition: context.c:966
struct ReportList * CTX_wm_reports(const bContext *C)
Definition: context.c:775
struct wmMsgBus * CTX_wm_message_bus(const bContext *C)
Definition: context.c:770
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm)
Definition: context.c:950
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
@ G_FILE_RECOVER_READ
Definition: BKE_global.h:225
@ G_FILE_AUTOPACK
Definition: BKE_global.h:209
@ G_FILE_RECOVER_WRITE
Definition: BKE_global.h:233
@ G_FILE_NO_UI
Definition: BKE_global.h:213
@ G_FILE_COMPRESS
Definition: BKE_global.h:210
#define G_FLAG_ALL_READFILE
Definition: BKE_global.h:170
#define G_MAIN
Definition: BKE_global.h:267
@ G_FLAG_SCRIPT_OVERRIDE_PREF
Definition: BKE_global.h:156
@ G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET
Definition: BKE_global.h:158
@ G_FLAG_USERPREF_NO_SAVE_ON_EXIT
Definition: BKE_global.h:152
@ G_FLAG_SCRIPT_AUTOEXEC_FAIL
Definition: BKE_global.h:157
@ G_FLAG_SCRIPT_AUTOEXEC
Definition: BKE_global.h:154
#define G_FLAG_ALL_RUNTIME
Definition: BKE_global.h:162
void IDP_FreeProperty(struct IDProperty *prop)
Definition: idprop.c:1093
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, bool force_auto)
@ ID_REMAP_SKIP_USER_CLEAR
Definition: BKE_lib_remap.h:63
@ ID_REMAP_SKIP_INDIRECT_USAGE
Definition: BKE_lib_remap.h:36
void void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, short remap_flags) ATTR_NONNULL(1
struct ImBuf * BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data)
Definition: main.c:532
#define BLEN_THUMB_SIZE
Definition: BKE_main.h:446
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:508
const char * BKE_main_blendfile_path_from_global(void)
Definition: main.c:562
bool BKE_main_namemap_validate(struct Main *bmain) ATTR_NONNULL()
bool BKE_main_namemap_get_name(struct Main *bmain, struct ID *id, char *name) ATTR_NONNULL()
void BKE_packedfile_pack_all(struct Main *bmain, struct ReportList *reports, bool verbose)
Definition: packedFile.c:230
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report_print_level_set(ReportList *reports, eReportType level)
Definition: report.c:204
void BKE_reports_clear(ReportList *reports)
Definition: report.c:63
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
void BKE_reports_init(ReportList *reports, int flag)
Definition: report.c:50
void BKE_scene_free_depsgraph_hash(struct Scene *scene)
Definition: scene.cc:3352
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
struct ARegion struct ARegion struct ScrArea struct ScrArea * BKE_screen_find_big_area(struct bScreen *screen, int spacetype, short min)
Definition: screen.c:937
void BKE_sound_init(struct Main *main)
UndoStack * BKE_undosys_stack_create(void)
Definition: undo_system.c:250
void BKE_undosys_stack_init_from_context(UndoStack *ustack, struct bContext *C)
Definition: undo_system.c:346
void BKE_undosys_stack_clear(UndoStack *ustack)
Definition: undo_system.c:262
void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
Definition: undo_system.c:340
void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace) SETTER_ATTRS
Definition: workspace.c:520
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:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:314
bool BLI_file_is_writable(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:167
#define O_BINARY
Definition: BLI_fileops.h:319
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:906
bool BLI_file_magic_is_gzip(const char header[4])
Definition: fileops.c:133
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL()
Definition: fileops.c:934
void BLI_filelist_entry_size_to_string(const struct stat *st, uint64_t st_size_fallback, bool compact, char r_size[FILELIST_DIRENTRY_SIZE_LEN])
int BLI_rename(const char *from, const char *to) ATTR_NONNULL()
Definition: fileops.c:1268
void BLI_file_free_lines(struct LinkNode *lines)
Definition: storage.c:564
bool BLI_file_magic_is_zstd(const char header[4])
Definition: fileops.c:140
struct stat BLI_stat_t
Definition: BLI_fileops.h:73
struct LinkNode * BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:518
int BLI_access(const char *filepath, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:927
void BLI_filelist_entry_datetime_to_string(const struct stat *st, int64_t ts, bool compact, char r_time[FILELIST_DIRENTRY_TIME_LEN], char r_date[FILELIST_DIRENTRY_DATE_LEN], bool *r_is_today, bool *r_is_yesterday)
Definition: BLI_filelist.c:323
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:920
Some types for dealing with directories.
#define FILELIST_DIRENTRY_SIZE_LEN
#define FILELIST_DIRENTRY_DATE_LEN
#define FILELIST_DIRENTRY_TIME_LEN
Wrapper for reading from various sources (e.g. raw files, compressed files, memory....
FileReader * BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT
FileReader * BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
FileReader * BLI_filereader_new_gzip(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:60
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
void * BLI_findstring_ptr(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
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)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int max_ii(int a, int b)
void BLI_math_time_seconds_decompose(double seconds, double *r_days, double *r_hours, double *r_minutes, double *r_seconds, double *r_milliseconds)
Definition: math_time.c:10
void BLI_split_dir_part(const char *string, char *dir, size_t dirlen)
Definition: path_util.c:1490
const char * BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1653
bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL()
Definition: path_util.c:1452
#define FILE_MAX
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL()
Definition: path_util.c:1420
bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:998
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
Definition: path_util.c:1206
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL()
Definition: path_util.c:1393
size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
const char * BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1765
void BLI_split_file_part(const char *string, char *file, size_t filelen)
Definition: path_util.c:1495
#define BLI_path_cmp
void BLI_join_dirfile(char *__restrict dst, size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1531
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:483
#define SNPRINTF(dst, format,...)
Definition: BLI_string.h:485
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:33
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:67
int BLI_thread_is_main(void)
Definition: threads.cc:207
void BLI_timer_on_file_load(void)
Definition: BLI_timer.c:141
#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:120
@ BLO_READ_SKIP_DATA
Definition: BLO_readfile.h:123
@ BLO_READ_SKIP_USERDEF
Definition: BLO_readfile.h:122
bool BLO_has_bfile_extension(const char *str)
Definition: readfile.c:1497
bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath)
Definition: undofile.c:198
external writefile.c function prototypes.
bool BLO_write_file(struct Main *mainvar, const char *filepath, int write_flags, const struct BlendFileWriteParams *params, struct ReportList *reports)
Definition: writefile.c:1315
eBLO_WritePathRemap
Definition: BLO_writefile.h:29
@ BLO_WRITE_PATH_REMAP_NONE
Definition: BLO_writefile.h:31
@ BLO_WRITE_PATH_REMAP_ABSOLUTE
Definition: BLO_writefile.h:37
@ BLO_WRITE_PATH_REMAP_RELATIVE
Definition: BLO_writefile.h:33
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define DATA_(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_ERROR(clg_ref,...)
Definition: CLG_log.h:190
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:189
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:187
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
@ OB_SOLID
Object is a sort of wrapper for general info.
@ R_ALPHAPREMUL
@ RGN_TYPE_WINDOW
#define MAXSEQ
@ FILE_SORT_DEFAULT
@ FILE_SORT_TIME
@ FILE_BLENDER
@ FILE_TYPE_BLENDER
@ FILE_TYPE_FOLDER
@ SPACE_VIEW3D
@ FILE_VERTICALDISPLAY
@ FILE_DEFAULTDISPLAY
@ USER_SAVE_PROMPT
@ USER_GLOBALUNDO
@ USER_RELPATHS
@ USER_FILENOUI
@ USER_FILECOMPRESS
@ USER_SCRIPT_AUTOEXEC_DISABLE
@ USER_AUTOSAVE
@ USER_FILE_PREVIEW_NONE
@ USER_FILE_PREVIEW_CAMERA
@ USER_FILE_PREVIEW_SCREENSHOT
@ USER_FILE_PREVIEW_AUTO
@ V3D_OFSDRAW_NONE
@ V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS
@ KEYCONF_INIT_DEFAULT
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ WM_WINDOW_IS_INIT
bool ED_asset_catalogs_get_save_catalogs_when_file_is_saved(void)
void ED_asset_catalogs_set_save_catalogs_when_file_is_saved(bool should_save)
void ED_assets_pre_save(struct Main *bmain)
int datatoc_startup_blend_size
const char datatoc_startup_blend[]
void ED_file_read_bookmarks(void)
Definition: space_file.c:1108
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)
void ED_preview_restart_queue_free(void)
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen)
Definition: screen_edit.c:736
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:343
void ED_editors_exit(struct Main *bmain, bool do_undo_system)
Definition: ed_util.c:213
void ED_editors_init(struct bContext *C)
Definition: ed_util.c:78
bool ED_editors_flush_edits(struct Main *bmain)
Definition: ed_util.c:325
void ED_view3d_local_collections_reset(struct bContext *C, bool reset_all)
Definition: view3d_view.c:1239
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, bool restore_rv3d_mats, struct GPUOffScreen *ofs, char err_out[256])
Definition: view3d_draw.c:1831
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:1980
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:1644
struct ImBuf * IMB_dupImBuf(const struct ImBuf *ibuf1)
struct ImBuf * IMB_allocFromBufferOwn(unsigned int *rect, float *rectf, unsigned int w, unsigned int h, unsigned int channels)
Definition: allocimbuf.c:415
Contains defines and structs used throughout the imbuf module.
@ IB_rect
@ THB_FAIL
Definition: IMB_thumbs.h:25
@ THB_LARGE
Definition: IMB_thumbs.h:24
@ THB_SOURCE_BLEND
Definition: IMB_thumbs.h:31
#define PREVIEW_RENDER_LARGE_HEIGHT
Definition: IMB_thumbs.h:41
void IMB_thumb_delete(const char *filepath, ThumbSize size)
Definition: thumbs.c:498
struct ImBuf * IMB_thumb_create(const char *filepath, ThumbSize size, ThumbSource source, struct ImBuf *img)
Definition: thumbs.c:468
void MEM_CacheLimiter_set_maximum(size_t m)
Read Guarded memory(de)allocation.
Platform independent time functions.
@ RNA_EQ_STRICT
Definition: RNA_access.h:771
@ PROP_POINTER
Definition: RNA_types.h:64
@ PROP_COLLECTION
Definition: RNA_types.h:65
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
void uiItemS_ex(uiLayout *layout, float factor)
@ UI_BUT_TEXT_LEFT
Definition: UI_interface.h:259
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.cc:5623
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_BUT_REDALERT
Definition: UI_interface.h:201
@ UI_BUT_ACTIVE_DEFAULT
Definition: UI_interface.h:212
@ UI_EMBOSS
Definition: UI_interface.h:108
void UI_block_theme_style_set(uiBlock *block, char theme_style)
Definition: interface.cc:3634
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetScaleY(uiLayout *layout, float scale)
void uiItemL(uiLayout *layout, const char *name, int icon)
uiLayout * uiItemsAlertBox(uiBlock *block, int size, eAlertIcon icon)
@ UI_BLOCK_THEME_STYLE_POPUP
Definition: UI_interface.h:770
void uiItemS(uiLayout *layout)
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
Definition: interface.cc:3629
#define UI_DPI_FAC
Definition: UI_interface.h:305
void UI_but_drawflag_disable(uiBut *but, int flag)
Definition: interface.cc:5878
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.cc:6000
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.cc:624
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.cc:5226
void UI_block_flag_enable(uiBlock *block, int flag)
Definition: interface.cc:5848
@ UI_BTYPE_BUT
Definition: UI_interface.h:330
@ UI_BTYPE_CHECKBOX
Definition: UI_interface.h:347
void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert)
void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
bool UI_popup_block_name_exists(const struct bScreen *screen, const char *name)
void UI_init_userdef(void)
Definition: interface.cc:6776
void UI_but_flag_enable(uiBut *but, int flag)
Definition: interface.cc:5858
@ UI_BLOCK_NUMSELECT
Definition: UI_interface.h:138
@ UI_BLOCK_LOOP
Definition: UI_interface.h:135
@ UI_BLOCK_KEEP_OPEN
Definition: UI_interface.h:144
@ UI_BLOCK_NO_WIN_CLIP
Definition: UI_interface.h:140
void UI_icons_reload_internal_textures(void)
@ ALERT_ICON_WARNING
@ ALERT_ICON_QUESTION
@ ALERT_ICON_ERROR
void UI_view2d_zoom_cache_reset(void)
Definition: view2d.cc:1027
@ WM_FILESEL_FILEPATH
Definition: WM_api.h:755
@ FILE_OPENFILE
Definition: WM_api.h:764
@ FILE_SAVE
Definition: WM_api.h:765
@ OPTYPE_INTERNAL
Definition: WM_types.h:168
#define NC_WINDOW
Definition: WM_types.h:325
#define ND_FILEREAD
Definition: WM_types.h:360
#define NC_WM
Definition: WM_types.h:324
#define ND_DATACHANGED
Definition: WM_types.h:362
void(* wmGenericCallbackFn)(struct bContext *C, void *user_data)
Definition: WM_types.h:133
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:208
#define ND_FILESAVE
Definition: WM_types.h:361
#define U
ATTR_WARN_UNUSED_RESULT const BMLoop * l
unsigned int U
Definition: btGjkEpa3.h:78
static char * basename(char *string)
Definition: datatoc.c:17
Scene scene
const Depsgraph * depsgraph
void * user_data
DEGForeachIDComponentCallback callback
int len
Definition: draw_manager.c:108
ListBase R_engines
Definition: engine.c:57
#define str(s)
uint col
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_global float * buffer
const int state
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define G(x, y, z)
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:92
T abs(const T &a)
return ret
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:5155
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
void RNA_property_collection_begin(PointerRNA *ptr, PropertyRNA *prop, CollectionPropertyIterator *iter)
Definition: rna_access.c:3675
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1010
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3493
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2138
void RNA_property_collection_next(CollectionPropertyIterator *iter)
Definition: rna_access.c:3709
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:5116
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
void RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop, char *value)
Definition: rna_access.c:3149
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2180
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:5301
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_property_collection_end(CollectionPropertyIterator *iter)
Definition: rna_access.c:3750
PropertyRNA * RNA_struct_iterator_property(StructRNA *type)
Definition: rna_access.c:634
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
Definition: rna_access.c:3239
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:3493
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:3711
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:3687
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
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:3597
#define INT32_MAX
Definition: stdint.h:137
__int64 int64_t
Definition: stdint.h:89
#define INT32_MIN
Definition: stdint.h:136
unsigned __int64 uint64_t
Definition: stdint.h:90
struct BMLoop * next
Definition: bmesh_class.h:233
char filepath[1024]
Definition: BLO_readfile.h:61
double lib_overrides_recursive_resync
Definition: BLO_readfile.h:88
struct ReportList * reports
Definition: BLO_readfile.h:80
struct LinkNode * resynced_lib_overrides_libraries
Definition: BLO_readfile.h:116
int resynced_lib_overrides_libraries_count
Definition: BLO_readfile.h:114
int proxies_to_lib_overrides_failures
Definition: BLO_readfile.h:107
struct BlendFileReadReport::@134 count
double lib_overrides_resync
Definition: BLO_readfile.h:87
struct BlendFileReadReport::@133 duration
int proxies_to_lib_overrides_success
Definition: BLO_readfile.h:105
FileReaderSeekFn seek
FileReaderCloseFn close
FileReaderReadFn read
bool is_untrusted
Definition: wm_files.c:2734
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
char recovered
Definition: BKE_main.h:138
ListBase scenes
Definition: BKE_main.h:168
ListBase wm
Definition: BKE_main.h:197
short subversionfile
Definition: BKE_main.h:125
bool has_forward_compatibility_issues
Definition: BKE_main.h:132
char filepath[1024]
Definition: BKE_main.h:124
BlendThumbnail * blen_thumb
Definition: BKE_main.h:165
ListBase libraries
Definition: BKE_main.h:169
short versionfile
Definition: BKE_main.h:125
struct MainIDRelations * relations
Definition: BKE_main.h:218
int(* run)(bContext *C, wmOperator *op)
Definition: wm_files.c:2565
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
struct RecentFile * next
Definition: WM_types.h:1270
char * filepath
Definition: WM_types.h:1271
char engine[32]
struct RenderData r
struct Object * camera
UserDef_Runtime runtime
View3DShading shading
Wrapper for bScreen.
const char * app_template_override
Definition: wm_files.h:47
const char * filepath_startup_override
Definition: wm_files.h:42
unsigned int use_factory_settings
Definition: wm_files.h:33
unsigned int use_empty_data
Definition: wm_files.h:38
unsigned int use_data
Definition: wm_files.h:25
unsigned int use_userdef
Definition: wm_files.h:27
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:966
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * translation_context
Definition: WM_types.h:891
const char * description
Definition: WM_types.h:893
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:954
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:911
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
const char *(* get_name)(struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:960
struct ReportList * reports
IDProperty * properties
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
struct wmKeyConfig * defaultconf
struct UndoStack * undo_stack
struct wmWindow * winactive
struct wmKeyConfig * userconf
struct wmTimer * autosavetimer
struct wmWindow * windrawable
struct wmKeyConfig * addonconf
struct wmWindow * parent
struct wmEvent * eventstate
struct wmEvent * event_last_handled
double PIL_check_seconds_timer(void)
Definition: time.c:64
static FT_Library library
void wm_clear_default_size(bContext *C)
Definition: wm.c:511
void wm_close_and_free_all(bContext *C, ListBase *wmlist)
Definition: wm.c:607
void WM_check(bContext *C)
Definition: wm.c:472
void WM_keyconfig_reload(bContext *C)
Definition: wm.c:424
void wm_add_default(Main *bmain, bContext *C)
Definition: wm.c:533
void WM_cursor_wait(bool val)
Definition: wm_cursors.c:209
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_fileselect(bContext *C, wmOperator *op)
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
void WM_report_banner_show(void)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
int WM_operator_name_call_with_properties(bContext *C, const char *opstring, wmOperatorCallContext context, IDProperty *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
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:1481
static void free_post_file_close_action(void *arg)
Definition: wm_files.c:3550
static uiBlock * block_create__close_file_dialog(struct bContext *C, struct ARegion *region, void *arg1)
Definition: wm_files.c:3866
static const char * wm_save_as_mainfile_get_name(wmOperatorType *ot, PointerRNA *ptr)
Definition: wm_files.c:3173
static void save_file_forwardcompat_saveas(bContext *C, void *arg_block, void *UNUSED(arg_data))
Definition: wm_files.c:3644
static void wm_autosave_location(char *filepath)
Definition: wm_files.c:1893
void WM_file_autosave_init(wmWindowManager *wm)
Definition: wm_files.c:1984
void wm_autosave_timer_end(wmWindowManager *wm)
Definition: wm_files.c:1976
static void create_operator_state(wmOperatorType *ot, int first_state)
Definition: wm_files.c:2545
#define BKE_READ_EXOTIC_OK_BLEND
Definition: wm_files.c:476
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:398
static void wm_block_autorun_warning_enable_scripts(bContext *C, void *arg_block, void *UNUSED(arg))
Definition: wm_files.c:3335
bool wm_operator_close_file_dialog_if_needed(bContext *C, wmOperator *op, wmGenericCallbackFn post_action_fn)
Definition: wm_files.c:4049
static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
Definition: wm_files.c:2769
static void wm_init_userdef(Main *bmain)
Definition: wm_files.c:440
static struct @1192 wm_test_autorun_revert_action_data
bool write_crash_blend(void)
Definition: wm_files.c:1710
static void save_file_forwardcompat_overwrite(bContext *C, void *arg_block, void *arg_data)
Definition: wm_files.c:3612
static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2893
static void wm_history_files_free(void)
Definition: wm_files.c:1439
static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
Definition: wm_files.c:2739
static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *UNUSED(arg))
Definition: wm_files.c:3308
static int operator_state_dispatch(bContext *C, wmOperator *op, OperatorDispatchTarget *targets)
Definition: wm_files.c:2568
static bool blend_save_check(bContext *UNUSED(C), wmOperator *op)
Definition: wm_files.c:3159
bool WM_file_recover_last_session(bContext *C, ReportList *reports)
Definition: wm_files.c:2883
void WM_OT_read_history(wmOperatorType *ot)
Definition: wm_files.c:2328
static void file_forwardcompat_detailed_info_show(uiLayout *parent_layout, Main *bmain)
Definition: wm_files.c:3564
static void wm_open_mainfile_after_dialog_callback(bContext *C, void *user_data)
Definition: wm_files.c:2595
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs)
Definition: wm_files.c:2053
static int wm_homefile_read_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2349
static int wm_open_mainfile__discard_changes(bContext *C, wmOperator *op)
Definition: wm_files.c:2601
static void save_file_forwardcompat_overwrite_button(uiBlock *block, wmGenericCallback *post_action)
Definition: wm_files.c:3634
static bool wm_revert_mainfile_poll(bContext *UNUSED(C))
Definition: wm_files.c:2858
#define BKE_READ_EXOTIC_FAIL_FORMAT
Definition: wm_files.c:474
void wm_test_autorun_revert_action_set(wmOperatorType *ot, PointerRNA *ptr)
Definition: wm_files.c:3486
void wm_homefile_read_ex(bContext *C, const struct wmHomeFileRead_Params *params_homefile, ReportList *reports, struct wmFileReadPost_Params **r_params_file_read_post)
Definition: wm_files.c:1048
#define BKE_READ_EXOTIC_FAIL_OPEN
Definition: wm_files.c:475
bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm)
Definition: wm_files.c:160
void WM_OT_save_as_mainfile(wmOperatorType *ot)
Definition: wm_files.c:3192
void wm_autosave_delete(void)
Definition: wm_files.c:2013
void WM_OT_open_mainfile(wmOperatorType *ot)
Definition: wm_files.c:2800
const char * WM_init_state_app_template_get(void)
Definition: wm_files.c:1037
static void wm_block_file_close_cancel_button(uiBlock *block, wmGenericCallback *post_action)
Definition: wm_files.c:3814
void wm_homefile_read_post(struct bContext *C, const struct wmFileReadPost_Params *params_file_read_post)
Definition: wm_files.c:1378
static RecentFile * wm_file_history_find(const char *filepath)
Definition: wm_files.c:1446
PointerRNA * ptr
Definition: wm_files.c:3480
void wm_autosave_timer_begin(wmWindowManager *wm)
Definition: wm_files.c:1971
static void save_catalogs_when_file_is_closed_set_fn(bContext *UNUSED(C), void *arg1, void *UNUSED(arg2))
Definition: wm_files.c:3858
static void rna_struct_update_when_changed(bContext *C, Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b)
Definition: wm_files.c:2198
void WM_OT_recover_last_session(wmOperatorType *ot)
Definition: wm_files.c:2931
void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
Definition: wm_files.c:1989
static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2687
static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2839
static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
Definition: wm_files.c:1934
static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports)
Definition: wm_files.c:2525
BLI_STATIC_ASSERT(sizeof(struct FileRuntime)<=sizeof(void *), "Struct must not exceed pointer size")
void wm_save_file_forwardcompat_dialog(bContext *C, wmOperator *op)
Definition: wm_files.c:3721
static void save_file_forwardcompat_cancel_button(uiBlock *block, wmGenericCallback *post_action)
Definition: wm_files.c:3604
static void wm_homefile_read_after_dialog_callback(bContext *C, void *user_data)
Definition: wm_files.c:2442
static OperatorDispatchTarget wm_open_mainfile_dispatch_targets[]
Definition: wm_files.c:2675
#define USERDEF_RESTORE(member)
static void wm_userpref_read_exceptions(UserDef *userdef_curr, const UserDef *userdef_prev)
Definition: wm_files.c:2184
static char * wm_open_mainfile_description(struct bContext *UNUSED(C), struct wmOperatorType *UNUSED(op), struct PointerRNA *params)
Definition: wm_files.c:2697
static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2978
void WM_OT_read_userpref(wmOperatorType *ot)
Definition: wm_files.c:2293
static void wm_test_autorun_revert_action_exec(bContext *C)
Definition: wm_files.c:3499
static void wm_recover_last_session_after_dialog_callback(bContext *C, void *user_data)
Definition: wm_files.c:2910
static char save_images_when_file_is_closed
Definition: wm_files.c:3740
static void wm_block_file_close_cancel(bContext *C, void *arg_block, void *UNUSED(arg_data))
Definition: wm_files.c:3742
void wm_file_read_report(bContext *C, Main *bmain)
Definition: wm_files.c:574
struct OperatorDispatchTarget OperatorDispatchTarget
static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:3064
void WM_OT_save_homefile(wmOperatorType *ot)
Definition: wm_files.c:2136
void WM_OT_read_factory_userpref(wmOperatorType *ot)
Definition: wm_files.c:2303
static int wm_userpref_write_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2153
static int get_operator_state(wmOperator *op)
Definition: wm_files.c:2553
void WM_init_state_app_template_set(const char *app_template)
Definition: wm_files.c:1025
static void save_set_compress(wmOperator *op)
Definition: wm_files.c:3025
bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
Definition: wm_files.c:900
static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:3081
static void wm_window_match_init(bContext *C, ListBase *wmlist)
Definition: wm_files.c:179
static void save_file_forwardcompat_saveas_button(uiBlock *block, wmGenericCallback *post_action)
Definition: wm_files.c:3652
static const char * save_file_forwardcompat_dialog_name
Definition: wm_files.c:3562
static int wm_read_exotic(const char *name)
Definition: wm_files.c:491
static char * wm_save_as_mainfile_get_description(bContext *UNUSED(C), wmOperatorType *UNUSED(ot), PointerRNA *ptr)
Definition: wm_files.c:3181
void WM_OT_save_mainfile(wmOperatorType *ot)
Definition: wm_files.c:3272
void WM_OT_recover_auto_save(wmOperatorType *ot)
Definition: wm_files.c:2990
void wm_homefile_read(bContext *C, const struct wmHomeFileRead_Params *params_homefile, ReportList *reports)
Definition: wm_files.c:1371
void wm_history_file_read(void)
Definition: wm_files.c:1391
static void wm_window_substitute_old(wmWindowManager *oldwm, wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
Definition: wm_files.c:225
char app_template[64]
Definition: wm_files.c:1021
static int wm_recover_last_session_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2916
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:262
static uiBlock * block_create_autorun_warning(struct bContext *C, struct ARegion *region, void *UNUSED(arg1))
Definition: wm_files.c:3356
static void wm_block_file_close_discard(bContext *C, void *arg_block, void *arg_data)
Definition: wm_files.c:3748
static RecentFile * wm_history_file_new(const char *filepath)
Definition: wm_files.c:1425
@ OPEN_MAINFILE_STATE_OPEN
Definition: wm_files.c:2590
@ OPEN_MAINFILE_STATE_DISCARD_CHANGES
Definition: wm_files.c:2588
@ OPEN_MAINFILE_STATE_SELECT_FILE_PATH
Definition: wm_files.c:2589
static void set_next_operator_state(wmOperator *op, int state)
Definition: wm_files.c:2558
void WM_file_tag_modified(void)
Definition: wm_files.c:150
void WM_file_autoexec_init(const char *filepath)
Definition: wm_files.c:559
static int wm_open_mainfile_dispatch(bContext *C, wmOperator *op)
Definition: wm_files.c:2682
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:309
static int wm_homefile_read_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:2448
static void wm_userpref_update_when_changed(bContext *C, Main *bmain, UserDef *userdef_prev, UserDef *userdef_curr)
Definition: wm_files.c:2232
static const char * close_file_dialog_name
Definition: wm_files.c:3856
static void save_file_forwardcompat_cancel(bContext *C, void *arg_block, void *UNUSED(arg_data))
Definition: wm_files.c:3598
static void wm_filepath_default(const Main *bmain, char *filepath)
Definition: wm_files.c:3018
void WM_OT_read_factory_settings(wmOperatorType *ot)
Definition: wm_files.c:2501
static int wm_userpref_read_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2250
static int wm_open_mainfile__open(bContext *C, wmOperator *op)
Definition: wm_files.c:2647
static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
Definition: wm_files.c:2321
void wm_test_autorun_warning(bContext *C)
Definition: wm_files.c:3519
static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_files.c:3229
wmOperatorType * ot
Definition: wm_files.c:3479
static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef))
Definition: wm_files.c:606
static void wm_file_read_post(bContext *C, const struct wmFileReadPost_Params *params)
Definition: wm_files.c:636
static uiBlock * block_create_save_file_forwardcompat_dialog(bContext *C, ARegion *region, void *arg1)
Definition: wm_files.c:3661
void wm_open_init_load_ui(wmOperator *op, bool use_prefs)
Definition: wm_files.c:2043
static CLG_LogRef LOG
Definition: wm_files.c:144
static void wm_history_file_free(RecentFile *recent)
Definition: wm_files.c:1432
static void wm_autosave_timer_begin_ex(wmWindowManager *wm, double timestep)
Definition: wm_files.c:1962
static void wm_open_mainfile_def_property_use_scripts(wmOperatorType *ot)
Definition: wm_files.c:2790
#define BKE_READ_EXOTIC_FAIL_PATH
Definition: wm_files.c:473
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:1727
static void file_read_reports_finalize(BlendFileReadReport *bf_reports)
Definition: wm_files.c:775
static void wm_free_operator_properties_callback(void *user_data)
Definition: wm_files.c:3556
static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_data)
Definition: wm_files.c:3762
static void save_set_filepath(bContext *C, wmOperator *op)
Definition: wm_files.c:3041
static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2949
void WM_OT_read_homefile(wmOperatorType *ot)
Definition: wm_files.c:2467
static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2692
static void wm_block_file_close_save_button(uiBlock *block, wmGenericCallback *post_action, const bool has_forwardcompat_issues)
Definition: wm_files.c:3830
static void wm_block_file_close_discard_button(uiBlock *block, wmGenericCallback *post_action)
Definition: wm_files.c:3822
static ImBuf * blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **r_thumb)
Definition: wm_files.c:1546
static int wm_homefile_write_exec(bContext *C, wmOperator *op)
Definition: wm_files.c:2077
static ImBuf * blend_file_thumb_from_camera(const bContext *C, Scene *scene, bScreen *screen, BlendThumbnail **r_thumb)
Definition: wm_files.c:1596
void WM_OT_save_userpref(wmOperatorType *ot)
Definition: wm_files.c:2165
static struct @1190 wm_init_state_app_template
static void wm_block_autorun_warning_reload_with_scripts(bContext *C, void *arg_block, void *UNUSED(arg))
Definition: wm_files.c:3317
static void wm_history_file_write(void)
Definition: wm_files.c:1455
static void read_homefile_props(wmOperatorType *ot)
Definition: wm_files.c:2456
static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
Definition: wm_files.c:2616
void WM_OT_revert_mainfile(wmOperatorType *ot)
Definition: wm_files.c:2864
void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action)
Definition: wm_files.c:4038
void WM_reinit_gizmomap_all(Main *bmain)
void WM_init_splash(bContext *C)
Definition: wm_init_exit.c:366
void wm_exit_schedule_delayed(const bContext *C)
Definition: wm_init_exit.c:421
void WM_jobs_kill_all(wmWindowManager *wm)
Definition: wm_jobs.c:551
void WM_keyconfig_update(wmWindowManager *wm)
Definition: wm_keymap.c:1829
void WM_msgbus_destroy(struct wmMsgBus *mbus)
@ WM_MSG_STATICTYPE_FILE_READ
void WM_msg_publish_static(struct wmMsgBus *mbus, int event)
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const 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_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
Definition: wm_operators.c:680
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:661
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:783
void WM_toolsystem_init(bContext *C)
wmGenericCallback * WM_generic_callback_steal(wmGenericCallback *callback)
Definition: wm_utils.c:30
void WM_generic_callback_free(wmGenericCallback *callback)
Definition: wm_utils.c:18
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1682
WorkSpaceLayout * WM_window_get_active_layout(const wmWindow *win)
Definition: wm_window.c:2290
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:366
uint * WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2])
Definition: wm_window.c:1953
void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
Definition: wm_window.c:2306
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
Definition: wm_window.c:684
void wm_window_clear_drawable(wmWindowManager *wm)
Definition: wm_window.c:1021
bScreen * WM_window_get_active_screen(const wmWindow *win)
Definition: wm_window.c:2300
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:1028
bool WM_window_is_temp_screen(const wmWindow *win)
Definition: wm_window.c:2311
void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
Definition: wm_window.c:2295
void WM_init_input_devices(void)
Definition: wm_window.c:2034
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1630