static void rna_Area_type_update(bContext *C, PointerRNA *ptr) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; bScreen *sc = (bScreen *)ptr->id.data; ScrArea *sa = (ScrArea *)ptr->data; /* XXX this call still use context, so we trick it to work in the right context */ for (win = wm->windows.first; win; win = win->next) { if (sc == win->screen) { wmWindow *prevwin = CTX_wm_window(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *prevar = CTX_wm_region(C); CTX_wm_window_set(C, win); CTX_wm_area_set(C, sa); CTX_wm_region_set(C, NULL); ED_area_newspace(C, sa, sa->butspacetype, true); ED_area_tag_redraw(sa); /* It is possible that new layers becomes visible. */ if (sa->spacetype == SPACE_VIEW3D) { DAG_on_visible_update(CTX_data_main(C), false); } CTX_wm_window_set(C, prevwin); CTX_wm_area_set(C, prevsa); CTX_wm_region_set(C, prevar); break; } } }
static void rna_Area_type_update(bContext *C, PointerRNA *ptr) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; bScreen *sc = (bScreen *)ptr->id.data; ScrArea *sa = (ScrArea *)ptr->data; /* XXX this call still use context, so we trick it to work in the right context */ for (win = wm->windows.first; win; win = win->next) { if (sc == win->screen) { wmWindow *prevwin = CTX_wm_window(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *prevar = CTX_wm_region(C); CTX_wm_window_set(C, win); CTX_wm_area_set(C, sa); CTX_wm_region_set(C, NULL); ED_area_newspace(C, sa, sa->butspacetype); ED_area_tag_redraw(sa); CTX_wm_window_set(C, prevwin); CTX_wm_area_set(C, prevsa); CTX_wm_region_set(C, prevar); break; } } }
void wm_draw_update(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; int drawmethod; GPU_free_unused_buffers(); for (win = wm->windows.first; win; win = win->next) { #ifdef WIN32 if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin); if (state == GHOST_kWindowStateMinimized) { /* do not update minimized windows, it gives issues on intel drivers (see [#33223]) * anyway, it seems logical to skip update for invisible windows */ continue; } } #endif if (win->drawmethod != U.wmdrawmethod) { wm_draw_window_clear(win); win->drawmethod = U.wmdrawmethod; } if (wm_draw_update_test_window(win)) { CTX_wm_window_set(C, win); /* sets context window+screen */ wm_window_make_drawable(wm, win); /* notifiers for screen redraw */ if (win->screen->do_refresh) ED_screen_refresh(wm, win); drawmethod = wm_automatic_draw_method(win); if (win->drawfail) wm_method_draw_overlap_all(C, win, 0); else if (drawmethod == USER_DRAW_FULL) wm_method_draw_full(C, win); else if (drawmethod == USER_DRAW_OVERLAP) wm_method_draw_overlap_all(C, win, 0); else if (drawmethod == USER_DRAW_OVERLAP_FLIP) wm_method_draw_overlap_all(C, win, 1); else // if (drawmethod == USER_DRAW_TRIPLE) wm_method_draw_triple(C, win); win->screen->do_draw_gesture = false; win->screen->do_draw_paintcursor = false; win->screen->do_draw_drag = false; wm_window_swap_buffers(win); CTX_wm_window_set(C, NULL); } } }
/* To be able to read files without windows closing, opening, moving * we try to prepare for worst case: * - active window gets active screen from file * - restoring the screens from non-active windows * Best case is all screens match, in that case they get assigned to proper window */ static void wm_window_match_init(bContext *C, ListBase *wmlist) { wmWindowManager *wm; wmWindow *win, *active_win; *wmlist = G.main->wm; BLI_listbase_clear(&G.main->wm); active_win = CTX_wm_window(C); /* first wrap up running stuff */ /* code copied from wm_init_exit.c */ for (wm = wmlist->first; wm; wm = wm->id.next) { WM_jobs_kill_all(wm); for (win = wm->windows.first; win; win = win->next) { CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, win->screen); } } /* reset active window */ 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 * (at least, in the 'startup splash' case), causing use-after-free error in later handling of the button * callbacks in UI code (see ui_apply_but_funcs_after()). * Tried solving this by always NULL-ing context's menu when setting wm/win/etc., but it broke popups refreshing * (see T47632), so for now just handling this specific case here. */ CTX_wm_menu_set(C, NULL); ED_editors_exit(C); /* just had return; here from r12991, this code could just get removed?*/ #if 0 if (wm == NULL) return; if (G.fileflags & G_FILE_NO_UI) return; /* we take apart the used screens from non-active window */ for (win = wm->windows.first; win; win = win->next) { BLI_strncpy(win->screenname, win->screen->id.name, MAX_ID_NAME); if (win != wm->winactive) { BLI_remlink(&G.main->screen, win->screen); //BLI_addtail(screenbase, win->screen); } } #endif }
void WM_init_splash(bContext *C) { if ((U.uiflag & USER_SPLASH_DISABLE) == 0) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *prevwin = CTX_wm_window(C); if (wm->windows.first) { CTX_wm_window_set(C, wm->windows.first); WM_operator_name_call(C, "WM_OT_splash", WM_OP_INVOKE_DEFAULT, NULL); CTX_wm_window_set(C, prevwin); } } }
void WM_window_open_temp(bContext *C, rcti *position, int type) { wmWindow *win; ScrArea *sa; /* changes rect to fit within desktop */ wm_window_check_position(position); /* test if we have a temp screen already */ for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) if (win->screen->temp) break; /* add new window? */ if (win == NULL) { win = wm_window_new(C); win->posx = position->xmin; win->posy = position->ymin; } win->sizex = position->xmax - position->xmin; win->sizey = position->ymax - position->ymin; if (win->ghostwin) { wm_window_set_size(win, win->sizex, win->sizey); wm_window_raise(win); } /* add new screen? */ if (win->screen == NULL) win->screen = ED_screen_add(win, CTX_data_scene(C), "temp"); win->screen->temp = 1; /* make window active, and validate/resize */ CTX_wm_window_set(C, win); WM_check(C); /* ensure it shows the right spacetype editor */ sa = win->screen->areabase.first; CTX_wm_area_set(C, sa); if (type == WM_WINDOW_RENDER) { ED_area_newspace(C, sa, SPACE_IMAGE); } else { ED_area_newspace(C, sa, SPACE_USERPREF); } ED_screen_set(C, win->screen); if (sa->spacetype == SPACE_IMAGE) GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render")); else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) GHOST_SetTitle(win->ghostwin, IFACE_("Blender User Preferences")); else if (sa->spacetype == SPACE_FILE) GHOST_SetTitle(win->ghostwin, IFACE_("Blender File View")); else GHOST_SetTitle(win->ghostwin, "Blender"); }
void wm_draw_update(bContext *C) { wmWindowManager *wm= CTX_wm_manager(C); wmWindow *win; int drawmethod; GPU_free_unused_buffers(); for(win= wm->windows.first; win; win= win->next) { if(win->drawmethod != U.wmdrawmethod) { wm_draw_window_clear(win); win->drawmethod= U.wmdrawmethod; } if(wm_draw_update_test_window(win)) { CTX_wm_window_set(C, win); /* sets context window+screen */ wm_window_make_drawable(C, win); /* notifiers for screen redraw */ if(win->screen->do_refresh) ED_screen_refresh(wm, win); drawmethod= wm_automatic_draw_method(win); if(win->drawfail) wm_method_draw_overlap_all(C, win, 0); else if(drawmethod == USER_DRAW_FULL) wm_method_draw_full(C, win); else if(drawmethod == USER_DRAW_OVERLAP) wm_method_draw_overlap_all(C, win, 0); else if(drawmethod == USER_DRAW_OVERLAP_FLIP) wm_method_draw_overlap_all(C, win, 1); else // if(drawmethod == USER_DRAW_TRIPLE) wm_method_draw_triple(C, win); win->screen->do_draw_gesture= 0; win->screen->do_draw_paintcursor= 0; win->screen->do_draw_drag= 0; wm_window_swap_buffers(win); CTX_wm_window_set(C, NULL); } } }
/* op can be NULL */ int WM_read_homefile(bContext *C, wmOperator *op) { ListBase wmbase; char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR]; char *home= BLI_gethome(); int from_memory= op?RNA_boolean_get(op->ptr, "factory"):0; int success; BLI_clean(home); free_ttfont(); /* still weird... what does it here? */ G.relbase_valid = 0; if (!from_memory) { BLI_make_file_string(G.sce, tstr, home, ".B25.blend"); } strcpy(scestr, G.sce); /* temporary store */ /* prevent loading no UI */ G.fileflags &= ~G_FILE_NO_UI; /* put aside screens to match with persistant windows later */ wm_window_match_init(C, &wmbase); if (!from_memory && BLI_exists(tstr)) { success = BKE_read_file(C, tstr, NULL, NULL); } else { success = BKE_read_file_from_memory(C, datatoc_B_blend, datatoc_B_blend_size, NULL, NULL); if (wmbase.first == NULL) wm_clear_default_size(C); } /* match the read WM with current WM */ wm_window_match_do(C, &wmbase); wm_check(C); /* opens window(s), checks keymaps */ strcpy(G.sce, scestr); /* restore */ wm_init_userdef(); /* When loading factory settings, the reset solid OpenGL lights need to be applied. */ GPU_default_lights(); /* XXX */ G.save_over = 0; // start with save preference untitled.blend G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in .B.blend... */ // mainwindow_set_filename_to_title(""); // empty string re-initializes title to "Blender" // refresh_interface_font(); // undo_editmode_clear(); BKE_reset_undo(); BKE_write_undo(C, "original"); /* save current state */ WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL); CTX_wm_window_set(C, NULL); /* exits queues */ return OPERATOR_FINISHED; }
/* To be able to read files without windows closing, opening, moving * we try to prepare for worst case: * - active window gets active screen from file * - restoring the screens from non-active windows * Best case is all screens match, in that case they get assigned to proper window */ static void wm_window_match_init(bContext *C, ListBase *wmlist) { wmWindowManager *wm; wmWindow *win, *active_win; *wmlist = G.main->wm; BLI_listbase_clear(&G.main->wm); active_win = CTX_wm_window(C); /* first wrap up running stuff */ /* code copied from wm_init_exit.c */ for (wm = wmlist->first; wm; wm = wm->id.next) { WM_jobs_kill_all(wm); for (win = wm->windows.first; win; win = win->next) { CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, win->screen); } } /* reset active window */ CTX_wm_window_set(C, active_win); ED_editors_exit(C); /* just had return; here from r12991, this code could just get removed?*/ #if 0 if (wm == NULL) return; if (G.fileflags & G_FILE_NO_UI) return; /* we take apart the used screens from non-active window */ for (win = wm->windows.first; win; win = win->next) { BLI_strncpy(win->screenname, win->screen->id.name, MAX_ID_NAME); if (win != wm->winactive) { BLI_remlink(&G.main->screen, win->screen); //BLI_addtail(screenbase, win->screen); } } #endif }
void WM_redraw_windows(bContext *C) { wmWindow *win_prev = CTX_wm_window(C); ScrArea *area_prev = CTX_wm_area(C); ARegion *ar_prev = CTX_wm_region(C); wm_draw_update(C); CTX_wm_window_set(C, win_prev); CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, ar_prev); }
/* this is event from ghost, or exit-blender op */ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { wmWindow *tmpwin; bool do_exit = false; /* first check if we have to quit (there are non-temp remaining windows) */ for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) { if (tmpwin == win) continue; if (tmpwin->screen->temp == 0) break; } if (tmpwin == NULL) do_exit = 1; if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) { if (do_exit) { if (!GHOST_confirmQuit(win->ghostwin)) return; } } /* let WM_exit do all freeing, for correct quit.blend save */ if (do_exit) { WM_exit(C); } else { bScreen *screen = win->screen; BLI_remlink(&wm->windows, win); wm_draw_window_clear(win); CTX_wm_window_set(C, win); /* needed by handlers */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); /* for regular use this will _never_ be NULL, * however we may be freeing an improperly initialized window. */ if (win->screen) { ED_screen_exit(C, win, win->screen); } wm_window_free(C, wm, win); /* if temp screen, delete it after window free (it stops jobs that can access it) */ if (screen && screen->temp) { Main *bmain = CTX_data_main(C); BKE_libblock_free(bmain, screen); } } }
/* this is event from ghost, or exit-blender op */ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { wmWindow *tmpwin; bScreen *screen = win->screen; /* first check if we have any non-temp remaining windows */ if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) { if (wm->windows.first) { for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) { if (tmpwin == win) continue; if (tmpwin->screen->temp == 0) break; } if (tmpwin == NULL) { if (!GHOST_confirmQuit(win->ghostwin)) return; } } } BLI_remlink(&wm->windows, win); wm_draw_window_clear(win); CTX_wm_window_set(C, win); /* needed by handlers */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, win->screen); wm_window_free(C, wm, win); /* if temp screen, delete it after window free (it stops jobs that can access it) */ if (screen->temp) { Main *bmain = CTX_data_main(C); BKE_libblock_free(&bmain->screen, screen); } /* check remaining windows */ if (wm->windows.first) { for (win = wm->windows.first; win; win = win->next) if (win->screen->temp == 0) break; /* in this case we close all */ if (win == NULL) WM_exit(C); } else WM_exit(C); }
void WM_read_file(bContext *C, char *name, ReportList *reports) { int retval; /* first try to append data from exotic file formats... */ /* it throws error box when file doesnt exist and returns -1 */ /* note; it should set some error message somewhere... (ton) */ retval= BKE_read_exotic(CTX_data_scene(C), name); /* we didn't succeed, now try to read Blender file */ if (retval== 0) { ListBase wmbase; /* put aside screens to match with persistant windows later */ /* also exit screens and editors */ wm_window_match_init(C, &wmbase); retval= BKE_read_file(C, name, NULL, reports); G.save_over = 1; /* match the read WM with current WM */ wm_window_match_do(C, &wmbase); wm_check(C); /* opens window(s), checks keymaps */ // XXX mainwindow_set_filename_to_title(G.main->name); if(retval==2) wm_init_userdef(); // in case a userdef is read from regular .blend if (retval!=0) { G.relbase_valid = 1; writeBlog(); } // XXX undo_editmode_clear(); BKE_reset_undo(); BKE_write_undo(C, "original"); /* save current state */ WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL); // refresh_interface_font(); CTX_wm_window_set(C, NULL); /* exits queues */ } else if(retval==1) BKE_write_undo(C, "Import file"); else if(retval == -1) { if(reports && reports->list.first == NULL) BKE_report(reports, RPT_ERROR, "Cannot read file."); } }
/* including window itself, C can be NULL. * ED_screen_exit should have been called */ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) { wmTimer *wt, *wtnext; /* update context */ if (C) { WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); if (CTX_wm_window(C) == win) CTX_wm_window_set(C, NULL); } /* always set drawable and active to NULL, * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */ wm->windrawable = NULL; wm->winactive = NULL; /* end running jobs, a job end also removes its timer */ for (wt = wm->timers.first; wt; wt = wtnext) { wtnext = wt->next; if (wt->win == win && wt->event_type == TIMERJOBS) wm_jobs_timer_ended(wm, wt); } /* timer removing, need to call this api function */ for (wt = wm->timers.first; wt; wt = wtnext) { wtnext = wt->next; if (wt->win == win) WM_event_remove_timer(wm, win, wt); } if (win->eventstate) MEM_freeN(win->eventstate); wm_event_free_all(win); wm_subwindows_free(win); wm_draw_data_free(win); wm_ghostwindow_destroy(win); MEM_freeN(win->stereo3d_format); MEM_freeN(win); }
/** * new window, no screen yet, but we open ghostwindow for it, * also gets the window level handlers * \note area-rip calls this. * \return the window or NULL. */ wmWindow *WM_window_open(bContext *C, const rcti *rect) { wmWindow *win_prev = CTX_wm_window(C); wmWindow *win = wm_window_new(C); win->posx = rect->xmin; win->posy = rect->ymin; win->sizex = BLI_rcti_size_x(rect); win->sizey = BLI_rcti_size_y(rect); win->drawmethod = U.wmdrawmethod; WM_check(C); if (win->ghostwin) { return win; } else { wm_window_close(C, CTX_wm_manager(C), win); CTX_wm_window_set(C, win_prev); return NULL; } }
/* To be able to read files without windows closing, opening, moving we try to prepare for worst case: - active window gets active screen from file - restoring the screens from non-active windows Best case is all screens match, in that case they get assigned to proper window */ static void wm_window_match_init(bContext *C, ListBase *wmlist) { wmWindowManager *wm= G.main->wm.first; wmWindow *win; *wmlist= G.main->wm; G.main->wm.first= G.main->wm.last= NULL; /* first wrap up running stuff */ /* code copied from wm_init_exit.c */ for(wm= wmlist->first; wm; wm= wm->id.next) { WM_jobs_stop_all(wm); for(win= wm->windows.first; win; win= win->next) { CTX_wm_window_set(C, win); /* needed by operator close callbacks */ ED_screen_exit(C, win, win->screen); } } ED_editors_exit(C); return; if(wm==NULL) return; if(G.fileflags & G_FILE_NO_UI) return; /* we take apart the used screens from non-active window */ for(win= wm->windows.first; win; win= win->next) { BLI_strncpy(win->screenname, win->screen->id.name, MAX_ID_NAME); if(win!=wm->winactive) { BLI_remlink(&G.main->screen, win->screen); //BLI_addtail(screenbase, win->screen); } } }
int wm_stereo3d_set_exec(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win_src = CTX_wm_window(C); wmWindow *win_dst = NULL; const bool is_fullscreen = WM_window_is_fullscreen(win_src); char prev_display_mode = win_src->stereo3d_format->display_mode; Stereo3dData *s3dd; bool ok = true; if (G.background) return OPERATOR_CANCELLED; if (op->customdata == NULL) { /* no invoke means we need to set the operator properties here */ wm_stereo3d_set_init(C, op); wm_stereo3d_set_properties(C, op); } s3dd = op->customdata; *win_src->stereo3d_format = s3dd->stereo3d_format; if (prev_display_mode == S3D_DISPLAY_PAGEFLIP && prev_display_mode != win_src->stereo3d_format->display_mode) { /* in case the hardward supports pageflip but not the display */ if ((win_dst = wm_window_copy_test(C, win_src))) { /* pass */ } else { BKE_report(op->reports, RPT_ERROR, "Failed to create a window without quad-buffer support, you may experience flickering"); ok = false; } } else if (win_src->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) { /* ED_screen_duplicate() can't handle other cases yet T44688 */ if (win_src->screen->state != SCREENNORMAL) { BKE_report(op->reports, RPT_ERROR, "Failed to switch to Time Sequential mode when in fullscreen"); ok = false; } /* pageflip requires a new window to be created with the proper OS flags */ else if ((win_dst = wm_window_copy_test(C, win_src))) { if (wm_stereo3d_quadbuffer_supported()) { BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created"); } else { wm_window_close(C, wm, win_dst); win_dst = NULL; BKE_report(op->reports, RPT_ERROR, "Quad-buffer not supported by the system"); ok = false; } } else { BKE_report(op->reports, RPT_ERROR, "Failed to create a window compatible with the time sequential display method"); ok = false; } } if (wm_stereo3d_is_fullscreen_required(s3dd->stereo3d_format.display_mode)) { if (!is_fullscreen) { BKE_report(op->reports, RPT_INFO, "Stereo 3D Mode requires the window to be fullscreen"); } } MEM_freeN(op->customdata); if (ok) { if (win_dst) { wm_window_close(C, wm, win_src); } WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; } else { /* without this, the popup won't be freed freed properly T44688 */ CTX_wm_window_set(C, win_src); win_src->stereo3d_format->display_mode = prev_display_mode; return OPERATOR_CANCELLED; } }
/** * \note doesn't run exit() call #WM_exit() for that. */ void WM_exit_ext(bContext *C, const bool do_python) { wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL; /* first wrap up running stuff, we assume only the active WM is running */ /* modal handlers are on window level freed, others too? */ /* note; same code copied in wm_files.c */ if (C && wm) { wmWindow *win; if (!G.background) { struct MemFile *undo_memfile = wm->undo_stack ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : NULL; if ((U.uiflag2 & USER_KEEP_SESSION) || (undo_memfile != NULL)) { /* save the undo state as quit.blend */ char filename[FILE_MAX]; bool has_edited; int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY); BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE); has_edited = ED_editors_flush_edits(C, false); if ((has_edited && BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL)) || (undo_memfile && BLO_memfile_write_file(undo_memfile, filename))) { printf("Saved session recovery to '%s'\n", filename); } } } WM_jobs_kill_all(wm); for (win = wm->windows.first; win; win = win->next) { CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, win->screen); } } BKE_addon_pref_type_free(); wm_operatortype_free(); wm_dropbox_free(); WM_menutype_free(); WM_uilisttype_free(); /* all non-screen and non-space stuff editors did, like editmode */ if (C) ED_editors_exit(C); ED_undosys_type_free(); // XXX // BIF_GlobalReebFree(); // BIF_freeRetarget(); BIF_freeTemplates(C); free_openrecent(); BKE_mball_cubeTable_free(); /* render code might still access databases */ RE_FreeAllRender(); RE_engines_exit(); ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */ if (C && wm) wm_free_reports(C); /* before BKE_blender_free! - since the ListBases get freed there */ BKE_sequencer_free_clipboard(); /* sequencer.c */ BKE_tracking_clipboard_free(); BKE_mask_clipboard_free(); BKE_vfont_clipboard_free(); #ifdef WITH_COMPOSITOR COM_deinitialize(); #endif BKE_blender_free(); /* blender.c, does entire library and spacetypes */ // free_matcopybuf(); ANIM_fcurves_copybuf_free(); ANIM_drivers_copybuf_free(); ANIM_driver_vars_copybuf_free(); ANIM_fmodifiers_copybuf_free(); ED_gpencil_anim_copybuf_free(); ED_gpencil_strokes_copybuf_free(); BKE_node_clipboard_clear(); BLF_exit(); #ifdef WITH_INTERNATIONAL BLF_free_unifont(); BLF_free_unifont_mono(); BLT_lang_free(); #endif ANIM_keyingset_infos_exit(); // free_txt_data(); #ifdef WITH_PYTHON /* option not to close python so we can use 'atexit' */ if (do_python && ((C == NULL) || CTX_py_init_get(C))) { /* XXX - old note */ /* before BKE_blender_free so py's gc happens while library still exists */ /* needed at least for a rare sigsegv that can happen in pydrivers */ /* Update for blender 2.5, move after BKE_blender_free because blender now holds references to PyObject's * so decref'ing them after python ends causes bad problems every time * the pyDriver bug can be fixed if it happens again we can deal with it then */ BPY_python_end(); } #else (void)do_python; #endif if (!G.background) { #ifdef WITH_OPENSUBDIV BKE_subsurf_osd_cleanup(); #endif GPU_global_buffer_pool_free(); GPU_free_unused_buffers(G_MAIN); GPU_exit(); } ED_file_exit(); /* for fsmenu */ UI_exit(); BKE_blender_userdef_data_free(&U, false); RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */ wm_ghost_exit(); CTX_free(C); #ifdef WITH_GAMEENGINE SYS_DeleteSystem(SYS_GetSystem()); #endif GHOST_DisposeSystemPaths(); DNA_sdna_current_free(); BLI_threadapi_exit(); /* No need to call this early, rather do it late so that other pieces of Blender using sound may exit cleanly, * see also T50676. */ BKE_sound_exit(); CLG_exit(); BKE_blender_atexit(); if (MEM_get_memory_blocks_in_use() != 0) { size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use(); printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", MEM_get_memory_blocks_in_use(), (double)mem_in_use / 1024 / 1024); MEM_printmemlist(); } wm_autosave_delete(); BKE_tempdir_session_purge(); }
bool WM_init_game(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; ScrArea *sa; ARegion *ar = NULL; Scene *scene = CTX_data_scene(C); if (!scene) { /* XXX, this should not be needed. */ Main *bmain = CTX_data_main(C); scene = bmain->scene.first; } win = wm->windows.first; /* first to get a valid window */ if (win) CTX_wm_window_set(C, win); sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0); ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); /* if we have a valid 3D view */ if (sa && ar) { ARegion *arhide; CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); /* disable quad view */ if (ar->alignment == RGN_ALIGN_QSPLIT) WM_operator_name_call(C, "SCREEN_OT_region_quadview", WM_OP_EXEC_DEFAULT, NULL); /* toolbox, properties panel and header are hidden */ for (arhide = sa->regionbase.first; arhide; arhide = arhide->next) { if (arhide->regiontype != RGN_TYPE_WINDOW) { if (!(arhide->flag & RGN_FLAG_HIDDEN)) { ED_region_toggle_hidden(C, arhide); } } } /* full screen the area */ if (!sa->full) { ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED); } /* Fullscreen */ if ((scene->gm.playerflag & GAME_PLAYER_FULLSCREEN)) { WM_operator_name_call(C, "WM_OT_window_fullscreen_toggle", WM_OP_EXEC_DEFAULT, NULL); wm_get_screensize(&ar->winrct.xmax, &ar->winrct.ymax); ar->winx = ar->winrct.xmax + 1; ar->winy = ar->winrct.ymax + 1; } else { GHOST_RectangleHandle rect = GHOST_GetClientBounds(win->ghostwin); ar->winrct.ymax = GHOST_GetHeightRectangle(rect); ar->winrct.xmax = GHOST_GetWidthRectangle(rect); ar->winx = ar->winrct.xmax + 1; ar->winy = ar->winrct.ymax + 1; GHOST_DisposeRectangle(rect); } WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL); BKE_sound_exit(); return true; } else { ReportTimerInfo *rti; BKE_report(&wm->reports, RPT_ERROR, "No valid 3D View found, game auto start is not possible"); /* After adding the report to the global list, reset the report timer. */ WM_event_remove_timer(wm, NULL, wm->reports.reporttimer); /* Records time since last report was added */ wm->reports.reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER, 0.02); rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); wm->reports.reporttimer->customdata = rti; return false; } }
/* mouse coordinate converversion happens here */ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr) { bContext *C = C_void_ptr; wmWindowManager *wm = CTX_wm_manager(C); GHOST_TEventType type = GHOST_GetEventType(evt); int time = GHOST_GetEventTime(evt); if (type == GHOST_kEventQuit) { WM_exit(C); } else { GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt); GHOST_TEventDataPtr data = GHOST_GetEventData(evt); wmWindow *win; /* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet. * Can happen on file read (especially full size window) */ if ((wm->initialized & WM_INIT_WINDOW) == 0) { return 1; } if (!ghostwin) { /* XXX - should be checked, why are we getting an event here, and */ /* what is it? */ puts("<!> event has no window"); return 1; } else if (!GHOST_ValidWindow(g_system, ghostwin)) { /* XXX - should be checked, why are we getting an event here, and */ /* what is it? */ puts("<!> event has invalid window"); return 1; } else { win = GHOST_GetWindowUserData(ghostwin); } switch (type) { case GHOST_kEventWindowDeactivate: wm_event_add_ghostevent(wm, win, type, time, data); win->active = 0; /* XXX */ /* clear modifiers for inactive windows */ win->eventstate->alt = 0; win->eventstate->ctrl = 0; win->eventstate->shift = 0; win->eventstate->oskey = 0; win->eventstate->keymodifier = 0; break; case GHOST_kEventWindowActivate: { GHOST_TEventKeyData kdata; wmEvent event; int wx, wy; const int keymodifier = ((query_qual(SHIFT) ? KM_SHIFT : 0) | (query_qual(CONTROL) ? KM_CTRL : 0) | (query_qual(ALT) ? KM_ALT : 0) | (query_qual(OS) ? KM_OSKEY : 0)); /* Win23/GHOST modifier bug, see T40317 */ #ifndef WIN32 //# define USE_WIN_ACTIVATE #endif wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */ win->active = 1; // window_handle(win, INPUTCHANGE, win->active); /* bad ghost support for modifier keys... so on activate we set the modifiers again */ /* TODO: This is not correct since a modifier may be held when a window is activated... * better solve this at ghost level. attempted fix r54450 but it caused bug [#34255] * * For now don't send GHOST_kEventKeyDown events, just set the 'eventstate'. */ kdata.ascii = '\0'; kdata.utf8_buf[0] = '\0'; if (win->eventstate->shift) { if ((keymodifier & KM_SHIFT) == 0) { kdata.key = GHOST_kKeyLeftShift; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } } #ifdef USE_WIN_ACTIVATE else { if (keymodifier & KM_SHIFT) { win->eventstate->shift = KM_MOD_FIRST; } } #endif if (win->eventstate->ctrl) { if ((keymodifier & KM_CTRL) == 0) { kdata.key = GHOST_kKeyLeftControl; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } } #ifdef USE_WIN_ACTIVATE else { if (keymodifier & KM_CTRL) { win->eventstate->ctrl = KM_MOD_FIRST; } } #endif if (win->eventstate->alt) { if ((keymodifier & KM_ALT) == 0) { kdata.key = GHOST_kKeyLeftAlt; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } } #ifdef USE_WIN_ACTIVATE else { if (keymodifier & KM_ALT) { win->eventstate->alt = KM_MOD_FIRST; } } #endif if (win->eventstate->oskey) { if ((keymodifier & KM_OSKEY) == 0) { kdata.key = GHOST_kKeyOS; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } } #ifdef USE_WIN_ACTIVATE else { if (keymodifier & KM_OSKEY) { win->eventstate->oskey = KM_MOD_FIRST; } } #endif #undef USE_WIN_ACTIVATE /* keymodifier zero, it hangs on hotkeys that open windows otherwise */ win->eventstate->keymodifier = 0; /* entering window, update mouse pos. but no event */ wm_get_cursor_position(win, &wx, &wy); win->eventstate->x = wx; win->eventstate->y = wy; win->addmousemove = 1; /* enables highlighted buttons */ wm_window_make_drawable(wm, win); /* window might be focused by mouse click in configuration of window manager * when focus is not following mouse * click could have been done on a button and depending on window manager settings * click would be passed to blender or not, but in any case button under cursor * should be activated, so at max next click on button without moving mouse * would trigger it's handle function * currently it seems to be common practice to generate new event for, but probably * we'll need utility function for this? (sergey) */ wm_event_init_from_window(win, &event); event.type = MOUSEMOVE; event.prevx = event.x; event.prevy = event.y; wm_event_add(win, &event); break; } case GHOST_kEventWindowClose: { wm_window_close(C, wm, win); break; } case GHOST_kEventWindowUpdate: { if (G.debug & G_DEBUG_EVENTS) { printf("%s: ghost redraw %d\n", __func__, win->winid); } wm_window_make_drawable(wm, win); WM_event_add_notifier(C, NC_WINDOW, NULL); break; } case GHOST_kEventWindowSize: case GHOST_kEventWindowMove: { GHOST_TWindowState state; state = GHOST_GetWindowState(win->ghostwin); win->windowstate = state; /* stop screencast if resize */ if (type == GHOST_kEventWindowSize) { WM_jobs_stop(wm, win->screen, NULL); } /* win32: gives undefined window size when minimized */ if (state != GHOST_kWindowStateMinimized) { GHOST_RectangleHandle client_rect; int l, t, r, b, scr_w, scr_h; int sizex, sizey, posx, posy; client_rect = GHOST_GetClientBounds(win->ghostwin); GHOST_GetRectangle(client_rect, &l, &t, &r, &b); GHOST_DisposeRectangle(client_rect); wm_get_desktopsize(&scr_w, &scr_h); sizex = r - l; sizey = b - t; posx = l; posy = scr_h - t - win->sizey; /* * Ghost sometimes send size or move events when the window hasn't changed. * One case of this is using compiz on linux. To alleviate the problem * we ignore all such event here. * * It might be good to eventually do that at Ghost level, but that is for * another time. */ if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || win->posy != posy) { win->sizex = sizex; win->sizey = sizey; win->posx = posx; win->posy = posy; /* debug prints */ if (G.debug & G_DEBUG_EVENTS) { const char *state_str; state = GHOST_GetWindowState(win->ghostwin); if (state == GHOST_kWindowStateNormal) { state_str = "normal"; } else if (state == GHOST_kWindowStateMinimized) { state_str = "minimized"; } else if (state == GHOST_kWindowStateMaximized) { state_str = "maximized"; } else if (state == GHOST_kWindowStateFullScreen) { state_str = "fullscreen"; } else { state_str = "<unknown>"; } printf("%s: window %d state = %s\n", __func__, win->winid, state_str); if (type != GHOST_kEventWindowSize) { printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey); } } wm_window_make_drawable(wm, win); wm_draw_window_clear(win); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); #if defined(__APPLE__) || defined(WIN32) /* OSX and Win32 don't return to the mainloop while resize */ wm_event_do_handlers(C); wm_event_do_notifiers(C); wm_draw_update(C); #endif } } break; } case GHOST_kEventOpenMainFile: { PointerRNA props_ptr; wmWindow *oldWindow; const char *path = GHOST_GetEventData(evt); if (path) { wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false); /* operator needs a valid window in context, ensures * it is correctly set */ oldWindow = CTX_wm_window(C); CTX_wm_window_set(C, win); WM_operator_properties_create_ptr(&props_ptr, ot); RNA_string_set(&props_ptr, "filepath", path); WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr); WM_operator_properties_free(&props_ptr); CTX_wm_window_set(C, oldWindow); } break; } case GHOST_kEventDraggingDropDone: { wmEvent event; GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt); int wx, wy; /* entering window, update mouse pos */ wm_get_cursor_position(win, &wx, &wy); win->eventstate->x = wx; win->eventstate->y = wy; wm_event_init_from_window(win, &event); /* copy last state, like mouse coords */ /* activate region */ event.type = MOUSEMOVE; event.prevx = event.x; event.prevy = event.y; wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */ win->active = 1; wm_event_add(win, &event); /* make blender drop event with custom data pointing to wm drags */ event.type = EVT_DROP; event.val = KM_RELEASE; event.custom = EVT_DATA_DRAGDROP; event.customdata = &wm->drags; event.customdatafree = 1; wm_event_add(win, &event); /* printf("Drop detected\n"); */ /* add drag data to wm for paths: */ if (ddd->dataType == GHOST_kDragnDropTypeFilenames) { GHOST_TStringArray *stra = ddd->data; int a, icon; for (a = 0; a < stra->count; a++) { printf("drop file %s\n", stra->strings[a]); /* try to get icon type from extension */ icon = ED_file_extension_icon((char *)stra->strings[a]); WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0, WM_DRAG_NOP); /* void poin should point to string, it makes a copy */ break; /* only one drop element supported now */ } } break; } case GHOST_kEventNativeResolutionChange: // printf("change, pixel size %f\n", GHOST_GetNativePixelSize(win->ghostwin)); U.pixelsize = wm_window_pixelsize(win); BKE_userdef_state(); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); break; case GHOST_kEventTrackpad: { GHOST_TEventTrackpadData *pd = data; wm_convert_cursor_position(win, &pd->x, &pd->y); wm_event_add_ghostevent(wm, win, type, time, data); break; } case GHOST_kEventCursorMove: { GHOST_TEventCursorData *cd = data; wm_convert_cursor_position(win, &cd->x, &cd->y); wm_event_add_ghostevent(wm, win, type, time, data); break; } default: wm_event_add_ghostevent(wm, win, type, time, data); break; } } return 1; }
/* only called once, for startup */ void WM_init(bContext *C, int argc, const char **argv) { if (!G.background) { wm_ghost_init(C); /* note: it assigns C to ghost! */ wm_init_cursor_data(); } GHOST_CreateSystemPaths(); BKE_addon_pref_type_init(); wm_operatortype_init(); wm_operatortypes_register(); WM_menutype_init(); WM_uilisttype_init(); ED_undosys_type_init(); BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update, ED_render_scene_update_pre); /* depsgraph.c */ ED_spacetypes_init(); /* editors/space_api/spacetype.c */ ED_file_init(); /* for fsmenu */ ED_node_init_butfuncs(); BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */ BLT_lang_init(); /* Must call first before doing any .blend file reading, since versionning code may create new IDs... See T57066. */ BLT_lang_set(NULL); /* reports cant be initialized before the wm, * but keep before file reading, since that may report errors */ wm_init_reports(C); /* get the default database, plus a wm */ wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, WM_init_state_app_template_get()); /* Call again to set from userpreferences... */ BLT_lang_set(NULL); if (!G.background) { #ifdef WITH_INPUT_NDOF /* sets 3D mouse deadzone */ WM_ndof_deadzone_set(U.ndof_deadzone); #endif GPU_init(); GPU_set_mipmap(G_MAIN, !(U.gameflags & USER_DISABLE_MIPMAP)); GPU_set_linear_mipmap(true); GPU_set_anisotropic(G_MAIN, U.anisotropic_filter); GPU_set_gpu_mipmapping(G_MAIN, U.use_gpu_mipmap); #ifdef WITH_OPENSUBDIV BKE_subsurf_osd_init(); #endif UI_init(); } else { /* Note: Currently only inits icons, which we now want in background mode too * (scripts could use those in background processing...). * In case we do more later, we may need to pass a 'background' flag. * Called from 'UI_init' above */ BKE_icons_init(1); } ED_spacemacros_init(); /* note: there is a bug where python needs initializing before loading the * startup.blend because it may contain PyDrivers. It also needs to be after * initializing space types and other internal data. * * However cant redo this at the moment. Solution is to load python * before wm_homefile_read() or make py-drivers check if python is running. * Will try fix when the crash can be repeated. - campbell. */ #ifdef WITH_PYTHON BPY_context_set(C); /* necessary evil */ BPY_python_start(argc, argv); BPY_python_reset(C); #else (void)argc; /* unused */ (void)argv; /* unused */ #endif if (!G.background && !wm_start_with_console) GHOST_toggleConsole(3); clear_matcopybuf(); ED_render_clear_mtex_copybuf(); // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); wm_history_file_read(); /* allow a path of "", this is what happens when making a new file */ #if 0 if (BKE_main_blendfile_path_from_global()[0] == '\0') BLI_make_file_string("/", G_MAIN->name, BKE_appdir_folder_default(), "untitled.blend"); #endif BLI_strncpy(G.lib, BKE_main_blendfile_path_from_global(), sizeof(G.lib)); #ifdef WITH_COMPOSITOR if (1) { extern void *COM_linker_hack; COM_linker_hack = COM_execute; } #endif /* load last session, uses regular file reading so it has to be in end (after init py etc) */ if (U.uiflag2 & USER_KEEP_SESSION) { /* calling WM_recover_last_session(C, NULL) has been moved to creator.c */ /* that prevents loading both the kept session, and the file on the command line */ } else { Main *bmain = CTX_data_main(C); /* note, logic here is from wm_file_read_post, * call functions that depend on Python being initialized. */ /* normally 'wm_homefile_read' will do this, * however python is not initialized when called from this function. * * unlikely any handlers are set but its possible, * note that recovering the last session does its own callbacks. */ CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST); wm_file_read_report(C, bmain); if (!G.background) { CTX_wm_window_set(C, NULL); } } }
/* op can be NULL */ int WM_read_homefile(bContext *C, ReportList *UNUSED(reports), short from_memory) { ListBase wmbase; char tstr[FILE_MAX]; int success = 0; free_ttfont(); /* still weird... what does it here? */ G.relbase_valid = 0; if (!from_memory) { char *cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); if (cfgdir) { BLI_make_file_string(G.main->name, tstr, cfgdir, BLENDER_STARTUP_FILE); } else { tstr[0] = '\0'; from_memory = 1; } } /* prevent loading no UI */ G.fileflags &= ~G_FILE_NO_UI; /* put aside screens to match with persistent windows later */ wm_window_match_init(C, &wmbase); if (!from_memory && BLI_exists(tstr)) { success = (BKE_read_file(C, tstr, NULL) != BKE_READ_FILE_FAIL); if (U.themes.first == NULL) { printf("\nError: No valid "STRINGIFY (BLENDER_STARTUP_FILE)", fall back to built-in default.\n\n"); success = 0; } } if (success == 0) { success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL); if (wmbase.first == NULL) wm_clear_default_size(C); #ifdef WITH_PYTHON_SECURITY /* not default */ /* use alternative setting for security nuts * otherwise we'd need to patch the binary blob - startup.blend.c */ U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE; #endif } /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise * can remove this eventually, only in a 2.53 and older, now its not written */ G.fileflags &= ~G_FILE_RELATIVE_REMAP; /* check userdef before open window, keymaps etc */ wm_init_userdef(C); /* match the read WM with current WM */ wm_window_match_do(C, &wmbase); WM_check(C); /* opens window(s), checks keymaps */ G.main->name[0] = '\0'; /* When loading factory settings, the reset solid OpenGL lights need to be applied. */ if (!G.background) GPU_default_lights(); /* XXX */ G.save_over = 0; // start with save preference untitled.blend G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */ // mainwindow_set_filename_to_title(""); // empty string re-initializes title to "Blender" // refresh_interface_font(); // undo_editmode_clear(); BKE_reset_undo(); BKE_write_undo(C, "original"); /* save current state */ ED_editors_init(C); DAG_on_visible_update(CTX_data_main(C), TRUE); #ifdef WITH_PYTHON if (CTX_py_init_get(C)) { /* sync addons, these may have changed from the defaults */ BPY_string_exec(C, "__import__('addon_utils').reset_all()"); BPY_driver_reset(); BPY_app_handlers_reset(FALSE); BPY_modules_load_user(C); } #endif WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); /* in background mode the scene will stay NULL */ if (!G.background) { CTX_wm_window_set(C, NULL); /* exits queues */ } return TRUE; }
/* custom_file can be NULL */ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const char *custom_file) { ListBase wmbase; char startstr[FILE_MAX]; char prefstr[FILE_MAX]; int success = 0; /* Indicates whether user prefereneces were really load from memory. * * This is used for versioning code, and for this we can not rely on from_memory * passed via argument. This is because there might be configuration folder * exists but it might not have userpref.blend and in this case we fallback to * reading home file from memory. * * And in this case versioning code is to be run. */ bool read_userdef_from_memory = true; /* options exclude eachother */ BLI_assert((from_memory && custom_file) == 0); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE); G.relbase_valid = 0; if (!from_memory) { const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); if (custom_file) { BLI_strncpy(startstr, custom_file, FILE_MAX); if (cfgdir) { BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE); } else { prefstr[0] = '\0'; } } else if (cfgdir) { BLI_make_file_string(G.main->name, startstr, cfgdir, BLENDER_STARTUP_FILE); BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE); } else { startstr[0] = '\0'; prefstr[0] = '\0'; from_memory = 1; } } /* prevent loading no UI */ G.fileflags &= ~G_FILE_NO_UI; /* put aside screens to match with persistent windows later */ wm_window_match_init(C, &wmbase); if (!from_memory) { if (BLI_access(startstr, R_OK) == 0) { success = (BKE_read_file(C, startstr, NULL) != BKE_READ_FILE_FAIL); } if (U.themes.first == NULL) { if (G.debug & G_DEBUG) printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", startstr); success = 0; } } if (success == 0 && custom_file && reports) { BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", custom_file); /*We can not return from here because wm is already reset*/ } if (success == 0) { success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true); if (wmbase.first == NULL) wm_clear_default_size(C); BLI_init_temporary_dir(U.tempdir); #ifdef WITH_PYTHON_SECURITY /* use alternative setting for security nuts * otherwise we'd need to patch the binary blob - startup.blend.c */ U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE; #endif } /* check new prefs only after startup.blend was finished */ if (!from_memory && BLI_exists(prefstr)) { int done = BKE_read_file_userdef(prefstr, NULL); if (done) { read_userdef_from_memory = false; printf("Read new prefs: %s\n", prefstr); } } /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise * can remove this eventually, only in a 2.53 and older, now its not written */ G.fileflags &= ~G_FILE_RELATIVE_REMAP; /* check userdef before open window, keymaps etc */ wm_init_userdef(C, read_userdef_from_memory); /* match the read WM with current WM */ wm_window_match_do(C, &wmbase); WM_check(C); /* opens window(s), checks keymaps */ G.main->name[0] = '\0'; /* When loading factory settings, the reset solid OpenGL lights need to be applied. */ if (!G.background) GPU_default_lights(); /* XXX */ G.save_over = 0; // start with save preference untitled.blend G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */ // refresh_interface_font(); // undo_editmode_clear(); BKE_reset_undo(); BKE_write_undo(C, "original"); /* save current state */ ED_editors_init(C); DAG_on_visible_update(CTX_data_main(C), TRUE); #ifdef WITH_PYTHON if (CTX_py_init_get(C)) { /* sync addons, these may have changed from the defaults */ BPY_string_exec(C, "__import__('addon_utils').reset_all()"); BPY_python_reset(C); } #endif /* important to do before NULL'ing the context */ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); /* in background mode the scene will stay NULL */ if (!G.background) { CTX_wm_window_set(C, NULL); /* exits queues */ } return TRUE; }
static int game_engine_exec(bContext *C, wmOperator *op) { #ifdef WITH_GAMEENGINE Scene *startscene = CTX_data_scene(C); Main *bmain = CTX_data_main(C); ScrArea /* *sa, */ /* UNUSED */ *prevsa = CTX_wm_area(C); ARegion *ar, *prevar = CTX_wm_region(C); wmWindow *prevwin = CTX_wm_window(C); RegionView3D *rv3d; rcti cam_frame; (void)op; /* unused */ /* bad context switch .. */ if (!ED_view3d_context_activate(C)) return OPERATOR_CANCELLED; /* redraw to hide any menus/popups, we don't go back to * the window manager until after this operator exits */ WM_redraw_windows(C); BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_PRE); rv3d = CTX_wm_region_view3d(C); /* sa = CTX_wm_area(C); */ /* UNUSED */ ar = CTX_wm_region(C); view3d_operator_needs_opengl(C); game_set_commmandline_options(&startscene->gm); if ((rv3d->persp == RV3D_CAMOB) && (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) && (startscene->gm.stereoflag != STEREO_DOME)) { /* Letterbox */ rctf cam_framef; ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false); cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin; cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin; cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin; cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin; BLI_rcti_isect(&ar->winrct, &cam_frame, &cam_frame); } else { cam_frame.xmin = ar->winrct.xmin; cam_frame.xmax = ar->winrct.xmax; cam_frame.ymin = ar->winrct.ymin; cam_frame.ymax = ar->winrct.ymax; } SaveState(C, prevwin); StartKetsjiShell(C, ar, &cam_frame, 1); /* window wasnt closed while the BGE was running */ if (BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) { prevwin = NULL; CTX_wm_window_set(C, NULL); } ED_area_tag_redraw(CTX_wm_area(C)); if (prevwin) { /* restore context, in case it changed in the meantime, for * example by working in another window or closing it */ CTX_wm_region_set(C, prevar); CTX_wm_window_set(C, prevwin); CTX_wm_area_set(C, prevsa); } RestoreState(C, prevwin); //XXX restore_all_scene_cfra(scene_cfra_store); BKE_scene_set_background(CTX_data_main(C), startscene); //XXX BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_POST); return OPERATOR_FINISHED; #else (void)C; /* unused */ BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build"); return OPERATOR_CANCELLED; #endif }
/* called by ghost, here we handle events for windows themselves or send to event system */ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr) { bContext *C = C_void_ptr; wmWindowManager *wm = CTX_wm_manager(C); GHOST_TEventType type = GHOST_GetEventType(evt); int time = GHOST_GetEventTime(evt); if (type == GHOST_kEventQuit) { WM_exit(C); } else { GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt); GHOST_TEventDataPtr data = GHOST_GetEventData(evt); wmWindow *win; if (!ghostwin) { /* XXX - should be checked, why are we getting an event here, and */ /* what is it? */ puts("<!> event has no window"); return 1; } else if (!GHOST_ValidWindow(g_system, ghostwin)) { /* XXX - should be checked, why are we getting an event here, and */ /* what is it? */ puts("<!> event has invalid window"); return 1; } else { win = GHOST_GetWindowUserData(ghostwin); } switch (type) { case GHOST_kEventWindowDeactivate: wm_event_add_ghostevent(wm, win, type, time, data); win->active = 0; /* XXX */ break; case GHOST_kEventWindowActivate: { GHOST_TEventKeyData kdata; wmEvent event; int cx, cy, wx, wy; wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */ win->active = 1; // window_handle(win, INPUTCHANGE, win->active); /* bad ghost support for modifier keys... so on activate we set the modifiers again */ kdata.ascii = '\0'; kdata.utf8_buf[0] = '\0'; if (win->eventstate->shift && !query_qual(SHIFT)) { kdata.key = GHOST_kKeyLeftShift; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } if (win->eventstate->ctrl && !query_qual(CONTROL)) { kdata.key = GHOST_kKeyLeftControl; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } if (win->eventstate->alt && !query_qual(ALT)) { kdata.key = GHOST_kKeyLeftAlt; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } if (win->eventstate->oskey && !query_qual(OS)) { kdata.key = GHOST_kKeyOS; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } /* keymodifier zero, it hangs on hotkeys that open windows otherwise */ win->eventstate->keymodifier = 0; /* entering window, update mouse pos. but no event */ GHOST_GetCursorPosition(g_system, &wx, &wy); GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy); win->eventstate->x = cx; win->eventstate->y = (win->sizey - 1) - cy; win->addmousemove = 1; /* enables highlighted buttons */ wm_window_make_drawable(C, win); /* window might be focused by mouse click in configuration of window manager * when focus is not following mouse * click could have been done on a button and depending on window manager settings * click would be passed to blender or not, but in any case button under cursor * should be activated, so at max next click on button without moving mouse * would trigger it's handle function * currently it seems to be common practice to generate new event for, but probably * we'll need utility function for this? (sergey) */ event = *(win->eventstate); event.type = MOUSEMOVE; event.prevx = event.x; event.prevy = event.y; wm_event_add(win, &event); break; } case GHOST_kEventWindowClose: { wm_window_close(C, wm, win); break; } case GHOST_kEventWindowUpdate: { if (G.debug & G_DEBUG_EVENTS) { printf("%s: ghost redraw %d\n", __func__, win->winid); } wm_window_make_drawable(C, win); WM_event_add_notifier(C, NC_WINDOW, NULL); break; } case GHOST_kEventWindowSize: case GHOST_kEventWindowMove: { GHOST_TWindowState state; state = GHOST_GetWindowState(win->ghostwin); win->windowstate = state; /* win32: gives undefined window size when minimized */ if (state != GHOST_kWindowStateMinimized) { GHOST_RectangleHandle client_rect; int l, t, r, b, scr_w, scr_h; int sizex, sizey, posx, posy; client_rect = GHOST_GetClientBounds(win->ghostwin); GHOST_GetRectangle(client_rect, &l, &t, &r, &b); GHOST_DisposeRectangle(client_rect); wm_get_screensize(&scr_w, &scr_h); sizex = r - l; sizey = b - t; posx = l; posy = scr_h - t - win->sizey; /* * Ghost sometimes send size or move events when the window hasn't changed. * One case of this is using compiz on linux. To alleviate the problem * we ignore all such event here. * * It might be good to eventually do that at Ghost level, but that is for * another time. */ if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || win->posy != posy) { win->sizex = sizex; win->sizey = sizey; win->posx = posx; win->posy = posy; /* debug prints */ if (G.debug & G_DEBUG_EVENTS) { const char *state_str; state = GHOST_GetWindowState(win->ghostwin); if (state == GHOST_kWindowStateNormal) { state_str = "normal"; } else if (state == GHOST_kWindowStateMinimized) { state_str = "minimized"; } else if (state == GHOST_kWindowStateMaximized) { state_str = "maximized"; } else if (state == GHOST_kWindowStateFullScreen) { state_str = "fullscreen"; } else { state_str = "<unknown>"; } printf("%s: window %d state = %s\n", __func__, win->winid, state_str); if (type != GHOST_kEventWindowSize) { printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey); } } wm_window_make_drawable(C, win); wm_draw_window_clear(win); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); } } break; } case GHOST_kEventOpenMainFile: { PointerRNA props_ptr; wmWindow *oldWindow; char *path = GHOST_GetEventData(evt); if (path) { /* operator needs a valid window in context, ensures * it is correctly set */ oldWindow = CTX_wm_window(C); CTX_wm_window_set(C, win); WM_operator_properties_create(&props_ptr, "WM_OT_open_mainfile"); RNA_string_set(&props_ptr, "filepath", path); WM_operator_name_call(C, "WM_OT_open_mainfile", WM_OP_EXEC_DEFAULT, &props_ptr); WM_operator_properties_free(&props_ptr); CTX_wm_window_set(C, oldWindow); } break; } case GHOST_kEventDraggingDropDone: { wmEvent event; GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt); int cx, cy, wx, wy; /* entering window, update mouse pos */ GHOST_GetCursorPosition(g_system, &wx, &wy); GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy); win->eventstate->x = cx; win->eventstate->y = (win->sizey - 1) - cy; event = *(win->eventstate); /* copy last state, like mouse coords */ /* activate region */ event.type = MOUSEMOVE; event.prevx = event.x; event.prevy = event.y; wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */ win->active = 1; wm_event_add(win, &event); /* make blender drop event with custom data pointing to wm drags */ event.type = EVT_DROP; event.val = KM_RELEASE; event.custom = EVT_DATA_LISTBASE; event.customdata = &wm->drags; event.customdatafree = 1; wm_event_add(win, &event); /* printf("Drop detected\n"); */ /* add drag data to wm for paths: */ if (ddd->dataType == GHOST_kDragnDropTypeFilenames) { GHOST_TStringArray *stra = ddd->data; int a, icon; for (a = 0; a < stra->count; a++) { printf("drop file %s\n", stra->strings[a]); /* try to get icon type from extension */ icon = ED_file_extension_icon((char *)stra->strings[a]); WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0); /* void poin should point to string, it makes a copy */ break; /* only one drop element supported now */ } } break; } default: wm_event_add_ghostevent(wm, win, type, time, data); break; } } return 1; }
void ED_render_scene_update(Main *bmain, Scene *scene, int updated) { /* viewport rendering update on data changes, happens after depsgraph * updates if there was any change. context is set to the 3d view */ bContext *C; wmWindowManager *wm; wmWindow *win; static bool recursive_check = false; /* don't do this render engine update if we're updating the scene from * other threads doing e.g. rendering or baking jobs */ if (!BLI_thread_is_main()) return; /* don't call this recursively for frame updates */ if (recursive_check) return; /* Do not call if no WM available, see T42688. */ if (BLI_listbase_is_empty(&bmain->wm)) return; recursive_check = true; C = CTX_create(); CTX_data_main_set(C, bmain); CTX_data_scene_set(C, scene); CTX_wm_manager_set(C, bmain->wm.first); wm = bmain->wm.first; for (win = wm->windows.first; win; win = win->next) { bScreen *sc = win->screen; ScrArea *sa; ARegion *ar; CTX_wm_window_set(C, win); for (sa = sc->areabase.first; sa; sa = sa->next) { if (sa->spacetype != SPACE_VIEW3D) continue; for (ar = sa->regionbase.first; ar; ar = ar->next) { RegionView3D *rv3d; RenderEngine *engine; if (ar->regiontype != RGN_TYPE_WINDOW) continue; rv3d = ar->regiondata; engine = rv3d->render_engine; /* call update if the scene changed, or if the render engine * tagged itself for update (e.g. because it was busy at the * time of the last update) */ if (engine && (updated || (engine->flag & RE_ENGINE_DO_UPDATE))) { CTX_wm_screen_set(C, sc); CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); engine->flag &= ~RE_ENGINE_DO_UPDATE; engine->type->view_update(engine, C); } } } } CTX_free(C); recursive_check = false; }
/* called in creator.c even... tsk, split this! */ void WM_exit(bContext *C) { wmWindow *win; sound_exit(); /* first wrap up running stuff, we assume only the active WM is running */ /* modal handlers are on window level freed, others too? */ /* note; same code copied in wm_files.c */ if(C && CTX_wm_manager(C)) { WM_jobs_stop_all(CTX_wm_manager(C)); for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) { CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, win->screen); } } wm_operatortype_free(); WM_menutype_free(); /* all non-screen and non-space stuff editors did, like editmode */ if(C) ED_editors_exit(C); // XXX // BIF_GlobalReebFree(); // BIF_freeRetarget(); BIF_freeTemplates(C); free_ttfont(); /* bke_font.h */ free_openrecent(); BKE_freecubetable(); fastshade_free_render(); /* shaded view */ ED_preview_free_dbase(); /* frees a Main dbase, before free_blender! */ if(C && CTX_wm_manager(C)) wm_free_reports(C); /* before free_blender! - since the ListBases get freed there */ free_blender(); /* blender.c, does entire library and spacetypes */ // free_matcopybuf(); free_anim_copybuf(); free_anim_drivers_copybuf(); free_posebuf(); // free_vertexpaint(); // free_imagepaint(); // fsmenu_free(); BLF_exit(); RE_FreeAllRender(); RE_engines_exit(); // free_txt_data(); #ifndef DISABLE_PYTHON /* XXX - old note */ /* before free_blender so py's gc happens while library still exists */ /* needed at least for a rare sigsegv that can happen in pydrivers */ /* Update for blender 2.5, move after free_blender because blender now holds references to PyObject's * so decref'ing them after python ends causes bad problems every time * the pyDriver bug can be fixed if it happens again we can deal with it then */ BPY_end_python(); #endif libtiff_exit(); #ifdef WITH_QUICKTIME quicktime_exit(); #endif if (!G.background) { // XXX UI_filelist_free_icons(); } GPU_buffer_pool_free(0); GPU_extensions_exit(); // if (copybuf) MEM_freeN(copybuf); // if (copybufinfo) MEM_freeN(copybufinfo); BKE_undo_save_quit(); // saves quit.blend if global undo is on BKE_reset_undo(); ED_file_exit(); /* for fsmenu */ UI_exit(); BKE_userdef_free(); RNA_exit(); /* should be after BPY_end_python so struct python slots are cleared */ wm_ghost_exit(); CTX_free(C); SYS_DeleteSystem(SYS_GetSystem()); if(MEM_get_memory_blocks_in_use()!=0) { printf("Error Totblock: %d\n", MEM_get_memory_blocks_in_use()); MEM_printmemlist(); } wm_autosave_delete(); printf("\nBlender quit\n"); #ifdef WIN32 /* ask user to press enter when in debug mode */ if(G.f & G_DEBUG) { printf("press enter key to exit...\n\n"); getchar(); } #endif exit(G.afbreek==1); }
/* note, doesnt run exit() call WM_exit() for that */ void WM_exit_ext(bContext *C, const short do_python) { wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL; sound_exit(); /* first wrap up running stuff, we assume only the active WM is running */ /* modal handlers are on window level freed, others too? */ /* note; same code copied in wm_files.c */ if (C && wm) { wmWindow *win; if (!G.background) { if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_valid(NULL)) { /* save the undo state as quit.blend */ char filename[FILE_MAX]; BLI_make_file_string("/", filename, BLI_temporary_dir(), BLENDER_QUIT_FILE); if (BKE_undo_save_file(filename)) printf("Saved session recovery to '%s'\n", filename); } } WM_jobs_kill_all(wm); for (win = wm->windows.first; win; win = win->next) { CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, win->screen); } } BKE_addon_pref_type_free(); wm_operatortype_free(); wm_dropbox_free(); WM_menutype_free(); WM_uilisttype_free(); /* all non-screen and non-space stuff editors did, like editmode */ if (C) ED_editors_exit(C); // XXX // BIF_GlobalReebFree(); // BIF_freeRetarget(); BIF_freeTemplates(C); free_openrecent(); BKE_mball_cubeTable_free(); /* render code might still access databases */ RE_FreeAllRender(); RE_engines_exit(); ED_preview_free_dbase(); /* frees a Main dbase, before free_blender! */ if (C && wm) wm_free_reports(C); /* before free_blender! - since the ListBases get freed there */ BKE_sequencer_free_clipboard(); /* sequencer.c */ BKE_tracking_clipboard_free(); #ifdef WITH_COMPOSITOR COM_deinitialize(); #endif free_blender(); /* blender.c, does entire library and spacetypes */ // free_matcopybuf(); free_anim_copybuf(); free_anim_drivers_copybuf(); free_fmodifiers_copybuf(); ED_clipboard_posebuf_free(); BKE_node_clipboard_clear(); BLF_exit(); #ifdef WITH_INTERNATIONAL BLF_free_unifont(); BLF_free_unifont_mono(); BLF_lang_free(); #endif ANIM_keyingset_infos_exit(); // free_txt_data(); #ifdef WITH_PYTHON /* option not to close python so we can use 'atexit' */ if (do_python) { /* XXX - old note */ /* before free_blender so py's gc happens while library still exists */ /* needed at least for a rare sigsegv that can happen in pydrivers */ /* Update for blender 2.5, move after free_blender because blender now holds references to PyObject's * so decref'ing them after python ends causes bad problems every time * the pyDriver bug can be fixed if it happens again we can deal with it then */ BPY_python_end(); } #else (void)do_python; #endif GPU_global_buffer_pool_free(); GPU_free_unused_buffers(); GPU_extensions_exit(); BKE_reset_undo(); ED_file_exit(); /* for fsmenu */ UI_exit(); BKE_userdef_free(); RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */ wm_ghost_exit(); CTX_free(C); #ifdef WITH_GAMEENGINE SYS_DeleteSystem(SYS_GetSystem()); #endif GHOST_DisposeSystemPaths(); if (MEM_get_memory_blocks_in_use() != 0) { printf("Error: Not freed memory blocks: %d\n", MEM_get_memory_blocks_in_use()); MEM_printmemlist(); } wm_autosave_delete(); printf("\nBlender quit\n"); #ifdef WIN32 /* ask user to press a key when in debug mode */ if (G.debug & G_DEBUG) { printf("Press any key to exit . . .\n\n"); wait_for_console_key(); } #endif }
/** * Logic shared between #WM_file_read & #wm_homefile_read, * updates to make after reading a file. */ static void wm_file_read_post(bContext *C, bool is_startup_file) { bool addons_loaded = false; wmWindowManager *wm = CTX_wm_manager(C); if (!G.background) { /* remove windows which failed to be added via WM_check */ wm_window_ghostwindows_remove_invalid(C, wm); } CTX_wm_window_set(C, wm->windows.first); ED_editors_init(C); DAG_on_visible_update(CTX_data_main(C), true); #ifdef WITH_PYTHON if (is_startup_file) { /* possible python hasn't been initialized */ if (CTX_py_init_get(C)) { /* sync addons, these may have changed from the defaults */ BPY_execute_string(C, "__import__('addon_utils').reset_all()"); BPY_python_reset(C); addons_loaded = true; } } else { /* run any texts that were loaded in and flagged as modules */ BPY_python_reset(C); addons_loaded = true; } #else UNUSED_VARS(is_startup_file); #endif /* WITH_PYTHON */ WM_operatortype_last_properties_clear_all(); /* important to do before NULL'ing the context */ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); /* would otherwise be handled by event loop */ if (G.background) { Main *bmain = CTX_data_main(C); BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C)); } WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); /* report any errors. * currently disabled if addons aren't yet loaded */ if (addons_loaded) { wm_file_read_report(C); } if (!G.background) { /* in background mode this makes it hard to load * a blend file and do anything since the screen * won't be set to a valid value again */ CTX_wm_window_set(C, NULL); /* exits queues */ } if (!G.background) { // undo_editmode_clear(); BKE_undo_reset(); BKE_undo_write(C, "original"); /* save current state */ } }
void WM_file_read(bContext *C, const char *filepath, ReportList *reports) { int retval; /* so we can get the error message */ errno = 0; WM_cursor_wait(1); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE); /* first try to append data from exotic file formats... */ /* it throws error box when file doesn't exist and returns -1 */ /* note; it should set some error message somewhere... (ton) */ retval = wm_read_exotic(CTX_data_scene(C), filepath); /* we didn't succeed, now try to read Blender file */ if (retval == BKE_READ_EXOTIC_OK_BLEND) { int G_f = G.f; ListBase wmbase; /* assume automated tasks with background, don't write recent file list */ const int do_history = (G.background == FALSE) && (CTX_wm_manager(C)->op_undo_depth == 0); /* put aside screens to match with persistent windows later */ /* also exit screens and editors */ wm_window_match_init(C, &wmbase); /* confusing this global... */ G.relbase_valid = 1; retval = BKE_read_file(C, filepath, reports); /* when loading startup.blend's, we can be left with a blank path */ if (G.main->name[0]) { G.save_over = 1; } else { G.save_over = 0; G.relbase_valid = 0; } /* this flag is initialized by the operator but overwritten on read. * need to re-enable it here else drivers + registered scripts wont work. */ if (G.f != G_f) { const int flags_keep = (G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF); G.f = (G.f & ~flags_keep) | (G_f & flags_keep); } /* match the read WM with current WM */ wm_window_match_do(C, &wmbase); WM_check(C); /* opens window(s), checks keymaps */ if (retval == BKE_READ_FILE_OK_USERPREFS) { /* in case a userdef is read from regular .blend */ wm_init_userdef(C, false); } if (retval != BKE_READ_FILE_FAIL) { if (do_history) { write_history(); } } WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); // refresh_interface_font(); CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); ED_editors_init(C); DAG_on_visible_update(CTX_data_main(C), TRUE); #ifdef WITH_PYTHON /* run any texts that were loaded in and flagged as modules */ BPY_python_reset(C); #endif /* important to do before NULL'ing the context */ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); if (!G.background) { /* in background mode this makes it hard to load * a blend file and do anything since the screen * won't be set to a valid value again */ CTX_wm_window_set(C, NULL); /* exits queues */ } #if 0 /* gives popups on windows but not linux, bug in report API * but disable for now to stop users getting annoyed */ /* TODO, make this show in header info window */ { Scene *sce; for (sce = G.main->scene.first; sce; sce = sce->id.next) { if (sce->r.engine[0] && BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL) { BKE_reportf(reports, RPT_ERROR, "Engine '%s' not available for scene '%s' " "(an addon may need to be installed or enabled)", sce->r.engine, sce->id.name + 2); } } } #endif BKE_reset_undo(); BKE_write_undo(C, "original"); /* save current state */ } else if (retval == BKE_READ_EXOTIC_OK_OTHER) BKE_write_undo(C, "Import file"); else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) { BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath, errno ? strerror(errno) : TIP_("unable to open the file")); } else if (retval == BKE_READ_EXOTIC_FAIL_FORMAT) { BKE_reportf(reports, RPT_ERROR, "File format is not supported in file '%s'", filepath); } else if (retval == BKE_READ_EXOTIC_FAIL_PATH) { BKE_reportf(reports, RPT_ERROR, "File path '%s' invalid", filepath); } else { BKE_reportf(reports, RPT_ERROR, "Unknown error loading '%s'", filepath); BLI_assert(!"invalid 'retval'"); } WM_cursor_wait(0); }