ability to have permanent callbacks that stay active when new blend files are loaded.
authorCampbell Barton <ideasman42@gmail.com>
Thu, 3 Nov 2011 06:53:52 +0000 (06:53 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 3 Nov 2011 06:53:52 +0000 (06:53 +0000)
this works by tagging functions, eg:

  def my_func(scene):
      pass

  bpy.app.handlers.permanent_tag(my_func, True)  # <-- important bit
  bpy.app.handlers.frame_change_pre.append(my_func)

source/blender/python/BPY_extern.h
source/blender/python/intern/bpy_app_handlers.c
source/blender/render/intern/source/convertblender.c
source/blender/windowmanager/intern/wm_files.c
source/blender/windowmanager/intern/wm_init_exit.c
source/creator/creator.c

index d8ddcd593a8a64fd0cd9482fe4466ccacc591837..29e0185c2f242cb37d0332a9090d31e9c24cee2d 100644 (file)
@@ -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);
index e7f74569f1a94e53f86c3c71db18150e48ed2519..9ca0e71e71ded6a9c7b54aeb4c99e74b5dbb1993 100644 (file)
@@ -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);
        }
 }
 
index 5968a6e64f82cb9aa679af8de21d1b878ca66ecc..7ef726a53302d37720f6b200f6b442856beed4a6 100644 (file)
@@ -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;
        }
index c292e9e2825eaeacb260aad0f353005788b52b4e..83e4681251f242a2f1551eadbf5140ed895a00ee 100644 (file)
@@ -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
index b0be4bb97209ac20c827c292882473c8160498e0..f32e2afa3e08c6cc601a40187603c51b89ee832d 100644 (file)
@@ -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
index 1d083af7d07123707edafbe43aa14fcc2ec3f383..2204ab85a2eec1b2f1fa16c996011f98ec75caba 100644 (file)
@@ -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