00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "py_commands.h"
00022 #include "Inform.h"
00023 #include "PythonTextInterp.h"
00024 #include "config.h"
00025 #include "VMDApp.h"
00026 #include "TextEvent.h"
00027
00028 #if defined(__APPLE__)
00029
00030 #include "Python/errcode.h"
00031 #else
00032 #include "errcode.h"
00033 #endif
00034
00035 #if PY_MAJOR_VERSION >= 3
00036 PyMODINIT_FUNC PyInit_vmd(void);
00037 #else
00038 extern "C" PyMODINIT_FUNC PyInit_vmd(void);
00039 #endif
00040
00041 static PyObject *cbdict = NULL;
00042
00043 static PyObject *add_callback(PyObject *, PyObject *args) {
00044 char *type;
00045 PyObject *temp;
00046
00047 if (!PyArg_ParseTuple(args, "sO:add_callback", &type, &temp))
00048 return NULL;
00049
00050 if (!PyCallable_Check(temp)) {
00051 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
00052 return NULL;
00053 }
00054 PyObject *cblist = PyDict_GetItemString(cbdict, type);
00055 if (!cblist) {
00056 PyErr_SetString(PyExc_KeyError, type);
00057 return NULL;
00058 }
00059 PyList_Append(cblist, temp);
00060 Py_XDECREF(temp);
00061 Py_INCREF(Py_None);
00062 return Py_None;
00063 }
00064
00065 static PyObject *del_callback(PyObject *, PyObject *args) {
00066 char *type;
00067 PyObject *temp;
00068
00069 if (!PyArg_ParseTuple(args, "sO:del_callback", &type, &temp))
00070 return NULL;
00071
00072 if (!PyCallable_Check(temp)) {
00073 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
00074 return NULL;
00075 }
00076 PyObject *cblist = PyDict_GetItemString(cbdict, type);
00077 if (!cblist) {
00078 PyErr_SetString(PyExc_KeyError, type);
00079 return NULL;
00080 }
00081 int ind = PySequence_Index(cblist, temp);
00082 if (ind >= 0) {
00083 PySequence_DelItem(cblist, ind);
00084 }
00085 Py_INCREF(Py_None);
00086 return Py_None;
00087 }
00088
00089 static void call_callbacks(const char *type, PyObject *arglist) {
00090 PyObject *cblist = PyDict_GetItemString(cbdict, type);
00091 if (!cblist) {
00092 msgErr << "Internal error: callback list " << type << " does not exist."
00093 << sendmsg;
00094 return;
00095 }
00096
00097
00098
00099
00100
00101 PyGILState_STATE state = PyGILState_Ensure();
00102
00103 for (int i=0; i<PyList_GET_SIZE(cblist); i++) {
00104 PyObject *obj = PyList_GET_ITEM(cblist, i);
00105 PyObject *result = PyEval_CallObject(obj, arglist);
00106 if (result == NULL) {
00107 PyErr_Print();
00108 PySequence_DelItem(cblist, i);
00109 i--;
00110 } else {
00111 Py_DECREF(result);
00112 }
00113 }
00114 Py_DECREF(arglist);
00115
00116 PyGILState_Release(state);
00117 }
00118
00119 static PyMethodDef CallbackMethods[] = {
00120 {"add_callback", (PyCFunction) add_callback, METH_VARARGS },
00121 {"del_callback", (PyCFunction) del_callback, METH_VARARGS },
00122 {NULL, NULL}
00123 };
00124
00125 #if PY_MAJOR_VERSION >= 3
00126 static struct PyModuleDef vmdcallbacksdef = {
00127 PyModuleDef_HEAD_INIT,
00128 "vmdcallbacks",
00129 NULL,
00130 -1,
00131 CallbackMethods,
00132 NULL,
00133 NULL,
00134 NULL,
00135 NULL
00136 };
00137 #endif
00138
00139 PyObject* initvmdcallbacks(void) {
00140 #if PY_MAJOR_VERSION >= 3
00141 PyObject *m = PyModule_Create(&vmdcallbacksdef);
00142 #else
00143 PyObject *m = Py_InitModule("vmdcallbacks", CallbackMethods);
00144 #endif
00145 PyObject *dict = PyDict_New();
00146 PyDict_SetItemString(dict, "display_update", PyList_New(0));
00147 PyDict_SetItemString(dict, "frame", PyList_New(0));
00148 PyDict_SetItemString(dict, "initialize_structure", PyList_New(0));
00149 PyDict_SetItemString(dict, "molecule", PyList_New(0));
00150 PyDict_SetItemString(dict, "pick_atom", PyList_New(0));
00151 PyDict_SetItemString(dict, "pick_event", PyList_New(0));
00152 PyDict_SetItemString(dict, "pick_value", PyList_New(0));
00153 PyDict_SetItemString(dict, "timestep", PyList_New(0));
00154 PyDict_SetItemString(dict, "trajectory", PyList_New(0));
00155 PyDict_SetItemString(dict, "userkey", PyList_New(0));
00156 PyObject_SetAttrString(m, "callbacks", dict);
00157 cbdict = dict;
00158
00159 return m;
00160 }
00161
00162 PythonTextInterp::PythonTextInterp(VMDApp *vmdapp) : app(vmdapp) {
00163 const char *oo_modules[] = {"Molecule", "Label", "Material", NULL};
00164 PyObject *vmdmodule;
00165 int retval, i;
00166
00167 msgInfo << "Starting Python..." << sendmsg;
00168
00169 #if PY_MAJOR_VERSION >= 3
00170
00171
00172 PyImport_AppendInittab("vmd", PyInit_vmd);
00173 #endif
00174
00175
00176 #if PY_MAJOR_VERSION >= 3
00177 PySys_AddWarnOption(L"default");
00178 #else
00179 PySys_AddWarnOption((char*) "default");
00180 #endif
00181
00182 #if 0 && PY_MAJOR_VERSION >= 3
00183
00184
00185 Py_SetProgramName(Py_DecodeLocale(app->argv_m[0], NULL));
00186 #endif
00187 Py_Initialize();
00188
00189
00190 #if PY_MAJOR_VERSION >= 3
00191 int argc = app->argc_m;
00192 wchar_t **wargv = (wchar_t **) PyMem_Malloc((argc+1) * sizeof(wchar_t*));
00193 memset(wargv, 0, (argc+1) * sizeof(wchar_t*));
00194
00195 for (i=0; i<argc; i++) {
00196 wargv[i] = Py_DecodeLocale(app->argv_m[i], NULL);
00197 }
00198
00199 PySys_SetArgv(argc, wargv);
00200 #else
00201 PySys_SetArgv(app->argc_m, (char **)app->argv_m);
00202 #endif
00203 set_vmdapp(app);
00204
00205
00206 PySys_SetObject((char*) "ps1", as_pystring(""));
00207 PySys_SetObject((char*) "ps2", as_pystring("... "));
00208
00209 vmdmodule = PyImport_ImportModule("vmd");
00210 i = 0;
00211 while (py_initializers[i].name) {
00212 const char *name = py_initializers[i].name;
00213
00214 PyObject *module = (*(py_initializers[i].initfunc))();
00215 i++;
00216 if (!module) {
00217 msgErr << "Failed to initialize builtin module " << name << sendmsg;
00218 PyErr_Print();
00219 continue;
00220 }
00221 retval = PyModule_AddObject(vmdmodule, CAST_HACK name, module);
00222 if (retval || PyErr_Occurred()) {
00223 msgErr << "Failed to import builtin module " << name << sendmsg;
00224 exit(1);
00225 }
00226 }
00227
00228
00229 for (const char **tmp = oo_modules; *tmp; tmp++) {
00230 PyObject *module = PyImport_ImportModule(*tmp);
00231 if (!module) {
00232 msgErr << "Failed to initialize object-oriented module " << *tmp << sendmsg;
00233 continue;
00234 }
00235 retval = PyModule_AddObject(vmdmodule, CAST_HACK *tmp, module);
00236 if (retval || PyErr_Occurred()) {
00237 msgErr << "Failed to initialize object-oriented module " << *tmp << sendmsg;
00238 continue;
00239 }
00240 }
00241
00242
00243 if (!evalString("from vmd import *")) {
00244 msgErr << "Failed to import VMD python modules" << sendmsg;
00245 exit(1);
00246 }
00247
00248
00249
00250
00251 have_tkinter = 1;
00252 in_tk = 0;
00253 needPrompt = 1;
00254 }
00255
00256 PythonTextInterp::~PythonTextInterp() {
00257 Py_Finalize();
00258 msgInfo << "Done with Python." << sendmsg;
00259 }
00260
00261 int PythonTextInterp::doTkUpdate() {
00262
00263
00264 if (in_tk) return 0;
00265 if (have_tkinter) {
00266 in_tk = 1;
00267 int rc = 1;
00268
00269
00270 #if PY_MAJOR_VERSION >= 3
00271 rc = evalString("import _tkinter\n");
00272 #else
00273 rc = evalString(
00274 "import Tkinter\n"
00275 "while Tkinter.tkinter.dooneevent(Tkinter.tkinter.DONT_WAIT):\n"
00276 "\tpass\n"
00277 );
00278 #endif
00279 in_tk = 0;
00280 if (rc) {
00281 return 1;
00282 }
00283
00284 have_tkinter = 0;
00285 }
00286 return 0;
00287 }
00288
00289 void PythonTextInterp::doEvent() {
00290
00291
00292 PyObject *arglist = Py_BuildValue("()");
00293 call_callbacks("display_update", arglist);
00294
00295 if (needPrompt) {
00296 printf(">>> ");
00297 fflush(stdout);
00298 needPrompt = 0;
00299 }
00300
00301 if (!vmd_check_stdin())
00302 return;
00303
00304 int code = PyRun_InteractiveOne(stdin, "VMD");
00305 needPrompt = 1;
00306 if (code == E_EOF) {
00307
00308
00309 app->textinterp_change("tcl");
00310 }
00311 }
00312
00313 int PythonTextInterp::evalString(const char *s) {
00314
00315
00316
00317 return !PyRun_SimpleString(s);
00318 }
00319
00320 int PythonTextInterp::evalFile(const char *s) {
00321 FILE *fid = fopen(s, "r");
00322 if (!fid) {
00323 msgErr << "Error opening file '" << s << "'" << sendmsg;
00324 return FALSE;
00325 }
00326 int code = PyRun_SimpleFile(fid, "VMD");
00327 fclose(fid);
00328 return !code;
00329 }
00330
00331 void PythonTextInterp::frame_cb(int molid, int frame) {
00332 PyObject *arglist = Py_BuildValue("(i,i)", molid, frame);
00333 call_callbacks("frame", arglist);
00334 }
00335
00336 void PythonTextInterp::initialize_structure_cb(int molid, int code) {
00337 PyObject *arglist = Py_BuildValue("(i,i)", molid, code);
00338 call_callbacks("initialize_structure", arglist);
00339 }
00340
00341 void PythonTextInterp::molecule_changed_cb(int molid, int code) {
00342 PyObject *arglist = Py_BuildValue("(i,i)", molid, code);
00343 call_callbacks("molecule", arglist);
00344 }
00345
00346 void PythonTextInterp::pick_atom_cb(int mol, int atom, int key_shift_state, bool ispick) {
00347 PyObject *arglist = Py_BuildValue("(i,i,i)", mol, atom, key_shift_state);
00348 call_callbacks("pick_atom", arglist);
00349 if (ispick) {
00350
00351
00352 PyObject *arglist = Py_BuildValue("(i)", 1);
00353 call_callbacks("pick_event", arglist);
00354 }
00355 }
00356
00357 void PythonTextInterp::pick_value_cb(float val) {
00358 PyObject *arglist = Py_BuildValue("(f)", val);
00359 call_callbacks("pick_value", arglist);
00360 }
00361
00362 void PythonTextInterp::timestep_cb(int id, int frame) {
00363 PyObject *arglist = Py_BuildValue("(i,i)", id, frame);
00364 call_callbacks("timestep", arglist);
00365 }
00366
00367 void PythonTextInterp::trajectory_cb(int id, const char *name) {
00368 PyObject *arglist = Py_BuildValue("(i,s)", id, name);
00369 call_callbacks("trajectory", arglist);
00370 }
00371
00372 void PythonTextInterp::python_cb(const char *cmd) {
00373 evalString(cmd);
00374 }
00375
00376 void PythonTextInterp::userkey_cb(const char *keydesc) {
00377 PyObject *arglist = Py_BuildValue("(s)", keydesc);
00378 call_callbacks("userkey", arglist);
00379 }
00380