Changeset View
Changeset View
Standalone View
Standalone View
source/blender/windowmanager/intern/wm_files.c
| Show First 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_packedFile.h" | #include "BKE_packedFile.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_sound.h" | #include "BKE_sound.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| #include "BKE_screen.h" | #include "BKE_screen.h" | ||||
| #include "BKE_workspace.h" | |||||
| #include "BLO_readfile.h" | #include "BLO_readfile.h" | ||||
| #include "BLO_writefile.h" | #include "BLO_writefile.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_define.h" | #include "RNA_define.h" | ||||
| #include "IMB_imbuf.h" | #include "IMB_imbuf.h" | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | for (wm = wmlist->first; wm; wm = wm->id.next) { | ||||
| WM_jobs_kill_all(wm); | WM_jobs_kill_all(wm); | ||||
| for (win = wm->windows.first; win; win = win->next) { | for (win = wm->windows.first; win; win = win->next) { | ||||
| CTX_wm_window_set(C, win); /* needed by operator close callbacks */ | CTX_wm_window_set(C, win); /* needed by operator close callbacks */ | ||||
| WM_event_remove_handlers(C, &win->handlers); | WM_event_remove_handlers(C, &win->handlers); | ||||
| WM_event_remove_handlers(C, &win->modalhandlers); | WM_event_remove_handlers(C, &win->modalhandlers); | ||||
| ED_screen_exit(C, win, win->screen); | ED_screen_exit(C, win, WM_window_get_active_screen(win)); | ||||
| } | } | ||||
| } | } | ||||
| /* reset active window */ | /* reset active window */ | ||||
| CTX_wm_window_set(C, active_win); | CTX_wm_window_set(C, active_win); | ||||
| /* XXX Hack! We have to clear context menu here, because removing all modalhandlers above frees the active menu | /* XXX Hack! We have to clear context menu here, because removing all modalhandlers above frees the active menu | ||||
| * (at least, in the 'startup splash' case), causing use-after-free error in later handling of the button | * (at least, in the 'startup splash' case), causing use-after-free error in later handling of the button | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | static void wm_window_match_do(bContext *C, ListBase *oldwmlist) | ||||
| else { | else { | ||||
| /* cases 3 and 4 */ | /* cases 3 and 4 */ | ||||
| /* we've read file without wm..., keep current one entirely alive */ | /* we've read file without wm..., keep current one entirely alive */ | ||||
| if (BLI_listbase_is_empty(&G.main->wm)) { | if (BLI_listbase_is_empty(&G.main->wm)) { | ||||
| bScreen *screen = NULL; | bScreen *screen = NULL; | ||||
| /* when loading without UI, no matching needed */ | /* when loading without UI, no matching needed */ | ||||
| /* XXX think we don't handle this correctly yet, it's activating workspace from old file */ | |||||
| if (!(G.fileflags & G_FILE_NO_UI) && (screen = CTX_wm_screen(C))) { | if (!(G.fileflags & G_FILE_NO_UI) && (screen = CTX_wm_screen(C))) { | ||||
| /* match oldwm to new dbase, only old files */ | /* match oldwm to new dbase, only old files */ | ||||
| for (wm = oldwmlist->first; wm; wm = wm->id.next) { | for (wm = oldwmlist->first; wm; wm = wm->id.next) { | ||||
| for (win = wm->windows.first; win; win = win->next) { | for (win = wm->windows.first; win; win = win->next) { | ||||
| WorkSpace *workspace = WM_window_get_active_workspace(win); | |||||
| /* all windows get active screen from file */ | /* all windows get active screen from file */ | ||||
| if (screen->winid == 0) | if (screen->winid == 0) { | ||||
| win->screen = screen; | WM_window_set_active_screen(win, workspace, screen); | ||||
| else | } | ||||
| win->screen = ED_screen_duplicate(win, screen); | else { | ||||
| WorkSpaceLayout *layout_old = WM_window_get_active_layout(win); | |||||
| WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win); | |||||
| WM_window_set_active_layout(win, workspace, layout_new); | |||||
| } | |||||
| BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname)); | bScreen *win_screen = WM_window_get_active_screen(win); | ||||
| win->screen->winid = win->winid; | BLI_strncpy(win->screenname, win_screen->id.name + 2, sizeof(win->screenname)); | ||||
| win_screen->winid = win->winid; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| G.main->wm = *oldwmlist; | G.main->wm = *oldwmlist; | ||||
| /* screens were read from file! */ | /* screens were read from file! */ | ||||
| ED_screens_initialize(G.main->wm.first); | ED_screens_initialize(G.main->wm.first); | ||||
| ▲ Show 20 Lines • Show All 304 Lines • ▼ Show 20 Lines | if (retval == BKE_READ_EXOTIC_OK_BLEND) { | ||||
| if (G.f != G_f) { | if (G.f != G_f) { | ||||
| const int flags_keep = (G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF); | const int flags_keep = (G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF); | ||||
| G.f = (G.f & ~flags_keep) | (G_f & flags_keep); | G.f = (G.f & ~flags_keep) | (G_f & flags_keep); | ||||
| } | } | ||||
| /* match the read WM with current WM */ | /* match the read WM with current WM */ | ||||
| wm_window_match_do(C, &wmbase); | wm_window_match_do(C, &wmbase); | ||||
| WM_check(C); /* opens window(s), checks keymaps */ | WM_check(C); /* opens window(s), checks keymaps */ | ||||
| wm_file_read_post(C, false); /* do before wm_init_usedef to ensure updated context */ | |||||
campbellbarton: This is going to cause problems,
- `wm_init_userdef` versions preferences, initializes temp… | |||||
SeverinAuthorUnsubmitted Not Done Inline ActionsThe issue I tried to fix with this re-ordering was a crash when loading startup.blend as regular .blend, see rB6bf890786305f. The important bits were the calls to CTX_wm_window_set in wm_file_read_post. IIRC calling CTX_wm_window_set once more in WM_file_read would've worked too, but I checked if reordering would be fine and it seemed so, so I decided to avoid the extra CTX_wm_window_set call. You're making good points however, will check the alternative(s) again. Severin: The issue I tried to fix with this re-ordering was a crash when loading startup.blend as… | |||||
| if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) { | if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) { | ||||
| /* in case a userdef is read from regular .blend */ | /* in case a userdef is read from regular .blend */ | ||||
| wm_init_userdef(C, false); | wm_init_userdef(C, false); | ||||
| } | } | ||||
| if (retval != BKE_BLENDFILE_READ_FAIL) { | if (retval != BKE_BLENDFILE_READ_FAIL) { | ||||
| if (do_history) { | if (do_history) { | ||||
| wm_history_file_update(); | wm_history_file_update(); | ||||
| } | } | ||||
| } | } | ||||
| wm_file_read_post(C, false); | |||||
| success = true; | success = true; | ||||
| } | } | ||||
| #if 0 | #if 0 | ||||
| else if (retval == BKE_READ_EXOTIC_OK_OTHER) | else if (retval == BKE_READ_EXOTIC_OK_OTHER) | ||||
| BKE_undo_write(C, "Import file"); | BKE_undo_write(C, "Import file"); | ||||
| #endif | #endif | ||||
| else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) { | else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) { | ||||
| BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath, | BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath, | ||||
| ▲ Show 20 Lines • Show All 761 Lines • ▼ Show 20 Lines | static int wm_homefile_write_exec(bContext *C, wmOperator *op) | ||||
| if (cfgdir == NULL) { | if (cfgdir == NULL) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Unable to create user config path"); | BKE_report(op->reports, RPT_ERROR, "Unable to create user config path"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE); | BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE); | ||||
| /* check current window and close it if temp */ | /* check current window and close it if temp */ | ||||
| if (win && win->screen->temp) | if (win && WM_window_is_temp_screen(win)) | ||||
| wm_window_close(C, wm, win); | wm_window_close(C, wm, win); | ||||
| /* update keymaps in user preferences */ | /* update keymaps in user preferences */ | ||||
| WM_keyconfig_update(wm); | WM_keyconfig_update(wm); | ||||
| BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL); | BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL); | ||||
| printf("trying to save homefile at %s ", filepath); | printf("trying to save homefile at %s ", filepath); | ||||
| ▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | void WM_OT_save_userpref(wmOperatorType *ot) | ||||
| ot->name = "Save User Settings"; | ot->name = "Save User Settings"; | ||||
| ot->idname = "WM_OT_save_userpref"; | ot->idname = "WM_OT_save_userpref"; | ||||
| ot->description = "Save user preferences separately, overrides startup file preferences"; | ot->description = "Save user preferences separately, overrides startup file preferences"; | ||||
| ot->invoke = WM_operator_confirm; | ot->invoke = WM_operator_confirm; | ||||
| ot->exec = wm_userpref_write_exec; | ot->exec = wm_userpref_write_exec; | ||||
| } | } | ||||
| static int wm_workspace_configuration_file_write_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| Main *bmain = CTX_data_main(C); | |||||
| char filepath[FILE_MAX]; | |||||
| const char *configdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL); | |||||
| if (configdir) { | |||||
| BLI_path_join(filepath, sizeof(filepath), configdir, BLENDER_WORKSPACES_FILE, NULL); | |||||
| printf("trying to save workspace configuration file at %s ", filepath); | |||||
| if (BKE_blendfile_workspace_config_write(bmain, filepath, op->reports) != 0) { | |||||
| printf("ok\n"); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| else { | |||||
| printf("fail\n"); | |||||
| } | |||||
| } | |||||
| else { | |||||
| BKE_report(op->reports, RPT_ERROR, "Unable to create workspace configuration file path"); | |||||
| } | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| void WM_OT_save_workspace_file(wmOperatorType *ot) | |||||
| { | |||||
| ot->name = "Save Workspace Configuration"; | |||||
| ot->idname = "WM_OT_save_workspace_file"; | |||||
| ot->description = "Save workspaces of the current file as part of the user configuration"; | |||||
| ot->invoke = WM_operator_confirm; | |||||
| ot->exec = wm_workspace_configuration_file_write_exec; | |||||
| } | |||||
| static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) | static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| ED_file_read_bookmarks(); | ED_file_read_bookmarks(); | ||||
| wm_history_file_read(); | wm_history_file_read(); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void WM_OT_read_history(wmOperatorType *ot) | void WM_OT_read_history(wmOperatorType *ot) | ||||
| ▲ Show 20 Lines • Show All 636 Lines • Show Last 20 Lines | |||||
This is going to cause problems,
This means addons may run before user preferences are properly versioned and initializes, which should be avoided since it could cause strange/undefined behavior.
Besides introducing problems (that can probably be worked around), the intended purpose of wm_file_read_post is to run last, so not really happy to move it before other operations.
What problems happen when the order is restored to the original state? - I think its better to try resolve that problem on it's own.