p3dpython can be a Panda app

This commit is contained in:
David Rose 2009-06-09 20:30:24 +00:00
parent 506154a6b6
commit b660d0f3e5
4 changed files with 63 additions and 75 deletions

View File

@ -1,6 +1,6 @@
// This directory is still experimental. Define HAVE_P3D_PLUGIN in
// your Config.pp to build it.
#define BUILD_DIRECTORY $[HAVE_P3D_PLUGIN]
#define BUILD_DIRECTORY $[and $[HAVE_P3D_PLUGIN],$[HAVE_PYTHON],$[HAVE_TINYXML]]
#begin lib_target
#define USE_PACKAGES tinyxml
@ -30,13 +30,20 @@
#end lib_target
#begin bin_target
#define USE_PACKAGES tinyxml
#define USE_PACKAGES tinyxml python
#define TARGET p3dpython
#define OTHER_LIBS \
dtoolutil:c dtoolbase:c dtool:m \
interrogatedb:c dconfig:c dtoolconfig:m \
express:c pandaexpress:m \
prc:c pstatclient:c pandabase:c linmath:c putil:c \
pipeline:c panda:m
#define SOURCES \
handleStream.cxx handleStream.h handleStream.I \
handleStreamBuf.cxx handleStreamBuf.h \
p3d_lock.h \
p3d_lock.h p3d_plugin.h \
p3dCInstance.cxx \
p3dCInstance.h p3dCInstance.I \
p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I

View File

@ -15,9 +15,11 @@
#ifndef P3DCINSTANCE_H
#define P3DCINSTANCE_H
#include "p3d_plugin.h"
#include "pandabase.h"
#include "p3d_plugin.h"
#include "pvector.h"
#include <vector>
#include <tinyxml.h>
class P3DSession;
@ -41,7 +43,7 @@ private:
string _keyword;
string _value;
};
typedef vector<Token> Tokens;
typedef pvector<Token> Tokens;
P3D_request_ready_func *_func;
string _p3d_filename;

View File

@ -13,6 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "p3dPythonRun.h"
#include "asyncTaskManager.h"
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::Constructor
@ -114,41 +115,10 @@ run_python() {
}
Py_DECREF(appmf);
// Construct a Python wrapper around our check_comm() method.
static PyMethodDef p3dpython_methods[] = {
{"check_comm", P3DPythonRun::py_check_comm, METH_VARARGS,
"Check for communications to and from the plugin host."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods);
if (p3dpython == NULL) {
PyErr_Print();
return false;
}
PyObject *check_comm = PyObject_GetAttrString(p3dpython, "check_comm");
if (check_comm == NULL) {
PyErr_Print();
return false;
}
// Now add check_comm() as a Python task.
PyObject *add_check_comm = PyObject_GetAttrString(appmf, "add_check_comm");
if (add_check_comm == NULL) {
PyErr_Print();
return false;
}
PyObject *task = PyObject_CallFunction
(add_check_comm, "Ol", check_comm, (long)this);
if (task == NULL) {
PyErr_Print();
return false;
}
Py_DECREF(task);
Py_DECREF(add_check_comm);
Py_DECREF(check_comm);
// Now add check_comm() as a task.
_check_comm_task = new GenericAsyncTask("check_comm", st_check_comm, this);
AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr();
task_mgr->add(_check_comm_task);
// Finally, get lost in taskMgr.run().
@ -212,8 +182,8 @@ handle_command(TiXmlDocument *doc) {
// from, and requests to be delivered to, the plugin
// host in the parent process.
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
check_comm() {
AsyncTask::DoneStatus P3DPythonRun::
check_comm(GenericAsyncTask *task) {
ACQUIRE_LOCK(_commands_lock);
while (!_commands.empty()) {
TiXmlDocument *doc = _commands.front();
@ -232,27 +202,21 @@ check_comm() {
}
RELEASE_LOCK(_commands_lock);
return AsyncTask::DS_cont;
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::py_check_comm
// Function: P3DPythonRun::st_check_comm
// Access: Private, Static
// Description: This method is added as a Python task function on the
// task manager. It is the Python wrapper around the
// check_comm method.
// Description: This static function wrapper around check_comm is
// necessary to add the method function to the
// GenericAsyncTask object.
////////////////////////////////////////////////////////////////////
PyObject *P3DPythonRun::
py_check_comm(PyObject *, PyObject *args) {
long this_int;
PyObject *task;
if (!PyArg_ParseTuple(args, "lO:check_comm", &this_int, &task)) {
return NULL;
}
P3DPythonRun *self = (P3DPythonRun *)(void *)this_int;
self->check_comm();
return PyObject_GetAttrString(task, "cont");
AsyncTask::DoneStatus P3DPythonRun::
st_check_comm(GenericAsyncTask *task, void *user_data) {
P3DPythonRun *self = (P3DPythonRun *)user_data;
return self->check_comm(task);
}
////////////////////////////////////////////////////////////////////
@ -266,6 +230,12 @@ void P3DPythonRun::
spawn_read_thread() {
assert(!_read_thread_continue);
// We have to use direct OS calls to create the thread instead of
// Panda constructs, because it has to be an actual thread, not
// necessarily a Panda thread (we can't use Panda's simple threads
// implementation, because we can't get overlapped I/O on an
// anonymous pipe in Windows).
_read_thread_continue = true;
#ifdef _WIN32
_read_thread = CreateThread(NULL, 0, &win_rt_thread_run, this, 0, NULL);
@ -356,8 +326,8 @@ terminate_instance(int id) {
delete inst;
// TODO: we don't currently have any way to stop just one instance
// of a multi-instance session. We could maybe close its window or
// something.
// of a multi-instance session. This will require a different
// Python interface than ShowBase.
terminate_session();
}

View File

@ -15,20 +15,22 @@
#ifndef P3DPYTHONRUN_H
#define P3DPYTHONRUN_H
#include <iostream>
#include <string>
#include <deque>
#include <map>
#include <assert.h>
#include <Python.h>
#include <tinyxml.h>
#include "pandabase.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include "p3d_lock.h"
#include "handleStream.h"
#include "p3dCInstance.h"
#include "genericAsyncTask.h"
#include "pmap.h"
#include "pdeque.h"
#ifdef _WIN32
#include <windows.h>
#endif
#include <Python.h>
#include <tinyxml.h>
using namespace std;
@ -56,8 +58,8 @@ public:
private:
void handle_command(TiXmlDocument *doc);
void check_comm();
static PyObject *py_check_comm(PyObject *, PyObject *args);
AsyncTask::DoneStatus check_comm(GenericAsyncTask *task);
static AsyncTask::DoneStatus st_check_comm(GenericAsyncTask *task, void *user_data);
void spawn_read_thread();
void join_read_thread();
@ -68,13 +70,14 @@ private:
private:
// This method runs only within the read thread.
void rt_thread_run();
#ifdef _WIN32
static DWORD WINAPI win_rt_thread_run(LPVOID data);
#endif
private:
typedef map<int, P3DCInstance *> Instances;
typedef pmap<int, P3DCInstance *> Instances;
Instances _instances;
string _program_name;
@ -85,9 +88,15 @@ private:
PyObject *_exit;
PyObject *_setupWindow;
PT(GenericAsyncTask) _check_comm_task;
// The remaining members are manipulated by the read thread.
typedef deque<TiXmlDocument *> Commands;
typedef pdeque<TiXmlDocument *> Commands;
Commands _commands;
// This has to be an actual OS LOCK instead of Panda's Mutex,
// because we have to use a true thread here, not one of Panda's
// simple threads.
LOCK _commands_lock;
HandleStream _pipe_read;