Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/bpython/intern/BPY_main.c')
-rw-r--r--source/blender/bpython/intern/BPY_main.c672
1 files changed, 672 insertions, 0 deletions
diff --git a/source/blender/bpython/intern/BPY_main.c b/source/blender/bpython/intern/BPY_main.c
new file mode 100644
index 00000000000..17995476749
--- /dev/null
+++ b/source/blender/bpython/intern/BPY_main.c
@@ -0,0 +1,672 @@
+/**
+ * blenkernel/py_main.c
+ * (cleaned up somewhat nzc apr-2001)
+
+ * $Id$
+ *
+ * ***** 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,
+ * 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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+/* NOTE: all externally callable routines have the prefix BPY_
+ -- see also ../include/BPY_extern.h */
+
+#include "BPY_main.h"
+#include "BPY_modules.h"
+#include "BPY_macros.h"
+#include "DNA_space_types.h"
+
+#include "b_interface.h"
+#include "mydevice.h"
+#include "import.h"
+
+/* PROTOS */
+
+extern void init_frozenmodules(void); // frozen module library
+extern void initmxTextTools(void);
+extern void inittess(void); // tesselator module
+
+void init_ourImport(void);
+
+
+/* GLOBALS */
+
+PyObject* ErrorObject = NULL;
+PyObject* callback = NULL;
+PyObject* callbackArgs = NULL;
+PyObject* blenderprogname = NULL;
+ID* script_link_id = NULL;
+
+/*------------------------------------------------------------------------*/
+/* START PYTHON (from creator.c) */
+
+void INITMODULE(BLENDERMODULE)(void);
+
+struct _inittab blendermodules[] = {
+#ifndef SHAREDMODULE // Blender module can alternatively be compiled shared
+ #ifdef STATIC_TEXTTOOLS // see api.h
+ { "mxTextTools" , initmxTextTools },
+ #endif
+ { MODNAME(BLENDERMODULE) , INITMODULE(BLENDERMODULE) },
+#endif
+#ifdef NO_RELEASE
+ { "tess" , inittess }, // GLU tesselator wrapper module
+#endif
+ { 0, 0}
+};
+
+/* hack to make sure, inittab is extended only first time */
+
+static short g_is_extended = 0;
+
+/** (Re)initializes the Python Interpreter.
+ * This function should be only called if the Python interpreter
+ * was not yet initialized (check Py_IsInitialized() )
+ */
+
+static void initBPythonInterpreter(void)
+{
+ Py_Initialize();
+
+ init_ourImport(); /* our own import, later: security */
+ if (!BPY_CHECKFLAG(G_NOFROZEN)) {
+ init_frozenmodules(); /* initialize frozen modules unless disabled */
+ }
+ init_syspath();
+}
+
+/** This function initializes Blender Python. It should be called only
+ * once at start, which is currently not the case (GameEngine Python).
+ * Therefore, it contains some dirty workarounds. They will be thrown
+ * into the grachten once the different APIs are merged into something
+ * more consistent.
+ *
+ */
+
+void BPY_start_python(void)
+{
+ Py_SetProgramName("blender");
+ if (BPY_DEBUGFLAG) {
+
+ Py_VerboseFlag = 1;
+ Py_DebugFlag = 1;
+ } else {
+#ifndef EXPERIMENTAL
+ Py_FrozenFlag = 1; /* no warnings about non set PYTHONHOME */
+ Py_NoSiteFlag = 1; /* disable auto site module import */
+#endif
+ }
+
+ if (!g_is_extended) {
+ g_is_extended = 1;
+ PyImport_ExtendInittab(blendermodules); /* extend builtin module table */
+ }
+
+ initBPythonInterpreter();
+#ifdef NO_RELEASE
+ if (PyRun_SimpleString("import startup"))
+ {
+ BPY_warn(("init script not found, continuing anyway\n"));
+ PyErr_Clear();
+ return;
+ }
+#endif
+}
+
+/** Ends the Python interpreter. This cleans up all global variables
+ * Blender-Python descriptor objects will (MUST!) decref on their
+ * raw blender objects, so this function should be called more or less
+ * immediately before garbage collection actions.
+ */
+
+void BPY_end_python(void)
+{
+ Py_Finalize();
+}
+
+void BPY_free_compiled_text(Text* text)
+{
+ if (!text->compiled) return;
+ Py_DECREF((PyObject*) text->compiled);
+ text->compiled = NULL;
+}
+
+void syspath_append(PyObject *dir)
+{
+ PyObject *m, *d;
+ PyObject *o;
+
+ PyErr_Clear();
+ m = PyImport_ImportModule("sys");
+ d = PyModule_GetDict(m);
+ o = PyDict_GetItemString(d, "path");
+ if (!PyList_Check(o)) {
+ return;
+ }
+ PyList_Append(o, dir);
+ if (PyErr_Occurred()) {
+ Py_FatalError("could not build sys.path");
+ }
+ Py_DECREF(m);
+}
+
+/* build blender specific system path for external modules */
+
+void init_syspath(void)
+{
+ PyObject *path;
+ PyObject *m, *d;
+ PyObject *p;
+ char *c;
+
+
+ char execdir[PATH_MAXCHAR], *progname;
+
+ int n;
+
+ path = Py_BuildValue("s", bprogname);
+
+ m = PyImport_ImportModule(MODNAME(BLENDERMODULE) ".sys");
+ if (m) {
+ d = PyModule_GetDict(m);
+ PyDict_SetItemString(d, "progname", path);
+ Py_DECREF(m);
+ } else {
+ BPY_debug(("Warning: could not set Blender.sys.progname\n"));
+ }
+
+ progname = BLI_last_slash(bprogname); /* looks for the last dir separator */
+
+ c = Py_GetPath(); /* get python system path */
+ PySys_SetPath(c); /* initialize */
+
+ n = progname - bprogname;
+ if (n > 0) {
+ strncpy(execdir, bprogname, n);
+ execdir[n] = '\0';
+
+ p = Py_BuildValue("s", execdir);
+ syspath_append(p); /* append to module search path */
+
+ /* set Blender.sys.progname */
+ } else {
+ BPY_debug(("Warning: could not determine argv[0] path\n"));
+ }
+ /* TODO look for the blender executable in the search path */
+ BPY_debug(("append to syspath: %s\n", U.pythondir));
+ if (U.pythondir) {
+ p = Py_BuildValue("s", U.pythondir);
+ syspath_append(p); /* append to module search path */
+ }
+ BPY_debug(("append done\n"));
+}
+
+
+#define FILENAME_LENGTH 24
+typedef struct _ScriptError {
+ char filename[FILENAME_LENGTH];
+ int lineno;
+} ScriptError;
+
+ScriptError g_script_error;
+
+int BPY_Err_getLinenumber()
+{
+ return g_script_error.lineno;
+}
+
+const char *BPY_Err_getFilename()
+{
+ return g_script_error.filename;
+}
+
+/** Returns (PyString) filename from a traceback object */
+
+PyObject *traceback_getFilename(PyObject *tb)
+{
+ PyObject *v;
+
+ v = PyObject_GetAttrString(tb, "tb_frame"); Py_DECREF(v);
+ v = PyObject_GetAttrString(v, "f_code"); Py_DECREF(v);
+ v = PyObject_GetAttrString(v, "co_filename");
+ return v;
+}
+
+/** Blender Python error handler. This catches the error and stores
+ * filename and line number in a global
+ */
+
+void BPY_Err_Handle(Text *text)
+{
+ PyObject *exception, *err, *tb, *v;
+
+ PyErr_Fetch(&exception, &err, &tb);
+
+ if (!exception && !tb) {
+ printf("FATAL: spurious exception\n");
+ return;
+ }
+
+ strcpy(g_script_error.filename, getName(text));
+
+ 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");
+ g_script_error.lineno = PyInt_AsLong(v);
+ Py_XDECREF(v);
+ return;
+ } else {
+ PyErr_NormalizeException(&exception, &err, &tb);
+ PyErr_Restore(exception, err, tb); // takes away reference!
+ PyErr_Print();
+ tb = PySys_GetObject("last_traceback");
+ Py_INCREF(tb);
+
+// check traceback objects and look for last traceback in the
+// same text file. This is used to jump to the line of where the
+// error occured. If the error occured in another text file or module,
+// the last frame in the current file is adressed
+
+ while (1) {
+ v = PyObject_GetAttrString(tb, "tb_next");
+ if (v == Py_None ||
+ strcmp(PyString_AsString(traceback_getFilename(v)), getName(text)))
+ 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);
+ }
+}
+
+/** Runs a Python string in the global name space of the given dictionary
+ 'globaldict' */
+
+static PyObject *newGlobalDictionary(void)
+{
+ PyObject *d = PyDict_New();
+ PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
+ PyDict_SetItemString(d, "__name__", PyString_FromString("__main__"));
+ return d;
+}
+
+static void releaseGlobalDictionary(PyObject *d)
+{
+ BPY_debug(("--- CLEAR namespace\n"));
+ PyDict_Clear(d);
+ Py_DECREF(d); // release dictionary
+}
+
+PyObject *BPY_runPython(Text *text, PyObject *globaldict)
+{
+ PyObject *ret;
+ char* buf = NULL;
+
+ if (!text->compiled)
+ {
+ buf = txt_to_buf(text);
+ /* bah, what a filthy hack -- removed */
+ /* strcat(buf, "\n"); */
+ text->compiled = Py_CompileString(buf, getName(text), Py_file_input);
+ MEM_freeN(buf);
+ if (PyErr_Occurred())
+ {
+ BPY_free_compiled_text(text);
+ return 0;
+ }
+ }
+ BPY_debug(("Run Python script \"%s\" ...\n", getName(text)));
+ ret = PyEval_EvalCode(text->compiled, globaldict, globaldict);
+ return ret;
+}
+
+/** This function is executed whenever ALT+PKEY is pressed -> drawtext.c
+ It returns the global namespace dictionary of the script context
+ (which is created newly when CLEAR_NAMESPACE is defined).
+ This may be stored in the SpaceText instance to give control over
+ namespace persistence. Remember that the same script may be executed
+ in several windows..
+ Namespace persistence is desired for scripts that use the GUI and
+ store callbacks to the current script.
+*/
+
+PyObject *BPY_txt_do_python(SpaceText *st)
+{
+ PyObject* d = NULL;
+ PyObject *ret;
+ Text *text = st->text;
+
+ if (!text)
+ {
+ return NULL;
+ }
+
+ /* TODO: make this an option: */
+#ifdef CLEAR_NAMESPACE
+ BPY_debug(("--- enable clear namespace\n"));
+ st->flags |= ST_CLEAR_NAMESPACE;
+#endif
+
+#ifdef CLEAR_NAMESPACE
+ d = newGlobalDictionary();
+#else
+ d = PyModule_GetDict(PyImport_AddModule("__main__"));
+#endif
+
+ ret = BPY_runPython(text, d);
+
+ if (!ret) {
+#ifdef CLEAR_NAMESPACE
+ releaseGlobalDictionary(d);
+#endif
+ BPY_Err_Handle(text);
+ Py_Finalize();
+ initBPythonInterpreter();
+ return NULL;
+ }
+ else
+ Py_DECREF(ret);
+
+
+ /* The following lines clear the global name space of the python
+ * interpreter. This is desired to release objects after execution
+ * of a script (remember that each wrapper object increments the refcount
+ * of the Blender Object.
+
+ * Exception: scripts that use the GUI rely on the
+ * persistent global namespace, so they need a workaround: The namespace
+ * is released when the GUI is exit.
+ * See opy_draw.c:Method_Register()
+ *
+ */
+
+#ifdef CLEAR_NAMESPACE
+ if (st->flags & ST_CLEAR_NAMESPACE) {
+ releaseGlobalDictionary(d);
+ garbage_collect(getGlobal()->main);
+ }
+#endif
+
+ return d;
+}
+
+/****************************************/
+/* SCRIPTLINKS */
+
+static void do_all_scriptlist(ListBase* list, short event)
+{
+ ID *id;
+
+ id = list->first;
+ while (id)
+ {
+ BPY_do_pyscript (id, event);
+ id = id->next;
+ }
+}
+
+void BPY_do_all_scripts(short event)
+{
+ do_all_scriptlist(getObjectList(), event);
+ do_all_scriptlist(getLampList(), event);
+ do_all_scriptlist(getCameraList(), event);
+ do_all_scriptlist(getMaterialList(), event);
+ do_all_scriptlist(getWorldList(), event);
+
+ BPY_do_pyscript(&scene_getCurrent()->id, event);
+}
+
+
+char *event_to_name(short event)
+{
+ switch (event) {
+ case SCRIPT_FRAMECHANGED:
+ return "FrameChanged";
+ case SCRIPT_ONLOAD:
+ return "OnLoad";
+ case SCRIPT_REDRAW:
+ return "Redraw";
+ default:
+ return "Unknown";
+ }
+}
+
+
+void BPY_do_pyscript(ID *id, short event)
+{
+ int i, offset;
+ char evName[24] = "";
+ char* structname = NULL;
+ ScriptLink* scriptlink;
+ PyObject *globaldict;
+
+ switch(GET_ID_TYPE(id)) {
+ case ID_OB: structname= "Object"; break;
+ case ID_LA: structname= "Lamp"; break;
+ case ID_CA: structname= "Camera"; break;
+ case ID_MA: structname= "Material"; break;
+ case ID_WO: structname= "World"; break;
+ case ID_SCE: structname= "Scene"; break;
+ default: return;
+ }
+
+ offset = BLO_findstruct_offset(structname, "scriptlink");
+ if (offset < 0)
+ {
+ BPY_warn(("Internal error, unable to find script link\n"));
+ return;
+ }
+ scriptlink = (ScriptLink*) (((char*)id) + offset);
+
+ /* no script provided */
+ if (!scriptlink->totscript) return;
+
+/* Debugging output */
+ switch (event)
+ {
+ case SCRIPT_FRAMECHANGED:
+ strcpy(evName, "SCRIPT_FRAMECHANGED");
+ BPY_debug(("do_pyscript(%s, %s)\n", getIDName(id), evName));
+ break;
+ case SCRIPT_ONLOAD:
+ strcpy(evName, "SCRIPT_ONLOAD");
+ BPY_debug(("do_pyscript(%s, %s)\n", getIDName(id), evName));
+ break;
+ case SCRIPT_REDRAW:
+ strcpy(evName, "SCRIPT_REDRAW");
+ BPY_debug(("do_pyscript(%s, %s)\n", getIDName(id), evName));
+ break;
+ default:
+ BPY_debug(("do_pyscript(): This should not happen !!!"));
+ break;
+ }
+
+/* END DEBUGGING */
+#ifndef SHAREDMODULE
+ set_scriptlinks(id, event);
+#endif
+ disable_where_script(1);
+ for (i = 0; i < scriptlink->totscript; i++)
+ {
+ if (scriptlink->flag[i] == event && scriptlink->scripts[i])
+ {
+ BPY_debug(("Evaluate script \"%s\" ...\n",
+ getIDName(scriptlink->scripts[i])));
+ script_link_id = id;
+#ifdef CLEAR_NAMESPACE
+ globaldict = newGlobalDictionary();
+#else
+ globaldict = PyModule_GetDict(PyImport_AddModule("__main__"));
+#endif
+ BPY_runPython((Text*) scriptlink->scripts[i], globaldict);
+#ifdef CLEAR_NAMESPACE
+ releaseGlobalDictionary(globaldict);
+#endif
+
+ script_link_id = NULL;
+ BPY_debug(("... done\n"));
+ }
+ }
+#ifndef SHAREDMODULE
+ release_scriptlinks(id);
+#endif
+ disable_where_script(0);
+}
+
+void BPY_clear_bad_scriptlink(ID *id, Text *byebye)
+{
+ ScriptLink* scriptlink;
+ int offset = -1;
+ char* structname = NULL;
+ int i;
+
+ switch (GET_ID_TYPE(id)) {
+ case ID_OB: structname = "Object"; break;
+ case ID_LA: structname = "Lamp"; break;
+ case ID_CA: structname = "Camera"; break;
+ case ID_MA: structname = "Material"; break;
+ case ID_WO: structname = "World"; break;
+ case ID_SCE: structname = "Scene"; break;
+ }
+
+ if (!structname) return;
+
+ offset= BLO_findstruct_offset(structname, "scriptlink");
+
+ if (offset<0) return;
+
+ scriptlink= (ScriptLink *) (((char *)id) + offset);
+
+ for(i=0; i<scriptlink->totscript; i++)
+ if ((Text*)scriptlink->scripts[i] == byebye)
+ scriptlink->scripts[i] = NULL;
+}
+
+void BPY_clear_bad_scriptlist(ListBase *list, Text *byebye)
+{
+ ID *id;
+
+ id= list->first;
+ while (id)
+ {
+ BPY_clear_bad_scriptlink(id, byebye);
+ id= id->next;
+ }
+}
+
+void BPY_clear_bad_scriptlinks(Text *byebye)
+{
+ BPY_clear_bad_scriptlist(getObjectList(), byebye);
+ BPY_clear_bad_scriptlist(getLampList(), byebye);
+ BPY_clear_bad_scriptlist(getCameraList(), byebye);
+ BPY_clear_bad_scriptlist(getMaterialList(), byebye);
+ BPY_clear_bad_scriptlist(getWorldList(), byebye);
+ BPY_clear_bad_scriptlink(&scene_getCurrent()->id, byebye);
+ allqueue(REDRAWBUTSSCRIPT, 0);
+}
+
+void BPY_free_scriptlink(ScriptLink *slink)
+{
+ if (slink->totscript)
+ {
+ if(slink->flag) MEM_freeN(slink->flag);
+ if(slink->scripts) MEM_freeN(slink->scripts);
+ }
+}
+
+void BPY_copy_scriptlink(ScriptLink *scriptlink)
+{
+ void *tmp;
+
+ if (scriptlink->totscript)
+ {
+ tmp = scriptlink->scripts;
+ scriptlink->scripts = MEM_mallocN(sizeof(ID*)*scriptlink->totscript, "scriptlistL");
+ memcpy(scriptlink->scripts, tmp, sizeof(ID*)*scriptlink->totscript);
+
+ tmp = scriptlink->flag;
+ scriptlink->flag = MEM_mallocN(sizeof(short)*scriptlink->totscript, "scriptlistF");
+ memcpy(scriptlink->flag, tmp, sizeof(short)*scriptlink->totscript);
+ }
+}
+
+/*
+ * Python alien graphics format conversion framework
+ *
+ * $Id$
+ *
+ *
+ *
+ */
+
+/* import importloader module with registered importers */
+#include "BPY_extern.h"
+#include "Python.h"
+
+
+int BPY_call_importloader(char *name)
+{
+ PyObject *mod, *tmp, *meth, *args;
+ int i, success = 0;
+
+ init_syspath();
+ mod = PyImport_ImportModule("Converter.importloader");
+ if (mod) {
+ meth = PyObject_GetAttrString(mod, "process"); // new ref
+ args = Py_BuildValue("(s)", name);
+ tmp = PyEval_CallObject(meth, args);
+ Py_DECREF(meth);
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ }
+
+ if (tmp) {
+ i = PyInt_AsLong(tmp);
+ if (i)
+ success = 1;
+ Py_DECREF(tmp);
+ }
+ Py_DECREF(mod);
+ } else {
+ PyErr_Print();
+ BPY_warn(("couldn't import 'importloader' \n"));
+ }
+ return success;
+}
+
+// more to come...