[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