own patch [#27752] Python Callback (Scriptlink functionality)
authorCampbell Barton <ideasman42@gmail.com>
Fri, 24 Jun 2011 16:54:30 +0000 (16:54 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 24 Jun 2011 16:54:30 +0000 (16:54 +0000)
Python:
 * adds bpy.app.handlers which contains lists, each for an event type:
   render_pre, render_post, load_pre, load_post, save_pre, save_post
 * each list item needs to be a callable object which takes 1 argument (the ID).
 * callbacks are cleared on file load.

Example:
 def MyFunc(scene): print("Callback:", data)
 bpy.app.handlers.render_post.append(MyFunc)

C:
 * This patch adds a generic C callback api which is currently only used by python.
 * Unlike python callbacks these are not cleared on file load.

13 files changed:
source/blender/blenkernel/intern/blender.c
source/blender/blenlib/BLI_callbacks.h
source/blender/blenlib/CMakeLists.txt
source/blender/blenlib/intern/callbacks.c [new file with mode: 0644]
source/blender/python/BPY_extern.h
source/blender/python/intern/CMakeLists.txt
source/blender/python/intern/bpy_app.c
source/blender/python/intern/bpy_app_handlers.c [new file with mode: 0644]
source/blender/python/intern/bpy_app_handlers.h [new file with mode: 0644]
source/blender/render/intern/source/pipeline.c
source/blender/windowmanager/intern/wm_files.c
source/blender/windowmanager/intern/wm_init_exit.c
source/creator/creator.c

index 0f545ad..633a055 100644 (file)
@@ -64,6 +64,7 @@
 #include "BLI_dynstr.h"
 #include "BLI_path_util.h"
 #include "BLI_utildefines.h"
 #include "BLI_dynstr.h"
 #include "BLI_path_util.h"
 #include "BLI_utildefines.h"
+#include "BLI_callbacks.h"
 
 #include "IMB_imbuf.h"
 
 
 #include "IMB_imbuf.h"
 
@@ -110,6 +111,9 @@ void free_blender(void)
        BKE_spacetypes_free();          /* after free main, it uses space callbacks */
        
        IMB_exit();
        BKE_spacetypes_free();          /* after free main, it uses space callbacks */
        
        IMB_exit();
+
+       BLI_cb_finalize();
+
        seq_stripelem_cache_destruct();
        
        free_nodesystem();      
        seq_stripelem_cache_destruct();
        
        free_nodesystem();      
index 9f6ac0c..89e4230 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * $Id:
  *
 /*
  * $Id:
  *
- * These callbacks are needed in the lib
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -29,7 +27,7 @@
  * ***** END GPL LICENSE BLOCK *****
  */
 
  * ***** END GPL LICENSE BLOCK *****
  */
 
-/** \file blender/blenlib/intern/BLI_callbacks.h
+/** \file blender/blenlib/BLI_callbacks.h
  *  \ingroup bli
  */
 
  *  \ingroup bli
  */
 
 #ifndef BLI_CALLBACKS_H
 #define BLI_CALLBACKS_H
 
 #ifndef BLI_CALLBACKS_H
 #define BLI_CALLBACKS_H
 
-// This is blenlib internal only
-void callLocalErrorCallBack(const char* msg);
+struct bContext;
+struct Main;
+struct ID;
+
+typedef enum {
+       BLI_CB_EVT_RENDER_PRE,
+       BLI_CB_EVT_RENDER_POST,
+       BLI_CB_EVT_LOAD_PRE,
+       BLI_CB_EVT_LOAD_POST,
+       BLI_CB_EVT_SAVE_PRE,
+       BLI_CB_EVT_SAVE_POST,
+       BLI_CB_EVT_TOT
+} eCbEvent;
+
+
+typedef struct {
+       struct bCallbackFuncStore *next, *prev;
+       void (* func)(struct Main *, struct ID *, void *arg);
+       void *arg;
+       short alloc;
+} bCallbackFuncStore;
+
+
+void BLI_exec_cb(struct Main *main, struct ID *self, eCbEvent evt);
+void BLI_add_cb(bCallbackFuncStore *funcstore, eCbEvent evt);
 
 #endif
 
 
 #endif
 
+
+void BLI_cb_init(void);
+void BLI_cb_finalize(void);
+
+
+/* This is blenlib internal only, unrelated to above */
+void callLocalErrorCallBack(const char* msg);
index 8964d02..2e05ac7 100644 (file)
@@ -52,6 +52,7 @@ set(SRC
        intern/DLRB_tree.c
        intern/boxpack2d.c
        intern/bpath.c
        intern/DLRB_tree.c
        intern/boxpack2d.c
        intern/bpath.c
+       intern/callbacks.c
        intern/cpu.c
        intern/dynlib.c
        intern/edgehash.c
        intern/cpu.c
        intern/dynlib.c
        intern/edgehash.c
diff --git a/source/blender/blenlib/intern/callbacks.c b/source/blender/blenlib/intern/callbacks.c
new file mode 100644 (file)
index 0000000..0c778dc
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation (2011)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_callbacks.h"
+
+#include "MEM_guardedalloc.h"
+
+static ListBase callback_slots[BLI_CB_EVT_TOT]= {{0}};
+
+void BLI_exec_cb(struct Main *main, struct ID *self, eCbEvent evt)
+{
+       ListBase *lb= &callback_slots[evt];
+       bCallbackFuncStore *funcstore;
+
+       for(funcstore= (bCallbackFuncStore *)lb->first; funcstore; funcstore= (bCallbackFuncStore *)funcstore->next) {
+               funcstore->func(main, self, funcstore->arg);
+       }
+}
+
+void BLI_add_cb(bCallbackFuncStore *funcstore, eCbEvent evt)
+{
+       ListBase *lb= &callback_slots[evt];
+       BLI_addtail(lb, funcstore);
+}
+
+void BLI_cb_init(void)
+{
+       /* do nothing */
+}
+
+/* call on application exit */
+void BLI_cb_finalize(void)
+{
+       eCbEvent evt;
+       for(evt= 0; evt < BLI_CB_EVT_TOT; evt++) {
+               ListBase *lb= &callback_slots[evt];
+               bCallbackFuncStore *funcstore;
+               bCallbackFuncStore *funcstore_next;
+               for(funcstore= (bCallbackFuncStore *)lb->first; funcstore; funcstore= funcstore_next) {
+                       funcstore_next= (bCallbackFuncStore *)funcstore->next;
+                       BLI_remlink(lb, funcstore);
+                       if(funcstore->alloc) {
+                               MEM_freeN(funcstore);
+                       }
+               }
+       }
+}
index ae5253d..cd5c8e5 100644 (file)
@@ -83,6 +83,8 @@ 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_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_driver_reset(void);
 float  BPY_driver_exec(struct ChannelDriver *driver);
 
 void   BPY_driver_reset(void);
 float  BPY_driver_exec(struct ChannelDriver *driver);
 
index 4e2d964..287ba45 100644 (file)
@@ -42,6 +42,7 @@ set(INC_SYS
 set(SRC
        bpy.c
        bpy_app.c
 set(SRC
        bpy.c
        bpy_app.c
+       bpy_app_handlers.c
        bpy_driver.c
        bpy_interface.c
        bpy_intern_string.c
        bpy_driver.c
        bpy_interface.c
        bpy_intern_string.c
@@ -59,6 +60,7 @@ set(SRC
 
        bpy.h
        bpy_app.h
 
        bpy.h
        bpy_app.h
+       bpy_app_handlers.h
        bpy_driver.h
        bpy_intern_string.h
        bpy_operator.h
        bpy_driver.h
        bpy_intern_string.h
        bpy_operator.h
index 41de117..079d522 100644 (file)
@@ -30,6 +30,7 @@
 #include <Python.h>
 
 #include "bpy_app.h"
 #include <Python.h>
 
 #include "bpy_app.h"
+#include "bpy_app_handlers.h"
 #include "bpy_driver.h"
 
 #include "BLI_path_util.h"
 #include "bpy_driver.h"
 
 #include "BLI_path_util.h"
@@ -74,6 +75,9 @@ static PyStructSequence_Field app_info_fields[]= {
        {(char *)"build_cxxflags", (char *)"C++ compiler flags"},
        {(char *)"build_linkflags", (char *)"Binary linking flags"},
        {(char *)"build_system", (char *)"Build system used"},
        {(char *)"build_cxxflags", (char *)"C++ compiler flags"},
        {(char *)"build_linkflags", (char *)"Binary linking flags"},
        {(char *)"build_system", (char *)"Build system used"},
+
+       /* submodules */
+       {(char *)"handlers", (char *)"Application handler callbacks"},
        {NULL}
 };
 
        {NULL}
 };
 
@@ -140,6 +144,8 @@ static PyObject *make_app_info(void)
        SetStrItem("Unknown");
 #endif
 
        SetStrItem("Unknown");
 #endif
 
+       SetObjItem(BPY_app_handlers_struct());
+
 #undef SetIntItem
 #undef SetStrItem
 #undef SetObjItem
 #undef SetIntItem
 #undef SetStrItem
 #undef SetObjItem
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
new file mode 100644 (file)
index 0000000..a944e88
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_handlers.c
+ *  \ingroup pythonintern
+ */
+
+#include <Python.h>
+#include "BLI_utildefines.h"
+#include "BLI_callbacks.h"
+
+#include "RNA_types.h"
+#include "RNA_access.h"
+#include "bpy_rna.h"
+#include "bpy_app_handlers.h"
+
+void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg);
+
+static PyTypeObject BlenderAppCbType;
+
+static PyStructSequence_Field app_cb_info_fields[]= {
+       {(char *)"render_pre", NULL},
+       {(char *)"render_post", NULL},
+    {(char *)"load_pre", NULL},
+       {(char *)"load_post", NULL},
+    {(char *)"save_pre", NULL},
+       {(char *)"save_post", NULL},
+       {NULL}
+};
+
+static PyStructSequence_Desc app_cb_info_desc= {
+       (char *)"bpy.app.handlers",     /* name */
+       (char *)"This module contains callbacks",    /* doc */
+       app_cb_info_fields,    /* fields */
+       (sizeof(app_cb_info_fields)/sizeof(PyStructSequence_Field)) - 1
+};
+
+/*
+#if (BLI_CB_EVT_TOT != ((sizeof(app_cb_info_fields)/sizeof(PyStructSequence_Field))))
+#  error "Callbacks are out of sync"
+#endif
+*/
+
+static PyObject *py_cb_array[BLI_CB_EVT_TOT]= {0};
+
+static PyObject *make_app_cb_info(void)
+{
+       PyObject *app_cb_info;
+       int pos= 0;
+
+       app_cb_info= PyStructSequence_New(&BlenderAppCbType);
+       if (app_cb_info == NULL) {
+               return NULL;
+       }
+
+       for(pos= 0; pos < BLI_CB_EVT_TOT; pos++) {
+               if(app_cb_info_fields[pos].name == NULL) {
+                       Py_FatalError("invalid callback slots 1");
+               }
+               PyStructSequence_SET_ITEM(app_cb_info, pos, (py_cb_array[pos]= PyList_New(0)));
+       }
+       if(app_cb_info_fields[pos].name != NULL) {
+               Py_FatalError("invalid callback slots 2");
+       }
+
+       return app_cb_info;
+}
+
+PyObject *BPY_app_handlers_struct(void)
+{
+       PyObject *ret;
+
+       PyStructSequence_InitType(&BlenderAppCbType, &app_cb_info_desc);
+
+       ret= make_app_cb_info();
+
+       /* prevent user from creating new instances */
+       BlenderAppCbType.tp_init= NULL;
+       BlenderAppCbType.tp_new= NULL;
+
+       /* assign the C callbacks */
+       if(ret) {
+               static bCallbackFuncStore funcstore_array[BLI_CB_EVT_TOT]= {{0}};
+               bCallbackFuncStore *funcstore;
+               int pos= 0;
+
+               for(pos= 0; pos < BLI_CB_EVT_TOT; pos++) {
+                       funcstore= &funcstore_array[pos];
+                       funcstore->func= bpy_app_generic_callback;
+                       funcstore->alloc= 0;
+                       funcstore->arg= SET_INT_IN_POINTER(pos);
+                       BLI_add_cb(funcstore, pos);
+               }
+       }
+
+       return ret;
+}
+
+void BPY_app_handlers_reset(void)
+{
+       int pos= 0;
+
+       for(pos= 0; pos < BLI_CB_EVT_TOT; pos++) {
+               PyList_SetSlice(py_cb_array[pos], 0, PY_SSIZE_T_MAX, NULL);
+       }
+}
+
+/* the actual callback - not necessarily called from py */
+void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *arg)
+{
+       PyObject *cb_list= py_cb_array[GET_INT_FROM_POINTER(arg)];
+       Py_ssize_t cb_list_len;
+       if((cb_list_len= PyList_GET_SIZE(cb_list)) > 0) {
+               PyGILState_STATE gilstate= PyGILState_Ensure();
+
+               PyObject* args= PyTuple_New(1); // save python creating each call
+               PyObject* func;
+               PyObject* ret;
+               Py_ssize_t pos;
+
+               /* setup arguments */
+               if(id) {
+                       PointerRNA id_ptr;
+                       RNA_id_pointer_create(id, &id_ptr);
+                       PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&id_ptr));
+               }
+               else {
+                       PyTuple_SET_ITEM(args, 0, Py_None);
+                       Py_INCREF(Py_None);
+               }
+
+               // Iterate the list and run the callbacks
+               for (pos=0; pos < cb_list_len; pos++) {
+                       func= PyList_GET_ITEM(cb_list, pos);
+                       ret= PyObject_Call(func, args, NULL);
+                       if (ret==NULL) {
+                               PyErr_Print();
+                               PyErr_Clear();
+                       }
+                       else {
+                               Py_DECREF(ret);
+                       }
+               }
+
+               Py_DECREF(args);
+
+               PyGILState_Release(gilstate);
+       }
+}
diff --git a/source/blender/python/intern/bpy_app_handlers.h b/source/blender/python/intern/bpy_app_handlers.h
new file mode 100644 (file)
index 0000000..5fdca82
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_handlers.h
+ *  \ingroup pythonintern
+ */
+
+#ifndef BPY_APP_HANDLERS_H
+#define BPY_APP_HANDLERS_H
+
+PyObject *BPY_app_handlers_struct(void);
+void BPY_app_handlers_clear(void);
+
+#endif // BPY_APP_HANDLERS_H
index 1d11234..b1c9820 100644 (file)
@@ -64,6 +64,7 @@
 #include "BLI_blenlib.h"
 #include "BLI_rand.h"
 #include "BLI_threads.h"
 #include "BLI_blenlib.h"
 #include "BLI_rand.h"
 #include "BLI_threads.h"
+#include "BLI_callbacks.h"
 #include "BLI_utildefines.h"
 
 #include "PIL_time.h"
 #include "BLI_utildefines.h"
 
 #include "PIL_time.h"
@@ -2915,6 +2916,9 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
        
        if(render_initialize_from_main(re, bmain, scene, srl, camera_override, lay, 0, 0)) {
                MEM_reset_peak_memory();
        
        if(render_initialize_from_main(re, bmain, scene, srl, camera_override, lay, 0, 0)) {
                MEM_reset_peak_memory();
+
+               BLI_exec_cb(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
+
                do_render_all_options(re);
 
                if(write_still && !G.afbreek) {
                do_render_all_options(re);
 
                if(write_still && !G.afbreek) {
@@ -2930,6 +2934,8 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
                                do_write_image_or_movie(re, scene, NULL, NULL, name);
                        }
                }
                                do_write_image_or_movie(re, scene, NULL, NULL, name);
                        }
                }
+
+               BLI_exec_cb(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */
        }
 
        /* UGLY WARNING */
        }
 
        /* UGLY WARNING */
@@ -3059,14 +3065,21 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
                        int nf = mh->get_next_frame(&re->r, reports);
                        if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) {
                                scene->r.cfra = re->r.cfra = nf;
                        int nf = mh->get_next_frame(&re->r, reports);
                        if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) {
                                scene->r.cfra = re->r.cfra = nf;
-                               
+
+                               BLI_exec_cb(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
+
                                do_render_all_options(re);
 
                                if(re->test_break(re->tbh) == 0) {
                                        if(!do_write_image_or_movie(re, scene, mh, reports, NULL))
                                                G.afbreek= 1;
                                }
                                do_render_all_options(re);
 
                                if(re->test_break(re->tbh) == 0) {
                                        if(!do_write_image_or_movie(re, scene, mh, reports, NULL))
                                                G.afbreek= 1;
                                }
-                       } else {
+
+                               if(G.afbreek == 0) {
+                                       BLI_exec_cb(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */
+                               }
+                       }
+                       else {
                                if(re->test_break(re->tbh))
                                        G.afbreek= 1;
                        }
                                if(re->test_break(re->tbh))
                                        G.afbreek= 1;
                        }
@@ -3113,6 +3126,10 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
                        }
 
                        re->r.cfra= scene->r.cfra;         /* weak.... */
                        }
 
                        re->r.cfra= scene->r.cfra;         /* weak.... */
+
+                       /* run callbacs before rendering, before the scene is updated */
+                       BLI_exec_cb(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
+
                        
                        do_render_all_options(re);
                        
                        
                        do_render_all_options(re);
                        
@@ -3134,6 +3151,10 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
                                
                                break;
                        }
                                
                                break;
                        }
+
+                       if(G.afbreek==0) {
+                               BLI_exec_cb(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */
+                       }
                }
        }
        
                }
        }
        
index c088d0d..4693c80 100644 (file)
@@ -57,6 +57,7 @@
 #include "BLI_blenlib.h"
 #include "BLI_linklist.h"
 #include "BLI_utildefines.h"
 #include "BLI_blenlib.h"
 #include "BLI_linklist.h"
 #include "BLI_utildefines.h"
+#include "BLI_callbacks.h"
 
 #include "DNA_anim_types.h"
 #include "DNA_ipo_types.h" // XXX old animation system
 
 #include "DNA_anim_types.h"
 #include "DNA_ipo_types.h" // XXX old animation system
@@ -342,6 +343,8 @@ void WM_read_file(bContext *C, const char *filepath, ReportList *reports)
 
        WM_cursor_wait(1);
 
 
        WM_cursor_wait(1);
 
+       BLI_exec_cb(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
+
        /* first try to append data from exotic file formats... */
        /* it throws error box when file doesnt exist and returns -1 */
        /* note; it should set some error message somewhere... (ton) */
        /* first try to append data from exotic file formats... */
        /* it throws error box when file doesnt exist and returns -1 */
        /* note; it should set some error message somewhere... (ton) */
@@ -392,6 +395,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();
 #ifdef WITH_PYTHON
                /* run any texts that were loaded in and flagged as modules */
                BPY_driver_reset();
+               BPY_app_handlers_reset();
                BPY_modules_load_user(C);
 #endif
                CTX_wm_window_set(C, NULL); /* exits queues */
                BPY_modules_load_user(C);
 #endif
                CTX_wm_window_set(C, NULL); /* exits queues */
@@ -411,7 +415,8 @@ void WM_read_file(bContext *C, const char *filepath, ReportList *reports)
                // XXX          undo_editmode_clear();
                BKE_reset_undo();
                BKE_write_undo(C, "original");  /* save current state */
                // XXX          undo_editmode_clear();
                BKE_reset_undo();
                BKE_write_undo(C, "original");  /* save current state */
-               
+
+               BLI_exec_cb(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
        }
        else if(retval == BKE_READ_EXOTIC_OK_OTHER)
                BKE_write_undo(C, "Import file");
        }
        else if(retval == BKE_READ_EXOTIC_OK_OTHER)
                BKE_write_undo(C, "Import file");
@@ -518,6 +523,7 @@ int WM_read_homefile(bContext *C, ReportList *reports, short from_memory)
                BPY_string_exec(C, "__import__('addon_utils').reset_all()");
 
                BPY_driver_reset();
                BPY_string_exec(C, "__import__('addon_utils').reset_all()");
 
                BPY_driver_reset();
+               BPY_app_handlers_reset();
                BPY_modules_load_user(C);
        }
 #endif
                BPY_modules_load_user(C);
        }
 #endif
@@ -716,6 +722,8 @@ int WM_write_file(bContext *C, const char *target, int fileflags, ReportList *re
                }
        }
 
                }
        }
 
+       BLI_exec_cb(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
+
        /* operator now handles overwrite checks */
 
        if (G.fileflags & G_AUTOPACK) {
        /* operator now handles overwrite checks */
 
        if (G.fileflags & G_AUTOPACK) {
@@ -752,6 +760,8 @@ int WM_write_file(bContext *C, const char *target, int fileflags, ReportList *re
                        write_history();
                }
 
                        write_history();
                }
 
+               BLI_exec_cb(G.main, NULL, BLI_CB_EVT_SAVE_POST);
+
                /* run this function after because the file cant be written before the blend is */
                if (ibuf_thumb) {
                        ibuf_thumb= IMB_thumb_create(filepath, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb);
                /* run this function after because the file cant be written before the blend is */
                if (ibuf_thumb) {
                        ibuf_thumb= IMB_thumb_create(filepath, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb);
index c61db1d..0bc2e5d 100644 (file)
@@ -155,6 +155,7 @@ void WM_init(bContext *C, int argc, const char **argv)
        BPY_python_start(argc, argv);
 
        BPY_driver_reset();
        BPY_python_start(argc, argv);
 
        BPY_driver_reset();
+       BPY_app_handlers_reset();
        BPY_modules_load_user(C);
 #else
        (void)argc; /* unused */
        BPY_modules_load_user(C);
 #else
        (void)argc; /* unused */
index 8b405d2..28447ac 100644 (file)
@@ -64,6 +64,7 @@
 #include "BLI_threads.h"
 #include "BLI_scanfill.h" // for BLI_setErrorCallBack, TODO, move elsewhere
 #include "BLI_utildefines.h"
 #include "BLI_threads.h"
 #include "BLI_scanfill.h" // for BLI_setErrorCallBack, TODO, move elsewhere
 #include "BLI_utildefines.h"
+#include "BLI_callbacks.h"
 
 #include "DNA_ID.h"
 #include "DNA_scene_types.h"
 
 #include "DNA_ID.h"
 #include "DNA_scene_types.h"
@@ -990,6 +991,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();
 #ifdef WITH_PYTHON
                /* run any texts that were loaded in and flagged as modules */
                BPY_driver_reset();
+               BPY_app_handlers_reset();
                BPY_modules_load_user(C);
 #endif
 
                BPY_modules_load_user(C);
 #endif
 
@@ -1199,6 +1201,8 @@ int main(int argc, const char **argv)
 
        IMB_init();
 
 
        IMB_init();
 
+       BLI_cb_init();
+
 #ifdef WITH_GAMEENGINE
        syshandle = SYS_GetSystem();
 #else
 #ifdef WITH_GAMEENGINE
        syshandle = SYS_GetSystem();
 #else