From 16377abda8adb6444e888d1144d9225fa6415e65 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Aug 2017 20:26:52 +1000 Subject: 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. --- source/blender/windowmanager/intern/wm.c | 4 ++ .../blender/windowmanager/intern/wm_event_system.c | 79 ++++++++++++---------- source/blender/windowmanager/wm_event_system.h | 3 +- 3 files changed, 51 insertions(+), 35 deletions(-) (limited to 'source/blender/windowmanager') diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 1738dabde2d..a09cc4aeb31 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -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 */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4f68e7cccca..7e7314cc0c8 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -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) diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index efc01b1f8a8..3fb9cd617bf 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -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 */ -- cgit v1.2.3