Fix T37795: Resetting a button to the default value could crash

Added ui_handle_afterfunc_add_operator so a button can queue an operator
to run without executing it immediately.
This commit is contained in:
Campbell Barton 2013-12-20 01:04:01 +11:00
parent 3fcfbf24b3
commit aab587817c
Notes: blender-bot 2023-02-14 11:29:52 +01:00
Referenced by issue #37795, Hard crash when pressing backspace while mouse hovers over Editor-type button.
3 changed files with 53 additions and 13 deletions

View File

@ -2055,15 +2055,23 @@ bool ui_set_but_string(bContext *C, uiBut *but, const char *str)
return false;
}
void ui_set_but_default(bContext *C, const bool all)
void ui_set_but_default(bContext *C, const bool all, const bool use_afterfunc)
{
const char *opstring = "UI_OT_reset_default_button";
PointerRNA ptr;
WM_operator_properties_create(&ptr, opstring);
RNA_boolean_set(&ptr, "all", all);
WM_operator_name_call(C, opstring, WM_OP_EXEC_DEFAULT, &ptr);
WM_operator_properties_free(&ptr);
if (use_afterfunc) {
PointerRNA *ptr;
wmOperatorType *ot = WM_operatortype_find(opstring, 0);
ptr = ui_handle_afterfunc_add_operator(ot, WM_OP_EXEC_DEFAULT, true);
RNA_boolean_set(ptr, "all", all);
}
else {
PointerRNA ptr;
WM_operator_properties_create(&ptr, opstring);
RNA_boolean_set(&ptr, "all", all);
WM_operator_name_call(C, opstring, WM_OP_EXEC_DEFAULT, &ptr);
WM_operator_properties_free(&ptr);
}
}
static double soft_range_round_up(double value, double max)

View File

@ -398,6 +398,40 @@ bool ui_is_but_utf8(const uiBut *but)
static ListBase UIAfterFuncs = {NULL, NULL};
static uiAfterFunc *ui_afterfunc_new(void)
{
uiAfterFunc *after;
after = MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc");
BLI_addtail(&UIAfterFuncs, after);
return after;
}
/**
* For executing operators after the button is pressed.
* (some non operator buttons need to trigger operators), see: [#37795]
*
* \note Can only call while handling buttons.
*/
PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext, bool create_props)
{
PointerRNA *ptr = NULL;
uiAfterFunc *after = ui_afterfunc_new();
after->optype = ot;
after->opcontext = opcontext;
if (create_props) {
ptr = MEM_callocN(sizeof(PointerRNA), __func__);
WM_operator_properties_create_ptr(ptr, ot);
after->opptr = ptr;
}
return ptr;
}
static void ui_apply_but_func(bContext *C, uiBut *but)
{
uiAfterFunc *after;
@ -410,7 +444,7 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
if (but->func || but->funcN || block->handle_func || but->rename_func ||
(but->type == BUTM && block->butm_func) || but->optype || but->rnaprop)
{
after = MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc");
after = ui_afterfunc_new();
if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) {
/* exception, this will crash due to removed button otherwise */
@ -452,8 +486,6 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
but->optype = NULL;
but->opcontext = 0;
but->opptr = NULL;
BLI_addtail(&UIAfterFuncs, after);
}
}
@ -477,9 +509,8 @@ static void ui_apply_undo(uiBut *but)
}
/* delayed, after all other funcs run, popups are closed, etc */
after = MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc");
after = ui_afterfunc_new();
BLI_strncpy(after->undostr, str, sizeof(after->undostr));
BLI_addtail(&UIAfterFuncs, after);
}
}
@ -5840,7 +5871,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
(event->type == BACKSPACEKEY && event->val == KM_PRESS))
{
/* ctrl+backspace = reset active button; backspace = reset a whole array*/
ui_set_but_default(C, !event->ctrl);
ui_set_but_default(C, !event->ctrl, true);
ED_region_tag_redraw(data->region);
retval = WM_UI_HANDLER_BREAK;
}

View File

@ -393,7 +393,7 @@ extern bool ui_set_but_string(struct bContext *C, uiBut *but, const char *str);
extern bool ui_set_but_string_eval_num(struct bContext *C, uiBut *but, const char *str, double *value);
extern int ui_get_but_string_max_length(uiBut *but);
extern void ui_set_but_default(struct bContext *C, const bool all);
extern void ui_set_but_default(struct bContext *C, const bool all, const bool use_afterfunc);
extern void ui_check_but(uiBut *but);
extern bool ui_is_but_float(const uiBut *but);
@ -515,6 +515,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, struct uiWidgetColors *wc
void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
/* interface_handlers.c */
PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext, bool create_props);
extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but);
extern void ui_button_execute_do(struct bContext *C, struct ARegion *ar, uiBut *but);