resolve some compiler warnings with intel c/c++ compiler
[blender-staging.git] / source / blender / python / BPY_interface.c
index acede12244fe0f4918cab48d4ef214803ca8dec3..59b72702c504dcbfcbfd0427be95e7eff417041b 100644 (file)
@@ -1,15 +1,12 @@
 /* 
  * $Id$
  *
- * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * ***** 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. The Blender
- * Foundation also sells licenses for use in proprietary software under
- * the Blender License.  See http://www.blender.org/BL/ for information
- * about this.
+ * 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
@@ -28,7 +25,7 @@
  * Contributor(s): Michel Selten, Willian P. Germano, Stephen Swaney,
  * Chris Keith, Chris Want, Ken Hughes
  *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * ***** END GPL LICENSE BLOCK *****
 */
 
 #include <Python.h>
 #include "MEM_guardedalloc.h"
 #include "BPY_extern.h"
 #include "BPY_menus.h"
-#include "BPI_script.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"
 
 /* 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 
  */
   
-int setup_armature_weakrefs()
+static int setup_armature_weakrefs()
 {
        PyObject *maindict;
        PyObject *main_module;
@@ -160,20 +159,18 @@ ScriptError g_script_error;
 /***************************************************************************
 * Function prototypes 
 ***************************************************************************/
-PyObject *RunPython( Text * text, PyObject * globaldict );
-char *GetName( Text * text );
-PyObject *CreateGlobalDictionary( void );
-void ReleaseGlobalDictionary( PyObject * dict );
-void DoAllScriptsFromList( ListBase * list, short event );
-PyObject *importText( char *name );
-void init_ourImport( void );
-void init_ourReload( void );
-PyObject *blender_import( PyObject * self, PyObject * args );
-PyObject *RunPython2( Text * text, PyObject * globaldict, PyObject *localdict );
+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 );
 
 
-void BPY_Err_Handle( char *script_name );
-PyObject *traceback_getFilename( PyObject * tb );
+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
@@ -181,6 +178,7 @@ PyObject *traceback_getFilename( PyObject * tb );
 ****************************************************************************/
 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;
@@ -226,6 +224,9 @@ void BPY_start_python( int argc, char **argv )
        Py_Initialize(  );
        PySys_SetArgv( argc_copy, argv_copy );
 
+       /* Initialize thread support (also acquires lock) */
+       PyEval_InitThreads();
+
        //Overrides __import__
        init_ourImport(  );
        init_ourReload(  );
@@ -236,6 +237,9 @@ void BPY_start_python( int argc, char **argv )
        //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;
 }
 
@@ -245,6 +249,9 @@ void BPY_start_python( int argc, char **argv )
 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 );
@@ -255,11 +262,16 @@ void BPY_end_python( void )
                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 = script->id.next) {
-               BPY_clear_script(script);
+       for (script = G.main->script.first; script; script = next_script) {
+               next_script = script->id.next;
                free_libblock( &G.main->script, script );
        }
 
@@ -279,7 +291,7 @@ void syspath_append( char *dirname )
        short ok=1;
        PyErr_Clear(  );
 
-       dir = Py_BuildValue( "s", dirname );
+       dir = PyString_FromString( dirname );
 
        mod_sys = PyImport_ImportModule( "sys" );       /* new ref */
        
@@ -293,32 +305,31 @@ void syspath_append( char *dirname )
                /* cant get the sys module */
                ok = 0;
        }
-
-       if (ok && PyList_Append( path, dir ) != 0)
-               ok = 0; /* append failed */
-
-       if( (ok==0) || PyErr_Occurred(  ) )
-               Py_FatalError( "could import or build sys.path, can't continue" );
-
+       
+       if (PySequence_Contains(path, dir)==0) { /* Only add if we need to */
+               if (ok && PyList_Append( path, dir ) != 0) /* decref below */
+                       ok = 0; /* append failed */
+       
+               if( (ok==0) || PyErr_Occurred(  ) )
+                       Py_FatalError( "could import or build sys.path, can't continue" );
+       }
+       Py_DECREF( dir );
        Py_XDECREF( mod_sys );
 }
 
 void init_syspath( int first_time )
 {
-       PyObject *path;
        PyObject *mod, *d;
        char *progname;
        char execdir[FILE_MAXDIR];      /*defines from DNA_space_types.h */
 
        int n;
 
-       path = Py_BuildValue( "s", bprogname );
-
        mod = PyImport_ImportModule( "Blender.sys" );
 
        if( mod ) {
                d = PyModule_GetDict( mod );
-               EXPP_dict_set_item_str( d, "progname", path );
+               EXPP_dict_set_item_str( d, "progname", PyString_FromString( bprogname ) );
                Py_DECREF( mod );
        } else
                printf( "Warning: could not set Blender.sys.progname\n" );
@@ -333,9 +344,10 @@ void init_syspath( int first_time )
                execdir[n] = '\0';
 
                syspath_append( execdir );      /* append to module search path */
-       } else
+       } else {
                printf( "Warning: could not determine argv[0] path\n" );
-
+       }
+       
        /* 
           attempt to import 'site' module as a check for valid
           python install found.
@@ -366,62 +378,112 @@ void init_syspath( int first_time )
 
        if( mod ) {
                d = PyModule_GetDict( mod );    /* borrowed ref */
-               EXPP_dict_set_item_str( d, "executable",
-                                     Py_BuildValue( "s", bprogname ) );
+               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{
                printf("import of sys module failed\n");
        }
 }
 
-/****************************************************************************
-* 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 )
+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("error: could not import python sys module. some modules may not import.\n");
+               PyGILState_Release(gilstate);
+               return;
+       }
+       
+       if (!bpy_orig_syspath_List) { /* should never happen */
+               printf("error refershing python path\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) */
-               if (upyslen > 2) { /* avoids doing anything if dir == '//' */
-                       char ending = U.pythondir[upyslen - 1];
-
-                       if (ending == '/' || ending == '\\')
-                               U.pythondir[upyslen - 1] = '\0';
+#ifdef WIN32
+               if (upyslen > 3) {
+#else
+               if (upyslen > 1) {
+#endif
+                       if (dirpath[upyslen-1] == '\\' || dirpath[upyslen-1] == '/') {
+                               dirpath[upyslen-1] = '\0';
+                       }
                }
 
-               BLI_strncpy(dirpath, U.pythondir, FILE_MAX);
-               BLI_convertstringcode(dirpath, G.sce, 0);
+               BLI_convertstringcode(dirpath, G.sce);
                syspath_append(dirpath);        /* append to module search path */
-
-               BLI_make_file_string("/", modpath, dirpath, "bpymodules");
+               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 */
 
-       return;
+       PyGILState_Release(gilstate);
 }
 
 /****************************************************************************
@@ -444,7 +506,7 @@ const char *BPY_Err_getFilename( void )
 /*****************************************************************************/
 /* Description: Return PyString filename from a traceback object           */
 /*****************************************************************************/
-PyObject *traceback_getFilename( PyObject * tb )
+static PyObject *traceback_getFilename( PyObject * tb )
 {
        PyObject *v = NULL;
 
@@ -468,7 +530,7 @@ PyObject *traceback_getFilename( PyObject * tb )
 * Description: Blender Python error handler. This catches the error and        
 * stores filename and line number in a global  
 *****************************************************************************/
-void BPY_Err_Handle( char *script_name )
+static void BPY_Err_Handle( char *script_name )
 {
        PyObject *exception, *err, *tb, *v;
 
@@ -490,6 +552,7 @@ void BPY_Err_Handle( char *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" );
@@ -562,6 +625,7 @@ int BPY_txt_do_python_Text( struct Text *text )
        BPy_constant *info;
        char textname[24];
        Script *script = G.main->script.first;
+       PyGILState_STATE gilstate;
 
        if( !text )
                return 0;
@@ -571,17 +635,19 @@ int BPY_txt_do_python_Text( struct Text *text )
                if( !strcmp( script->id.name + 2, text->id.name + 2 ) ) {
                        /* if this text is already a running script, 
                         * just move to it: */
-                       SpaceScript *sc;
-                       newspace( curarea, SPACE_SCRIPT );
-                       sc = curarea->spacedata.first;
-                       sc->script = script;
-                       return 1;
+                       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, GetName( text ) );
+       script = alloc_libblock( &G.main->script, ID_SCRIPT, text->id.name+2 );
 
        if( !script ) {
                printf( "couldn't allocate memory for Script struct!" );
@@ -592,8 +658,7 @@ int BPY_txt_do_python_Text( struct Text *text )
         * 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, GetName( text ),
-                    strlen( GetName( text ) ) + 1 );
+       BLI_strncpy( textname, text->id.name+2, 21 );
 
        script->id.us = 1;
        script->flags = SCRIPT_RUNNING;
@@ -601,11 +666,14 @@ int BPY_txt_do_python_Text( struct Text *text )
        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;
        }
 
@@ -628,9 +696,8 @@ int BPY_txt_do_python_Text( struct Text *text )
                BPY_Err_Handle( textname );
                ReleaseGlobalDictionary( py_dict );
                script->py_globaldict = NULL;
-               if( G.main->script.first )
-                       free_libblock( &G.main->script, script );
-
+               free_libblock( &G.main->script, script );
+               PyGILState_Release(gilstate);
                return 0;
        } else {
                Py_DECREF( py_result );
@@ -642,6 +709,8 @@ int BPY_txt_do_python_Text( struct Text *text )
                }
        }
 
+       PyGILState_Release(gilstate);
+
        return 1;               /* normal return */
 }
 
@@ -650,13 +719,23 @@ int BPY_txt_do_python_Text( struct Text *text )
 * automatically. The script can be a file or a Blender Text in the current 
 * .blend.
 ****************************************************************************/
-void BPY_run_python_script( char *fn )
+void BPY_run_python_script( const char *fn )
 {
+       char filename[FILE_MAXDIR + FILE_MAXFILE];
        Text *text = NULL;
        int is_blender_text = 0;
-
-       if (!BLI_exists(fn)) {  /* if there's no such filename ... */
-               text = G.main->text.first;      /* try an already existing Blender Text */
+       
+       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;
@@ -671,11 +750,14 @@ void BPY_run_python_script( char *fn )
        }
 
        else {
-               text = add_text(fn);
+               /* 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", fn);
+                               "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);
@@ -692,17 +774,152 @@ void BPY_run_python_script( char *fn )
                /* 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. */
-               Text *txtptr = G.main->text.first;
-               while (txtptr) {
-                       if (txtptr == text) {
-                               free_libblock(&G.main->text, text);
-                               break;
-                       }
-                       txtptr = txtptr->id.next;
+               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  
@@ -712,22 +929,50 @@ void BPY_run_python_script( char *fn )
 *****************************************************************************/
 int BPY_menu_do_python( short menutype, int event )
 {
-       PyObject *py_dict, *py_res, *pyarg = NULL;
-       BPy_constant *info;
        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;
-       FILE *fp = NULL;
-       char *buffer, *s;
-       char filestr[FILE_MAXDIR + FILE_MAXFILE];
        char scriptname[21];
        Script *script = NULL;
-       int len;
-
-       pym = BPyMenu_GetEntry( menutype, ( short ) event );
+       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,
@@ -749,23 +994,20 @@ int BPY_menu_do_python( short menutype, int event )
                        if( arg >= 0 ) {
                                while( arg-- )
                                        pysm = pysm->next;
-                               pyarg = PyString_FromString( pysm->arg );
-                       } else
+                               argstr = pysm->arg;
+                       } else {
+                               PyGILState_Release(gilstate);
                                return 0;
+                       }
                }
        }
 
-       if( !pyarg ) { /* no submenus */
-               Py_INCREF( Py_None );
-               pyarg = Py_None;
-       }
-
        if( pym->dir ) { /* script is in U.pythondir */
-               char upythondir[FILE_MAXDIR];
+               char upythondir[FILE_MAX];
 
                /* dirs in Blender can be "//", which has a special meaning */
-               BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR);
-               BLI_convertstringcode(upythondir, G.sce, 0); /* if so, this expands it */
+               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 */
@@ -773,19 +1015,13 @@ int BPY_menu_do_python( short menutype, int event )
 
                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 );
        }
 
-       fp = fopen( filestr, "rb" );
-       if( !fp ) {
-               printf( "Error loading script: couldn't open file %s\n",
-                       filestr );
-               return 0;
-       }
-
        BLI_strncpy(scriptname, pym->name, 21);
        len = strlen(scriptname) - 1;
        /* by convention, scripts that open the file browser or have submenus
@@ -800,7 +1036,7 @@ int BPY_menu_do_python( short menutype, int event )
 
        if( !script ) {
                printf( "couldn't allocate memory for Script struct!" );
-               fclose( fp );
+               PyGILState_Release(gilstate);
                return 0;
        }
 
@@ -815,6 +1051,7 @@ int BPY_menu_do_python( short menutype, int event )
        case PYMENU_RENDER:
        case PYMENU_WIZARDS:
        case PYMENU_SCRIPTTEMPLATE:
+       case PYMENU_TEXTPLUGIN:
        case PYMENU_MESHFACEKEY:
                break;
 
@@ -844,107 +1081,12 @@ int BPY_menu_do_python( short menutype, int event )
                }
                break;
        }
-
-       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;
-
-       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 );
-       }
-
-       /* 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 */
-
-       fseek( fp, 0L, SEEK_END );
-       len = ftell( fp );
-       fseek( fp, 0L, SEEK_SET );
-
-       buffer = MEM_mallocN( len + 2, "pyfilebuf" );   /* len+2 to add '\n\0' */
-       len = fread( buffer, 1, len, fp );
-
-       buffer[len] = '\n';     /* fix syntax error in files w/o eol */
-       buffer[len + 1] = '\0';
-
-       /* fast clean-up of dos cr/lf line endings: change '\r' to space */
-
-       /* we also have to check for line splitters: '\\' */
-       /* to avoid possible syntax errors on dos files on win */
-        /**/
-               /* but first make sure we won't disturb memory below &buffer[0]: */
-               if( *buffer == '\r' )
-               *buffer = ' ';
-
-       /* now handle the whole buffer */
-       for( s = buffer + 1; *s != '\0'; s++ ) {
-               if( *s == '\r' ) {
-                       if( *( s - 1 ) == '\\' ) {      /* special case: long lines split with '\': */
-                               *( s - 1 ) = ' ';       /* we write ' \', because '\ ' is a syntax error */
-                               *s = '\\';
-                       } else
-                               *s = ' ';       /* not a split line, just replace '\r' with ' ' */
-               }
-       }
-
-       fclose( fp );
-
-
-       if( !setup_armature_weakrefs()){
-               printf("Oops - weakref dict\n");
-               MEM_freeN( buffer );
-               return 0;
-       }
-
-       /* run the string buffer */
-
-       py_res = PyRun_String( buffer, Py_file_input, py_dict, py_dict );
-
-       MEM_freeN( buffer );
-
-       if( !py_res ) {         /* Failed execution of the script */
-
-               BPY_Err_Handle( script->id.name + 2 );
-               ReleaseGlobalDictionary( py_dict );
-               script->py_globaldict = NULL;
-               if( G.main->script.first )
-                       free_libblock( &G.main->script, script );
-               error( "Python script error: check console" );
-
-               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( 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. */
-                       }
-
-               }
-       }
+       
+       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 */
 }
@@ -955,12 +1097,10 @@ int BPY_menu_do_python( short menutype, int event )
 *****************************************************************************/
 void BPY_free_compiled_text( struct Text *text )
 {
-       if( !text->compiled )
-               return;
-       Py_DECREF( ( PyObject * ) text->compiled );
-       text->compiled = NULL;
-
-       return;
+       if( text->compiled ) {
+               Py_DECREF( ( PyObject * ) text->compiled );
+               text->compiled = NULL;
+       }
 }
 
 /*****************************************************************************
@@ -968,14 +1108,20 @@ void BPY_free_compiled_text( struct Text *text )
 *****************************************************************************/
 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( "Python script error: check console" );
+               error_pyscript(  );
        }
 
+       PyGILState_Release(gilstate);
+
        free_libblock( &G.main->script, script );
        return;
 }
@@ -992,13 +1138,17 @@ static void unlink_script( Script * script )
                                if( sl->spacetype == SPACE_SCRIPT ) {
                                        SpaceScript *sc = ( SpaceScript * ) sl;
 
-                                       if( sc->script == script ) {
+                                       if( sc->script == script ) {                                    
                                                sc->script = NULL;
 
-                                               if( sc ==
-                                                   area->spacedata.first ) {
-                                                       scrarea_queue_redraw
-                                                               ( area );
+                                               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;
                                                }
                                        }
                                }
@@ -1007,16 +1157,21 @@ static void unlink_script( Script * script )
        }
 }
 
+/* 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;
        }
 
@@ -1028,7 +1183,9 @@ void BPY_clear_script( Script * script )
        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 ) {
@@ -1037,6 +1194,8 @@ void BPY_clear_script( Script * script )
                script->py_globaldict = NULL;
        }
 
+       PyGILState_Release(gilstate);
+
        unlink_script( script );
 }
 
@@ -1088,15 +1247,16 @@ static int bpy_pydriver_create_dict(void)
 
        /* If there's a Blender text called pydrivers.py, import it.
         * Users can add their own functions to this module. */
-       mod = importText("pydrivers"); /* can also use PyImport_Import() */
-       if (mod) {
-               PyDict_SetItemString(d, "pydrivers", mod);
-               PyDict_SetItemString(d, "p", mod);
-               Py_DECREF(mod);
+       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();
+               }
        }
-       else
-               PyErr_Clear();
-
        /* short aliases for some Get() functions: */
 
        /* ob(obname) == Blender.Object.Get(obname) */
@@ -1180,6 +1340,45 @@ int BPY_is_pyconstraint(Text *text)
        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.
@@ -1192,11 +1391,14 @@ void BPY_pyconstraint_update(Object *owner, bConstraint *con)
                /* 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);
@@ -1205,6 +1407,7 @@ void BPY_pyconstraint_update(Object *owner, bConstraint *con)
                        BPY_Err_Handle(data->text->id.name);
                        ReleaseGlobalDictionary(globals);
                        data->flag |= PYCON_SCRIPTERROR;
+                       PyGILState_Release(gilstate);
                        return;
                }
                
@@ -1260,6 +1463,10 @@ void BPY_pyconstraint_update(Object *owner, bConstraint *con)
                        
                        /* clear globals */
                        ReleaseGlobalDictionary(globals);
+
+                       PyGILState_Release(gilstate);
+
+                       return;
                }
                else {
                        /* NUM_TARGETS is not defined or equals 0 */
@@ -1270,6 +1477,8 @@ void BPY_pyconstraint_update(Object *owner, bConstraint *con)
                        data->tarnum = 0;
                        data->flag &= ~PYCON_USETARGETS;
                        
+                       PyGILState_Release(gilstate);
+
                        return;
                }
        }
@@ -1298,10 +1507,13 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
        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 
@@ -1320,6 +1532,8 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
        
        if (!setup_armature_weakrefs()) {
                fprintf(stderr, "Oops - weakref dict setup\n");
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1335,7 +1549,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
                Py_XDECREF(tarmats);
                
                ReleaseGlobalDictionary(globals);
-               
+
+               PyGILState_Release(gilstate);
+
                return;
        }
 
@@ -1352,7 +1568,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
                Py_XDECREF(tarmats);
                
                ReleaseGlobalDictionary(globals);
-               
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1371,7 +1589,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
                Py_XDECREF(tarmats);
                
                ReleaseGlobalDictionary(globals);
-               
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1385,7 +1605,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
                Py_XDECREF(tarmats);
                
                ReleaseGlobalDictionary(globals);
-               
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1400,7 +1622,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
                Py_XDECREF(retval);
                
                ReleaseGlobalDictionary(globals);
-               
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1415,7 +1639,9 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
                Py_XDECREF(retval);
                
                ReleaseGlobalDictionary(globals);
-               
+
+               PyGILState_Release(gilstate);
+
                return;
        }       
 
@@ -1434,6 +1660,8 @@ void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase
        
        /* clear globals */
        ReleaseGlobalDictionary(globals);
+
+       PyGILState_Release(gilstate);
 }
 
 /* This evaluates the target matrix for each target the PyConstraint uses.
@@ -1448,11 +1676,14 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
        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);
@@ -1469,6 +1700,7 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
        
        if (!setup_armature_weakrefs()) {
                fprintf(stderr, "Oops - weakref dict setup\n");
+               PyGILState_Release(gilstate);
                return;
        }
        
@@ -1485,7 +1717,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
                Py_XDECREF(tarmat);
                
                ReleaseGlobalDictionary(globals);
-               
+
+               PyGILState_Release(gilstate);
+
                return;
        }
 
@@ -1502,7 +1736,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
                Py_XDECREF(tarmat);
                
                ReleaseGlobalDictionary(globals);
-               
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1522,6 +1758,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
                Py_XDECREF(tarmat);
                
                ReleaseGlobalDictionary(globals);
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1537,6 +1776,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
                Py_XDECREF(tarmat);
                
                ReleaseGlobalDictionary(globals);
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1550,6 +1792,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
                Py_XDECREF(retval);
                
                ReleaseGlobalDictionary(globals);
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1565,6 +1810,9 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
                Py_XDECREF(retval);
                
                ReleaseGlobalDictionary(globals);
+
+               PyGILState_Release(gilstate);
+
                return;
        }       
 
@@ -1584,6 +1832,8 @@ void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
        
        /* clear globals */
        ReleaseGlobalDictionary(globals);
+
+       PyGILState_Release(gilstate);
 }
 
 /* This draws+handles the user-defined interface for editing pyconstraints idprops */
@@ -1594,10 +1844,13 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
        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);
@@ -1608,9 +1861,12 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
                BPY_Err_Handle(con->text->id.name);
                ReleaseGlobalDictionary(globals);
                con->flag |= PYCON_SCRIPTERROR;
-       
+               
                /* free temp objects */
                Py_XDECREF(idprop);
+               
+               PyGILState_Release(gilstate);
+               
                return;
        }
 
@@ -1624,6 +1880,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
                /* free temp objects */
                ReleaseGlobalDictionary( globals );
                Py_XDECREF(idprop);
+
+               PyGILState_Release(gilstate);
+
                return;
        }
        
@@ -1636,6 +1895,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
                ReleaseGlobalDictionary( globals );
                
                Py_XDECREF(idprop);
+               
+               PyGILState_Release(gilstate);
+               
                return;
        }
        
@@ -1646,6 +1908,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
                /* free temp objects */
                ReleaseGlobalDictionary(globals);
                Py_XDECREF(idprop);
+               
+               PyGILState_Release(gilstate);
+               
                return;
        }
        else {
@@ -1655,6 +1920,9 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
                /* free temp objects */
                Py_XDECREF(idprop);
                Py_DECREF(retval);
+               
+               PyGILState_Release(gilstate);
+               
                return;
        }
 }
@@ -1665,12 +1933,16 @@ void BPY_pyconstraint_settings(void *arg1, void *arg2)
  * 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;
 }
 
@@ -1713,15 +1985,19 @@ float BPY_pydriver_eval(IpoDriver *driver)
        PyObject *retval, *bpy_ob = NULL;
        float result = 0.0f; /* default return */
        int setitem_retval;
+       PyGILState_STATE gilstate;
 
-       if (!driver) return result;
+       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;
                }
        }
@@ -1738,6 +2014,7 @@ float BPY_pydriver_eval(IpoDriver *driver)
 
        if( !setup_armature_weakrefs()){
                fprintf( stderr, "Oops - weakref dict setup\n");
+               PyGILState_Release(gilstate);
                return result;
        }
 
@@ -1745,13 +2022,19 @@ float BPY_pydriver_eval(IpoDriver *driver)
                bpy_pydriver_Dict);
 
        if (retval == NULL) {
-               return pydriver_error(driver);
+               result = pydriver_error(driver);
+               PyGILState_Release(gilstate);
+               return result;
        }
 
        result = ( float )PyFloat_AsDouble( retval );
+       Py_DECREF(retval);
        
-       if (result == -1 && PyErr_Occurred()) 
-               return pydriver_error(driver);
+       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");
@@ -1759,6 +2042,8 @@ float BPY_pydriver_eval(IpoDriver *driver)
        /* all fine, make sure the "invalid expression" flag is cleared */
        driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
 
+       PyGILState_Release(gilstate);
+
        return result;
 }
 
@@ -1795,15 +2080,20 @@ static int bpy_button_eval_error(char *expr) {
 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");
+                               "Button Python Eval error: couldn't create Python dictionary \n");
+                       PyGILState_Release(gilstate);
                        return -1;
                }
        }
@@ -1811,6 +2101,7 @@ int BPY_button_eval(char *expr, double *value)
 
        if( !setup_armature_weakrefs()){
                fprintf(stderr, "Oops - weakref dict\n");
+               PyGILState_Release(gilstate);
                return -1;
        }
 
@@ -1818,20 +2109,26 @@ int BPY_button_eval(char *expr, double *value)
                bpy_pydriver_Dict);
 
        if (retval == NULL) {
-               return bpy_button_eval_error(expr);
+               ret = bpy_button_eval_error(expr);
+               PyGILState_Release(gilstate);
+               return ret;
        }
        else {
                floatval = PyNumber_Float(retval);
                Py_DECREF(retval);
        }
 
-       if (floatval == NULL) 
-               return bpy_button_eval_error(expr);
-       else {
+       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 */
 }
 
@@ -1865,8 +2162,14 @@ void BPY_clear_bad_scriptlinks( struct Text *byebye )
 *      For the scene, only the current active scene the scripts are 
 *      executed (if any).
 *****************************************************************************/
-void BPY_do_all_scripts( short event )
+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 );
@@ -1875,6 +2178,21 @@ void BPY_do_all_scripts( short 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;
 }
 
@@ -1936,25 +2254,30 @@ void BPY_do_pyscript( ID * id, short event )
                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. */
+               /* 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 );
 
@@ -2002,6 +2325,8 @@ void BPY_do_pyscript( ID * id, short event )
                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);
        }
 }
 
@@ -2149,10 +2474,11 @@ int BPY_add_spacehandler(Text *text, ScrArea *sa, char spacetype)
 }
 
 int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
-       unsigned short space_event )
+       short eventValue, unsigned short space_event )
 {
        ScriptLink *scriptlink;
        int retval = 0;
+       PyGILState_STATE gilstate;
        
        if (!sa || !(G.f & G_DOSCRIPTLINKS)) return 0;
        
@@ -2175,9 +2501,12 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
                        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;
                }
                
@@ -2185,11 +2514,12 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
                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 to 0 */
+               /* 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);
@@ -2198,7 +2528,7 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
                                glMatrixMode(GL_MODELVIEW);
                                glPushMatrix();
                        }
-
+                       
                        if( ( scriptlink->flag[index] == space_event ) &&
                            ( scriptlink->scripts[index] != NULL ) ) {
                                dict = CreateGlobalDictionary();
@@ -2218,7 +2548,7 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short 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. */
@@ -2228,7 +2558,7 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
                                        break;
                                }
                        }
-
+                       
                        /* for DRAW handlers: */
                        if (event == 0) {
                                glMatrixMode(GL_PROJECTION);
@@ -2238,12 +2568,14 @@ int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
                                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:
@@ -2380,7 +2712,7 @@ int BPY_call_importloader( char *name )
 *              The Python dictionary containing global variables needs to
 *              be passed in globaldict.
 *****************************************************************************/
-PyObject *RunPython( Text * text, PyObject * globaldict )
+static PyObject *RunPython( Text * text, PyObject * globaldict )
 {
        char *buf = NULL;
 
@@ -2391,8 +2723,7 @@ PyObject *RunPython( Text * text, PyObject * globaldict )
                buf = txt_to_buf( text );
 
                text->compiled =
-                       Py_CompileString( buf, GetName( text ),
-                                         Py_file_input );
+                       Py_CompileString( buf, text->id.name+2, Py_file_input );
 
                MEM_freeN( buf );
 
@@ -2406,19 +2737,10 @@ PyObject *RunPython( Text * text, PyObject * globaldict )
        return PyEval_EvalCode( text->compiled, globaldict, globaldict );
 }
 
-/*****************************************************************************
-* Description: This function returns the value of the name field of the        
-*      given Text struct.
-*****************************************************************************/
-char *GetName( Text * text )
-{
-       return ( text->id.name + 2 );
-}
-
 /*****************************************************************************
 * Description: This function creates a new Python dictionary object.
 *****************************************************************************/
-PyObject *CreateGlobalDictionary( void )
+static PyObject *CreateGlobalDictionary( void )
 {
        PyObject *dict = PyDict_New(  );
 
@@ -2432,7 +2754,7 @@ PyObject *CreateGlobalDictionary( void )
 /*****************************************************************************
 * Description: This function deletes a given Python dictionary object.
 *****************************************************************************/
-void ReleaseGlobalDictionary( PyObject * dict )
+static void ReleaseGlobalDictionary( PyObject * dict )
 {
        PyDict_Clear( dict );
        Py_DECREF( dict );      /* Release dictionary. */
@@ -2445,7 +2767,7 @@ void ReleaseGlobalDictionary( PyObject * dict )
 *              list argument. The event by which the function has been 
 *              called, is passed in the event argument.
 *****************************************************************************/
-void DoAllScriptsFromList( ListBase * list, short event )
+static void DoAllScriptsFromList( ListBase * list, short event )
 {
        ID *id;
 
@@ -2459,49 +2781,38 @@ void DoAllScriptsFromList( ListBase * list, short event )
        return;
 }
 
-PyObject *importText( char *name )
+static PyObject *importText( char *name )
 {
        Text *text;
-       char *txtname;
+       char txtname[22]; /* 21+NULL */
        char *buf = NULL;
        int namelen = strlen( name );
-
-       txtname = malloc( namelen + 3 + 1 );
-       if( !txtname )
-               return NULL;
-
+       
+       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 );
 
-       text = ( Text * ) & ( G.main->text.first );
-
-       while( text ) {
-               if( !strcmp( txtname, GetName( text ) ) )
+       for(text = G.main->text.first; text; text = text->id.next) {
+               if( !strcmp( txtname, text->id.name+2 ) )
                        break;
-               text = text->id.next;
        }
 
-       if( !text ) {
-               free( txtname );
+       if( !text )
                return NULL;
-       }
 
        if( !text->compiled ) {
                buf = txt_to_buf( text );
-               text->compiled =
-                       Py_CompileString( buf, GetName( text ),
-                                         Py_file_input );
+               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 );
-                       free( txtname );
                        return NULL;
                }
        }
 
-       free( txtname );
        return PyImport_ExecCodeModule( name, text->compiled );
 }
 
@@ -2509,7 +2820,7 @@ static PyMethodDef bimport[] = {
        {"blimport", blender_import, METH_VARARGS, "our own import"}
 };
 
-PyObject *blender_import( PyObject * self, PyObject * args )
+static PyObject *blender_import( PyObject * self, PyObject * args )
 {
        PyObject *exception, *err, *tb;
        char *name;
@@ -2540,7 +2851,7 @@ PyObject *blender_import( PyObject * self, PyObject * args )
        return m;
 }
 
-void init_ourImport( void )
+static void init_ourImport( void )
 {
        PyObject *m, *d;
        PyObject *import = PyCFunction_New( bimport, NULL );
@@ -2572,7 +2883,7 @@ static PyObject *reimportText( PyObject *module )
        /* look up the text object */
        text = ( Text * ) & ( G.main->text.first );
        while( text ) {
-               if( !strcmp( txtname, GetName( text ) ) )
+               if( !strcmp( txtname, text->id.name+2 ) )
                        break;
                text = text->id.next;
        }
@@ -2589,8 +2900,7 @@ static PyObject *reimportText( PyObject *module )
 
        /* compile the buffer */
        buf = txt_to_buf( text );
-       text->compiled = Py_CompileString( buf, GetName( text ),
-                       Py_file_input );
+       text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input );
        MEM_freeN( buf );
 
        /* if compile failed.... return this error */
@@ -2642,7 +2952,7 @@ static PyMethodDef breload[] = {
        {"blreload", blender_reload, METH_VARARGS, "our own reload"}
 };
 
-void init_ourReload( void )
+static void init_ourReload( void )
 {
        PyObject *m, *d;
        PyObject *reload = PyCFunction_New( breload, NULL );
@@ -2651,3 +2961,21 @@ void init_ourReload( void )
        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");
+}