Skip to content
Snippets Groups Projects
BPY_interface.c 35.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* 
     *
     * ***** BEGIN GPL/BL DUAL 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.
     *
     * 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,
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
     * 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.
     *
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
     * Contributor(s): Michel Selten, Willian P. Germano, Stephen Swaney,
     * Chris Keith
    
     *
     * ***** END GPL/BL DUAL LICENSE BLOCK *****
    */
    #ifdef HAVE_CONFIG_H
    #include <config.h>
    #endif
    
    #include "compile.h" /* for the PyCodeObject */
    #include "eval.h" /* for PyEval_EvalCode */
    
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    #include <BLI_blenlib.h> /* for BLI_last_slash() */
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    #include <BIF_interface.h> /* for pupmenu() */
    
    #include <BIF_space.h>
    #include <BIF_screen.h>
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    #include <BIF_toolbox.h>
    
    #include <BKE_object.h> /* during_scriptlink() */
    
    #include <BKE_utildefines.h>
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    #include <BPI_script.h>
    
    
    #include <DNA_lamp_types.h>
    #include <DNA_material_types.h>
    #include <DNA_object_types.h>
    #include <DNA_scene_types.h>
    
    #include <DNA_space_types.h>
    #include <DNA_text_types.h>
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    #include <DNA_userdef_types.h> /* for U.pythondir */
    
    
    #include "BPY_menus.h"
    
    #include "api2_2x/EXPP_interface.h"
    
    #include "api2_2x/modules.h"
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* bpy_registryDict is declared in api2_2x/Registry.h and defined
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
     * here.	This Python dictionary will be used to store data that scripts
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
     * choose to preserve after they are executed, so user changes can be
     * restored next time the script is used.  Check the Blender.Registry module. */
    extern PyObject *bpy_registryDict;
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Structure definitions																										 */
    
    /*****************************************************************************/
    
    #define FILENAME_LENGTH 24
    typedef struct _ScriptError {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	char filename[FILENAME_LENGTH];
    	int lineno;
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Global variables																													 */
    
    /*****************************************************************************/
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Function prototypes																											 */
    
    /*****************************************************************************/
    
    PyObject *RunPython(Text *text, PyObject *globaldict);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    char		 *GetName(Text *text);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    void			ReleaseGlobalDictionary (PyObject * dict);
    void			DoAllScriptsFromList (ListBase * list, short event);
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    PyObject *importText(char *name);
    void init_ourImport(void);
    PyObject *blender_import(PyObject *self, PyObject *args);
    
    /*****************************************************************************/
    /* Description: This function will initialise Python and all the implemented */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /*							api variations.																							 */
    /* Notes:				Currently only the api for 2.2x will be initialised.				 */
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	bpy_registryDict = PyDict_New(); /* check comment at start of this file */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (!bpy_registryDict)
    		printf("Error: Couldn't create the Registry Python Dictionary!");
    
    /* TODO: Shouldn't "blender" be replaced by PACKAGE ?? (config.h) */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	Py_SetProgramName("blender");
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	Py_Initialize ();
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	init_ourImport ();
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	initBlenderApi2_2x ();
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	init_syspath();
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return;
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Description: This function will terminate the Python interpreter					 */
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (bpy_registryDict) {
    		Py_DECREF (bpy_registryDict);
    		bpy_registryDict = NULL;
    	}
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	Py_Finalize();
    
    
    	BPyMenu_RemoveAllEntries(); /* freeing bpymenu mem */
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	/* a script might've opened a .blend file but didn't close it, so: */
    	EXPP_Library_Close();
    
    	return;
    
    void syspath_append(char *dirname)
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyObject *mod_sys, *dict, *path, *dir;
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyErr_Clear();
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    	dir = Py_BuildValue("s", dirname);
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	mod_sys = PyImport_ImportModule("sys"); /* new ref */
    	dict = PyModule_GetDict(mod_sys);				/* borrowed ref */
    	path = PyDict_GetItemString(dict, "path"); /* borrowed ref */
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (!PyList_Check(path)) return;
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyList_Append(path, dir);
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (PyErr_Occurred()) Py_FatalError("could not build sys.path");
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	Py_DECREF(mod_sys);
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    }
    
    void init_syspath(void)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyObject *path;
    	PyObject *mod, *d;
    	PyObject *p;
    	char *c, *progname;
    	char execdir[FILE_MAXDIR + FILE_MAXFILE];/*defines from DNA_space_types.h*/
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	int n;
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	path = Py_BuildValue("s", bprogname);
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	mod = PyImport_ImportModule("Blender.sys");
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (mod) {
    		d = PyModule_GetDict(mod);
    		PyDict_SetItemString(d, "progname", path);
    		Py_DECREF(mod);
    	}
    	else
    		printf("Warning: could not set Blender.sys.progname\n");
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	progname = BLI_last_slash(bprogname); /* looks for the last dir separator */
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	c = Py_GetPath(); /* get python system path */
    	PySys_SetPath(c); /* initialize */
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	n = progname - bprogname;
    	if (n > 0) {
    		strncpy(execdir, bprogname, n);
    		if (execdir[n-1] == '.') n--; /*fix for when run as ./blender */
    		execdir[n] = '\0';
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		syspath_append(execdir);	/* append to module search path */
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		/* set Blender.sys.progname */
    	}
    	else
    		printf ("Warning: could not determine argv[0] path\n");
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	/* 
    	 * bring in the site module so we can add 
    	 * site-package dirs to sys.path 
    	 */
    
    Stephen Swaney's avatar
     
    Stephen Swaney committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	mod = PyImport_ImportModule("site"); /* new ref */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (mod) {
    		PyObject* item;
    		int size = 0;
    		int index;
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		/* get the value of 'sitedirs' from the module */
    
    Stephen Swaney's avatar
     
    Stephen Swaney committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		/* the ref man says GetDict() never fails!!! */
    		d = PyModule_GetDict (mod); /* borrowed ref */
    		p = PyDict_GetItemString (d, "sitedirs");  /* borrowed ref */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		if( p ) {  /* we got our string */
    			/* append each item in sitedirs list to path */
    			size = PyList_Size (p);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    			for (index = 0; index < size; index++) {
    	item	= PySequence_GetItem (p, index);	/* new ref */
    
    Stephen Swaney's avatar
     
    Stephen Swaney committed
    	if( item )
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		syspath_append (PyString_AsString(item));
    			}
    		}
    		Py_DECREF(mod);
    	}
    	else {	/* import 'site' failed */
    		PyErr_Clear();
    		printf("sys_init:warning - no sitedirs added from site module.\n");
    	}
    
    	/* 
    	 * initialize the sys module
    	 * set sys.executable to the Blender exe 
    	 * set argv[0] to the Blender exe
    	 */
    
    	mod = PyImport_ImportModule("sys"); /* new ref */
    
    	if (mod) {
    		d = PyModule_GetDict(mod); /* borrowed ref */
    		PyDict_SetItemString(d, "executable", Py_BuildValue("s", bprogname));
    		/* in the future this can be extended to have more argv's if needed: */
    		PyDict_SetItemString(d, "argv", Py_BuildValue("[s]", bprogname));
    		Py_DECREF(mod);
    	}
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    }
    
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* 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.																	 */
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    /*****************************************************************************/
    
    void BPY_post_start_python(void)
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyObject *result, *dict;
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (U.pythondir && U.pythondir[0] != '\0')
    		syspath_append(U.pythondir);	/* append to module search path */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	BPyMenu_Init(0); /* get dynamic menus (registered scripts) data */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    	dict = PyDict_New();
    
    	/* here we check if the user has (some of) the expected modules */
    	if (dict) {
    		char *s = "import chunk, gzip, math, os, struct, string";
    		result = PyRun_String(s, Py_eval_input, dict, dict);
    		if (!result) {
    			PyErr_Clear();
    			/*XXX print msg about this, point to readme.html */
    		}
    		else Py_DECREF(result);
    		Py_DECREF(dict);
    	}
    
    Willian Padovani Germano's avatar
     
    Willian Padovani Germano committed
    }
    
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Description: This function will return the linenumber on which an error	 */
    /*							has occurred in the Python script.													 */
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return g_script_error.lineno;
    
    /*****************************************************************************/
    /* Description: This function will return the filename of the python script. */
    /*****************************************************************************/
    
    const char *BPY_Err_getFilename(void)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return g_script_error.filename;
    
    }
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Description: Return PyString filename from a traceback object						 */
    
    /*****************************************************************************/
    PyObject *traceback_getFilename(PyObject *tb)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyObject *v;
    
    
    /* co_filename is in f_code, which is in tb_frame, which is in tb */
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	v = PyObject_GetAttrString(tb, "tb_frame"); Py_XDECREF(v);
    	v = PyObject_GetAttrString(v, "f_code"); Py_XDECREF(v);
    	v = PyObject_GetAttrString(v, "co_filename");
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return v;
    
    }
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* 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)
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyObject *exception, *err, *tb, *v;
    
    	if (!script_name) {
    		printf("Error: script has NULL name\n");
    		return;
    	}
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyErr_Fetch(&exception, &err, &tb);
    
    	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_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;
    		}
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		/* this avoids an abort in Python 2.3's garbage collecting: */
    		PyErr_Clear(); 
    		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");
    			return;
    		}
    
    		Py_INCREF(tb);
    
    
    /* From old bpython BPY_main.c:
     * 'check traceback objects and look for last traceback in the
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
     *	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."' */
    
    		while (1) { 
    			v = PyObject_GetAttrString(tb, "tb_next");
    
    			if (v == Py_None || strcmp(PyString_AsString(traceback_getFilename(v)),
    															script_name)) {
    				break;
    			}
    
    			Py_DECREF(tb);
    			tb = v;
    		}
    
    		v = PyObject_GetAttrString(tb, "tb_lineno");
    		g_script_error.lineno = PyInt_AsLong(v);
    		Py_XDECREF(v);
    		v = traceback_getFilename(tb);
    		strncpy(g_script_error.filename, PyString_AsString(v), FILENAME_LENGTH);
    		Py_XDECREF(v);
    		Py_DECREF(tb);
    	}
    
    	return;
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* 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.								 */
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    int BPY_txt_do_python_Text(struct Text* text)
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyObject *py_dict, *py_result;
    
    	BPy_constant *info;
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	char textname[24];
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (!text) return 0;
    
    
    	/* check if this text is already running */
    	while (script) {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		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;
    		}
    		script = script->id.next;
    	}
    
    	/* Create a new script structure and initialize it: */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	script = alloc_libblock(&G.main->script, ID_SCRIPT, GetName(text));
    
    
    	if (!script) {
    		printf("couldn't allocate memory for Script struct!");
    		return 0;
    	}
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	/* 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, GetName(text), strlen(GetName(text))+1);
    
    
    	script->id.us = 1;
    	script->flags = SCRIPT_RUNNING;
    	script->py_draw = NULL;
    	script->py_event = NULL;
    	script->py_button = NULL;
    
    	py_dict = CreateGlobalDictionary();
    
    	script->py_globaldict = py_dict;
    
    
    	info = (BPy_constant *)M_constant_New();
    	if (info) {
    		constant_insert(info, "name", PyString_FromString(script->id.name+2));
    		Py_INCREF (Py_None);
    		constant_insert(info, "arg", Py_None);
    		PyDict_SetItemString(py_dict, "__script__", (PyObject *)info);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	py_result = RunPython (text, py_dict); /* Run the script */
    
    	if (!py_result) { /* Failed execution of the script */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		BPY_Err_Handle(textname);
    
    		ReleaseGlobalDictionary(py_dict);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		if (G.main->script.first) free_libblock(&G.main->script, script);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		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);
    		}
    	}
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return 1; /* normal return */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Description: The original function of this name has been refactored			 */
    /* into BPY_txt_do_python_Text.  That version is needed for the command			 */
    /* line support for Python.  This is here to keep the interface the					 */
    /* same and reduce code changes elsewhere.																	 */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /*****************************************************************************/
    int BPY_txt_do_python(struct SpaceText* st)
    {
    	return BPY_txt_do_python_Text(st->text);
    }
    
    /*****************************************************************************/
    /* Description: Called from command line to run a Python script
    * automatically. */
    /*****************************************************************************/
    void BPY_run_python_script(char *fn)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	Text	*text = NULL;
    	int is_blenText = 0;
    
    	if ( !BLI_exists(fn) ) { /* if there's no such filename ...*/
    		text = G.main->text.first; /* try an already existing Blender Text */
    		while (text) {
    			if (!strcmp(fn, text->id.name+2)) break;
    			text = text->id.next;
    		}
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		if (!text) {
    			printf("\nError: no such file or Blender text -- %s.\n", fn);
    			return;
    		}
    		else is_blenText = 1; /* fn is already a Blender Text */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (!is_blenText) text = add_text(fn);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (text == NULL) {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		printf("Error in BPY_run_python_script: couldn't create Blender text "
    			"from %s\n", fn);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		// Chris: On Windows if I continue I just get a segmentation
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		// violation.  To get a baseline file I exit here.
    		exit(2);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	}
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    	if (BPY_txt_do_python_Text(text) != 1) {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		printf( "\nError executing Python script from command-line:\n"
    			"%s (at line %d).\n", fn, BPY_Err_getLinenumber());
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (!is_blenText) free_libblock(&G.main->text, text);
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* 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)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	PyObject *py_dict, *py_res, *pyarg = NULL;
    
    	BPy_constant *info;
    	BPyMenu *pym;
    	BPySubMenu *pysm;
    	FILE *fp = NULL;
    
    	char *buffer, *s;
    
    	char filestr[FILE_MAXDIR+FILE_MAXFILE];
    
    	char dirname[FILE_MAXDIR];
    
    	Script *script = G.main->script.first;
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	int len;
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	pym = BPyMenu_GetEntry(menutype, (short)event);
    
    
    	if (!pym) return 0;
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    
    	if (pym->version > G.version)
    		notice ("Version mismatch: script was written for Blender %d. "
    						"It may fail with yours: %d.", pym->version, G.version);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    
    /* 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;
    				pyarg = PyString_FromString(pysm->arg);
    			}
    			else return 0;
    		}
    	}
    
    	if (!pyarg) {/* no submenus */
    		Py_INCREF (Py_None);
    		pyarg = Py_None;
    	}
    
    
    	if (pym->dir) /* script is in U.pythondir */
    		BLI_make_file_string("/", filestr, U.pythondir, pym->filename);
    	else { /* script is in ~/.blender/scripts/ */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		BLI_make_file_string("/", dirname, bpy_gethome(), "scripts");
    
    		BLI_make_file_string("/", filestr, dirname,	pym->filename);
    	}
    
    
    	fp = fopen(filestr, "rb");
    	if (!fp) {
    
    		printf("Error loading script: couldn't open file %s\n", filestr);
    		return 0;
    	}
    
    	/* Create a new script structure and initialize it: */
    	script = alloc_libblock(&G.main->script, ID_SCRIPT, pym->name);
    
    	if (!script) {
    		printf("couldn't allocate memory for Script struct!");
    		fclose(fp);
    		return 0;
    	}
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	/* let's find a proper area for an eventual script gui:
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	 * (still experimenting here, need definition on which win
    	 * each group will be put to code this properly) */
    	switch (menutype) {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		case PYMENU_IMPORT: /* first 3 were handled in header_info.c */
    		case PYMENU_EXPORT:
    		case PYMENU_HELP: 
    		case PYMENU_WIZARDS:
    			break;
    
    		default:
    			if (curarea->spacetype != SPACE_SCRIPT) {
    				ScrArea *sa = NULL;
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    				sa = find_biggest_area_of_type(SPACE_BUTS);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    				if (sa) {
    					if ((1.5 * sa->winx) < sa->winy) sa = NULL; /* too narrow? */
    				}
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    				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);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    				if (!sa) sa = find_biggest_area();
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    				areawinset(sa->win);
    			}
    			break;
    
    	script->id.us = 1;
    	script->flags = SCRIPT_RUNNING;
    	script->py_draw = NULL;
    	script->py_event = NULL;
    	script->py_button = NULL;
    
    	py_dict = CreateGlobalDictionary();
    
    	script->py_globaldict = py_dict;
    
    	info = (BPy_constant *)M_constant_New();
    	if (info) {
    		constant_insert(info, "name", PyString_FromString(script->id.name+2));
    		constant_insert(info, "arg", pyarg);
    		PyDict_SetItemString(py_dict, "__script__", (PyObject *)info);
    	}
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	/* 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);
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	buffer = MEM_mallocN(len+2, "pyfilebuf"); /* len+2 to add '\n\0' */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	len = fread(buffer, 1, len, fp);
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	buffer[len] = '\n'; /* fix syntax error in files w/o eol*/
    	buffer[len+1] = '\0';
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	/* 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);
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	/* 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 */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		BPY_Err_Handle(script->id.name+2);
    
    		PyErr_Print();
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		if (G.main->script.first) free_libblock(&G.main->script, script);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		error ("Python script error: check console");
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		return 0;
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		Py_DECREF (py_res);
    
    		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. */
    			}
    	
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return 1; /* normal return */
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Description:																															 */
    /* Notes:																																		 */
    
    /*****************************************************************************/
    
    void BPY_free_compiled_text(struct Text* text)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (!text->compiled) return;
    	Py_DECREF((PyObject*) text->compiled);
    	text->compiled = NULL;
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return;
    
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Description: This function frees a finished (flags == 0) script.					 */
    
    /*****************************************************************************/
    void BPY_free_finished_script(Script *script)
    {
    	if (!script) return;
    
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (PyErr_Occurred()) { /* if script ended after filesel */
    		PyErr_Print(); /* eventual errors are handled now */
    		error ("Python script error: check console");
    	}
    
    
    	free_libblock(&G.main->script, script);
    	return;
    }
    
    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);
    						}
    					}
    				}
    			}
    		}
    	}
    }
    
    void BPY_clear_script (Script *script)
    {
    	PyObject *dict;
    
    	if (!script) return;
    
    	Py_XDECREF((PyObject *)script->py_draw);
    	Py_XDECREF((PyObject *)script->py_event);
    	Py_XDECREF((PyObject *)script->py_button);
    
    	dict = script->py_globaldict;
    
    	if (dict) {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    		PyDict_Clear (dict);
    		Py_DECREF (dict);		/* Release dictionary. */
    
    		script->py_globaldict = NULL;
    	}
    
    	unlink_script (script);
    }
    
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* ScriptLinks																															 */
    
    /*****************************************************************************/
    
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Description:																															 */
    /* Notes:				Not implemented yet																					 */
    
    /*****************************************************************************/
    
    void BPY_clear_bad_scriptlinks(struct Text *byebye)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	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);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return;
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* 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)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	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);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	BPY_do_pyscript (&(G.scene->id), event);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return;
    
    /*****************************************************************************/
    /* Description: Execute a Python script when an event occurs. The following  */
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /*							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;
    	}
    }
    
    static PyObject *ID_asPyObject(ID *id)
    
    	switch (MAKE_ID2 (id->name[0], id->name[1])) {
    	case ID_OB:
    		return Object_CreatePyObject((Object*) id);
    	case ID_LA:
    		return Lamp_CreatePyObject((Lamp*) id);
    	case ID_CA:
    		return Camera_CreatePyObject((Camera*) id);
    	case ID_MA:
    		return Material_CreatePyObject((Material*) id);
    	case ID_WO:
    		return World_CreatePyObject((World*) id);
    	case ID_SCE:
    		return Scene_CreatePyObject((Scene*) id);
    	default:
    
    		Py_INCREF (Py_None);
    		return Py_None;
    
    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 = ID_getScriptlink(id);
    
    	if (scriptlink && scriptlink->totscript) {
    		PyObject *dict;
    		PyObject *ret;
    
    		int index, during_slink = during_scriptlink();
    
    		/* invalid scriptlinks (new .blend was just loaded), return */
    		if (during_slink < 0) 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(during_slink);
    
    		/* set globals in Blender module to identify scriptlink */
    
    		Py_INCREF(Py_True);
    		PyDict_SetItemString(g_blenderdict, "bylink", Py_True);
    		PyDict_SetItemString(g_blenderdict, "link", ID_asPyObject(id));
    		PyDict_SetItemString(g_blenderdict, "event", 
    			PyString_FromString(event_to_name(event)));
    
    		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);
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    					/* Failed execution of the script */
    					BPY_Err_Handle (scriptlink->scripts[index]->name+2);
    
    					//BPY_end_python ();
    					//BPY_start_python ();
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    					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(during_slink - 1);
    
    		/* cleanup bylink flag and clear link so PyObject can be released */
    
    		Py_INCREF(Py_False);
    		PyDict_SetItemString(g_blenderdict, "bylink", Py_False);
    		Py_INCREF(Py_None);
    		PyDict_SetItemString(g_blenderdict, "link", Py_None);
    
    		PyDict_SetItemString(g_blenderdict, "event", PyString_FromString(""));
    
    /*****************************************************************************/
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    /* Description:																															 */
    /* Notes:																																		 */
    
    /*****************************************************************************/
    
    void BPY_free_scriptlink(struct ScriptLink *slink)
    {
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	if (slink->totscript) {
    		if(slink->flag) MEM_freeN(slink->flag);
    		if(slink->scripts) MEM_freeN(slink->scripts); 
    	}
    
    Willian Padovani Germano's avatar
    Willian Padovani Germano committed
    	return;