diff options
Diffstat (limited to 'source/blender/python/BPY_interface.c')
-rw-r--r-- | source/blender/python/BPY_interface.c | 3024 |
1 files changed, 0 insertions, 3024 deletions
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c deleted file mode 100644 index 331f72021f2..00000000000 --- a/source/blender/python/BPY_interface.c +++ /dev/null @@ -1,3024 +0,0 @@ -/* - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * This is a new part of Blender. - * - * Contributor(s): Michel Selten, Willian P. Germano, Stephen Swaney, - * Chris Keith, Chris Want, Ken Hughes - * - * ***** END GPL LICENSE BLOCK ***** -*/ - -#include <Python.h> - -#include "compile.h" /* for the PyCodeObject */ -#include "eval.h" /* for PyEval_EvalCode */ -#include "BLI_blenlib.h" /* for BLI_last_slash() */ -#include "BIF_interface.h" /* for pupmenu() */ -#include "BIF_space.h" -#include "BIF_screen.h" -#include "BIF_toolbox.h" -#include "BKE_action.h" /* for get_pose_channel() */ -#include "BKE_library.h" -#include "BKE_object.h" /* during_scriptlink() */ -#include "BKE_text.h" -#include "BKE_constraint.h" /* for bConstraintOb */ -#include "BKE_idprop.h" - -#include "DNA_curve_types.h" /* for struct IpoDriver */ -#include "DNA_ID.h" /* ipo driver */ -#include "DNA_object_types.h" /* ipo driver */ -#include "DNA_constraint_types.h" /* for pyconstraint */ - -#include "DNA_screen_types.h" -#include "DNA_userdef_types.h" /* for U.pythondir */ -#include "MEM_guardedalloc.h" -#include "BPY_extern.h" -#include "BPY_menus.h" -#include "DNA_space_types.h" -#include "BKE_global.h" -#include "BKE_main.h" -#include "BKE_armature.h" -#include "BKE_depsgraph.h" -#include "api2_2x/EXPP_interface.h" -#include "api2_2x/constant.h" -#include "api2_2x/gen_utils.h" -#include "api2_2x/gen_library.h" /* GetPyObjectFromID */ -#include "api2_2x/BGL.h" -#include "api2_2x/Blender.h" -#include "api2_2x/Camera.h" -#include "api2_2x/Draw.h" -#include "api2_2x/Object.h" -#include "api2_2x/Registry.h" -#include "api2_2x/Pose.h" -#include "api2_2x/bpy.h" /* for the new "bpy" module */ - -/*these next two are for pyconstraints*/ -#include "api2_2x/IDProp.h" -#include "api2_2x/matrix.h" - -/* for scriptlinks */ -#include "DNA_lamp_types.h" -#include "DNA_camera_types.h" -#include "DNA_world_types.h" -#include "DNA_scene_types.h" -#include "DNA_material_types.h" - -/* bpy_registryDict is declared in api2_2x/Registry.h and defined - * in api2_2x/Registry.c - * This Python dictionary will be used to store data that scripts - * choose to preserve after they are executed, so user changes can be - * restored next time the script is used. Check the Blender.Registry module. - */ -/*#include "api2_2x/Registry.h" */ - -/* for pydrivers (ipo drivers defined by one-line Python expressions) */ -PyObject *bpy_pydriver_Dict = NULL; -PyObject *bpy_orig_syspath_List = NULL; - - -/* - * set up a weakref list for Armatures - * creates list in __main__ module dict - */ - -static int setup_armature_weakrefs() -{ - PyObject *maindict; - PyObject *main_module; - char *list_name = ARM_WEAKREF_LIST_NAME; - - main_module = PyImport_AddModule( "__main__"); - if(main_module){ - PyObject *weakreflink; - maindict= PyModule_GetDict(main_module); - - /* check if there is already a dict entry for the armature weakrefs, - * and delete if so before making another one */ - - weakreflink= PyDict_GetItemString(maindict,list_name); - if( weakreflink != NULL ) { - PyDict_DelItemString(maindict,list_name); - Py_XDECREF( weakreflink ); - } - - if (PyDict_SetItemString(maindict, - list_name, - PyList_New(0)) == -1){ - printf("Oops - setup_armature_weakrefs()\n"); - - return 0; - } - } - return 1; -} - -/* Declares the modules and their initialization functions - * These are TOP-LEVEL modules e.g. import `module` - there is no - * support for packages here e.g. import `package.module` */ - -static struct _inittab BPy_Inittab_Modules[] = { - {"Blender", M_Blender_Init}, - {"bpy", m_bpy_init}, - {NULL, NULL} -}; - -/************************************************************************* -* Structure definitions -**************************************************************************/ -#define FILENAME_LENGTH 24 - -typedef struct _ScriptError { - char filename[FILENAME_LENGTH]; - int lineno; -} ScriptError; - -/**************************************************************************** -* Global variables -****************************************************************************/ -ScriptError g_script_error; - -/*************************************************************************** -* Function prototypes -***************************************************************************/ -static PyObject *RunPython( Text * text, PyObject * globaldict ); -static PyObject *CreateGlobalDictionary( void ); -static void ReleaseGlobalDictionary( PyObject * dict ); -static void DoAllScriptsFromList( ListBase * list, short event ); -static PyObject *importText( char *name ); -static void init_ourImport( void ); -static void init_ourReload( void ); -static PyObject *blender_import( PyObject * self, PyObject * args, PyObject * kw); - - -static void BPY_Err_Handle( char *script_name ); -static PyObject *traceback_getFilename( PyObject * tb ); - -/**************************************************************************** -* Description: This function will start the interpreter and load all modules -* as well as search for a python installation. -****************************************************************************/ -void BPY_start_python( int argc, char **argv ) -{ - PyThreadState *py_tstate = NULL; - static int argc_copy = 0; - static char **argv_copy = NULL; - int first_time = argc; - - /* we keep a copy of the values of argc and argv so that the game engine - * can call BPY_start_python(0, NULL) whenever a game ends, without having - * to know argc and argv there (in source/blender/src/space.c) */ - if( first_time ) { - argc_copy = argc; - argv_copy = argv; - } - - //stuff for Registry module - bpy_registryDict = PyDict_New( );/* check comment at start of this file */ - if( !bpy_registryDict ) - printf( "Warning: Couldn't create the Registry Python Dictionary!" ); - Py_SetProgramName( "blender" ); - - /* Py_Initialize() will attempt to import the site module and - * print an error if not found. See init_syspath() for the - * rest of our init msgs. - */ - - /* print Python version - * Py_GetVersion() returns a ptr to a static string "9.9.9 (aaaa..." - */ - { - int count = 3; /* a nice default for major.minor. example 2.5 */ - const char *version = Py_GetVersion(); - /* we know a blank is there somewhere! */ - char *blank_ptr = strchr( version, ' '); - if(blank_ptr) - count = blank_ptr - version; - - printf( "Compiled with Python version %.*s.\n", count, version ); - } - - - //Initialize the TOP-LEVEL modules - PyImport_ExtendInittab(BPy_Inittab_Modules); - - //Start the interpreter - Py_Initialize( ); - - PySys_SetArgv( argc_copy, argv_copy ); - /* Initialize thread support (also acquires lock) */ - PyEval_InitThreads(); - - //Overrides __import__ - init_ourImport( ); - init_ourReload( ); - - //init a global dictionary - g_blenderdict = NULL; - - //Look for a python installation - init_syspath( first_time ); /* not first_time: some msgs are suppressed */ - py_tstate = PyGILState_GetThisThreadState(); - PyEval_ReleaseThread(py_tstate); - - return; -} - -/*****************************************************************************/ -/* Description: This function will terminate the Python interpreter */ -/*****************************************************************************/ -void BPY_end_python( void ) -{ - Script *script = NULL; - Script *next_script = NULL; - - PyGILState_Ensure(); /* finalizing, no need to grab the state */ - - if( bpy_registryDict ) { - Py_DECREF( bpy_registryDict ); - bpy_registryDict = NULL; - } - - if( bpy_pydriver_Dict ) { - Py_DECREF( bpy_pydriver_Dict ); - bpy_pydriver_Dict = NULL; - } - - if( bpy_orig_syspath_List ) { - Py_DECREF( bpy_orig_syspath_List ); - bpy_orig_syspath_List = NULL; - } - - /* Freeing all scripts here prevents problems with the order in which - * Python is finalized and G.main is freed in exit_usiblender() */ - for (script = G.main->script.first; script; script = next_script) { - next_script = script->id.next; - free_libblock( &G.main->script, script ); - } - - Py_Finalize( ); - - BPyMenu_RemoveAllEntries( ); /* freeing bpymenu mem */ - - /* a script might've opened a .blend file but didn't close it, so: */ - EXPP_Library_Close( ); - - return; -} - -void syspath_append( char *dirname ) -{ - PyObject *mod_sys= NULL, *dict= NULL, *path= NULL, *dir= NULL; - short ok=1; - - mod_sys = PyImport_ImportModule( "sys" ); /* new ref */ - - if (mod_sys) { - dict = PyModule_GetDict( mod_sys ); /* borrowed ref */ - path = PyDict_GetItemString( dict, "path" ); /* borrowed ref */ - if ( !PyList_Check( path ) ) { - ok = 0; - } - } else { - /* cant get the sys module */ - /* PyErr_Clear(); is called below */ - ok = 0; - } - - dir = PyString_FromString( dirname ); - - if (ok && PySequence_Contains(path, dir)==0) { /* Only add if we need to */ - if (PyList_Append( path, dir ) != 0) /* decref below */ - ok = 0; /* append failed */ - } - - if( (ok==0) || PyErr_Occurred( ) ) - fprintf(stderr, "Warning: could import or build sys.path\n" ); - - PyErr_Clear(); - Py_DECREF( dir ); - Py_XDECREF( mod_sys ); -} - -void init_syspath( int first_time ) -{ - PyObject *mod, *d; - char *progname; - char execdir[FILE_MAXDIR]; /*defines from DNA_space_types.h */ - - int n; - - mod = PyImport_ImportModule( "Blender.sys" ); - - if( mod ) { - d = PyModule_GetDict( mod ); - EXPP_dict_set_item_str( d, "progname", PyString_FromString( bprogname ) ); - Py_DECREF( mod ); - } else { - printf( "Warning: could not set Blender.sys\n" ); - PyErr_Clear(); - } - - progname = BLI_last_slash( bprogname ); /* looks for the last dir separator */ - - n = progname - bprogname; - if( n > 0 ) { - strncpy( execdir, bprogname, n ); - if( execdir[n - 1] == '.' ) - n--; /*fix for when run as ./blender */ - execdir[n] = '\0'; - - syspath_append( execdir ); /* append to module search path */ - } else { - printf( "Warning: could not determine argv[0] path\n" ); - } - - /* - attempt to import 'site' module as a check for valid - python install found. - */ - - printf("Checking for installed Python... "); /* appears after msg "Compiled with Python 2.x" */ - mod = PyImport_ImportModule( "site" ); /* new ref */ - - if( mod ) { - printf("got it!\n"); - Py_DECREF( mod ); - } else { /* import 'site' failed */ - PyErr_Clear( ); - if( first_time ) { - printf( "No installed Python found.\n" ); - printf( "Only built-in modules are available. Some scripts may not run.\n" ); - printf( "Continuing happily.\n" ); - } - } - - - /* - * initialize the sys module - * set sys.executable to the Blender exe - */ - - mod = PyImport_ImportModule( "sys" ); /* new ref */ - - if( mod ) { - d = PyModule_GetDict( mod ); /* borrowed ref */ - EXPP_dict_set_item_str( d, "executable", Py_BuildValue( "s", bprogname ) ); - - if (bpy_orig_syspath_List == NULL) { - /* backup the original sys.path to rebuild later */ - PyObject *syspath = PyDict_GetItemString( d, "path" ); /* borrowed ref */ - if (bpy_orig_syspath_List) { /* This should never happen but just incase, be nice */ - Py_DECREF(bpy_orig_syspath_List); - } - bpy_orig_syspath_List = PyList_GetSlice(syspath, 0, PyList_Size(syspath)); - } - - Py_DECREF( mod ); - } else{ - PyErr_Clear( ); - printf("Warning: import of sys module failed\n"); - } -} - -void BPY_rebuild_syspath( void ) -{ - PyObject *mod, *dict, *syspath; - char dirpath[FILE_MAX]; - char *sdir = NULL; - PyGILState_STATE gilstate = PyGILState_Ensure(); - - mod = PyImport_ImportModule( "sys" ); - if (!mod) { - printf("Warning: could not import python sys module. some modules may not import.\n"); - PyErr_Clear( ); - PyGILState_Release(gilstate); - return; - } - - if (!bpy_orig_syspath_List) { /* should never happen */ - printf("Warning: cant refresh python path, bpy_orig_syspath_List is NULL\n"); - Py_DECREF(mod); - PyGILState_Release(gilstate); - return; - } - - dict = PyModule_GetDict( mod ); /* borrowed ref */ - - /* Reset sys.path */ - syspath = PyDict_GetItemString( dict, "path" ); /* borrowed ref */ - PyList_SetSlice(syspath, 0, PyList_Size(syspath), bpy_orig_syspath_List); - - if(U.pythondir[0] != '\0' ) { - char modpath[FILE_MAX]; - int upyslen = strlen(U.pythondir); - BLI_strncpy(dirpath, U.pythondir, FILE_MAX); - - /* check if user pydir ends with a slash and, if so, remove the slash - * (for eventual implementations of c library's stat function that might - * not like it) */ -#ifdef WIN32 - if (upyslen > 3) { -#else - if (upyslen > 1) { -#endif - if (dirpath[upyslen-1] == '\\' || dirpath[upyslen-1] == '/') { - dirpath[upyslen-1] = '\0'; - } - } - - BLI_convertstringcode(dirpath, G.sce); - syspath_append(dirpath); /* append to module search path */ - BLI_join_dirfile( modpath, dirpath, "bpymodules" ); - if (BLI_exists(modpath)) syspath_append(modpath); - } - - sdir = bpy_gethome(1); - if (sdir) { - syspath_append(sdir); - BLI_make_file_string("/", dirpath, sdir, "bpymodules"); - if (BLI_exists(dirpath)) syspath_append(dirpath); - } - - Py_DECREF(mod); - PyGILState_Release(gilstate); -} - -int BPY_path_update( void ) -{ - BPyMenu_RemoveAllEntries(); /* free old data */ - BPY_rebuild_syspath(); - if (BPyMenu_Init(1) == -1) { /* re-eval scripts registration in menus */ - return 0; - } - return 1; -} - -/**************************************************************************** -* Description: This function finishes Python initialization in Blender. - -Because U.pythondir (user defined dir for scripts) isn't -initialized when BPY_start_Python needs to be executed, we -postpone adding U.pythondir to sys.path and also BPyMenus -(mechanism to register scripts in Blender menus) for when -that dir info is available. -****************************************************************************/ -void BPY_post_start_python( void ) -{ - PyGILState_STATE gilstate = PyGILState_Ensure(); - - BPY_rebuild_syspath(); - BPyMenu_Init( 0 ); /* get dynamic menus (registered scripts) data */ - - PyGILState_Release(gilstate); -} - -/**************************************************************************** -* Description: This function will return the linenumber on which an error -* has occurred in the Python script. -****************************************************************************/ -int BPY_Err_getLinenumber( void ) -{ - return g_script_error.lineno; -} - -/*****************************************************************************/ -/* Description: This function will return the filename of the python script. */ -/*****************************************************************************/ -const char *BPY_Err_getFilename( void ) -{ - return g_script_error.filename; -} - -/*****************************************************************************/ -/* Description: Return PyString filename from a traceback object */ -/*****************************************************************************/ -static PyObject *traceback_getFilename( PyObject * tb ) -{ - PyObject *v = NULL; - -/* co_filename is in f_code, which is in tb_frame, which is in tb */ - - v = PyObject_GetAttrString( tb, "tb_frame" ); - if (v) { - Py_DECREF( v ); - v = PyObject_GetAttrString( v, "f_code" ); - if (v) { - Py_DECREF( v ); - v = PyObject_GetAttrString( v, "co_filename" ); - } - } - - if (v) return v; - else return PyString_FromString("unknown"); -} - -static void BPY_Err_Clear(void) -{ - /* Added in 2.48a, the last_traceback can reference Objects for example, increasing - * their user count. Not to mention holding references to wrapped data. - * This is especially bad when the PyObject for the wrapped data is free'd, after blender - * has alredy dealocated the pointer */ - PySys_SetObject( "last_traceback", Py_None); - - PyErr_Clear(); -} -/**************************************************************************** -* Description: Blender Python error handler. This catches the error and -* stores filename and line number in a global -*****************************************************************************/ -static void BPY_Err_Handle( char *script_name ) -{ - PyObject *exception, *err, *tb, *v; - - if( !script_name ) { - printf( "Error: script has NULL name\n" ); - BPY_Err_Clear(); - return; - } - - PyErr_Fetch( &exception, &err, &tb ); - - if (!script_name) script_name = "untitled"; - //if( !exception && !tb ) { - // printf( "FATAL: spurious exception\n" ); - // return; - //} - - strcpy( g_script_error.filename, script_name ); - - if( exception - && PyErr_GivenExceptionMatches( exception, PyExc_SyntaxError ) ) { - /* no traceback available when SyntaxError */ - PyErr_NormalizeException( &exception, &err, &tb ); - PyErr_Restore( exception, err, tb ); /* takes away reference! */ - PyErr_Print( ); - v = PyObject_GetAttrString( err, "lineno" ); - if( v ) { - g_script_error.lineno = PyInt_AsLong( v ); - Py_DECREF( v ); - } else { - g_script_error.lineno = -1; - } - /* this avoids an abort in Python 2.3's garbage collecting: - PyErr_Clear() */ - BPY_Err_Clear(); /* Calls PyErr_Clear as well */ - return; - } else { - PyErr_NormalizeException( &exception, &err, &tb ); - PyErr_Restore( exception, err, tb ); /* takes away reference! */ - PyErr_Print( ); - tb = PySys_GetObject( "last_traceback" ); - - if( !tb ) { - printf( "\nCan't get traceback\n" ); - BPY_Err_Clear(); /* incase there is still some data hanging about */ - return; - } - - Py_INCREF( tb ); - -/* From old bpython BPY_main.c: - * 'check traceback objects and look for last traceback in the - * same text file. This is used to jump to the line of where the - * error occured. "If the error occured in another text file or module, - * the last frame in the current file is adressed."' - */ - - for(;;) { - v = PyObject_GetAttrString( tb, "tb_next" ); - - if( !v || v == Py_None || - strcmp(PyString_AsString(traceback_getFilename(v)), script_name)) { - break; - } - - Py_DECREF( tb ); - tb = v; - } - - v = PyObject_GetAttrString( tb, "tb_lineno" ); - if (v) { - g_script_error.lineno = PyInt_AsLong(v); - Py_DECREF(v); - } - v = traceback_getFilename( tb ); - if (v) { - strncpy( g_script_error.filename, PyString_AsString( v ), - FILENAME_LENGTH ); - Py_DECREF(v); - } - Py_DECREF( tb ); - } - - BPY_Err_Clear(); - return; -} - -/**************************************************************************** -* Description: This function executes the script passed by st. -* Notes: It is called by blender/src/drawtext.c when a Blender user -* presses ALT+PKEY in the script's text window. -*****************************************************************************/ -int BPY_txt_do_python_Text( struct Text *text ) -{ - PyObject *py_dict, *py_result; - BPy_constant *info; - char textname[24]; - Script *script = G.main->script.first; - PyGILState_STATE gilstate; - - if( !text ) - return 0; - - /* check if this text is already running */ - while( script ) { - if( !strcmp( script->id.name + 2, text->id.name + 2 ) ) { - /* if this text is already a running script, - * just move to it: */ - if (!G.background) { - SpaceScript *sc; - newspace( curarea, SPACE_SCRIPT ); - sc = curarea->spacedata.first; - sc->script = script; - return 1; - } - } - script = script->id.next; - } - - /* Create a new script structure and initialize it: */ - script = alloc_libblock( &G.main->script, ID_SCRIPT, text->id.name+2 ); - - if( !script ) { - printf( "couldn't allocate memory for Script struct!" ); - return 0; - } - - /* if in the script Blender.Load(blendfile) is not the last command, - * an error after it will call BPY_Err_Handle below, but the text struct - * will have been deallocated already, so we need to copy its name here. - */ - BLI_strncpy( textname, text->id.name+2, 21 ); - - script->id.us = 1; - script->flags = SCRIPT_RUNNING; - script->py_draw = NULL; - script->py_event = NULL; - script->py_button = NULL; - script->py_browsercallback = NULL; - strncpy(script->scriptname, text->id.name+2, sizeof(script->scriptname)); - gilstate = PyGILState_Ensure(); - - py_dict = CreateGlobalDictionary( ); - - if( !setup_armature_weakrefs()){ - printf("Oops - weakref dict\n"); - PyGILState_Release(gilstate); - return 0; - } - - script->py_globaldict = py_dict; - - info = ( BPy_constant * ) PyConstant_New( ); - if( info ) { - PyConstant_Insert( info, "name", - PyString_FromString( script->id.name + 2 ) ); - Py_INCREF( Py_None ); - PyConstant_Insert( info, "arg", Py_None ); - EXPP_dict_set_item_str( py_dict, "__script__", - ( PyObject * ) info ); - } - - py_result = RunPython( text, py_dict ); /* Run the script */ - - if( !py_result ) { /* Failed execution of the script */ - - BPY_Err_Handle( textname ); - ReleaseGlobalDictionary( py_dict ); - script->py_globaldict = NULL; - free_libblock( &G.main->script, script ); - PyGILState_Release(gilstate); - return 0; - } else { - Py_DECREF( py_result ); - script->flags &= ~SCRIPT_RUNNING; - if( !script->flags ) { - ReleaseGlobalDictionary( py_dict ); - script->py_globaldict = NULL; - free_libblock( &G.main->script, script ); - } - } - - PyGILState_Release(gilstate); - - return 1; /* normal return */ -} - -/**************************************************************************** -* Description: Called from command line to run a Python script -* automatically. The script can be a file or a Blender Text in the current -* .blend. -****************************************************************************/ -void BPY_run_python_script( const char *fn ) -{ - char filename[FILE_MAXDIR + FILE_MAXFILE]; - Text *text = NULL; - int is_blender_text = 0; - - BLI_strncpy(filename, fn, FILE_MAXDIR + FILE_MAXFILE); - - if (!BLI_exists(filename)) - BLI_convertstringcwd(filename); - - if (!BLI_exists(filename)) { /* if there's no such filename ... */ - /* try an already existing Blender Text. - * use 'fn' rather then filename for this since were looking for - * internal text - */ - text = G.main->text.first; - - while (text) { - if (!strcmp(fn, text->id.name + 2)) break; - text = text->id.next; - } - - if (text == NULL) { - printf("\nError: no such file or Blender text -- %s.\n", fn); - return; - } - else is_blender_text = 1; /* fn is already a Blender Text */ - } - - else { - /* use filename here since we know it exists, - * 'fn' may have been a relative path - */ - text = add_text(filename); - - if (text == NULL) { - printf("\nError in BPY_run_python_script:\n" - "couldn't create Blender text from \"%s\"\n", filename); - /* Chris: On Windows if I continue I just get a segmentation - * violation. To get a baseline file I exit here. */ - exit(2); - /* return; */ - } - } - - if (BPY_txt_do_python_Text(text) != 1) { - printf("\nError executing Python script from command-line:\n" - "%s (at line %d).\n", fn, BPY_Err_getLinenumber()); - } - - if (!is_blender_text) { - /* We can't simply free the text, since the script might have called - * Blender.Load() to load a new .blend, freeing previous data. - * So we check if the pointer is still valid. */ - if (BLI_findindex(&G.main->text, text) != -1) { - free_libblock(&G.main->text, text); - } - } -} - -int BPY_run_script(Script *script) -{ - PyObject *py_dict, *py_res, *pyarg; - Text *text = NULL; - BPy_constant *info; - - PyGILState_STATE gilstate = PyGILState_Ensure(); - - if (!BLI_exists(script->scriptname)) { - /* The file dosnt exist, maybe this blend file was made on some other persons computer? */ - char fname[FILE_MAX]; - char fpath[FILE_MAX]; - char ftmp[FILE_MAX]; - char *bpyhome = bpy_gethome(1); - - if (bpyhome) { - BLI_strncpy(ftmp, script->scriptname, sizeof(ftmp)); - BLI_split_dirfile_basic(ftmp, NULL, fname); /* get the filename only - fname */ - BLI_strncpy(fpath, bpy_gethome(1), sizeof(fpath)); - BLI_add_slash(fpath); - strcat(fpath, fname); - - if (BLI_exists(fpath)) { - strncpy(script->scriptname, fpath, sizeof(script->scriptname)); - } else { - bpyhome = NULL; /* a bit dodgy, this is so the line below runs */ - } - } - - if (bpyhome == NULL && U.pythondir[0]) { - BLI_make_file_string("/", fpath, U.pythondir, fname); - if (BLI_exists(fpath)) { - strncpy(script->scriptname, fpath, sizeof(script->scriptname)); - } - } - - /* cant find the file?, fallback to text block */ - if (!BLI_exists(script->scriptname)) { - for (text=G.main->text.first; text; text=text->id.next) { - if (strcmp(script->scriptname, text->id.name+2)==0) { - break; - } - } - } - } - if (text) { - Py_INCREF( Py_None ); - pyarg = Py_None; - } else { - if (!BLI_exists(script->scriptname)) { - printf( "Script does not exit %s\n", script->scriptname ); - free_libblock( &G.main->script, script ); - PyGILState_Release(gilstate); - return 0; - } - - if( script->scriptarg[0] == '\0' ) { /* no submenus */ - Py_INCREF( Py_None ); - pyarg = Py_None; - } else { - pyarg = PyString_FromString( script->scriptarg ); - } - } - - script->id.us = 1; - script->flags = SCRIPT_RUNNING; - script->py_draw = NULL; - script->py_event = NULL; - script->py_button = NULL; - script->py_browsercallback = NULL; - - py_dict = CreateGlobalDictionary( ); - - script->py_globaldict = py_dict; - - if( !setup_armature_weakrefs()){ - printf("Oops - weakref dict\n"); - free_libblock( &G.main->script, script ); - ReleaseGlobalDictionary( py_dict ); - PyGILState_Release(gilstate); - return 0; - } - - info = ( BPy_constant * ) PyConstant_New( ); - if( info ) { - PyConstant_Insert( info, "name", - PyString_FromString( script->id.name + 2 ) ); - PyConstant_Insert( info, "arg", pyarg ); - EXPP_dict_set_item_str( py_dict, "__script__", - ( PyObject * ) info ); - } - - if (text) { - py_res = RunPython( text, py_dict ); - } else { - char pystring[sizeof(script->scriptname) + 15]; - sprintf(pystring, "execfile(r'%s')", script->scriptname); - py_res = PyRun_String( pystring, Py_file_input, py_dict, py_dict ); - } - - if( !py_res ) { /* Failed execution of the script */ - /* Previously we used PyRun_File to run directly the code on a FILE - * object, but as written in the Python/C API Ref Manual, chapter 2, - * 'FILE structs for different C libraries can be different and - * incompatible'. - * So now we load the script file data to a buffer */ - BPY_Err_Handle( script->id.name + 2 ); - ReleaseGlobalDictionary( py_dict ); - script->py_globaldict = NULL; - free_libblock( &G.main->script, script ); - error_pyscript( ); - - PyGILState_Release(gilstate); - return 0; - } else { - Py_DECREF( py_res ); - script->flags &= ~SCRIPT_RUNNING; - - if( !script->flags ) { - ReleaseGlobalDictionary( py_dict ); - script->py_globaldict = NULL; - free_libblock( &G.main->script, script ); - - /* special case: called from the menu in the Scripts window - * we have to change sc->script pointer, since it'll be freed here.*/ - if (!G.background) { - if( curarea->spacetype == SPACE_SCRIPT ) { - SpaceScript *sc = curarea->spacedata.first; - sc->script = G.main->script.first; /* can be null, which is ok ... */ - /* ... meaning no other script is running right now. */ - } - } - - } - } - - PyGILState_Release(gilstate); - return 1; -} - -/**************************************************************************** -* Description: This function executes the script chosen from a menu. -* Notes: It is called by the ui code in src/header_???.c when a user -* clicks on a menu entry that refers to a script. -* Scripts are searched in the BPyMenuTable, using the given -* menutype and event values to know which one was chosen. -*****************************************************************************/ -int BPY_menu_do_python( short menutype, int event ) -{ - BPyMenu *pym; - pym = BPyMenu_GetEntry( menutype, ( short ) event ); - return BPY_menu_invoke( pym, menutype ); -} - -/**************************************************************************** -* Description: This function executes the script by its shortcut. -* Notes: It is called by the ui code in src/???.c when a user presses an -* unassigned key combination. Scripts are searched in the BPyMenuTable, -* using the given menutype and event values to know which one to invoke. -*****************************************************************************/ -int BPY_menu_do_shortcut( short menutype, unsigned short key, unsigned short qual ) -{ - BPyMenu *pym; - pym = BPyMenu_GetEntry( menutype, 0 ); - - while ( pym ) { - if ( pym->key && pym->key == key && pym->qual == qual ) { - return BPY_menu_invoke( pym, menutype ); - } - pym = pym->next; - } - - return 0; -} - -/**************************************************************************** -* Description: This function executes the script described by a menu item. -*****************************************************************************/ -int BPY_menu_invoke( BPyMenu *pym, short menutype ) -{ - char *argstr = NULL; - BPySubMenu *pysm; - char scriptname[21]; - Script *script = NULL; - int ret, len; - PyGILState_STATE gilstate; - char filestr[FILE_MAX]; - - if( !pym ) - return 0; - - gilstate = PyGILState_Ensure(); - - if( pym->version > G.version ) - notice( "Version mismatch: script was written for Blender %d. " - "It may fail with yours: %d.", pym->version, - G.version ); - -/* if there are submenus, let the user choose one from a pupmenu that we - * create here.*/ - pysm = pym->submenus; - if( pysm ) { - char *pupstr; - int arg; - - pupstr = BPyMenu_CreatePupmenuStr( pym, menutype ); - - if( pupstr ) { - arg = pupmenu( pupstr ); - MEM_freeN( pupstr ); - - if( arg >= 0 ) { - while( arg-- ) - pysm = pysm->next; - argstr = pysm->arg; - } else { - PyGILState_Release(gilstate); - return 0; - } - } - } - - if( pym->dir ) { /* script is in U.pythondir */ - char upythondir[FILE_MAX]; - - /* dirs in Blender can be "//", which has a special meaning */ - BLI_strncpy(upythondir, U.pythondir, FILE_MAX); - BLI_convertstringcode(upythondir, G.sce); /* if so, this expands it */ - BLI_make_file_string( "/", filestr, upythondir, pym->filename ); - } - else { /* script is in default scripts dir */ - char *scriptsdir = bpy_gethome(1); - - if (!scriptsdir) { - printf("Error loading script: can't find default scripts dir!"); - PyGILState_Release(gilstate); - return 0; - } - - BLI_make_file_string( "/", filestr, scriptsdir, pym->filename ); - } - - BLI_strncpy(scriptname, pym->name, 21); - len = strlen(scriptname) - 1; - /* by convention, scripts that open the file browser or have submenus - * display '...'. Here we remove them from the datablock name */ - while ((len > 0) && scriptname[len] == '.') { - scriptname[len] = '\0'; - len--; - } - - /* Create a new script structure and initialize it: */ - script = alloc_libblock( &G.main->script, ID_SCRIPT, scriptname ); - - if( !script ) { - printf( "couldn't allocate memory for Script struct!" ); - PyGILState_Release(gilstate); - return 0; - } - - /* let's find a proper area for an eventual script gui: - * (still experimenting here, need definition on which win - * each group will be put to code this properly) */ - switch ( menutype ) { - - case PYMENU_IMPORT: /* first 4 were handled in header_info.c */ - case PYMENU_EXPORT: - case PYMENU_HELP: - case PYMENU_RENDER: - case PYMENU_WIZARDS: - case PYMENU_SCRIPTTEMPLATE: - case PYMENU_TEXTPLUGIN: - case PYMENU_MESHFACEKEY: - break; - - default: - if( curarea->spacetype != SPACE_SCRIPT ) { - ScrArea *sa = NULL; - - sa = find_biggest_area_of_type( SPACE_BUTS ); - if( sa ) { - if( ( 1.5 * sa->winx ) < sa->winy ) - sa = NULL; /* too narrow? */ - } - - if( !sa ) - sa = find_biggest_area_of_type( SPACE_SCRIPT ); - if( !sa ) - sa = find_biggest_area_of_type( SPACE_TEXT ); - if( !sa ) - sa = find_biggest_area_of_type( SPACE_IMAGE ); /* group UV */ - if( !sa ) - sa = find_biggest_area_of_type( SPACE_VIEW3D ); - - if( !sa ) - sa = find_biggest_area( ); - - areawinset( sa->win ); - } - break; - } - - strncpy(script->scriptname, filestr, sizeof(script->scriptname)); - if (argstr!=NULL && argstr[0] != '\0') - strncpy(script->scriptarg, argstr, sizeof(script->scriptarg)); - - ret = BPY_run_script(script); - - return 1; /* normal return */ -} - -/***************************************************************************** -* Description: -* Notes: -*****************************************************************************/ -void BPY_free_compiled_text( struct Text *text ) -{ - if( text->compiled ) { - Py_DECREF( ( PyObject * ) text->compiled ); - text->compiled = NULL; - } -} - -/***************************************************************************** -* Description: This function frees a finished (flags == 0) script. -*****************************************************************************/ -void BPY_free_finished_script( Script * script ) -{ - PyGILState_STATE gilstate; - - if( !script ) - return; - - gilstate = PyGILState_Ensure(); - - if( PyErr_Occurred( ) ) { /* if script ended after filesel */ - PyErr_Print( ); /* eventual errors are handled now */ - error_pyscript( ); - } - - PyGILState_Release(gilstate); - - free_libblock( &G.main->script, script ); - return; -} - -static void unlink_script( Script * script ) -{ /* copied from unlink_text in drawtext.c */ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - - for( scr = G.main->screen.first; scr; scr = scr->id.next ) { - for( area = scr->areabase.first; area; area = area->next ) { - for( sl = area->spacedata.first; sl; sl = sl->next ) { - if( sl->spacetype == SPACE_SCRIPT ) { - SpaceScript *sc = ( SpaceScript * ) sl; - - if( sc->script == script ) { - sc->script = NULL; - - if( sc == area->spacedata.first ) { - scrarea_queue_redraw( area ); - } - - if (sc->but_refs) { - BPy_Set_DrawButtonsList(sc->but_refs); - BPy_Free_DrawButtonsList(); - sc->but_refs = NULL; - } - } - } - } - } - } -} - -/* This is called from free_libblock( &G.main->script, script ); */ -void BPY_clear_script( Script * script ) -{ - PyObject *dict; - PyGILState_STATE gilstate; - - if( !script ) - return; - - gilstate = PyGILState_Ensure(); - - if (!Py_IsInitialized()) { - printf("\nError: trying to free script data after finalizing Python!"); - printf("\nScript name: %s\n", script->id.name+2); - PyGILState_Release(gilstate); - return; - } - - Py_XDECREF( ( PyObject * ) script->py_draw ); - Py_XDECREF( ( PyObject * ) script->py_event ); - Py_XDECREF( ( PyObject * ) script->py_button ); - Py_XDECREF( ( PyObject * ) script->py_browsercallback ); - script->py_draw = NULL; - script->py_event = NULL; - script->py_button = NULL; - script->py_browsercallback = NULL; - script->scriptname[0] = '\0'; - script->scriptarg[0] = '\0'; - - dict = script->py_globaldict; - - if( dict ) { - PyDict_Clear( dict ); - Py_DECREF( dict ); /* Release dictionary. */ - script->py_globaldict = NULL; - } - - PyGILState_Release(gilstate); - - unlink_script( script ); -} - -/* PyDrivers */ - -/* PyDrivers are Ipo Drivers governed by expressions written in Python. - * Expressions here are one-liners that evaluate to a float value. */ - -/* For faster execution we keep a special dictionary for pydrivers, with - * the needed modules and aliases. */ -static int bpy_pydriver_create_dict(void) -{ - PyObject *d, *mod; - - if (bpy_pydriver_Dict) return -1; - - d = PyDict_New(); - if (!d) return -1; - - bpy_pydriver_Dict = d; - - /* import some modules: builtins, Blender, math, Blender.noise */ - - PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins()); - - mod = PyImport_ImportModule("Blender"); - if (mod) { - PyDict_SetItemString(d, "Blender", mod); - PyDict_SetItemString(d, "b", mod); - Py_DECREF(mod); - } else { - PyErr_Clear(); - } - - mod = PyImport_ImportModule("math"); - if (mod) { - PyDict_Merge(d, PyModule_GetDict(mod), 0); /* 0 - dont overwrite existing values */ - - /* Only keep for backwards compat! - just import all math into root, they are standard */ - PyDict_SetItemString(d, "math", mod); - PyDict_SetItemString(d, "m", mod); - Py_DECREF(mod); - } - - mod = PyImport_ImportModule("Blender.Noise"); - if (mod) { - PyDict_SetItemString(d, "noise", mod); - PyDict_SetItemString(d, "n", mod); - Py_DECREF(mod); - } else { - PyErr_Clear(); - } - - /* If there's a Blender text called pydrivers.py, import it. - * Users can add their own functions to this module. */ - if (G.f&G_DOSCRIPTLINKS) { - mod = importText("pydrivers"); /* can also use PyImport_Import() */ - if (mod) { - PyDict_SetItemString(d, "pydrivers", mod); - PyDict_SetItemString(d, "p", mod); - Py_DECREF(mod); - } else { - PyErr_Clear(); - } - } - /* short aliases for some Get() functions: */ - - /* ob(obname) == Blender.Object.Get(obname) */ - mod = PyImport_ImportModule("Blender.Object"); - if (mod) { - PyObject *fcn = PyObject_GetAttrString(mod, "Get"); - Py_DECREF(mod); - if (fcn) { - PyDict_SetItemString(d, "ob", fcn); - Py_DECREF(fcn); - } - } else { - PyErr_Clear(); - } - - /* TODO - change these */ - /* me(meshname) == Blender.Mesh.Get(meshname) */ - mod = PyImport_ImportModule("Blender.Mesh"); - if (mod) { - PyObject *fcn = PyObject_GetAttrString(mod, "Get"); - Py_DECREF(mod); - if (fcn) { - PyDict_SetItemString(d, "me", fcn); - Py_DECREF(fcn); - } - } else { - PyErr_Clear(); - } - - /* ma(matname) == Blender.Material.Get(matname) */ - mod = PyImport_ImportModule("Blender.Material"); - if (mod) { - PyObject *fcn = PyObject_GetAttrString(mod, "Get"); - Py_DECREF(mod); - if (fcn) { - PyDict_SetItemString(d, "ma", fcn); - Py_DECREF(fcn); - } - } else { - PyErr_Clear(); - } - - return 0; -} - -/* error return function for BPY_eval_pydriver */ -static float pydriver_error(IpoDriver *driver) { - - if (bpy_pydriver_oblist) - bpy_pydriver_freeList(); - - if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */ - PyDict_Clear(bpy_pydriver_Dict); - Py_DECREF(bpy_pydriver_Dict); - bpy_pydriver_Dict = NULL; - } - - driver->flag |= IPO_DRIVER_FLAG_INVALID; /* py expression failed */ - - if (driver->ob) - fprintf(stderr, "\nError in Ipo Driver: Object %s\nThis is the failed Python expression:\n'%s'\n\n", driver->ob->id.name+2, driver->name); - else - fprintf(stderr, "\nError in Ipo Driver: No Object\nThis is the failed Python expression:\n'%s'\n\n", driver->name); - - PyErr_Print(); - - return 0.0f; -} - - -/********PyConstraints*********/ - -/* This function checks whether a text-buffer is a PyConstraint candidate. - * It uses simple text parsing that could be easily confused! - */ -int BPY_is_pyconstraint(Text *text) -{ - TextLine *tline = text->lines.first; - - if (tline && (tline->len > 10)) { - char *line = tline->line; - - /* Expected format: #BPYCONSTRAINT - * The actual checks are forgiving, so slight variations also work. */ - if (line && line[0] == '#' && strstr(line, "BPYCONSTRAINT")) return 1; - } - return 0; -} - -/* This function frees links from pyconstraints to a given text-buffer. - * Used when a text-buffer is unlinked! - */ -void BPY_free_pyconstraint_links(Text *text) -{ - Object *ob; - bConstraint *con; - short update; - - /*check all pyconstraints*/ - for (ob=G.main->object.first; ob; ob=ob->id.next) { - update = 0; - if(ob->type==OB_ARMATURE && ob->pose) { - bPoseChannel *pchan; - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - for (con = pchan->constraints.first; con; con=con->next) { - if (con->type==CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text==text) data->text = NULL; - update = 1; - - } - } - } - } - for (con = ob->constraints.first; con; con=con->next) { - if (con->type==CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text==text) data->text = NULL; - update = 1; - } - } - - if (update) { - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - } - } -} - -/* This function is called to update PyConstraint data so that it is compatible with the script. - * Some of the allocating/freeing of memory for constraint targets occurs here, espcially - * if the number of targets changes. - */ -void BPY_pyconstraint_update(Object *owner, bConstraint *con) -{ - bPythonConstraint *data= con->data; - - if (data->text) { - /* script does exist. it is assumed that this is a valid pyconstraint script */ - PyObject *globals; - PyObject *retval, *gval; - PyGILState_STATE gilstate; - int num, i; - - /* clear the relevant flags first */ - data->flag = 0; - - gilstate = PyGILState_Ensure(); - - /* populate globals dictionary */ - globals = CreateGlobalDictionary(); - retval = RunPython(data->text, globals); - - if (retval == NULL) { - BPY_Err_Handle(data->text->id.name); - ReleaseGlobalDictionary(globals); - data->flag |= PYCON_SCRIPTERROR; - PyGILState_Release(gilstate); - return; - } - - Py_XDECREF(retval); - retval = NULL; - - /* try to find NUM_TARGETS */ - gval = PyDict_GetItemString(globals, "NUM_TARGETS"); - if ( (gval) && (num= PyInt_AsLong(gval)) ) { - /* NUM_TARGETS is defined... and non-zero */ - bConstraintTarget *ct; - - /* check if it is valid (just make sure it is not negative) - * TODO: PyInt_AsLong may return -1 as sign of invalid input... - */ - num = abs(num); - data->flag |= PYCON_USETARGETS; - - /* check if the number of targets has changed */ - if (num < data->tarnum) { - /* free a few targets */ - num= data->tarnum - num; - for (i = 0; i < num; i++, data->tarnum--) { - ct= data->targets.last; - BLI_freelinkN(&data->targets, ct); - } - } - else if (num > data->tarnum) { - /* add a few targets */ - num = num - data->tarnum; - for (i = 0; i < num; i++, data->tarnum++) { - ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget"); - BLI_addtail(&data->targets, ct); - } - } - - /* validate targets */ - con->flag &= ~CONSTRAINT_DISABLE; - for (ct= data->targets.first; ct; ct= ct->next) { - if (!exist_object(ct->tar)) { - ct->tar = NULL; - con->flag |= CONSTRAINT_DISABLE; - break; - } - - if ((ct->tar == owner) && (ct->subtarget[0] != 0)) { - if (get_named_bone(get_armature(owner), ct->subtarget) == NULL) { - con->flag |= CONSTRAINT_DISABLE; - break; - } - } - } - - /* clear globals */ - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - else { - /* NUM_TARGETS is not defined or equals 0 */ - ReleaseGlobalDictionary(globals); - - /* free all targets */ - BLI_freelistN(&data->targets); - data->tarnum = 0; - data->flag &= ~PYCON_USETARGETS; - - PyGILState_Release(gilstate); - - return; - } - } - else { - /* no script, so clear any settings/data now */ - data->tarnum = 0; - data->flag = 0; - con->flag &= ~CONSTRAINT_DISABLE; - - BLI_freelistN(&data->targets); - - /* supposedly this should still leave the base struct... */ - IDP_FreeProperty(data->prop); - } -} - -/* PyConstraints Evaluation Function (only called from evaluate_constraint) - * This function is responsible for modifying the ownermat that it is passed. - */ -void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase *targets) -{ - PyObject *srcmat, *tarmat, *tarmats, *idprop; - PyObject *globals; - PyObject *gval; - PyObject *pyargs, *retval; - bConstraintTarget *ct; - MatrixObject *retmat; - int row, col, index; - PyGILState_STATE gilstate; - - if (!con->text) return; - if (con->flag & PYCON_SCRIPTERROR) return; - - gilstate = PyGILState_Ensure(); - - globals = CreateGlobalDictionary(); - - /* wrap blender-data as PyObjects for evaluation - * - we expose the owner's matrix as pymatrix - * - id-properties are wrapped using the id-properties pyapi - * - targets are presented as a list of matrices - */ - srcmat = newMatrixObject((float *)cob->matrix, 4, 4, Py_NEW); - idprop = BPy_Wrap_IDProperty(NULL, con->prop, NULL); - - tarmats= PyList_New(con->tarnum); - for (ct=targets->first, index=0; ct; ct=ct->next, index++) { - tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW); - PyList_SET_ITEM(tarmats, index, tarmat); - } - - if (!setup_armature_weakrefs()) { - fprintf(stderr, "Oops - weakref dict setup\n"); - PyGILState_Release(gilstate); - - return; - } - - retval = RunPython(con->text, globals); - - if (retval == NULL) { - BPY_Err_Handle(con->text->id.name); - con->flag |= PYCON_SCRIPTERROR; - - /* free temp objects */ - Py_XDECREF(idprop); - Py_XDECREF(srcmat); - Py_XDECREF(tarmats); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - if (retval) {Py_XDECREF( retval );} - retval = NULL; - - gval = PyDict_GetItemString(globals, "doConstraint"); - if (!gval) { - printf("ERROR: no doConstraint function in constraint!\n"); - - /* free temp objects */ - Py_XDECREF(idprop); - Py_XDECREF(srcmat); - Py_XDECREF(tarmats); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - /* Now for the fun part! Try and find the functions we need. */ - if (PyFunction_Check(gval)) { - pyargs = Py_BuildValue("OOO", srcmat, tarmats, idprop); - retval = PyObject_CallObject(gval, pyargs); - Py_XDECREF(pyargs); - } - else { - printf("ERROR: doConstraint is supposed to be a function!\n"); - con->flag |= PYCON_SCRIPTERROR; - - Py_XDECREF(idprop); - Py_XDECREF(srcmat); - Py_XDECREF(tarmats); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - if (!retval) { - BPY_Err_Handle(con->text->id.name); - con->flag |= PYCON_SCRIPTERROR; - - /* free temp objects */ - Py_XDECREF(idprop); - Py_XDECREF(srcmat); - Py_XDECREF(tarmats); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - - if (!PyObject_TypeCheck(retval, &matrix_Type)) { - printf("Error in PyConstraint - doConstraint: Function not returning a matrix!\n"); - con->flag |= PYCON_SCRIPTERROR; - - Py_XDECREF(idprop); - Py_XDECREF(srcmat); - Py_XDECREF(tarmats); - Py_XDECREF(retval); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - retmat = (MatrixObject *)retval; - if (retmat->rowSize != 4 || retmat->colSize != 4) { - printf("Error in PyConstraint - doConstraint: Matrix returned is the wrong size!\n"); - con->flag |= PYCON_SCRIPTERROR; - - Py_XDECREF(idprop); - Py_XDECREF(srcmat); - Py_XDECREF(tarmats); - Py_XDECREF(retval); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - /* this is the reverse of code taken from newMatrix() */ - for(row = 0; row < 4; row++) { - for(col = 0; col < 4; col++) { - cob->matrix[row][col] = retmat->contigPtr[row*4+col]; - } - } - - /* free temp objects */ - Py_XDECREF(idprop); - Py_XDECREF(srcmat); - Py_XDECREF(tarmats); - Py_XDECREF(retval); - - /* clear globals */ - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); -} - -/* This evaluates the target matrix for each target the PyConstraint uses. - * NOTE: it only does one target at a time! - */ -void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct) -{ - PyObject *tar, *subtar; - PyObject *tarmat, *idprop; - PyObject *globals; - PyObject *gval; - PyObject *pyargs, *retval; - MatrixObject *retmat; - int row, col; - PyGILState_STATE gilstate; - - if (!con->text) return; - if (con->flag & PYCON_SCRIPTERROR) return; - if (!ct) return; - - gilstate = PyGILState_Ensure(); - - globals = CreateGlobalDictionary(); - - tar = Object_CreatePyObject(ct->tar); - if ((ct->tar) && (ct->tar->type==OB_ARMATURE)) { - bPoseChannel *pchan; - pchan = get_pose_channel(ct->tar->pose, ct->subtarget); - subtar = PyPoseBone_FromPosechannel(pchan); - } - else - subtar = PyString_FromString(ct->subtarget); - - tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW); - idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL); - - if (!setup_armature_weakrefs()) { - fprintf(stderr, "Oops - weakref dict setup\n"); - PyGILState_Release(gilstate); - return; - } - - retval = RunPython(con->text, globals); - - if (retval == NULL) { - BPY_Err_Handle(con->text->id.name); - con->flag |= PYCON_SCRIPTERROR; - - /* free temp objects */ - Py_XDECREF(tar); - Py_XDECREF(subtar); - Py_XDECREF(idprop); - Py_XDECREF(tarmat); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - Py_XDECREF(retval); - retval = NULL; - - /* try to find doTarget function to set the target matrix */ - gval = PyDict_GetItemString(globals, "doTarget"); - if (!gval) { - /* free temp objects */ - Py_XDECREF(tar); - Py_XDECREF(subtar); - Py_XDECREF(idprop); - Py_XDECREF(tarmat); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - /* Now for the fun part! Try and find the functions we need.*/ - if (PyFunction_Check(gval)) { - pyargs = Py_BuildValue("OOOO", tar, subtar, tarmat, idprop); - retval = PyObject_CallObject(gval, pyargs); - Py_XDECREF(pyargs); - } - else { - printf("ERROR: doTarget is supposed to be a function!\n"); - con->flag |= PYCON_SCRIPTERROR; - - Py_XDECREF(tar); - Py_XDECREF(subtar); - Py_XDECREF(idprop); - Py_XDECREF(tarmat); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - if (!retval) { - BPY_Err_Handle(con->text->id.name); - con->flag |= PYCON_SCRIPTERROR; - - - /* free temp objects */ - Py_XDECREF(tar); - Py_XDECREF(subtar); - Py_XDECREF(idprop); - Py_XDECREF(tarmat); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - if (!PyObject_TypeCheck(retval, &matrix_Type)) { - con->flag |= PYCON_SCRIPTERROR; - - Py_XDECREF(tar); - Py_XDECREF(subtar); - Py_XDECREF(idprop); - Py_XDECREF(tarmat); - Py_XDECREF(retval); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - retmat = (MatrixObject *)retval; - if (retmat->rowSize != 4 || retmat->colSize != 4) { - printf("Error in PyConstraint - doTarget: Matrix returned is the wrong size!\n"); - con->flag |= PYCON_SCRIPTERROR; - - Py_XDECREF(tar); - Py_XDECREF(subtar); - Py_XDECREF(idprop); - Py_XDECREF(tarmat); - Py_XDECREF(retval); - - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); - - return; - } - - /* this is the reverse of code taken from newMatrix() */ - for(row = 0; row < 4; row++) { - for(col = 0; col < 4; col++) { - ct->matrix[row][col] = retmat->contigPtr[row*4+col]; - } - } - - /* free temp objects */ - Py_XDECREF(tar); - Py_XDECREF(subtar); - Py_XDECREF(idprop); - Py_XDECREF(tarmat); - Py_XDECREF(retval); - - /* clear globals */ - ReleaseGlobalDictionary(globals); - - PyGILState_Release(gilstate); -} - -/* This draws+handles the user-defined interface for editing pyconstraints idprops */ -void BPY_pyconstraint_settings(void *arg1, void *arg2) -{ - bPythonConstraint *con= (bPythonConstraint *)arg1; - PyObject *idprop; - PyObject *globals; - PyObject *gval; - PyObject *retval; - PyGILState_STATE gilstate; - - if (!con->text) return; - if (con->flag & PYCON_SCRIPTERROR) return; - - gilstate = PyGILState_Ensure(); - - globals = CreateGlobalDictionary(); - - idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL); - - retval = RunPython(con->text, globals); - - if (retval == NULL) { - BPY_Err_Handle(con->text->id.name); - ReleaseGlobalDictionary(globals); - con->flag |= PYCON_SCRIPTERROR; - - /* free temp objects */ - Py_XDECREF(idprop); - - PyGILState_Release(gilstate); - - return; - } - - if (retval) {Py_XDECREF( retval );} - retval = NULL; - - gval = PyDict_GetItemString(globals, "getSettings"); - if (!gval) { - printf("ERROR: no getSettings function in constraint!\n"); - - /* free temp objects */ - ReleaseGlobalDictionary( globals ); - Py_XDECREF(idprop); - - PyGILState_Release(gilstate); - - return; - } - - /* Now for the fun part! Try and find the functions we need. */ - if (PyFunction_Check(gval)) { - retval = PyObject_CallFunction(gval, "O", idprop); - } - else { - printf("ERROR: getSettings is supposed to be a function!\n"); - ReleaseGlobalDictionary( globals ); - - Py_XDECREF(idprop); - - PyGILState_Release(gilstate); - - return; - } - - if (!retval) { - BPY_Err_Handle(con->text->id.name); - con->flag |= PYCON_SCRIPTERROR; - - /* free temp objects */ - ReleaseGlobalDictionary(globals); - Py_XDECREF(idprop); - - PyGILState_Release(gilstate); - - return; - } - else { - /* clear globals */ - ReleaseGlobalDictionary(globals); - - /* free temp objects */ - Py_XDECREF(idprop); - Py_DECREF(retval); - - PyGILState_Release(gilstate); - - return; - } -} - -/* Update function, it gets rid of pydrivers global dictionary, forcing - * BPY_pydriver_eval to recreate it. This function is used to force - * reloading the Blender text module "pydrivers.py", if available, so - * updates in it reach pydriver evaluation. */ -void BPY_pydriver_update(void) -{ - PyGILState_STATE gilstate = PyGILState_Ensure(); - - if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */ - PyDict_Clear(bpy_pydriver_Dict); - Py_DECREF(bpy_pydriver_Dict); - bpy_pydriver_Dict = NULL; - } - - PyGILState_Release(gilstate); - - return; -} - -/* for depsgraph.c, runs py expr once to collect all refs. made - * to objects (self refs. to the object that owns the py driver - * are not allowed). */ -struct Object **BPY_pydriver_get_objects(IpoDriver *driver) -{ - /*if (!driver || !driver->ob || driver->name[0] == '\0') - return NULL;*/ - - /*PyErr_Clear();*/ - - /* clear the flag that marks invalid python expressions */ - driver->flag &= ~IPO_DRIVER_FLAG_INVALID; - - /* tell we're running a pydriver, so Get() functions know they need - * to add the requested obj to our list */ - bpy_pydriver_running(1); - - /* append driver owner object as the 1st ob in the list; - * we put it there to make sure it is not itself referenced in - * its pydriver expression */ - bpy_pydriver_appendToList(driver->ob); - - /* this will append any other ob referenced in expr (driver->name) - * or set the driver's error flag if driver's py expression fails */ - BPY_pydriver_eval(driver); - - bpy_pydriver_running(0); /* ok, we're done */ - - return bpy_pydriver_obArrayFromList(); /* NULL if eval failed */ -} - -/* This evals py driver expressions, 'expr' is a Python expression that - * should evaluate to a float number, which is returned. */ -float BPY_pydriver_eval(IpoDriver *driver) -{ - char *expr = NULL; - PyObject *retval, *bpy_ob = NULL; - float result = 0.0f; /* default return */ - int setitem_retval; - PyGILState_STATE gilstate; - - if (!driver || (G.f&G_DOSCRIPTLINKS)==0) return result; - - expr = driver->name; /* the py expression to be evaluated */ - if (!expr || expr[0]=='\0') return result; - - gilstate = PyGILState_Ensure(); - - if (!bpy_pydriver_Dict) { - if (bpy_pydriver_create_dict() != 0) { - fprintf(stderr, "Pydriver error: couldn't create Python dictionary"); - PyGILState_Release(gilstate); - return result; - } - } - - if (driver->ob) - bpy_ob = Object_CreatePyObject(driver->ob); - - if (!bpy_ob) { - Py_INCREF(Py_None); - bpy_ob = Py_None; - } - - setitem_retval = EXPP_dict_set_item_str(bpy_pydriver_Dict, "self", bpy_ob); - - if( !setup_armature_weakrefs()){ - fprintf( stderr, "Oops - weakref dict setup\n"); - PyGILState_Release(gilstate); - return result; - } - - retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, - bpy_pydriver_Dict); - - if (retval == NULL) { - result = pydriver_error(driver); - PyGILState_Release(gilstate); - return result; - } - - result = ( float )PyFloat_AsDouble( retval ); - Py_DECREF(retval); - - if (result == -1 && PyErr_Occurred()) { - result = pydriver_error(driver); - PyGILState_Release(gilstate); - return result; - } - - /* remove 'self', since this dict is also used by py buttons */ - if (setitem_retval == 0) PyDict_DelItemString(bpy_pydriver_Dict, "self"); - - /* all fine, make sure the "invalid expression" flag is cleared */ - driver->flag &= ~IPO_DRIVER_FLAG_INVALID; - - PyGILState_Release(gilstate); - - return result; -} - -/* Button Python Evaluation */ - -/* Python evaluation for gui buttons: - * users can write any valid Python expression (that evals to an int or float) - * inside Blender's gui number buttons and have them evaluated to their - * actual int or float value. - * - * The global dict used for pydrivers is also used here, so all imported - * modules for pydrivers (including the pydrivers.py Blender text) are - * available for button py eval, too. */ - -static int bpy_button_eval_error(char *expr) { - - if (bpy_pydriver_oblist) - bpy_pydriver_freeList(); - - if (bpy_pydriver_Dict) { /* free the persistent global dict */ - /* it's the same dict used by pydrivers */ - PyDict_Clear(bpy_pydriver_Dict); - Py_DECREF(bpy_pydriver_Dict); - bpy_pydriver_Dict = NULL; - } - - fprintf(stderr, "\nError in button evaluation:\nThis is the failed Python expression:\n'%s'\n\n", expr); - - PyErr_Print(); - - return -1; -} - -int BPY_button_eval(char *expr, double *value) -{ - PyObject *retval, *floatval; - PyGILState_STATE gilstate; - int ret; - - if (!value || !expr || expr[0]=='\0') return -1; - - *value = 0.0; /* default value */ - - gilstate = PyGILState_Ensure(); - - if (!bpy_pydriver_Dict) { - if (bpy_pydriver_create_dict() != 0) { - fprintf(stderr, - "Button Python Eval error: couldn't create Python dictionary \n"); - PyGILState_Release(gilstate); - return -1; - } - } - - - if( !setup_armature_weakrefs()){ - fprintf(stderr, "Oops - weakref dict\n"); - PyGILState_Release(gilstate); - return -1; - } - - retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, - bpy_pydriver_Dict); - - if (retval == NULL) { - ret = bpy_button_eval_error(expr); - PyGILState_Release(gilstate); - return ret; - } - else { - floatval = PyNumber_Float(retval); - Py_DECREF(retval); - } - - if (floatval == NULL) { - ret = bpy_button_eval_error(expr); - PyGILState_Release(gilstate); - return ret; - } else { - *value = (float)PyFloat_AsDouble(floatval); - Py_DECREF(floatval); - } - - PyGILState_Release(gilstate); - - return 0; /* successful exit */ -} - - -/*****************************************************************************/ -/* ScriptLinks */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* Description: */ -/* Notes: Not implemented yet */ -/*****************************************************************************/ -void BPY_clear_bad_scriptlinks( struct Text *byebye ) -{ -/* - BPY_clear_bad_scriptlist(getObjectList(), byebye); - BPY_clear_bad_scriptlist(getLampList(), byebye); - BPY_clear_bad_scriptlist(getCameraList(), byebye); - BPY_clear_bad_scriptlist(getMaterialList(), byebye); - BPY_clear_bad_scriptlist(getWorldList(), byebye); - BPY_clear_bad_scriptlink(&scene_getCurrent()->id, byebye); - - allqueue(REDRAWBUTSSCRIPT, 0); -*/ - return; -} - -/***************************************************************************** -* Description: Loop through all scripts of a list of object types, and -* execute these scripts. -* For the scene, only the current active scene the scripts are -* executed (if any). -*****************************************************************************/ -void BPY_do_all_scripts( short event, short anim ) -{ - /* during stills rendering we disable FRAMECHANGED events */ - static char disable_frame_changed = 0; - - if ((event == SCRIPT_FRAMECHANGED) && disable_frame_changed) - return; - - DoAllScriptsFromList( &( G.main->object ), event ); - DoAllScriptsFromList( &( G.main->lamp ), event ); - DoAllScriptsFromList( &( G.main->camera ), event ); - DoAllScriptsFromList( &( G.main->mat ), event ); - DoAllScriptsFromList( &( G.main->world ), event ); - - BPY_do_pyscript( &( G.scene->id ), event ); - - /* Don't allow the Python Interpreter to release the GIL on - * its own, to guarantee PyNodes work properly. For Blender this - * is currently the best default behavior. - * The following code in C is equivalent in Python to: - * "import sys; sys.setcheckinterval(sys.maxint)" */ - if (event == SCRIPT_RENDER) { - _Py_CheckInterval = PyInt_GetMax(); - if (!anim) - disable_frame_changed = 1; - } - else if (event == SCRIPT_POSTRENDER) { - _Py_CheckInterval = 100; /* Python default */ - disable_frame_changed = 0; - } - - return; -} - -/***************************************************************************** -* Description: Execute a Python script when an event occurs. The following -* events are possible: frame changed, load script and redraw. -* Only events happening to one of the following object types -* are handled: Object, Lamp, Camera, Material, World and -* Scene. -*****************************************************************************/ - -static ScriptLink *ID_getScriptlink( ID * id ) -{ - switch ( MAKE_ID2( id->name[0], id->name[1] ) ) { - case ID_OB: - return &( ( Object * ) id )->scriptlink; - case ID_LA: - return &( ( Lamp * ) id )->scriptlink; - case ID_CA: - return &( ( Camera * ) id )->scriptlink; - case ID_MA: - return &( ( Material * ) id )->scriptlink; - case ID_WO: - return &( ( World * ) id )->scriptlink; - case ID_SCE: - return &( ( Scene * ) id )->scriptlink; - default: - return NULL; - } -} - -int BPY_has_onload_script( void ) -{ - ScriptLink *slink = &G.scene->scriptlink; - int i; - - if( !slink || !slink->totscript ) - return 0; - - for( i = 0; i < slink->totscript; i++ ) { - if( ( slink->flag[i] == SCRIPT_ONLOAD ) - && ( slink->scripts[i] != NULL ) ) - return 1; - } - - return 0; -} - -void BPY_do_pyscript( ID * id, short event ) -{ - ScriptLink *scriptlink; - - if( !id ) return; - - scriptlink = ID_getScriptlink( id ); - - if( scriptlink && scriptlink->totscript ) { - PyObject *value; - PyObject *dict; - PyObject *ret; - int index, during_slink = during_scriptlink( ); - PyGILState_STATE gilstate; - - /* invalid scriptlinks (new .blend was just loaded), return */ - if( during_slink < 0 ) - return; - - gilstate = PyGILState_Ensure(); - - if( !setup_armature_weakrefs()){ - printf("Oops - weakref dict, this is a bug\n"); - PyGILState_Release(gilstate); - return; - } - - value = GetPyObjectFromID( id ); - if( !value){ - printf("Oops - could not get a valid python object for Blender.link, this is a bug\n"); - PyGILState_Release(gilstate); - return; - } - - /* tell we're running a scriptlink. The sum also tells if this - * script is running nested inside another. Blender.Load needs - * this info to avoid trouble with invalid slink pointers. */ - during_slink++; - disable_where_scriptlink( (short)during_slink ); - - /* set globals in Blender module to identify scriptlink */ - PyDict_SetItemString( g_blenderdict, "bylink", Py_True); - EXPP_dict_set_item_str( g_blenderdict, "link", value ); - EXPP_dict_set_item_str( g_blenderdict, "event", - PyString_FromString( event_to_name - ( event ) ) ); - if (event == SCRIPT_POSTRENDER) event = SCRIPT_RENDER; - - for( index = 0; index < scriptlink->totscript; index++ ) { - if( ( scriptlink->flag[index] == event ) && - ( scriptlink->scripts[index] != NULL ) ) { - dict = CreateGlobalDictionary( ); - ret = RunPython( ( Text * ) scriptlink-> - scripts[index], dict ); - ReleaseGlobalDictionary( dict ); - - if( !ret ) { - /* Failed execution of the script */ - BPY_Err_Handle( scriptlink-> - scripts[index]->name + - 2 ); - //BPY_end_python (); - //BPY_start_python (); - } else { - Py_DECREF( ret ); - } - /* If a scriptlink has just loaded a new .blend file, the - * scriptlink pointer became invalid (see api2_2x/Blender.c), - * so we stop here. */ - if( during_scriptlink( ) == -1 ) { - during_slink = 1; - break; - } - } - } - - disable_where_scriptlink( (short)(during_slink - 1) ); - - /* cleanup bylink flag and clear link so PyObject - * can be released - */ - PyDict_SetItemString(g_blenderdict, "bylink", Py_False); - PyDict_SetItemString( g_blenderdict, "link", Py_None ); - EXPP_dict_set_item_str( g_blenderdict, "event", PyString_FromString( "" ) ); - - PyGILState_Release(gilstate); - } -} - - -/* SPACE HANDLERS */ - -/* These are special script links that can be assigned to ScrArea's to - * (EVENT type) receive events sent to a given space (and use or ignore them) or - * (DRAW type) be called after the space is drawn, to draw anything on top of - * the space area. */ - -/* How to add space handlers to other spaces: - * - add the space event defines to DNA_scriptlink_types.h, as done for - * 3d view: SPACEHANDLER_VIEW3D_EVENT, for example; - * - add the new defines to Blender.SpaceHandler dictionary in Blender.c; - * - check space.c for how to call the event handlers; - * - check drawview.c for how to call the draw handlers; - * - check header_view3d.c for how to add the "Space Handler Scripts" menu. - * Note: DRAW handlers should be called with 'event = 0', chech drawview.c */ - -int BPY_has_spacehandler(Text *text, ScrArea *sa) -{ - ScriptLink *slink; - int index; - - if (!sa || !text) return 0; - - slink = &sa->scriptlink; - - for (index = 0; index < slink->totscript; index++) { - if (slink->scripts[index] && (slink->scripts[index] == (ID *)text)) - return 1; - } - - return 0; -} - -int BPY_is_spacehandler(Text *text, char spacetype) -{ - TextLine *tline = text->lines.first; - unsigned short type = 0; - - if (tline && (tline->len > 10)) { - char *line = tline->line; - - /* Expected format: # SPACEHANDLER.SPACE.TYPE - * Ex: # SPACEHANDLER.VIEW3D.DRAW - * The actual checks are forgiving, so slight variations also work. */ - if (line && line[0] == '#' && strstr(line, "HANDLER")) { - line++; /* skip '#' */ - - /* only done for 3D View right now, trivial to add for others: */ - switch (spacetype) { - case SPACE_VIEW3D: - if (strstr(line, "3D")) { /* VIEW3D, 3DVIEW */ - if (strstr(line, "DRAW")) type = SPACEHANDLER_VIEW3D_DRAW; - else if (strstr(line, "EVENT")) type = SPACEHANDLER_VIEW3D_EVENT; - } - break; - } - } - } - return type; /* 0 if not a space handler */ -} - -int BPY_del_spacehandler(Text *text, ScrArea *sa) -{ - ScriptLink *slink; - int i, j; - - if (!sa || !text) return -1; - - slink = &sa->scriptlink; - if (slink->totscript < 1) return -1; - - for (i = 0; i < slink->totscript; i++) { - if (text == (Text *)slink->scripts[i]) { - - for (j = i; j < slink->totscript - 1; j++) { - slink->flag[j] = slink->flag[j+1]; - slink->scripts[j] = slink->scripts[j+1]; - } - slink->totscript--; - /* like done in buttons_script.c we just free memory - * if all slinks have been removed -- less fragmentation, - * these should be quite small arrays */ - if (slink->totscript == 0) { - if (slink->scripts) MEM_freeN(slink->scripts); - if (slink->flag) MEM_freeN(slink->flag); - break; - } - } - } - return 0; -} - -int BPY_add_spacehandler(Text *text, ScrArea *sa, char spacetype) -{ - unsigned short handlertype; - - if (!sa || !text) return -1; - - handlertype = (unsigned short)BPY_is_spacehandler(text, spacetype); - - if (handlertype) { - ScriptLink *slink = &sa->scriptlink; - void *stmp, *ftmp; - unsigned short space_event = SPACEHANDLER_VIEW3D_EVENT; - - /* extend slink */ - - stmp= slink->scripts; - slink->scripts= MEM_mallocN(sizeof(ID*)*(slink->totscript+1), - "spacehandlerscripts"); - - ftmp= slink->flag; - slink->flag= MEM_mallocN(sizeof(short*)*(slink->totscript+1), - "spacehandlerflags"); - - if (slink->totscript) { - memcpy(slink->scripts, stmp, sizeof(ID*)*(slink->totscript)); - MEM_freeN(stmp); - - memcpy(slink->flag, ftmp, sizeof(short)*(slink->totscript)); - MEM_freeN(ftmp); - } - - switch (spacetype) { - case SPACE_VIEW3D: - if (handlertype == 1) space_event = SPACEHANDLER_VIEW3D_EVENT; - else space_event = SPACEHANDLER_VIEW3D_DRAW; - break; - default: - break; - } - - slink->scripts[slink->totscript] = (ID *)text; - slink->flag[slink->totscript]= space_event; - - slink->totscript++; - slink->actscript = slink->totscript; - - } - return 0; -} - -int BPY_do_spacehandlers( ScrArea *sa, unsigned short event, - short eventValue, unsigned short space_event ) -{ - ScriptLink *scriptlink; - int retval = 0; - PyGILState_STATE gilstate; - - if (!sa || !(G.f & G_DOSCRIPTLINKS)) return 0; - - scriptlink = &sa->scriptlink; - - if (scriptlink->totscript > 0) { - PyObject *dict; - PyObject *ret; - int index, during_slink = during_scriptlink(); - - /* invalid scriptlinks (new .blend was just loaded), return */ - if (during_slink < 0) return 0; - - /* tell we're running a scriptlink. The sum also tells if this script - * is running nested inside another. Blender.Load needs this info to - * avoid trouble with invalid slink pointers. - * Update (test): allow EVENT space handlers to call file/image selectors, - * still disabled for DRAW space handlers: */ - if (event == 0) { /* event = 0: DRAW space handler */ - during_slink++; - disable_where_scriptlink( (short)during_slink ); - } - - gilstate = PyGILState_Ensure(); - - if( !setup_armature_weakrefs()){ - printf("Oops - weakref dict, this is a bug\n"); - PyGILState_Release(gilstate); - return 0; - } - - /* set globals in Blender module to identify space handler scriptlink */ - PyDict_SetItemString(g_blenderdict, "bylink", Py_True); - /* unlike normal scriptlinks, here Blender.link is int (space event type) */ - EXPP_dict_set_item_str(g_blenderdict, "link", PyInt_FromLong(space_event)); - /* note: DRAW space_events set event and val to 0 */ - EXPP_dict_set_item_str(g_blenderdict, "event", PyInt_FromLong(event)); - EXPP_dict_set_item_str(g_blenderdict, "eventValue", PyInt_FromLong(eventValue)); - /* now run all assigned space handlers for this space and space_event */ - for( index = 0; index < scriptlink->totscript; index++ ) { - - /* for DRAW handlers: */ - if (event == 0) { - glPushAttrib(GL_ALL_ATTRIB_BITS); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - } - - if( ( scriptlink->flag[index] == space_event ) && - ( scriptlink->scripts[index] != NULL ) ) { - dict = CreateGlobalDictionary(); - ret = RunPython( ( Text * ) scriptlink->scripts[index], dict ); - ReleaseGlobalDictionary( dict ); - - if (!ret) { /* Failed execution of the script */ - BPY_Err_Handle( scriptlink->scripts[index]->name+2 ); - } else { - Py_DECREF(ret); - - /* an EVENT type (event != 0) script can either accept an event or - * ignore it: - * if the script sets Blender.event to None it accepted it; - * otherwise the space's event handling callback that called us - * can go on processing the event */ - if (event && (PyDict_GetItemString(g_blenderdict,"event") == Py_None)) - retval = 1; /* event was swallowed */ - } - - /* If a scriptlink has just loaded a new .blend file, the - * scriptlink pointer became invalid (see api2_2x/Blender.c), - * so we stop here. */ - if( during_scriptlink( ) == -1 ) { - during_slink = 1; - if (event == 0) glPopAttrib(); - break; - } - } - - /* for DRAW handlers: */ - if (event == 0) { - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glPopAttrib(); - disable_where_scriptlink( (short)(during_slink - 1) ); - } - - } - - PyDict_SetItemString(g_blenderdict, "bylink", Py_False); - PyDict_SetItemString(g_blenderdict, "link", Py_None ); - EXPP_dict_set_item_str(g_blenderdict, "event", PyString_FromString("")); - - PyGILState_Release(gilstate); - } - - /* retval: - * space_event is of type EVENT: - * 0 - event was returned, - * 1 - event was processed; - * space_event is of type DRAW: - * 0 always */ - - return retval; -} - -/***************************************************************************** -* Description: -* Notes: -*****************************************************************************/ -void BPY_free_scriptlink( struct ScriptLink *slink ) -{ - if( slink->totscript ) { - if( slink->flag ) { - MEM_freeN( slink->flag ); - slink->flag= NULL; - } - if( slink->scripts ) { - MEM_freeN( slink->scripts ); - slink->scripts= NULL; - } - } - - return; -} - -static int CheckAllSpaceHandlers(Text *text) -{ - bScreen *screen; - ScrArea *sa; - ScriptLink *slink; - int fixed = 0; - - for (screen = G.main->screen.first; screen; screen = screen->id.next) { - for (sa = screen->areabase.first; sa; sa = sa->next) { - slink = &sa->scriptlink; - if (!slink->totscript) continue; - if (BPY_del_spacehandler(text, sa) == 0) fixed++; - } - } - return fixed; -} - -static int CheckAllScriptsFromList( ListBase * list, Text * text ) -{ - ID *id; - ScriptLink *scriptlink; - int index; - int fixed = 0; - - id = list->first; - - while( id != NULL ) { - scriptlink = ID_getScriptlink( id ); - if( scriptlink && scriptlink->totscript ) { - for( index = 0; index < scriptlink->totscript; index++) { - if ((Text *)scriptlink->scripts[index] == text) { - scriptlink->scripts[index] = NULL; - fixed++; - } - } - } - id = id->next; - } - - return fixed; -} - -/* When a Text is deleted, we need to unlink it from eventual scriptlinks */ -int BPY_check_all_scriptlinks( Text * text ) -{ - int fixed = 0; - fixed += CheckAllScriptsFromList( &( G.main->object ), text ); - fixed += CheckAllScriptsFromList( &( G.main->lamp ), text ); - fixed += CheckAllScriptsFromList( &( G.main->camera ), text ); - fixed += CheckAllScriptsFromList( &( G.main->mat ), text ); - fixed += CheckAllScriptsFromList( &( G.main->world ), text ); - fixed += CheckAllScriptsFromList( &( G.main->scene ), text ); - fixed += CheckAllSpaceHandlers(text); - - return fixed; -} - -/***************************************************************************** -* Description: -* Notes: -*****************************************************************************/ -void BPY_copy_scriptlink( struct ScriptLink *scriptlink ) -{ - void *tmp; - - if( scriptlink->totscript ) { - - tmp = scriptlink->scripts; - scriptlink->scripts = - MEM_mallocN( sizeof( ID * ) * scriptlink->totscript, - "scriptlistL" ); - memcpy( scriptlink->scripts, tmp, - sizeof( ID * ) * scriptlink->totscript ); - - tmp = scriptlink->flag; - scriptlink->flag = - MEM_mallocN( sizeof( short ) * scriptlink->totscript, - "scriptlistF" ); - memcpy( scriptlink->flag, tmp, - sizeof( short ) * scriptlink->totscript ); - } - - return; -} - -/**************************************************************************** -* Description: -* Notes: Not implemented yet -*****************************************************************************/ -int BPY_call_importloader( char *name ) -{ /* XXX Should this function go away from Blender? */ - printf( "In BPY_call_importloader(name=%s)\n", name ); - return ( 0 ); -} - -/***************************************************************************** -* Private functions -*****************************************************************************/ - -/***************************************************************************** -* Description: This function executes the python script passed by text. -* The Python dictionary containing global variables needs to -* be passed in globaldict. -* NOTE: Make sure BPY_Err_Handle() runs if this returns NULL -* otherwise pointers can be left in sys.last_traceback that become invalid. -*****************************************************************************/ -static PyObject *RunPython( Text * text, PyObject * globaldict ) -{ - char *buf = NULL; - -/* The script text is compiled to Python bytecode and saved at text->compiled - * to speed-up execution if the user executes the script multiple times */ - - if( !text->compiled ) { /* if it wasn't already compiled, do it now */ - buf = txt_to_buf( text ); - - text->compiled = - Py_CompileString( buf, text->id.name+2, Py_file_input ); - - MEM_freeN( buf ); - - if( PyErr_Occurred( ) ) { - BPY_free_compiled_text( text ); - return NULL; - } - - } - - return PyEval_EvalCode( text->compiled, globaldict, globaldict ); -} - -/***************************************************************************** -* Description: This function creates a new Python dictionary object. -*****************************************************************************/ -static PyObject *CreateGlobalDictionary( void ) -{ - PyObject *dict = PyDict_New( ); - - PyDict_SetItemString( dict, "__builtins__", PyEval_GetBuiltins( ) ); - EXPP_dict_set_item_str( dict, "__name__", - PyString_FromString( "__main__" ) ); - - return dict; -} - -/***************************************************************************** -* Description: This function deletes a given Python dictionary object. -*****************************************************************************/ -static void ReleaseGlobalDictionary( PyObject * dict ) -{ - PyDict_Clear( dict ); - Py_DECREF( dict ); /* Release dictionary. */ - - return; -} - -/*************************************************************************** -* Description: This function runs all scripts (if any) present in the -* list argument. The event by which the function has been -* called, is passed in the event argument. -*****************************************************************************/ -static void DoAllScriptsFromList( ListBase * list, short event ) -{ - ID *id; - - id = list->first; - - while( id != NULL ) { - BPY_do_pyscript( id, event ); - id = id->next; - } - - return; -} - -static PyObject *importText( char *name ) -{ - Text *text; - char txtname[22]; /* 21+NULL */ - char *buf = NULL; - int namelen = strlen( name ); - - if (namelen>21-3) return NULL; /* we know this cant be importable, the name is too long for blender! */ - - memcpy( txtname, name, namelen ); - memcpy( &txtname[namelen], ".py", 4 ); - - for(text = G.main->text.first; text; text = text->id.next) { - if( !strcmp( txtname, text->id.name+2 ) ) - break; - } - - if( !text ) - return NULL; - - if( !text->compiled ) { - buf = txt_to_buf( text ); - text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input ); - MEM_freeN( buf ); - - if( PyErr_Occurred( ) ) { - PyErr_Print( ); - BPY_free_compiled_text( text ); - return NULL; - } - } - - return PyImport_ExecCodeModule( name, text->compiled ); -} - -static PyMethodDef bimport[] = { - {"blimport", blender_import, METH_KEYWORDS, "our own import"} -}; - -static PyObject *blender_import( PyObject * self, PyObject * args, PyObject * kw) -{ - PyObject *exception, *err, *tb; - char *name; - PyObject *globals = NULL, *locals = NULL, *fromlist = NULL; - PyObject *m; - - //PyObject_Print(args, stderr, 0); -#if (PY_VERSION_HEX >= 0x02060000) - int dummy_val; /* what does this do?*/ - static char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", 0}; - - if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOOi:bimport", kwlist, - &name, &globals, &locals, &fromlist, &dummy_val) ) - return NULL; -#else - static char *kwlist[] = {"name", "globals", "locals", "fromlist", 0}; - - if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOO:bimport", kwlist, - &name, &globals, &locals, &fromlist ) ) - return NULL; -#endif - m = PyImport_ImportModuleEx( name, globals, locals, fromlist ); - - if( m ) - return m; - else - PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */ - - m = importText( name ); - if( m ) { /* found module, ignore above exception */ - PyErr_Clear( ); - Py_XDECREF( exception ); - Py_XDECREF( err ); - Py_XDECREF( tb ); - printf( "imported from text buffer...\n" ); - } else { - PyErr_Restore( exception, err, tb ); - } - return m; -} - -static void init_ourImport( void ) -{ - PyObject *m, *d; - PyObject *import = PyCFunction_New( bimport, NULL ); - - m = PyImport_AddModule( "__builtin__" ); - d = PyModule_GetDict( m ); - - EXPP_dict_set_item_str( d, "__import__", import ); -} - -/* - * find in-memory module and recompile - */ - -static PyObject *reimportText( PyObject *module ) -{ - Text *text; - char *txtname; - char *name; - char *buf = NULL; - - /* get name, filename from the module itself */ - - txtname = PyModule_GetFilename( module ); - name = PyModule_GetName( module ); - if( !txtname || !name) - return NULL; - - /* look up the text object */ - text = ( Text * ) & ( G.main->text.first ); - while( text ) { - if( !strcmp( txtname, text->id.name+2 ) ) - break; - text = text->id.next; - } - - /* uh-oh.... didn't find it */ - if( !text ) - return NULL; - - /* if previously compiled, free the object */ - /* (can't see how could be NULL, but check just in case) */ - if( text->compiled ){ - Py_DECREF( (PyObject *)text->compiled ); - } - - /* compile the buffer */ - buf = txt_to_buf( text ); - text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input ); - MEM_freeN( buf ); - - /* if compile failed.... return this error */ - if( PyErr_Occurred( ) ) { - PyErr_Print( ); - BPY_free_compiled_text( text ); - return NULL; - } - - /* make into a module */ - return PyImport_ExecCodeModule( name, text->compiled ); -} - -/* - * our reload() module, to handle reloading in-memory scripts - */ - -static PyObject *blender_reload( PyObject * self, PyObject * args ) -{ - PyObject *exception, *err, *tb; - PyObject *module = NULL; - PyObject *newmodule = NULL; - - /* check for a module arg */ - if( !PyArg_ParseTuple( args, "O:breload", &module ) ) - return NULL; - - /* try reimporting from file */ - newmodule = PyImport_ReloadModule( module ); - if( newmodule ) - return newmodule; - - /* no file, try importing from memory */ - PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */ - - newmodule = reimportText( module ); - if( newmodule ) { /* found module, ignore above exception */ - PyErr_Clear( ); - Py_XDECREF( exception ); - Py_XDECREF( err ); - Py_XDECREF( tb ); - } else - PyErr_Restore( exception, err, tb ); - - return newmodule; -} - -static PyMethodDef breload[] = { - {"blreload", blender_reload, METH_VARARGS, "our own reload"} -}; - -static void init_ourReload( void ) -{ - PyObject *m, *d; - PyObject *reload = PyCFunction_New( breload, NULL ); - - m = PyImport_AddModule( "__builtin__" ); - d = PyModule_GetDict( m ); - EXPP_dict_set_item_str( d, "reload", reload ); -} - - -void BPY_scripts_clear_pyobjects( void ) -{ - Script *script; - for (script=G.main->script.first; script; script=script->id.next) { - Py_XDECREF((PyObject *)script->py_draw); - Py_XDECREF((PyObject *)script->py_event); - Py_XDECREF((PyObject *)script->py_button); - Py_XDECREF((PyObject *)script->py_browsercallback); - Py_XDECREF((PyObject *)script->py_globaldict); - SCRIPT_SET_NULL(script) - } -} -void error_pyscript( void ) -{ - error("Python script error: check console"); -} |