Fix #136563: Crash clicking on a light after it has been deleted
Failure to refresh the highlighted gizmo meant that clicking on a highlighted gizmo would attempt to activate it even though it's poll function failed - which crashed in this case. Resolve the common-case by ensuring a call to refresh the gizmo-map causes the event system to re-evaluate the highlighted gizmo, even if the cursor doesn't move. Since it's still possible the call to "refresh" the gizmo is missed, gizmo_tweak_invoke now checks the gizmo-groups poll succeeds with an assert and early return if it doesn't. This would have prevented the crash although the highlighted-gizmo still won't be reset - causing the cursor to display as if it's over a gizmo until it's moved.
This commit is contained in:
@@ -572,8 +572,16 @@ static wmOperatorStatus gizmo_tweak_invoke(bContext *C, wmOperator *op, const wm
|
||||
|
||||
if (!gz) {
|
||||
/* #wm_handlers_do_intern shouldn't let this happen. */
|
||||
BLI_assert_unreachable();
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
BLI_assert_msg(false, "the gizmo should never be null, this is a bug!");
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
if (!WM_gizmo_group_type_poll(C, gz->parent_gzgroup->type)) {
|
||||
/* The event-system should prevent this from happening, see: #137146.
|
||||
* May be caused by the context changing without tagging #wmGizmoMap::tag_highlight_pending,
|
||||
* typically via #WM_gizmomap_tag_refresh. */
|
||||
BLI_assert_msg(false, "the gizmo-group's poll should always succeed, this is a bug!");
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
const int highlight_part_init = gz->highlight_part;
|
||||
|
||||
@@ -107,6 +107,9 @@ struct wmGizmoMap {
|
||||
/** When set, one of the items in 'groups' has #wmGizmoGroup.tag_remove set. */
|
||||
bool tag_remove_group;
|
||||
|
||||
/** When set, the event system re-calculates highlight even without cursor motion. */
|
||||
bool tag_highlight_pending;
|
||||
|
||||
/**
|
||||
* \brief Gizmo map runtime context
|
||||
*
|
||||
|
||||
@@ -314,6 +314,9 @@ void WM_gizmomap_tag_refresh_drawstep(wmGizmoMap *gzmap, const eWM_GizmoFlagMapD
|
||||
BLI_assert(uint(drawstep) < WM_GIZMOMAP_DRAWSTEP_MAX);
|
||||
if (gzmap) {
|
||||
gzmap->update_flag[drawstep] |= (GIZMOMAP_IS_PREPARE_DRAW | GIZMOMAP_IS_REFRESH_CALLBACK);
|
||||
/* This could be split out into a separate tagging function,
|
||||
* in practice both when refreshing the highlight should also be updated. */
|
||||
gzmap->tag_highlight_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,6 +326,8 @@ void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
|
||||
for (int i = 0; i < WM_GIZMOMAP_DRAWSTEP_MAX; i++) {
|
||||
gzmap->update_flag[i] |= (GIZMOMAP_IS_PREPARE_DRAW | GIZMOMAP_IS_REFRESH_CALLBACK);
|
||||
}
|
||||
/* See code-comment for #WM_gizmomap_tag_refresh_drawstep. */
|
||||
gzmap->tag_highlight_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,6 +744,15 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
|
||||
return result;
|
||||
}
|
||||
|
||||
bool wm_gizmomap_highlight_pending(const wmGizmoMap *gzmap)
|
||||
{
|
||||
return gzmap->tag_highlight_pending;
|
||||
}
|
||||
bool wm_gizmomap_highlight_handled(wmGizmoMap *gzmap)
|
||||
{
|
||||
return gzmap->tag_highlight_pending = false;
|
||||
}
|
||||
|
||||
wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
|
||||
bContext *C,
|
||||
const wmEvent *event,
|
||||
|
||||
@@ -78,6 +78,8 @@ void wm_gizmomaps_handled_modal_update(bContext *C, wmEvent *event, wmEventHandl
|
||||
void wm_gizmomap_handler_context_op(bContext *C, wmEventHandler_Op *handler);
|
||||
void wm_gizmomap_handler_context_gizmo(bContext *C, wmEventHandler_Gizmo *handler);
|
||||
|
||||
bool wm_gizmomap_highlight_pending(const wmGizmoMap *gzmap);
|
||||
bool wm_gizmomap_highlight_handled(wmGizmoMap *gzmap);
|
||||
/**
|
||||
* Try to find a gizmo under the mouse position. 2D intersections have priority over
|
||||
* 3D ones (could check for smallest screen-space distance but not needed right now).
|
||||
|
||||
@@ -3270,6 +3270,12 @@ static eHandlerActionFlag wm_handlers_do_gizmo_handler(bContext *C,
|
||||
}
|
||||
}
|
||||
|
||||
if (prev.gz_modal == nullptr) {
|
||||
if (handle_highlight == false && wm_gizmomap_highlight_pending(gzmap)) {
|
||||
handle_highlight = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle_highlight) {
|
||||
int part = -1;
|
||||
gz = wm_gizmomap_highlight_find(gzmap, C, event, &part);
|
||||
@@ -3288,6 +3294,8 @@ static eHandlerActionFlag wm_handlers_do_gizmo_handler(bContext *C,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wm_gizmomap_highlight_handled(gzmap);
|
||||
}
|
||||
|
||||
/* Don't use from now on. */
|
||||
|
||||
Reference in New Issue
Block a user