Fix T37795: Resetting a button to the default value could crash
authorCampbell Barton <ideasman42@gmail.com>
Thu, 19 Dec 2013 14:04:01 +0000 (01:04 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 19 Dec 2013 14:07:09 +0000 (01:07 +1100)
Added ui_handle_afterfunc_add_operator so a button can queue an operator
to run without executing it immediately.

source/blender/editors/interface/interface.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_intern.h

index d09b3dea98a67f4de0d30f96e72edb6196122c59..b1c66a65c35f103d6eda7f4e8893ba2f841c1068 100644 (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)
index 8a4f89af4a30afc7cd10ec0e11d525020af53862..f44595d6af663ec7766b436aee7cbdf84f4a2dc2 100644 (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;
                }
index afdcd7abc54b79e83d16f8c0c8a87705d641d814..e11b93ca69b6421cc9c11da4b2bddc1ccd852b91 100644 (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);