Page MenuHome
Paste P2670

Fix/workaround T66913: ensure evaluation after frame change from operators
ActivePublic

Authored by Campbell Barton (campbellbarton) on Dec 17 2021, 12:49 PM.
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 1b6df9fb0db..7c235b04181 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -953,7 +953,25 @@ static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
return wm && (wm->op_undo_depth == 0) && (ot->flag & (OPTYPE_REGISTER | OPTYPE_UNDO));
}
-static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, const bool store)
+struct wmOperatorFinishedData {
+ /** To detect when the scene changes. */
+ Scene *scene;
+ /** To detect when the frame changes. */
+ int scene_frame;
+};
+
+static void wm_operator_finished_pre_setup(bContext *C,
+ struct wmOperatorFinishedData *op_finished_data)
+{
+ op_finished_data->scene = CTX_data_scene(C);
+ op_finished_data->scene_frame = op_finished_data->scene->r.cfra;
+}
+
+static void wm_operator_finished(bContext *C,
+ wmOperator *op,
+ const bool repeat,
+ const bool store,
+ struct wmOperatorFinishedData *op_finished_data)
{
wmWindowManager *wm = CTX_wm_manager(C);
enum {
@@ -971,7 +989,16 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
/* We don't want to do undo pushes for operators that are being
* called from operators that already do an undo push. Usually
* this will happen for python operators that call C operators. */
- if (wm->op_undo_depth == 0) {
+ if ((wm->op_undo_depth == 0) && (op->type->flag & (OPTYPE_UNDO | OPTYPE_UNDO_GROUPED))) {
+ if (G.is_rendering == false) {
+ const bool is_anim = (op_finished_data->scene == CTX_data_scene(C)) &&
+ (op_finished_data->scene_frame != op_finished_data->scene->r.cfra);
+ if (is_anim) {
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ ED_update_for_newframe(CTX_data_main(C), depsgraph);
+ }
+ }
+
if (op->type->flag & OPTYPE_UNDO) {
ED_undo_push_op(C, op);
if (repeat == 0) {
@@ -1042,6 +1069,9 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
return retval;
}
+ struct wmOperatorFinishedData op_finished_data = {NULL};
+ wm_operator_finished_pre_setup(C, &op_finished_data);
+
if (op->type->exec) {
if (op->type->flag & OPTYPE_UNDO) {
wm->op_undo_depth++;
@@ -1063,7 +1093,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
}
if (retval & OPERATOR_FINISHED) {
- wm_operator_finished(C, op, repeat, store && wm->op_undo_depth == 0);
+ wm_operator_finished(C, op, repeat, store && wm->op_undo_depth == 0, &op_finished_data);
}
else if (repeat == 0) {
/* warning: modal from exec is bad practice, but avoid crashing. */
@@ -1303,6 +1333,9 @@ static int wm_operator_invoke(bContext *C,
ot->idname);
}
+ struct wmOperatorFinishedData op_finished_data = {NULL};
+ wm_operator_finished_pre_setup(C, &op_finished_data);
+
if (op->type->invoke && event) {
wm_region_mouse_co(C, event);
@@ -1346,7 +1379,7 @@ static int wm_operator_invoke(bContext *C,
}
else if (retval & OPERATOR_FINISHED) {
const bool store = !is_nested_call && use_last_properties;
- wm_operator_finished(C, op, false, store);
+ wm_operator_finished(C, op, false, store, &op_finished_data);
}
else if (retval & OPERATOR_RUNNING_MODAL) {
/* Take ownership of reports (in case python provided own). */
@@ -2210,6 +2243,9 @@ static int wm_handler_operator_call(bContext *C,
struct wmEvent_ModalMapStore event_backup;
wm_event_modalkeymap_begin(C, op, event, &event_backup);
+ struct wmOperatorFinishedData op_finished_data = {NULL};
+ wm_operator_finished_pre_setup(C, &op_finished_data);
+
if (ot->flag & OPTYPE_UNDO) {
wm->op_undo_depth++;
}
@@ -2245,7 +2281,7 @@ static int wm_handler_operator_call(bContext *C,
/* Important to run 'wm_operator_finished' before NULLing the context members. */
if (retval & OPERATOR_FINISHED) {
- wm_operator_finished(C, op, false, true);
+ wm_operator_finished(C, op, false, true, &op_finished_data);
handler->op = NULL;
}
else if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {