mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 01:44:06 -04:00
async JavaScript
This commit is contained in:
parent
8aa18e2e9c
commit
aa8285f5a4
@ -168,11 +168,13 @@ run_python() {
|
|||||||
Py_DECREF(runp3d);
|
Py_DECREF(runp3d);
|
||||||
|
|
||||||
|
|
||||||
// Construct a Python wrapper around our request_func() method.
|
// Construct a Python wrapper around our methods we need to expose to Python.
|
||||||
static PyMethodDef p3dpython_methods[] = {
|
static PyMethodDef p3dpython_methods[] = {
|
||||||
{"request_func", P3DPythonRun::st_request_func, METH_VARARGS,
|
{ "check_comm", P3DPythonRun::st_check_comm, METH_VARARGS,
|
||||||
"Send an asynchronous request to the plugin host"},
|
"Poll for communications from the parent process" },
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{ "request_func", P3DPythonRun::st_request_func, METH_VARARGS,
|
||||||
|
"Send an asynchronous request to the plugin host" },
|
||||||
|
{ NULL, NULL, 0, NULL } /* Sentinel */
|
||||||
};
|
};
|
||||||
PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods);
|
PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods);
|
||||||
if (p3dpython == NULL) {
|
if (p3dpython == NULL) {
|
||||||
@ -196,11 +198,31 @@ run_python() {
|
|||||||
Py_DECREF(request_func);
|
Py_DECREF(request_func);
|
||||||
|
|
||||||
|
|
||||||
// Now add check_comm() as a task.
|
// Now add check_comm() as a task. It can be a threaded task, but
|
||||||
_check_comm_task = new GenericAsyncTask("check_comm", task_check_comm, this);
|
// this does mean that application programmers will have to be alert
|
||||||
|
// to asynchronous calls coming in from JavaScript. We'll put it on
|
||||||
|
// its own task chain so the application programmer can decide how
|
||||||
|
// it should be.
|
||||||
AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr();
|
AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr();
|
||||||
|
PT(AsyncTaskChain) chain = task_mgr->make_task_chain("JavaScript");
|
||||||
|
chain->set_num_threads(1);
|
||||||
|
chain->set_thread_priority(TP_low);
|
||||||
|
|
||||||
|
PyObject *check_comm = PyObject_GetAttrString(p3dpython, "check_comm");
|
||||||
|
if (check_comm == NULL) {
|
||||||
|
PyErr_Print();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to make it a PythonTask, not just a GenericAsyncTask,
|
||||||
|
// because we need the code in PythonTask that supports calling into
|
||||||
|
// Python from a separate thread.
|
||||||
|
_check_comm_task = new PythonTask(check_comm, "check_comm");
|
||||||
|
_check_comm_task->set_task_chain("JavaScript");
|
||||||
task_mgr->add(_check_comm_task);
|
task_mgr->add(_check_comm_task);
|
||||||
|
|
||||||
|
Py_DECREF(check_comm);
|
||||||
|
|
||||||
// Finally, get lost in taskMgr.run().
|
// Finally, get lost in taskMgr.run().
|
||||||
PyObject *done = PyObject_CallMethod(_taskMgr, (char *)"run", (char *)"");
|
PyObject *done = PyObject_CallMethod(_taskMgr, (char *)"run", (char *)"");
|
||||||
if (done == NULL) {
|
if (done == NULL) {
|
||||||
@ -216,11 +238,14 @@ run_python() {
|
|||||||
// Function: P3DPythonRun::handle_command
|
// Function: P3DPythonRun::handle_command
|
||||||
// Access: Private
|
// Access: Private
|
||||||
// Description: Handles a command received from the plugin host, via
|
// Description: Handles a command received from the plugin host, via
|
||||||
// an XML syntax on the wire.
|
// an XML syntax on the wire. Ownership of the XML
|
||||||
|
// document object is passed into this method.
|
||||||
|
//
|
||||||
|
// It's important *not* to be holding _commands_lock
|
||||||
|
// when calling this method.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DPythonRun::
|
void P3DPythonRun::
|
||||||
handle_command(TiXmlDocument *doc) {
|
handle_command(TiXmlDocument *doc) {
|
||||||
nout << "received: " << *doc << "\n" << flush;
|
|
||||||
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
||||||
if (xcommand != NULL) {
|
if (xcommand != NULL) {
|
||||||
bool needs_response = false;
|
bool needs_response = false;
|
||||||
@ -281,9 +306,15 @@ handle_command(TiXmlDocument *doc) {
|
|||||||
handle_pyobj_command(xcommand, needs_response, want_response_id);
|
handle_pyobj_command(xcommand, needs_response, want_response_id);
|
||||||
|
|
||||||
} else if (strcmp(cmd, "script_response") == 0) {
|
} else if (strcmp(cmd, "script_response") == 0) {
|
||||||
// Response from a script request.
|
// Response from a script request. In this case, we just
|
||||||
assert(!needs_response);
|
// store it away instead of processing it immediately.
|
||||||
nout << "Ignoring unexpected script_response\n";
|
|
||||||
|
MutexHolder holder(_responses_lock);
|
||||||
|
_responses.push_back(doc);
|
||||||
|
|
||||||
|
// And now we must return out, instead of deleting the
|
||||||
|
// document at the bottom of this method.
|
||||||
|
return;
|
||||||
|
|
||||||
} else if (strcmp(cmd, "drop_pyobj") == 0) {
|
} else if (strcmp(cmd, "drop_pyobj") == 0) {
|
||||||
int object_id;
|
int object_id;
|
||||||
@ -312,6 +343,8 @@ handle_command(TiXmlDocument *doc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -560,45 +593,40 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
|
|||||||
// Function: P3DPythonRun::check_comm
|
// Function: P3DPythonRun::check_comm
|
||||||
// Access: Private
|
// Access: Private
|
||||||
// Description: This method is added to the task manager (via
|
// Description: This method is added to the task manager (via
|
||||||
// task_check_comm, below) so that it gets a call every
|
// st_check_comm, below) so that it gets a call every
|
||||||
// frame. Its job is to check for commands received
|
// frame. Its job is to check for commands received
|
||||||
// from the plugin host in the parent process.
|
// from the plugin host in the parent process.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DPythonRun::
|
void P3DPythonRun::
|
||||||
check_comm() {
|
check_comm() {
|
||||||
nout << ":" << flush;
|
// nout << ":" << flush;
|
||||||
ACQUIRE_LOCK(_commands_lock);
|
ACQUIRE_LOCK(_commands_lock);
|
||||||
while (!_commands.empty()) {
|
while (!_commands.empty()) {
|
||||||
TiXmlDocument *doc = _commands.front();
|
TiXmlDocument *doc = _commands.front();
|
||||||
_commands.pop_front();
|
_commands.pop_front();
|
||||||
assert(_commands.size() < 10);
|
|
||||||
RELEASE_LOCK(_commands_lock);
|
RELEASE_LOCK(_commands_lock);
|
||||||
handle_command(doc);
|
handle_command(doc);
|
||||||
delete doc;
|
|
||||||
ACQUIRE_LOCK(_commands_lock);
|
ACQUIRE_LOCK(_commands_lock);
|
||||||
}
|
}
|
||||||
|
RELEASE_LOCK(_commands_lock);
|
||||||
|
|
||||||
if (!_program_continue) {
|
if (!_program_continue) {
|
||||||
// The low-level thread detected an error, for instance pipe
|
// The low-level thread detected an error, for instance pipe
|
||||||
// closed. We should exit gracefully.
|
// closed. We should exit gracefully.
|
||||||
terminate_session();
|
terminate_session();
|
||||||
}
|
}
|
||||||
|
|
||||||
RELEASE_LOCK(_commands_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DPythonRun::task_check_comm
|
// Function: P3DPythonRun::st_check_comm
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
// Description: This static function wrapper around check_comm is
|
// Description: This is a static Python wrapper around py_check_comm,
|
||||||
// necessary to add the method function to the
|
// needed to add the function to a PythonTask.
|
||||||
// GenericAsyncTask object.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
AsyncTask::DoneStatus P3DPythonRun::
|
PyObject *P3DPythonRun::
|
||||||
task_check_comm(GenericAsyncTask *task, void *user_data) {
|
st_check_comm(PyObject *, PyObject *args) {
|
||||||
P3DPythonRun *self = (P3DPythonRun *)user_data;
|
P3DPythonRun::_global_ptr->check_comm();
|
||||||
self->check_comm();
|
return Py_BuildValue("i", AsyncTask::DS_cont);
|
||||||
return AsyncTask::DS_cont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -611,54 +639,63 @@ task_check_comm(GenericAsyncTask *task, void *user_data) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
TiXmlDocument *P3DPythonRun::
|
TiXmlDocument *P3DPythonRun::
|
||||||
wait_script_response(int response_id) {
|
wait_script_response(int response_id) {
|
||||||
nout << "waiting script_response " << response_id << "\n" << flush;
|
// nout << "waiting script_response " << response_id << "\n" << flush;
|
||||||
while (true) {
|
while (true) {
|
||||||
ACQUIRE_LOCK(_commands_lock);
|
|
||||||
|
|
||||||
Commands::iterator ci;
|
Commands::iterator ci;
|
||||||
|
|
||||||
|
// First, walk through the _commands queue to see if there's
|
||||||
|
// anything that needs immediate processing.
|
||||||
|
ACQUIRE_LOCK(_commands_lock);
|
||||||
for (ci = _commands.begin(); ci != _commands.end(); ++ci) {
|
for (ci = _commands.begin(); ci != _commands.end(); ++ci) {
|
||||||
TiXmlDocument *doc = (*ci);
|
TiXmlDocument *doc = (*ci);
|
||||||
|
|
||||||
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
||||||
if (xcommand != NULL) {
|
if (xcommand != NULL) {
|
||||||
const char *cmd = xcommand->Attribute("cmd");
|
const char *cmd = xcommand->Attribute("cmd");
|
||||||
if (cmd != NULL && strcmp(cmd, "script_response") == 0) {
|
if ((cmd != NULL && strcmp(cmd, "script_response") == 0) ||
|
||||||
int unique_id;
|
xcommand->Attribute("want_response_id") != NULL) {
|
||||||
if (xcommand->QueryIntAttribute("unique_id", &unique_id) == TIXML_SUCCESS) {
|
|
||||||
if (unique_id == response_id) {
|
|
||||||
// This is the response we were waiting for.
|
|
||||||
_commands.erase(ci);
|
|
||||||
RELEASE_LOCK(_commands_lock);
|
|
||||||
nout << "got script_response " << unique_id << "\n" << flush;
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// It's not the response we're waiting for, but maybe we need
|
// This is either a response, or it's a command that will
|
||||||
// to handle it anyway.
|
// want a response itself. In either case we should handle
|
||||||
bool needs_response = false;
|
// it right away. ("handling" a response means moving it to
|
||||||
int want_response_id;
|
// the _responses queue.)
|
||||||
if (xcommand->QueryIntAttribute("want_response_id", &want_response_id) == TIXML_SUCCESS) {
|
|
||||||
// This command will be wanting a response. We'd better
|
|
||||||
// honor it right away, or we risk deadlock with the browser
|
|
||||||
// process and the Python process waiting for each other.
|
|
||||||
nout << "honoring response " << want_response_id << "\n" << flush;
|
|
||||||
_commands.erase(ci);
|
_commands.erase(ci);
|
||||||
RELEASE_LOCK(_commands_lock);
|
RELEASE_LOCK(_commands_lock);
|
||||||
handle_command(doc);
|
handle_command(doc);
|
||||||
delete doc;
|
|
||||||
ACQUIRE_LOCK(_commands_lock);
|
ACQUIRE_LOCK(_commands_lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RELEASE_LOCK(_commands_lock);
|
||||||
|
|
||||||
|
// Now, walk through the _responses queue to look for the
|
||||||
|
// particular response we're waiting for.
|
||||||
|
_responses_lock.acquire();
|
||||||
|
for (ci = _responses.begin(); ci != _responses.end(); ++ci) {
|
||||||
|
TiXmlDocument *doc = (*ci);
|
||||||
|
|
||||||
|
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
||||||
|
assert(xcommand != NULL);
|
||||||
|
const char *cmd = xcommand->Attribute("cmd");
|
||||||
|
assert(cmd != NULL && strcmp(cmd, "script_response") == 0);
|
||||||
|
|
||||||
|
int unique_id;
|
||||||
|
if (xcommand->QueryIntAttribute("unique_id", &unique_id) == TIXML_SUCCESS) {
|
||||||
|
if (unique_id == response_id) {
|
||||||
|
// This is the response we were waiting for.
|
||||||
|
_responses.erase(ci);
|
||||||
|
_responses_lock.release();
|
||||||
|
// nout << "got script_response " << unique_id << "\n" << flush;
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_responses_lock.release();
|
||||||
|
|
||||||
if (!_program_continue) {
|
if (!_program_continue) {
|
||||||
terminate_session();
|
terminate_session();
|
||||||
}
|
}
|
||||||
|
|
||||||
RELEASE_LOCK(_commands_lock);
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Make sure we process the Windows event loop while we're
|
// Make sure we process the Windows event loop while we're
|
||||||
@ -671,7 +708,7 @@ wait_script_response(int response_id) {
|
|||||||
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD);
|
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD);
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
nout << "." << flush;
|
// nout << "." << flush;
|
||||||
|
|
||||||
// It hasn't shown up yet. Give the sub-thread a chance to
|
// It hasn't shown up yet. Give the sub-thread a chance to
|
||||||
// process the input and append it to the queue.
|
// process the input and append it to the queue.
|
||||||
|
@ -25,9 +25,10 @@
|
|||||||
#include "p3d_lock.h"
|
#include "p3d_lock.h"
|
||||||
#include "handleStream.h"
|
#include "handleStream.h"
|
||||||
#include "p3dCInstance.h"
|
#include "p3dCInstance.h"
|
||||||
#include "genericAsyncTask.h"
|
#include "pythonTask.h"
|
||||||
#include "pmap.h"
|
#include "pmap.h"
|
||||||
#include "pdeque.h"
|
#include "pdeque.h"
|
||||||
|
#include "pmutex.h"
|
||||||
#include "get_tinyxml.h"
|
#include "get_tinyxml.h"
|
||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
@ -75,7 +76,7 @@ private:
|
|||||||
void handle_script_response_command(TiXmlElement *xcommand);
|
void handle_script_response_command(TiXmlElement *xcommand);
|
||||||
|
|
||||||
void check_comm();
|
void check_comm();
|
||||||
static AsyncTask::DoneStatus task_check_comm(GenericAsyncTask *task, void *user_data);
|
static PyObject *st_check_comm(PyObject *, PyObject *args);
|
||||||
TiXmlDocument *wait_script_response(int response_id);
|
TiXmlDocument *wait_script_response(int response_id);
|
||||||
|
|
||||||
PyObject *py_request_func(PyObject *args);
|
PyObject *py_request_func(PyObject *args);
|
||||||
@ -118,7 +119,7 @@ private:
|
|||||||
PyObject *_browser_object_class;
|
PyObject *_browser_object_class;
|
||||||
PyObject *_taskMgr;
|
PyObject *_taskMgr;
|
||||||
|
|
||||||
PT(GenericAsyncTask) _check_comm_task;
|
PT(PythonTask) _check_comm_task;
|
||||||
|
|
||||||
// This map keeps track of the PyObject pointers we have delivered
|
// This map keeps track of the PyObject pointers we have delivered
|
||||||
// to the parent process. We have to hold the reference count on
|
// to the parent process. We have to hold the reference count on
|
||||||
@ -128,8 +129,14 @@ private:
|
|||||||
SentObjects _sent_objects;
|
SentObjects _sent_objects;
|
||||||
int _next_sent_id;
|
int _next_sent_id;
|
||||||
|
|
||||||
// The remaining members are manipulated by the read thread.
|
|
||||||
typedef pdeque<TiXmlDocument *> Commands;
|
typedef pdeque<TiXmlDocument *> Commands;
|
||||||
|
|
||||||
|
// This is a special queue of responses extracted from the _commands
|
||||||
|
// queue, below. It's protected by the Panda mutex.
|
||||||
|
Commands _responses;
|
||||||
|
Mutex _responses_lock;
|
||||||
|
|
||||||
|
// The remaining members are manipulated by the read thread.
|
||||||
Commands _commands;
|
Commands _commands;
|
||||||
|
|
||||||
// This has to be an actual OS LOCK instead of Panda's Mutex,
|
// This has to be an actual OS LOCK instead of Panda's Mutex,
|
||||||
|
@ -311,6 +311,7 @@ class Messenger:
|
|||||||
|
|
||||||
if taskChain:
|
if taskChain:
|
||||||
# Queue the event onto the indicated task chain.
|
# Queue the event onto the indicated task chain.
|
||||||
|
from direct.task.TaskManagerGlobal import taskMgr
|
||||||
taskMgr.add(self.__lockAndDispatch, name = 'Messenger-%s-%s' % (event, taskChain), extraArgs = [acceptorDict, event, sentArgs, foundWatch], taskChain = taskChain)
|
taskMgr.add(self.__lockAndDispatch, name = 'Messenger-%s-%s' % (event, taskChain), extraArgs = [acceptorDict, event, sentArgs, foundWatch], taskChain = taskChain)
|
||||||
else:
|
else:
|
||||||
# Handle the event immediately.
|
# Handle the event immediately.
|
||||||
|
@ -68,12 +68,18 @@ class BrowserObject:
|
|||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __call__(self, *args):
|
def __call__(self, *args, **kw):
|
||||||
|
needsResponse = True
|
||||||
|
if 'needsResponse' in kw:
|
||||||
|
needsResponse = kw['needsResponse']
|
||||||
|
del kw['needsResponse']
|
||||||
|
if kw:
|
||||||
|
raise ArgumentError, 'Keyword arguments not supported'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
parentObj, attribName = self.__boundMethod
|
parentObj, attribName = self.__boundMethod
|
||||||
if parentObj:
|
if parentObj:
|
||||||
# Call it as a method.
|
# Call it as a method.
|
||||||
needsResponse = True
|
|
||||||
if parentObj is self.__runner.dom and attribName == 'alert':
|
if parentObj is self.__runner.dom and attribName == 'alert':
|
||||||
# As a special hack, we don't wait for the return
|
# As a special hack, we don't wait for the return
|
||||||
# value from the alert() call, since this is a
|
# value from the alert() call, since this is a
|
||||||
@ -98,7 +104,7 @@ class BrowserObject:
|
|||||||
raise AttributeError
|
raise AttributeError
|
||||||
else:
|
else:
|
||||||
# Call it as a plain function.
|
# Call it as a plain function.
|
||||||
result = self.__runner.scriptRequest('call', self, value = args)
|
result = self.__runner.scriptRequest('call', self, value = args, needsResponse = needsResponse)
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
# Some odd problem on the call.
|
# Some odd problem on the call.
|
||||||
raise TypeError
|
raise TypeError
|
||||||
@ -208,11 +214,17 @@ class MethodWrapper:
|
|||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __call__(self, *args):
|
def __call__(self, *args, **kw):
|
||||||
|
needsResponse = True
|
||||||
|
if 'needsResponse' in kw:
|
||||||
|
needsResponse = kw['needsResponse']
|
||||||
|
del kw['needsResponse']
|
||||||
|
if kw:
|
||||||
|
raise ArgumentError, 'Keyword arguments not supported'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
parentObj, attribName = self.__boundMethod
|
parentObj, attribName = self.__boundMethod
|
||||||
# Call it as a method.
|
# Call it as a method.
|
||||||
needsResponse = True
|
|
||||||
if parentObj is self.__runner.dom and attribName == 'alert':
|
if parentObj is self.__runner.dom and attribName == 'alert':
|
||||||
# As a special hack, we don't wait for the return
|
# As a special hack, we don't wait for the return
|
||||||
# value from the alert() call, since this is a
|
# value from the alert() call, since this is a
|
||||||
|
@ -25,6 +25,7 @@ from direct.showbase.DirectObject import DirectObject
|
|||||||
from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, HTTPClient, Thread, WindowProperties
|
from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, HTTPClient, Thread, WindowProperties
|
||||||
from direct.stdpy import file
|
from direct.stdpy import file
|
||||||
from direct.task.TaskManagerGlobal import taskMgr
|
from direct.task.TaskManagerGlobal import taskMgr
|
||||||
|
from direct.showbase.MessengerGlobal import messenger
|
||||||
from direct.showbase import AppRunnerGlobal
|
from direct.showbase import AppRunnerGlobal
|
||||||
|
|
||||||
# These imports are read by the C++ wrapper in p3dPythonRun.cxx.
|
# These imports are read by the C++ wrapper in p3dPythonRun.cxx.
|
||||||
@ -98,6 +99,11 @@ class AppRunner(DirectObject):
|
|||||||
if AppRunnerGlobal.appRunner is None:
|
if AppRunnerGlobal.appRunner is None:
|
||||||
AppRunnerGlobal.appRunner = self
|
AppRunnerGlobal.appRunner = self
|
||||||
|
|
||||||
|
# We use this messenger hook to dispatch this startIfReady()
|
||||||
|
# call back to the main thread.
|
||||||
|
self.accept('startIfReady', self.startIfReady)
|
||||||
|
|
||||||
|
|
||||||
def setSessionId(self, sessionId):
|
def setSessionId(self, sessionId):
|
||||||
""" This message should come in at startup. """
|
""" This message should come in at startup. """
|
||||||
self.sessionId = sessionId
|
self.sessionId = sessionId
|
||||||
@ -167,6 +173,9 @@ class AppRunner(DirectObject):
|
|||||||
if self.gotWindow and self.gotP3DFilename:
|
if self.gotWindow and self.gotP3DFilename:
|
||||||
self.started = True
|
self.started = True
|
||||||
|
|
||||||
|
# Now we can ignore future calls to startIfReady().
|
||||||
|
self.ignore('startIfReady')
|
||||||
|
|
||||||
# Hang a hook so we know when the window is actually opened.
|
# Hang a hook so we know when the window is actually opened.
|
||||||
self.acceptOnce('window-event', self.windowEvent)
|
self.acceptOnce('window-event', self.windowEvent)
|
||||||
|
|
||||||
@ -265,7 +274,8 @@ class AppRunner(DirectObject):
|
|||||||
|
|
||||||
self.gotP3DFilename = True
|
self.gotP3DFilename = True
|
||||||
|
|
||||||
self.startIfReady()
|
# Send this call to the main thread; don't call it directly.
|
||||||
|
messenger.send('startIfReady', taskChain = 'default')
|
||||||
|
|
||||||
def clearWindowPrc(self):
|
def clearWindowPrc(self):
|
||||||
""" Clears the windowPrc file that was created in a previous
|
""" Clears the windowPrc file that was created in a previous
|
||||||
@ -325,7 +335,9 @@ class AppRunner(DirectObject):
|
|||||||
self.windowPrc = loadPrcFileData("setupWindow", data)
|
self.windowPrc = loadPrcFileData("setupWindow", data)
|
||||||
|
|
||||||
self.gotWindow = True
|
self.gotWindow = True
|
||||||
self.startIfReady()
|
|
||||||
|
# Send this call to the main thread; don't call it directly.
|
||||||
|
messenger.send('startIfReady', taskChain = 'default')
|
||||||
|
|
||||||
def setRequestFunc(self, func):
|
def setRequestFunc(self, func):
|
||||||
""" This method is called by the plugin at startup to supply a
|
""" This method is called by the plugin at startup to supply a
|
||||||
@ -468,4 +480,4 @@ if __name__ == '__main__':
|
|||||||
except ArgumentError, e:
|
except ArgumentError, e:
|
||||||
print e.args[0]
|
print e.args[0]
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
run()
|
taskMgr.run()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user