diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index d8ddcd593a8..29e0185c2f2 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -71,7 +71,7 @@ void BPY_text_free_code(struct Text *text); void BPY_modules_update(struct bContext *C); // XXX - annoying, need this for pointers that get out of date void BPY_modules_load_user(struct bContext *C); -void BPY_app_handlers_reset(void); +void BPY_app_handlers_reset(const short do_all); void BPY_driver_reset(void); float BPY_driver_exec(struct ChannelDriver *driver); diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index e7f74569f1a..9ca0e71e71d 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -49,6 +49,11 @@ static PyStructSequence_Field app_cb_info_fields[]= { {(char *)"save_post", NULL}, {(char *)"scene_update_pre", NULL}, {(char *)"scene_update_post", NULL}, + + /* sets the permanent tag */ +# define APP_CB_OTHER_FIELDS 1 + {(char *)"permanent_tag", NULL}, + {NULL} }; @@ -65,6 +70,71 @@ static PyStructSequence_Desc app_cb_info_desc= { #endif */ +/* --------------------------------------------------------------------------*/ +/* permanent tagging code */ +#define PERMINENT_CB_ID "_bpy_permanent_tag" + +PyDoc_STRVAR(bpy_app_handlers_permanent_tag_doc, +".. function:: permanent_tag(func, state=True)\n" +"\n" +" Set the function as being permanent so its not cleared when new blend files are loaded.\n" +"\n" +" :arg func: The function to set as permanent.\n" +" :type func: function\n" +" :arg state: Set the permanent state to True or False.\n" +" :type state: bool\n" +" :return: the function argument\n" +" :rtype: function\n" +); + +static PyObject *bpy_app_handlers_permanent_tag(PyObject *UNUSED(self), PyObject *args) +{ + PyObject *value; + int state= 1; + + if(!PyArg_ParseTuple(args, "O|i:permanent_tag", &value, &state)) + return NULL; + + if (PyFunction_Check(value)) { + PyObject **dict_ptr= _PyObject_GetDictPtr(value); + if (dict_ptr == NULL) { + PyErr_SetString(PyExc_ValueError, + "bpy.app.handlers.permanent_tag wasn't able to " + "get the dictionary from the function passed"); + return NULL; + } + else { + if (state) { + /* set id */ + if (*dict_ptr == NULL) { + *dict_ptr= PyDict_New(); + } + + PyDict_SetItemString(*dict_ptr, PERMINENT_CB_ID, Py_None); + } + else { + /* clear id */ + if (*dict_ptr) { + PyDict_DelItemString(*dict_ptr, PERMINENT_CB_ID); + } + } + } + + Py_INCREF(value); + return value; + } + else { + PyErr_SetString(PyExc_ValueError, + "bpy.app.handlers.permanent_tag expected a function"); + return NULL; + } +} + +static PyMethodDef meth_bpy_app_handlers_permanent_tag= {"permanent_tag", (PyCFunction)bpy_app_handlers_permanent_tag, METH_VARARGS, bpy_app_handlers_permanent_tag_doc}; + + + + static PyObject *py_cb_array[BLI_CB_EVT_TOT]= {NULL}; static PyObject *make_app_cb_info(void) @@ -83,10 +153,13 @@ static PyObject *make_app_cb_info(void) } PyStructSequence_SET_ITEM(app_cb_info, pos, (py_cb_array[pos]= PyList_New(0))); } - if (app_cb_info_fields[pos].name != NULL) { + if (app_cb_info_fields[pos + APP_CB_OTHER_FIELDS].name != NULL) { Py_FatalError("invalid callback slots 2"); } + /* custom function */ + PyStructSequence_SET_ITEM(app_cb_info, pos++, (PyObject *)PyCFunction_New(&meth_bpy_app_handlers_permanent_tag, NULL)); + return app_cb_info; } @@ -120,12 +193,46 @@ PyObject *BPY_app_handlers_struct(void) return ret; } -void BPY_app_handlers_reset(void) +void BPY_app_handlers_reset(const short do_all) { int pos= 0; + if (do_all) { for (pos= 0; pos < BLI_CB_EVT_TOT; pos++) { - PyList_SetSlice(py_cb_array[pos], 0, PY_SSIZE_T_MAX, NULL); + /* clear list */ + PyList_SetSlice(py_cb_array[pos], 0, PY_SSIZE_T_MAX, NULL); + } + } + else { + /* save string conversion thrashing */ + PyObject *perm_id_str= PyUnicode_FromString(PERMINENT_CB_ID); + + for (pos= 0; pos < BLI_CB_EVT_TOT; pos++) { + /* clear only items without PERMINENT_CB_ID */ + PyObject *ls= py_cb_array[pos]; + Py_ssize_t i; + + PyObject *item; + PyObject **dict_ptr; + + for(i= PyList_GET_SIZE(ls) - 1; i >= 0; i--) { + + if ( (PyFunction_Check((item= PyList_GET_ITEM(ls, i)))) && + (dict_ptr= _PyObject_GetDictPtr(item)) && + (*dict_ptr) && + (PyDict_GetItem(*dict_ptr, perm_id_str) != NULL)) + { + /* keep */ + } + else { + /* remove */ + /* PySequence_DelItem(ls, i); */ /* more obvious buw slower */ + PyList_SetSlice(ls, i, i + 1, NULL); + } + } + } + + Py_DECREF(perm_id_str); } } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 5968a6e64f8..7ef726a5330 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -2391,7 +2391,7 @@ static void do_displacement(Render *re, ObjectRen *obr, float mat[][4], float im /* Object Size with parenting */ obt=obr->ob; while(obt){ - add_v3_v3v3(temp, obt->size, obt->dsize); + mul_v3_v3v3(temp, obt->size, obt->dsize); scale[0]*=temp[0]; scale[1]*=temp[1]; scale[2]*=temp[2]; obt=obt->parent; } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index c292e9e2825..83e4681251f 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -408,7 +408,7 @@ void WM_read_file(bContext *C, const char *filepath, ReportList *reports) #ifdef WITH_PYTHON /* run any texts that were loaded in and flagged as modules */ BPY_driver_reset(); - BPY_app_handlers_reset(); + BPY_app_handlers_reset(FALSE); BPY_modules_load_user(C); #endif @@ -538,7 +538,7 @@ int WM_read_homefile(bContext *C, ReportList *UNUSED(reports), short from_memory BPY_string_exec(C, "__import__('addon_utils').reset_all()"); BPY_driver_reset(); - BPY_app_handlers_reset(); + BPY_app_handlers_reset(FALSE); BPY_modules_load_user(C); } #endif diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index b0be4bb9720..f32e2afa3e0 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -61,8 +61,9 @@ #include "BKE_sequencer.h" /* free seq clipboard */ #include "BKE_material.h" /* clear_matcopybuf */ -#include "BLI_blenlib.h" -#include "BLI_winstuff.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" #include "RE_engine.h" #include "RE_pipeline.h" /* RE_ free stuff */ @@ -158,7 +159,7 @@ void WM_init(bContext *C, int argc, const char **argv) BPY_python_start(argc, argv); BPY_driver_reset(); - BPY_app_handlers_reset(); /* causes addon callbacks to be freed [#28068], + BPY_app_handlers_reset(FALSE); /* causes addon callbacks to be freed [#28068], * but this is actually what we want. */ BPY_modules_load_user(C); #else diff --git a/source/creator/creator.c b/source/creator/creator.c index 1d083af7d07..2204ab85a2e 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -971,7 +971,7 @@ static int load_file(int UNUSED(argc), const char **argv, void *data) #ifdef WITH_PYTHON /* run any texts that were loaded in and flagged as modules */ BPY_driver_reset(); - BPY_app_handlers_reset(); + BPY_app_handlers_reset(FALSE); BPY_modules_load_user(C); #endif