[Bf-committers] [Bf-blender-cvs] SVN commit: /data/svn/bf-blender [11387] trunk/blender/source/blender: = Draw Module Fixed=
Joe Eagar
joeedh at gmail.com
Fri Jul 27 08:18:15 CEST 2007
BTW, this should be merged into the stable branch before the final 2.45
release, but I suppose people should have a few days first just in case
there's any bugs or problems I didn't catch.
Joe
Joseph Eagar wrote:
> Revision: 11387
> http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=11387
> Author: joeedh
> Date: 2007-07-27 08:14:25 +0200 (Fri, 27 Jul 2007)
>
> Log Message:
> -----------
> =Draw Module Fixed=
>
> This commit fixes the Draw module. All buttons/widgets created via the Draw
> module in a SpaceScript area are now inserted into a global list attached to
> the SpaceScript data. This list is cleared before each draw, when freeing
> the space, and when the area is switched to another space.c
>
> This is necessary to prevent Blender's internal UI code from getting invalid
> pointers to python data. In addition, it allows storing widget tooltips
> inside the python Button objects, which solves that little bit of stupidity.
>
> Note that this reverts the previous weaklist solution. In fact, I had to go
> over each previous commit by Campbell after this code originally branched
> before the weaklist commit and re-add each commit. So if anything is
> missing, just tell me, or feel free to re-add it.
>
> Modified Paths:
> --------------
> trunk/blender/source/blender/blenloader/intern/writefile.c
> trunk/blender/source/blender/makesdna/DNA_space_types.h
> trunk/blender/source/blender/python/BPY_extern.h
> trunk/blender/source/blender/python/api2_2x/Draw.c
> trunk/blender/source/blender/python/api2_2x/Draw.h
> trunk/blender/source/blender/src/drawscript.c
> trunk/blender/source/blender/src/space.c
>
> Modified: trunk/blender/source/blender/blenloader/intern/writefile.c
> ===================================================================
> --- trunk/blender/source/blender/blenloader/intern/writefile.c 2007-07-27 05:06:05 UTC (rev 11386)
> +++ trunk/blender/source/blender/blenloader/intern/writefile.c 2007-07-27 06:14:25 UTC (rev 11387)
> @@ -1582,6 +1582,8 @@
> writestruct(wd, DATA, "SpaceText", 1, sl);
> }
> else if(sl->spacetype==SPACE_SCRIPT) {
> + SpaceScript *sc = (SpaceScript*)sl;
> + sc->but_refs = NULL;
> writestruct(wd, DATA, "SpaceScript", 1, sl);
> }
> else if(sl->spacetype==SPACE_ACTION) {
>
> Modified: trunk/blender/source/blender/makesdna/DNA_space_types.h
> ===================================================================
> --- trunk/blender/source/blender/makesdna/DNA_space_types.h 2007-07-27 05:06:05 UTC (rev 11386)
> +++ trunk/blender/source/blender/makesdna/DNA_space_types.h 2007-07-27 06:14:25 UTC (rev 11387)
> @@ -292,9 +292,10 @@
> struct ScrArea *area;
> struct Script *script;
>
> - int pad2;
> short flags, menunr;
> -
> + int pad1;
> +
> + void *but_refs;
> } SpaceScript;
>
> typedef struct SpaceTime {
>
> Modified: trunk/blender/source/blender/python/BPY_extern.h
> ===================================================================
> --- trunk/blender/source/blender/python/BPY_extern.h 2007-07-27 05:06:05 UTC (rev 11386)
> +++ trunk/blender/source/blender/python/BPY_extern.h 2007-07-27 06:14:25 UTC (rev 11387)
> @@ -51,6 +51,25 @@
> extern "C" {
> #endif
>
> + /*These two next functions are important for making sure the Draw module
> + works correctly. Before calling any gui callback using the Draw module,
> + the following code must be executed:
> +
> + if (some_drawspace_pylist) {
> + BPy_Set_DrawButtonsList(some_drawspace_pylist->but_refs);
> + BPy_Free_DrawButtonsList();
> + }
> + some_drawspace_pylist = PyList_New(0);
> + BPy_Set_DrawButtonsList(some_drawspace_pylist);
> +
> + Also, BPy_Free_DrawButtonsList() must be called as necassary when a drawspace
> + with python callbacks is destroyed.
> +
> + This is necassary to avoid blender buttons storing invalid pointers to freed
> + python data.*/
> + void BPy_Set_DrawButtonsList(void *list);
> + void BPy_Free_DrawButtonsList(void);
> +
> void BPY_pyconstraint_eval(struct bPythonConstraint *con, float ownermat[][4], float targetmat[][4]);
> void BPY_pyconstraint_settings(void *arg1, void *arg2);
> int BPY_pyconstraint_targets(struct bPythonConstraint *con, float targetmat[][4]);
>
> Modified: trunk/blender/source/blender/python/api2_2x/Draw.c
> ===================================================================
> --- trunk/blender/source/blender/python/api2_2x/Draw.c 2007-07-27 05:06:05 UTC (rev 11386)
> +++ trunk/blender/source/blender/python/api2_2x/Draw.c 2007-07-27 06:14:25 UTC (rev 11387)
> @@ -134,19 +134,13 @@
> /* CLEVER NUMBUT */
> static PyObject *Method_PupBlock( PyObject * self, PyObject * args );
>
> -PyObject * pycallback_weakref_dealloc(PyObject *self, PyObject *weakref);
> -/* python callable */
> -PyObject * pycallback_weakref_dealloc__pyfunc;
> +static uiBlock *Get_uiBlock( void );
>
> -static uiBlock *Get_uiBlock( void );
> static void py_slider_update( void *butv, void *data2_unused );
>
> /* hack to get 1 block for the UIBlock, only ever 1 at a time */
> static uiBlock *uiblock=NULL;
>
> -/* store weakref's to callbacks here */
> -static PyObject *callback_list;
> -
> static char Draw_doc[] = "The Blender.Draw submodule";
>
> static char Method_UIBlock_doc[] = "(drawfunc, x,y) - Popup dialog where buttons can be drawn (expemental)";
> @@ -362,6 +356,12 @@
>
> static char Method_Exit_doc[] = "() - Exit the windowing interface";
>
> +/*This is needed for button callbacks. Any button that uses a callback gets added to this list.
> + On the C side of drawing begin, this list should be cleared.
> + Each entry is a tuple of the form (button, callback py object)
> +*/
> +PyObject *M_Button_List = NULL;
> +
> /*
> * here we engage in some macro trickery to define the PyMethodDef table
> */
> @@ -602,7 +602,13 @@
>
> static Button *newbutton( void )
> {
> - return ( Button * ) PyObject_NEW( Button, &Button_Type );
> + Button *but = NULL;
> +
> + but = ( Button * ) PyObject_NEW( Button, &Button_Type );
> + but->tooltip[0] = 0; /*NULL-terminate tooltip string*/
> + but->tooltip[255] = 0; /*necassary to insure we always have a NULL-terminated string, as
> + according to the docs strncpy doesn't do this for us.*/
> + return but;
> }
>
> /* GUI interface routines */
> @@ -623,6 +629,10 @@
> scrarea_queue_redraw( sc->area );
> }
>
> + BPy_Set_DrawButtonsList(sc->but_refs);
> + BPy_Free_DrawButtonsList(); /*clear all temp button references*/
> + sc->but_refs = NULL;
> +
> Py_XDECREF( ( PyObject * ) script->py_draw );
> Py_XDECREF( ( PyObject * ) script->py_event );
> Py_XDECREF( ( PyObject * ) script->py_button );
> @@ -676,6 +686,13 @@
> UI_HELV, curarea->win );
>
> if( script->py_draw ) {
> + if (sc->but_refs) {
> + BPy_Set_DrawButtonsList(sc->but_refs);
> + BPy_Free_DrawButtonsList(); /*clear all temp button references*/
> + }
> + sc->but_refs = PyList_New(0);
> + BPy_Set_DrawButtonsList(sc->but_refs);
> +
> glPushAttrib( GL_ALL_ATTRIB_BITS );
> exec_callback( sc, script->py_draw, Py_BuildValue( "()" ) );
> glPopAttrib( );
> @@ -717,10 +734,7 @@
>
> if (event == UI_BUT_EVENT) {
> /* check that event is in free range for script button events;
> - * read the comment before check_button_event() below to understand
> - *
> - * This will never run from UIBlock so no need to check if uiblock==NULL
> - * And only sub EXPP_BUTTON_EVENTS_OFFSET in that case */
> + * read the comment before check_button_event() below to understand */
> if (val >= EXPP_BUTTON_EVENTS_OFFSET && val < 0x4000)
> spacescript_do_pywin_buttons(sc, val - EXPP_BUTTON_EVENTS_OFFSET);
> return;
> @@ -758,14 +772,6 @@
> if (callback==NULL || callback == Py_None)
> return;
>
> - if (callback) {
> - if (!PySequence_Contains(callback_list, callback)) {
> - printf("Error, the callback is out of scope.\n\tmake the callback global to resolve this.\n");
> - return;
> - }
> - callback = PyWeakref_GetObject(callback);
> - }
> -
> /* Button types support
> case MENU:
> case TEX:
> @@ -832,33 +838,51 @@
> Py_XDECREF( result );
> }
>
> -PyObject * pycallback_weakref_dealloc(PyObject *self, PyObject *weakref)
> +/*note that this function populates the drawbutton ref lists.*/
> +static void set_pycallback(uiBut *ubut, PyObject *callback, Button *but)
> {
> - int i = PySequence_Index(callback_list, weakref);
> - if (i==-1) {
> - printf("callback weakref internal error, weakref not in list\n\tthis should never happen.\n");
> - return NULL;
> + PyObject *tuple;
> + if (!callback || !PyCallable_Check(callback)) {
> + if (M_Button_List && but) {
> + PyList_Append(M_Button_List, (PyObject*)but);
> + }
> + return;
> }
> - PySequence_DelItem(callback_list, i);
> - Py_RETURN_NONE;
> +
> + if (M_Button_List) {
> + if (but) tuple = PyTuple_New(2);
> + else tuple = PyTuple_New(1);
> +
> + /*the tuple API mandates this*/
> + Py_XINCREF(callback);
> + Py_XINCREF(but); /*this checks for NULL*/
> +
> + PyTuple_SET_ITEM(tuple, 0, callback);
> + if (but) PyTuple_SET_ITEM(tuple, 1, (PyObject*)but);
> +
> + PyList_Append(M_Button_List, tuple);
> + Py_DECREF(tuple); /*we have to do this to aovid double references.*/
> +
> + uiButSetFunc(ubut, exec_but_callback, callback, ubut);
> + }
> }
> -static void set_pycallback(uiBut *ubut, PyObject *callback)
> +
> +void BPy_Set_DrawButtonsList(void *list)
> {
> - PyObject *weakref;
> - if (!callback || !PyCallable_Check(callback)) return;
> -
> - /* This works in most cases except where there are local functions
> - * that are deallocated so we must use weakrefs, will complain rather then crashing */
> - /*uiButSetFunc(ubut, exec_but_callback, callback, ubut);*/
> -
> - weakref = PyWeakref_NewRef(callback, pycallback_weakref_dealloc__pyfunc);
> - PyList_Append(callback_list, weakref);
> - Py_DECREF(weakref);
> -
> - /*printf("adding weakref, totlength %i\n", PyList_Size(callback_list));*/
> - uiButSetFunc(ubut, exec_but_callback, weakref, ubut);
> + M_Button_List = list;
> }
>
> +/*this MUST be called after doing UI stuff.*/
> +void BPy_Free_DrawButtonsList(void)
> +{
> + /*Clear the list.*/
> + if (M_Button_List) {
> + PyList_SetSlice(M_Button_List, 0, PyList_Size(M_Button_List), NULL);
> + Py_DECREF(M_Button_List);
> + M_Button_List = NULL;
> + }
> +}
> +
> static PyObject *Method_Exit( PyObject * self )
> {
> SpaceScript *sc;
> @@ -1047,6 +1071,7 @@
> return (PyObject*) but;
> }
>
> +
> static PyObject *Method_UIBlock( PyObject * self, PyObject * args )
> {
> PyObject *val = NULL;
> @@ -1060,13 +1085,15 @@
> if (uiblock)
> return EXPP_ReturnPyObjError( PyExc_RuntimeError,
> "cannot run more then 1 UIBlock at a time" );
> +
> + BPy_Set_DrawButtonsList(PyList_New(0));
>
> mywinset(G.curscreen->mainwin);
> uiblock= uiNewBlock(&listb, "numbuts", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
>
> uiBlockSetFlag(uiblock, UI_BLOCK_LOOP|UI_BLOCK_REDRAW);
> result = PyObject_CallObject( val, Py_BuildValue( "()" ) );
> -
> +
> if (!result) {
> PyErr_Print( );
> error( "Python script error: check console" );
> @@ -1076,11 +1103,17 @@
> }
> uiFreeBlocks(&listb);
> uiblock = NULL;
> + BPy_Free_DrawButtonsList(); /*clear all temp button references*/
>
> Py_XDECREF( result );
> Py_RETURN_NONE;
> }
>
> +void Set_uiBlock(uiBlock *block)
> +{
> + uiblock = block;
> +}
> +
> static uiBlock *Get_uiBlock( void )
> {
> char butblock[32];
> @@ -1149,7 +1182,7 @@
> block = Get_uiBlock( );
> if( block ) {
> uiBut *ubut = uiDefBut( block, BUT, event, name, (short)x, (short)y, (short)w, (short)h, 0, 0, 0, 0, 0, tip );
> - set_pycallback(ubut, callback);
> + set_pycallback(ubut, callback, NULL);
> }
> Py_RETURN_NONE;
> }
> @@ -1173,12 +1206,13 @@
> but = newbutton( );
> but->type = BINT_TYPE;
> but->val.asint = def;
> -
> + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
> +
> block = Get_uiBlock( );
> if( block ) {
> uiBut *ubut = uiDefButI( block, MENU, event, name, (short)x, (short)y, (short)w, (short)h,
> - &but->val.asint, 0, 0, 0, 0, tip );
> - set_pycallback(ubut, callback);
> + &but->val.asint, 0, 0, 0, 0, but->tooltip );
> + set_pycallback(ubut, callback, but);
> }
> return ( PyObject * ) but;
> }
> @@ -1202,12 +1236,13 @@
> but = newbutton( );
> but->type = BINT_TYPE;
> but->val.asint = def;
> -
> + if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
> +
> block = Get_uiBlock( );
> if( block ) {
> uiBut *ubut = uiDefButI( block, TOG, event, name, (short)x, (short)y, (short)w, (short)h,
> - &but->val.asint, 0, 0, 0, 0, tip );
> - set_pycallback(ubut, callback);
>
> @@ Diff output truncated at 10240 characters. @@
>
> _______________________________________________
> Bf-blender-cvs mailing list
> Bf-blender-cvs at blender.org
> http://lists.blender.org/mailman/listinfo/bf-blender-cvs
>
>
More information about the Bf-committers
mailing list