[Bf-committers] [Bf-blender-cvs] SVN commit: /data/svn/bf-blender [11387] trunk/blender/source/blender: = Draw Module Fixed=

Diego Hernan Borghetti bdiego at gmail.com
Fri Jul 27 16:03:29 CEST 2007


On Thu, 26 Jul 2007, Joe Eagar wrote:

> 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
>>
>>
>
> _______________________________________________
> Bf-committers mailing list
> Bf-committers at blender.org
> http://lists.blender.org/mailman/listinfo/bf-committers
>

Hi Joe:

Thanks to point this, to me, i stop merge things from trunk, so all the RC 
are build without changes. When all the rc are finish (OSX Intel, Irix and 
Linux 64 (alut problem)), i start merge again.

-- 
 			Diego


More information about the Bf-committers mailing list