From 4d581c01cce783fd5f2deed4a65db9128c174c2d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 22 Oct 2015 18:42:44 +1100 Subject: Fix T46561: Crash in outliner delete hierarchy When children & parents were selected in the outliner, it attempted to free the the object twice. --- .../editors/space_outliner/outliner_intern.h | 11 ++++++-- .../editors/space_outliner/outliner_tools.c | 32 ++++++++++++++++------ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index c89a1bb1b9f..f10e6be2fa9 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -150,8 +150,15 @@ int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, boo /* outliner_edit.c ---------------------------------------------- */ -void outliner_do_object_operation(struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, - void (*operation_cb)(struct bContext *C, struct Scene *scene, struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *)); +void outliner_do_object_operation_ex( + struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, + void (*operation_cb)(struct bContext *C, struct Scene *scene, + struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *), + bool recurse_selected); +void outliner_do_object_operation( + struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, + void (*operation_cb)(struct bContext *C, struct Scene *scene, + struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *)); int common_restrict_check(struct bContext *C, struct Object *ob); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 50171d7f032..863f09d4039 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -516,15 +516,20 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te) id_lib_extern(&group->id); } -void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, - void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, - TreeStoreElem *, TreeStoreElem *)) +/** + * \param select_recurse: Set to false for operations which are already recursively operating on their children. + */ +void outliner_do_object_operation_ex( + bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, + void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, + TreeStoreElem *, TreeStoreElem *), + bool select_recurse) { TreeElement *te; - TreeStoreElem *tselem; for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); + TreeStoreElem *tselem = TREESTORE(te); + bool select_handled = false; if (tselem->flag & TSE_SELECTED) { if (tselem->type == 0 && te->idcode == ID_OB) { // when objects selected in other scenes... dunno if that should be allowed @@ -536,14 +541,25 @@ void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soop * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the * outliner isn't showing scenes: Visible Layer draw mode for eg. */ operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem); + select_handled = true; } } if (TSELEM_OPEN(tselem, soops)) { - outliner_do_object_operation(C, scene_act, soops, &te->subtree, operation_cb); + if ((select_handled == false) || select_recurse) { + outliner_do_object_operation_ex(C, scene_act, soops, &te->subtree, operation_cb, select_recurse); + } } } } +void outliner_do_object_operation( + bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, + void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, + TreeStoreElem *, TreeStoreElem *)) +{ + outliner_do_object_operation_ex(C, scene_act, soops, lb, operation_cb, true); +} + /* ******************************************** */ static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), @@ -876,7 +892,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) } else if (event == OL_OP_SELECT_HIERARCHY) { Scene *sce = scene; // to be able to delete, scenes are set... - outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_hierarchy_cb); + outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_select_hierarchy_cb, false); if (scene != sce) { ED_screen_set_scene(C, CTX_wm_screen(C), sce); } @@ -903,7 +919,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } else if (event == OL_OP_DELETE_HIERARCHY) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_hierarchy_cb); + outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_delete_hierarchy_cb, false); /* XXX: See OL_OP_DELETE comment above. */ outliner_cleanup_tree(soops); -- cgit v1.2.3