[Bf-blender-cvs] [4b0e7fe511b] master: Fix T99462: Deleting Missing Libraries Crashes Blender.

Bastien Montagne noreply at git.blender.org
Wed Jul 6 11:35:15 CEST 2022


Commit: 4b0e7fe511b14aecad105d83115592f43d27dbc0
Author: Bastien Montagne
Date:   Wed Jul 6 10:53:22 2022 +0200
Branches: master
https://developer.blender.org/rB4b0e7fe511b14aecad105d83115592f43d27dbc0

Fix T99462: Deleting Missing Libraries Crashes Blender.

Usual same issue with outliner operations, where you apply it on one
item, and then try to apply it again on same item listed somewhere else
in the tree...

Fixed by using the 'multi-tagged deletion' code we now have for IDs,
that way tree-walking function just tags IDs for deletion, and they all
get deleted at once at the end.

===================================================================

M	source/blender/editors/space_outliner/outliner_edit.cc
M	source/blender/editors/space_outliner/outliner_intern.hh
M	source/blender/editors/space_outliner/outliner_tools.cc

===================================================================

diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index c4a9398a5f7..32860bc2cff 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -447,7 +447,7 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
 /** \name ID Delete Operator
  * \{ */
 
-static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
+static void id_delete_tag(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
 {
   Main *bmain = CTX_data_main(C);
   ID *id = tselem->id;
@@ -484,35 +484,39 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
     return;
   }
   if (te->idcode == ID_WS) {
-    BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT);
-    if (id->tag & LIB_TAG_DOIT) {
+    BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_PRE_EXISTING);
+    if (id->tag & LIB_TAG_PRE_EXISTING) {
       BKE_reportf(
           reports, RPT_WARNING, "Cannot delete currently visible workspace id '%s'", id->name);
+      BKE_main_id_tag_idcode(bmain, ID_WS, LIB_TAG_PRE_EXISTING, false);
       return;
     }
+    BKE_main_id_tag_idcode(bmain, ID_WS, LIB_TAG_PRE_EXISTING, false);
   }
 
-  BKE_id_delete(bmain, id);
+  id->tag |= LIB_TAG_DOIT;
 
   WM_event_add_notifier(C, NC_WINDOW, nullptr);
 }
 
-void id_delete_fn(bContext *C,
-                  ReportList *reports,
-                  Scene *UNUSED(scene),
-                  TreeElement *te,
-                  TreeStoreElem *UNUSED(tsep),
-                  TreeStoreElem *tselem,
-                  void *UNUSED(user_data))
+void id_delete_tag_fn(bContext *C,
+                      ReportList *reports,
+                      Scene *UNUSED(scene),
+                      TreeElement *te,
+                      TreeStoreElem *UNUSED(tsep),
+                      TreeStoreElem *tselem,
+                      void *UNUSED(user_data))
 {
-  id_delete(C, reports, te, tselem);
+  id_delete_tag(C, reports, te, tselem);
 }
 
-static int outliner_id_delete_invoke_do(bContext *C,
-                                        ReportList *reports,
-                                        TreeElement *te,
-                                        const float mval[2])
+static int outliner_id_delete_tag(bContext *C,
+                                  ReportList *reports,
+                                  TreeElement *te,
+                                  const float mval[2])
 {
+  int id_tagged_num = 0;
+
   if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
     TreeStoreElem *tselem = TREESTORE(te);
 
@@ -522,26 +526,27 @@ static int outliner_id_delete_invoke_do(bContext *C,
                     RPT_ERROR_INVALID_INPUT,
                     "Cannot delete indirectly linked library '%s'",
                     ((Library *)tselem->id)->filepath_abs);
-        return OPERATOR_CANCELLED;
       }
-      id_delete(C, reports, te, tselem);
-      return OPERATOR_FINISHED;
+      else {
+        id_delete_tag(C, reports, te, tselem);
+        id_tagged_num++;
+      }
     }
   }
   else {
     LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
-      int ret;
-      if ((ret = outliner_id_delete_invoke_do(C, reports, te_sub, mval))) {
-        return ret;
+      if ((id_tagged_num += outliner_id_delete_tag(C, reports, te_sub, mval)) != 0) {
+        break;
       }
     }
   }
 
-  return 0;
+  return id_tagged_num;
 }
 
 static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
+  Main *bmain = CTX_data_main(C);
   ARegion *region = CTX_wm_region(C);
   SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
   float fmval[2];
@@ -550,15 +555,21 @@ static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent
 
   UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
 
+  int id_tagged_num = 0;
+  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
   LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
-    int ret;
-
-    if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) {
-      return ret;
+    if ((id_tagged_num += outliner_id_delete_tag(C, op->reports, te, fmval)) != 0) {
+      break;
     }
   }
+  if (id_tagged_num == 0) {
+    BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+    return OPERATOR_CANCELLED;
+  }
 
-  return OPERATOR_CANCELLED;
+  BKE_id_multi_tagged_delete(bmain);
+  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+  return OPERATOR_FINISHED;
 }
 
 void OUTLINER_OT_id_delete(wmOperatorType *ot)
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index a0dcb49aa43..19090641173 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -437,7 +437,7 @@ void lib_reload_fn(struct bContext *C,
                    struct TreeStoreElem *tselem,
                    void *user_data);
 
-void id_delete_fn(struct bContext *C,
+void id_delete_tag_fn(struct bContext *C,
                   struct ReportList *reports,
                   struct Scene *scene,
                   struct TreeElement *te,
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index ec19e8d5e5b..04e74f5438b 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -2185,6 +2185,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
 
 static int outliner_id_operation_exec(bContext *C, wmOperator *op)
 {
+  Main *bmain = CTX_data_main(C);
   wmWindowManager *wm = CTX_wm_manager(C);
   Scene *scene = CTX_data_scene(C);
   SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -2381,8 +2382,10 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
     }
     case OUTLINER_IDOP_DELETE: {
       if (idlevel > 0) {
+        BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
         outliner_do_libdata_operation(
-            C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
+            C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
+        BKE_id_multi_tagged_delete(bmain);
         ED_undo_push(C, "Delete");
       }
       break;
@@ -2507,6 +2510,7 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = {
 
 static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
 {
+  Main *bmain = CTX_data_main(C);
   Scene *scene = CTX_data_scene(C);
   SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
   int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
@@ -2522,7 +2526,10 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
   eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type");
   switch (event) {
     case OL_LIB_DELETE: {
-      outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
+      BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+      outliner_do_libdata_operation(
+          C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
+      BKE_id_multi_tagged_delete(bmain);
       ED_undo_push(C, "Delete Library");
       break;
     }



More information about the Bf-blender-cvs mailing list