WM: initialize WM and deps before handling events
This avoids obscure bugs where operators could run from events that happen before the UI and depsgraph have been initialized. See: D2809 for details.
This commit is contained in:
@@ -495,6 +495,10 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist)
|
||||
|
||||
void WM_main(bContext *C)
|
||||
{
|
||||
/* Single refresh before handling events.
|
||||
* This ensures we don't run operators before the depsgraph has been evaluated. */
|
||||
wm_event_do_refresh_wm_and_depsgraph(C);
|
||||
|
||||
while (1) {
|
||||
|
||||
/* get events from ghost, handle window events, add to window queues */
|
||||
|
||||
@@ -263,13 +263,56 @@ static void wm_notifier_clear(wmNotifier *note)
|
||||
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
|
||||
}
|
||||
|
||||
/**
|
||||
* Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop.
|
||||
* This ensures operators don't run before the UI and depsgraph are initialized.
|
||||
*/
|
||||
void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
uint64_t win_combine_v3d_datamask = 0;
|
||||
|
||||
/* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
|
||||
for (wmWindow *win = wm->windows.first; win; win = win->next) {
|
||||
win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
|
||||
}
|
||||
|
||||
/* cached: editor refresh callbacks now, they get context */
|
||||
for (wmWindow *win = wm->windows.first; win; win = win->next) {
|
||||
ScrArea *sa;
|
||||
|
||||
CTX_wm_window_set(C, win);
|
||||
for (sa = win->screen->areabase.first; sa; sa = sa->next) {
|
||||
if (sa->do_refresh) {
|
||||
CTX_wm_area_set(C, sa);
|
||||
ED_area_do_refresh(C, sa);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX make lock in future, or separated derivedmesh users in scene */
|
||||
if (G.is_rendering == false) {
|
||||
/* depsgraph & animation: update tagged datablocks */
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
/* copied to set's in scene_update_tagged_recursive() */
|
||||
win->screen->scene->customdata_mask = win_combine_v3d_datamask;
|
||||
|
||||
/* XXX, hack so operators can enforce datamasks [#26482], gl render */
|
||||
win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
|
||||
|
||||
BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
|
||||
}
|
||||
}
|
||||
|
||||
CTX_wm_window_set(C, NULL);
|
||||
}
|
||||
|
||||
/* called in mainloop */
|
||||
void wm_event_do_notifiers(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmNotifier *note, *next;
|
||||
wmWindow *win;
|
||||
uint64_t win_combine_v3d_datamask = 0;
|
||||
|
||||
if (wm == NULL)
|
||||
return;
|
||||
@@ -373,39 +416,7 @@ void wm_event_do_notifiers(bContext *C)
|
||||
MEM_freeN(note);
|
||||
}
|
||||
|
||||
/* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
|
||||
for (win = wm->windows.first; win; win = win->next) {
|
||||
win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
|
||||
}
|
||||
|
||||
/* cached: editor refresh callbacks now, they get context */
|
||||
for (win = wm->windows.first; win; win = win->next) {
|
||||
ScrArea *sa;
|
||||
|
||||
CTX_wm_window_set(C, win);
|
||||
for (sa = win->screen->areabase.first; sa; sa = sa->next) {
|
||||
if (sa->do_refresh) {
|
||||
CTX_wm_area_set(C, sa);
|
||||
ED_area_do_refresh(C, sa);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX make lock in future, or separated derivedmesh users in scene */
|
||||
if (G.is_rendering == false) {
|
||||
/* depsgraph & animation: update tagged datablocks */
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
/* copied to set's in scene_update_tagged_recursive() */
|
||||
win->screen->scene->customdata_mask = win_combine_v3d_datamask;
|
||||
|
||||
/* XXX, hack so operators can enforce datamasks [#26482], gl render */
|
||||
win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
|
||||
|
||||
BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
|
||||
}
|
||||
}
|
||||
|
||||
CTX_wm_window_set(C, NULL);
|
||||
wm_event_do_refresh_wm_and_depsgraph(C);
|
||||
}
|
||||
|
||||
static int wm_event_always_pass(const wmEvent *event)
|
||||
|
||||
@@ -87,7 +87,8 @@ void wm_event_do_handlers (bContext *C);
|
||||
|
||||
void wm_event_add_ghostevent (wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata);
|
||||
|
||||
void wm_event_do_notifiers (bContext *C);
|
||||
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
|
||||
void wm_event_do_notifiers(bContext *C);
|
||||
|
||||
/* wm_keymap.c */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user