diff options
-rw-r--r-- | source/blender/blenkernel/intern/library_remap.c | 5 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_ID.h | 4 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_ID.c | 12 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_internal.h | 1 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.c | 44 |
6 files changed, 55 insertions, 12 deletions
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 62cc5108b4e..49effd033e3 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -959,8 +959,13 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b DAG_id_type_tag(bmain, type); #ifdef WITH_PYTHON +#ifdef WITH_PYTHON_SAFETY BPY_id_release(id); #endif + if (id->py_instance) { + BPY_DECREF_RNA_INVALIDATE(id->py_instance); + } +#endif if (do_id_user) { BKE_libblock_relink_ex(bmain, id, NULL, NULL, true); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index caf58ba3f86..5e12fc969ab 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2210,6 +2210,7 @@ static void direct_link_id(FileData *fd, ID *id) /* this case means the data was written incorrectly, it should not happen */ IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } + id->py_instance = NULL; } /* ************ READ CurveMapping *************** */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 923df70dd4d..564aa994df1 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -131,6 +131,10 @@ typedef struct ID { int us; int icon_id; IDProperty *properties; + + void *py_instance; + + void *pad1; } ID; /** diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 9d42ba55ecc..9205e15671b 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -387,6 +387,14 @@ static void rna_ID_animation_data_free(ID *id, Main *bmain) DAG_relations_tag_update(bmain); } +#ifdef WITH_PYTHON +void **rna_ID_instance(PointerRNA *ptr) +{ + ID *id = (ID *)ptr->data; + return &id->py_instance; +} +#endif + static void rna_IDPArray_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { IDProperty *prop = (IDProperty *)ptr->data; @@ -1064,6 +1072,10 @@ static void rna_def_ID(BlenderRNA *brna) "Tag the ID to update its display data, " "e.g. when calling :class:`bpy.types.Scene.update`"); RNA_def_enum_flag(func, "refresh", update_flag_items, 0, "", "Type of updates to perform"); + +#ifdef WITH_PYTHON + RNA_def_struct_register_funcs(srna, NULL, NULL, "rna_ID_instance"); +#endif } static void rna_def_library(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 01c3c8033cf..2d513bd60b4 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -217,6 +217,7 @@ void rna_ID_name_set(struct PointerRNA *ptr, const char *value); struct StructRNA *rna_ID_refine(struct PointerRNA *ptr); struct IDProperty *rna_ID_idprops(struct PointerRNA *ptr, bool create); void rna_ID_fake_user_set(struct PointerRNA *ptr, int value); +void **rna_ID_instance(PointerRNA *ptr); struct IDProperty *rna_PropertyGroup_idprops(struct PointerRNA *ptr, bool create); void rna_PropertyGroup_unregister(struct Main *bmain, struct StructRNA *type); struct StructRNA *rna_PropertyGroup_register(struct Main *bmain, struct ReportList *reports, void *data, diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 1a9fd920af5..deb045c514b 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -6762,7 +6762,30 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) if (ptr->data == NULL && ptr->type == NULL) { /* Operator RNA has NULL data */ Py_RETURN_NONE; } - else { + + /* New in 2.8x, since not many types support instancing + * we may want to use a flag to avoid looping over all classes. - campbell */ + void **instance = ptr->data ? RNA_struct_instance(ptr) : NULL; + if (instance && *instance) { + pyrna = *instance; + + /* Refine may have changed types after the first instance was created. */ + if (ptr->type == pyrna->ptr.type) { + Py_INCREF(pyrna); + return (PyObject *)pyrna; + } + else { + /* Existing users will need to use 'type_recast' method. */ + Py_DECREF(pyrna); + *instance = NULL; + /* Continue as if no instance was made */ +#if 0 /* no need to assign, will be written to next... */ + pyrna = NULL; +#endif + } + } + + { PyTypeObject *tp = (PyTypeObject *)pyrna_struct_Subtype(ptr); if (tp) { @@ -6783,6 +6806,12 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) return NULL; } + /* Blender's instance owns a reference (to avoid Python freeing it). */ + if (instance) { + *instance = pyrna; + Py_INCREF(pyrna); + } + pyrna->ptr = *ptr; #ifdef PYRNA_FREE_SUPPORT pyrna->freeptr = false; @@ -7547,7 +7576,6 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param PyObject *args; PyObject *ret = NULL, *py_srna = NULL, *py_class_instance = NULL, *parmitem; PyTypeObject *py_class; - void **py_class_instance_store = NULL; PropertyRNA *parm; ParameterIterator iter; PointerRNA funcptr; @@ -7562,7 +7590,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param PyGILState_STATE gilstate; #ifdef USE_PEDANTIC_WRITE - const bool is_operator = RNA_struct_is_a(ptr->type, &RNA_Operator); + const bool is_readonly_init = !RNA_struct_is_a(ptr->type, &RNA_Operator); // const char *func_id = RNA_function_identifier(func); /* UNUSED */ /* testing, for correctness, not operator and not draw function */ const bool is_readonly = !(RNA_function_flag(func) & FUNC_ALLOW_WRITE); @@ -7597,10 +7625,6 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param py_class_instance = *instance; Py_INCREF(py_class_instance); } - else { - /* store the instance here once its created */ - py_class_instance_store = instance; - } } } /* end exception */ @@ -7627,7 +7651,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if (py_class->tp_init) { #ifdef USE_PEDANTIC_WRITE const int prev_write = rna_disallow_writes; - rna_disallow_writes = is_operator ? false : true; /* only operators can write on __init__ */ + rna_disallow_writes = is_readonly_init ? false : true; /* only operators can write on __init__ */ #endif /* true in most cases even when the class its self doesn't define an __init__ function. */ @@ -7671,10 +7695,6 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if (py_class_instance == NULL) { err = -1; /* so the error is not overridden below */ } - else if (py_class_instance_store) { - *py_class_instance_store = py_class_instance; - Py_INCREF(py_class_instance); - } } } |