bi-directional communication

This commit is contained in:
David Rose 2009-06-11 02:20:43 +00:00
parent 3f42a08968
commit ce182cb038
18 changed files with 407 additions and 249 deletions

View File

@ -6,6 +6,7 @@ from LoggerGlobal import defaultLogger
from direct.showbase import PythonUtil
import time
import types
import sys
class Notifier:
serverDelta = 0
@ -237,7 +238,7 @@ class Notifier:
if self.streamWriter:
self.streamWriter.appendData(string + '\n')
else:
print string
print >> sys.stderr, string
def debugStateCall(self, obj=None, fsmMemberName='fsm',
secondaryFsm='secondaryFSM'):

View File

@ -33,7 +33,7 @@
#define USE_PACKAGES tinyxml python
#define TARGET p3dpython
#define OTHER_LIBS \
#define OTHER_LIBS \
dtoolutil:c dtoolbase:c dtool:m \
interrogatedb:c dconfig:c dtoolconfig:m \
express:c pandaexpress:m \
@ -51,11 +51,19 @@
#end bin_target
#begin bin_target
#define USE_PACKAGES openssl
#define TARGET panda3d
#define OTHER_LIBS \
prc:c dtoolutil:c dtoolbase:c dtool:m \
interrogatedb:c dconfig:c dtoolconfig:m \
express:c pandaexpress:m \
pstatclient:c pandabase:c linmath:c putil:c \
pipeline:c panda:m \
pystub
#define SOURCES \
panda3d.cxx \
$[if $[WINDOWS_PLATFORM],wingetopt.h wingetopt.c]
panda3d.cxx
#define WIN_SYS_LIBS user32.lib gdi32.lib

View File

@ -311,7 +311,7 @@ write_chars(const char *start, size_t length) {
BOOL success = WriteFile(_handle, start, length, &bytes_written, NULL);
if (!success) {
DWORD error = GetLastError();
if (error != ERROR_BROKEN_PIPE) {
if (error != ERROR_NO_DATA && error != ERROR_BROKEN_PIPE) {
cerr
<< "Error writing " << length
<< " bytes, windows error code 0x" << hex

View File

@ -153,6 +153,7 @@ get_request() {
////////////////////////////////////////////////////////////////////
void P3DInstance::
add_request(P3D_request *request) {
cerr << "adding a request\n";
assert(request->_instance == this);
ACQUIRE_LOCK(_request_lock);

View File

@ -23,14 +23,3 @@ INLINE int P3DInstanceManager::
get_num_instances() const {
return _instances.size();
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_dll_filename
// Access: Public
// Description: Returns the DLL filename that was passed to
// initialize().
////////////////////////////////////////////////////////////////////
INLINE const string &P3DInstanceManager::
get_dll_filename() const {
return _dll_filename;
}

View File

@ -46,15 +46,13 @@ P3DInstanceManager::
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::initialize
// Access: Public
// Description: Called by the host at application startup, this
// receives the name of the DLL that contains this code
// (for patching purposes). It returns true if the DLL
// is successfully initialized, false if it should be
// immediately shut down and redownloaded.
// Description: Called by the host at application startup. It
// returns true if the DLL is successfully initialized,
// false if it should be immediately shut down and
// redownloaded.
////////////////////////////////////////////////////////////////////
bool P3DInstanceManager::
initialize(const string &config_xml, const string &dll_filename) {
_dll_filename = dll_filename;
initialize() {
return true;
}

View File

@ -34,7 +34,7 @@ private:
~P3DInstanceManager();
public:
bool initialize(const string &config_xml, const string &dll_filename);
bool initialize();
P3DInstance *
create_instance(P3D_request_ready_func *func,
@ -53,15 +53,12 @@ public:
INLINE int get_num_instances() const;
INLINE const string &get_dll_filename() const;
int get_unique_session_index();
void signal_request_ready();
static P3DInstanceManager *get_global_ptr();
private:
string _dll_filename;
string _p3d_root_directory;
typedef set<P3DInstance *> Instances;

View File

@ -103,16 +103,17 @@ run_python() {
PyErr_Print();
return false;
}
_exit = PyObject_GetAttrString(appmf, "exit");
if (_exit == NULL) {
PyErr_Print();
return false;
}
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
if (_setupWindow == NULL) {
PyErr_Print();
return false;
}
_taskMgr = PyObject_GetAttrString(appmf, "taskMgr");
if (_taskMgr == NULL) {
PyErr_Print();
return false;
}
Py_DECREF(appmf);
// Now add check_comm() as a task.
@ -121,14 +122,8 @@ run_python() {
task_mgr->add(_check_comm_task);
// Finally, get lost in taskMgr.run().
PyObject *taskMgr = PyObject_GetAttrString(appmf, "taskMgr");
if (taskMgr == NULL) {
PyErr_Print();
return false;
}
cerr << "calling run()\n";
PyObject *done = PyObject_CallMethod(taskMgr, "run", "");
PyObject *done = PyObject_CallMethod(_taskMgr, "run", "");
if (done == NULL) {
PyErr_Print();
return false;
@ -136,8 +131,6 @@ run_python() {
Py_DECREF(done);
cerr << "done calling run()\n";
Py_DECREF(taskMgr);
return true;
}
@ -165,6 +158,8 @@ handle_command(TiXmlDocument *doc) {
if (xcommand->Attribute("id", &id)) {
terminate_instance(id);
}
} else if (strcmp(cmd, "exit") == 0) {
terminate_session();
} else {
cerr << "Unhandled command " << cmd << "\n";
@ -251,6 +246,7 @@ void P3DPythonRun::
join_read_thread() {
cerr << "waiting for thread\n";
_read_thread_continue = false;
_pipe_read.close();
#ifdef _WIN32
assert(_read_thread != NULL);
@ -346,11 +342,14 @@ terminate_session() {
}
_instances.clear();
PyObject *result = PyObject_CallFunction(_exit, "");
cerr << "calling stop()\n";
PyObject *result = PyObject_CallMethod(_taskMgr, "stop", "");
if (result == NULL) {
PyErr_Print();
return;
}
Py_XDECREF(result);
Py_DECREF(result);
cerr << "done calling stop()\n";
}
////////////////////////////////////////////////////////////////////
@ -372,7 +371,21 @@ rt_thread_run() {
return;
}
// Successfully read an XML document. Feed it to the parent.
// Successfully read an XML document.
// Check for one special case: the "exit" command means we shut
// down the read thread along with everything else.
TiXmlElement *xcommand = doc->FirstChildElement("command");
if (xcommand != NULL) {
const char *cmd = xcommand->Attribute("cmd");
if (cmd != NULL) {
if (strcmp(cmd, "exit") == 0) {
_read_thread_continue = false;
}
}
}
// Feed the command up to the parent.
ACQUIRE_LOCK(_commands_lock);
_commands.push_back(doc);
RELEASE_LOCK(_commands_lock);

View File

@ -90,8 +90,8 @@ private:
char **_py_argv;
PyObject *_runPackedApp;
PyObject *_exit;
PyObject *_setupWindow;
PyObject *_taskMgr;
PT(GenericAsyncTask) _check_comm_task;

View File

@ -34,6 +34,10 @@ P3DSession(P3DInstance *inst) {
_python_version = inst->get_python_version();
_python_root_dir = "C:/p3drun";
INIT_LOCK(_instances_lock);
_read_thread_continue = false;
string p3dpython = "c:/cygwin/home/drose/player/direct/built/bin/p3dpython.exe";
// string p3dpython = _python_root_dir + "/p3dpython.exe";
@ -122,12 +126,15 @@ P3DSession(P3DInstance *inst) {
_pipe_read.open_read(r_from);
_pipe_write.open_write(w_to);
#endif // _WIN32
if (!_pipe_read) {
cerr << "unable to open read pipe\n";
}
if (!_pipe_write) {
cerr << "unable to open write pipe\n";
}
spawn_read_thread();
}
////////////////////////////////////////////////////////////////////
@ -139,13 +146,34 @@ P3DSession(P3DInstance *inst) {
P3DSession::
~P3DSession() {
if (_started_p3dpython) {
cerr << "Terminating process.\n";
// Messy. Shouldn't use TerminateProcess unless necessary.
TerminateProcess(_p3dpython.hProcess, 2);
// Tell the process we're going away.
TiXmlDocument doc;
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
TiXmlElement *xcommand = new TiXmlElement("command");
xcommand->SetAttribute("cmd", "exit");
doc.LinkEndChild(decl);
doc.LinkEndChild(xcommand);
_pipe_write << doc << flush;
// Also close the pipe, to help underscore the point.
_pipe_write.close();
_pipe_read.close();
#ifdef _WIN32
// Now give the process a chance to terminate itself cleanly.
if (WaitForSingleObject(_p3dpython.hProcess, 2000) == WAIT_TIMEOUT) {
// It didn't shut down cleanly, so kill it the hard way.
cerr << "Terminating process.\n";
TerminateProcess(_p3dpython.hProcess, 2);
}
CloseHandle(_p3dpython.hProcess);
CloseHandle(_p3dpython.hThread);
#endif
}
join_read_thread();
DESTROY_LOCK(_instances_lock);
}
////////////////////////////////////////////////////////////////////
@ -164,8 +192,10 @@ start_instance(P3DInstance *inst) {
assert(inst->get_session_key() == _session_key);
assert(inst->get_python_version() == _python_version);
ACQUIRE_LOCK(_instances_lock);
inst->_session = this;
bool inserted = _instances.insert(inst).second;
bool inserted = _instances.insert(Instances::value_type(inst->get_instance_id(), inst)).second;
RELEASE_LOCK(_instances_lock);
assert(inserted);
TiXmlDocument doc;
@ -201,8 +231,118 @@ terminate_instance(P3DInstance *inst) {
_pipe_write << doc << flush;
ACQUIRE_LOCK(_instances_lock);
if (inst->_session == this) {
inst->_session = NULL;
_instances.erase(inst);
_instances.erase(inst->get_instance_id());
}
RELEASE_LOCK(_instances_lock);
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::spawn_read_thread
// Access: Private
// Description: Starts the read thread. This thread is responsible
// for reading the standard input socket for XML
// requests and storing them in the _requests queue.
////////////////////////////////////////////////////////////////////
void P3DSession::
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);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::join_read_thread
// Access: Private
// Description: Waits for the read thread to stop.
////////////////////////////////////////////////////////////////////
void P3DSession::
join_read_thread() {
cerr << "session waiting for thread\n";
_read_thread_continue = false;
_pipe_read.close();
#ifdef _WIN32
assert(_read_thread != NULL);
WaitForSingleObject(_read_thread, INFINITE);
CloseHandle(_read_thread);
_read_thread = NULL;
#endif
cerr << "session done waiting for thread\n";
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::rt_thread_run
// Access: Private
// Description: The main function for the read thread.
////////////////////////////////////////////////////////////////////
void P3DSession::
rt_thread_run() {
cerr << "session thread reading.\n";
while (_read_thread_continue) {
TiXmlDocument *doc = new TiXmlDocument;
_pipe_read >> *doc;
if (!_pipe_read || _pipe_read.eof()) {
// Some error on reading. Abort.
cerr << "Error on session reading.\n";
rt_terminate();
return;
}
// Successfully read an XML document.
cerr << "Session got request: " << *doc << "\n";
// TODO: feed the request up to the parent.
delete doc;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::rt_terminate
// Access: Private
// Description: Got a closed pipe from the sub-process. Send a
// terminate request for all instances.
////////////////////////////////////////////////////////////////////
void P3DSession::
rt_terminate() {
Instances icopy;
ACQUIRE_LOCK(_instances_lock);
icopy = _instances;
RELEASE_LOCK(_instances_lock);
// TODO: got a race condition here. What happens if someone deletes
// an instance while we're processing this loop?
for (Instances::iterator ii = icopy.begin(); ii != icopy.end(); ++ii) {
P3DInstance *inst = (*ii).second;
P3D_request *request = new P3D_request;
request->_instance = inst;
request->_request_type = P3D_RT_stop;
inst->add_request(request);
}
}
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DPython::win_rt_thread_run
// Access: Private, Static
// Description: The Windows flavor of the thread callback function.
////////////////////////////////////////////////////////////////////
DWORD P3DSession::
win_rt_thread_run(LPVOID data) {
((P3DSession *)data)->rt_thread_run();
return 0;
}
#endif

View File

@ -42,22 +42,43 @@ public:
INLINE int get_num_instances() const;
private:
void spawn_read_thread();
void join_read_thread();
private:
// These methods run only within the read thread.
void rt_thread_run();
void rt_terminate();
#ifdef _WIN32
static DWORD WINAPI win_rt_thread_run(LPVOID data);
#endif
private:
string _session_key;
string _python_version;
string _python_root_dir;
typedef set<P3DInstance *> Instances;
typedef map<int, P3DInstance *> Instances;
Instances _instances;
LOCK _instances_lock;
// Members for communicating with the p3dpython child process.
bool _started_p3dpython;
#ifdef _WIN32
PROCESS_INFORMATION _p3dpython;
#endif
// The remaining members are manipulated by the read thread.
HandleStream _pipe_read;
HandleStream _pipe_write;
bool _read_thread_continue;
#ifdef _WIN32
HANDLE _read_thread;
#endif
};
#include "p3dSession.I"

View File

@ -23,24 +23,14 @@ bool initialized_lock = false;
LOCK _lock;
bool
P3D_initialize(const char *config_xml, const char *dll_filename) {
string config_xml_str;
if (config_xml != NULL) {
config_xml_str = config_xml;
}
string dll_filename_str;
if (dll_filename != NULL) {
dll_filename_str = dll_filename;
}
P3D_initialize() {
if (!initialized_lock) {
INIT_LOCK(_lock);
initialized_lock = true;
}
ACQUIRE_LOCK(_lock);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
bool result = inst_mgr->initialize(config_xml_str, dll_filename_str);
bool result = inst_mgr->initialize();
RELEASE_LOCK(_lock);
return result;
}

View File

@ -74,22 +74,14 @@ extern "C" {
to being specific to a particular instance. */
/* This function should be called immediately after the plugin is
loaded. The config_xml parameter is the plugin configuration data,
formatted as an XML stream (it contains the XML data itself; it is
not a filename). The exact contents of this XML stream are
documented elsewhere. This config_xml parameter may be the empty
string or NULL; if so, the plugin will use its own internal default
configuration.
The dll_filename parameter is the filename of the plugin's dll
itself, which is needed for self-patching.
loaded.
This function returns true if the plugin is valid, false otherwise.
If it returns false, the host should not call any more functions in
this API, and should immediately unload the DLL and (if possible)
download a new one. */
typedef bool
P3D_initialize_func(const char *config_xml, const char *dll_filename);
P3D_initialize_func();
/* This function frees a pointer returned by
P3D_instance_get_property(), or another similar function that
@ -266,7 +258,6 @@ P3D_instance_set_property_func(P3D_instance *instance,
typedef enum {
P3D_RT_stop,
P3D_RT_new_config_xml,
P3D_RT_patch,
P3D_RT_get_url,
P3D_RT_post_url,
} P3D_request_type;
@ -291,16 +282,6 @@ typedef struct {
const char *_config_xml;
} P3D_request_new_config_xml;
/* A patch request. The plugin has determined that it is out of date
and needs to be patched. It has already applied the patch to
itself, and the resulting patched dll is referenced in the request
data. The host should respond by finishing all active instances,
unloading the DLL, moving the patched dll onto the original DLL,
and reloading the DLL and (optionally) restarting the instances. */
typedef struct {
const char *_patched_filename;
} P3D_request_patch;
/* A get_url request. The plugin would like to retrieve data for a
particular URL. The plugin is responsible for supplying a valid
URL string, and a unique integer ID. The unique ID is needed to
@ -334,7 +315,6 @@ typedef struct {
union {
P3D_request_stop _stop;
P3D_request_new_config_xml _new_config_xml;
P3D_request_patch _patch;
P3D_request_get_url _get_url;
P3D_request_post_url _post_url;
} _request;

View File

@ -12,20 +12,34 @@
//
////////////////////////////////////////////////////////////////////
#include "p3d_plugin.h"
// This program must link with Panda for HTTPClient support. This
// means it probably should be built with LINK_ALL_STATIC defined, so
// we won't have to deal with confusing .dll or .so files that might
// compete on the disk with the dynamically-loaded versions. There's
// no competition in memory address space, though, because
// p3d_plugin--the only file we dynamically link in--doesn't itself
// link with Panda.
#include <iostream>
#include <string>
#include <math.h>
#include "pandabase.h"
#ifdef _WIN32
#include "wingetopt.h"
#include <windows.h>
#else
#include <getopt.h>
#endif
using namespace std;
#include "httpClient.h"
#include "httpChannel.h"
#include "Ramfile.h"
#include "thread.h"
#include "p3d_plugin.h"
#include "pset.h"
#ifndef HAVE_GETOPT
#include "gnu_getopt.h"
#else
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#endif
static const string default_plugin_filename = "libp3d_plugin";
@ -41,9 +55,88 @@ P3D_check_request_func *P3D_check_request;
P3D_request_finish_func *P3D_request_finish;
P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
typedef pset<P3D_instance *> Instances;
Instances _instances;
class URLGetterThread : public Thread {
public:
URLGetterThread(P3D_instance *instance,
int unique_id,
const URLSpec &url,
const string &post_data);
protected:
virtual void thread_main();
private:
P3D_instance *_instance;
int _unique_id;
URLSpec _url;
string _post_data;
};
URLGetterThread::
URLGetterThread(P3D_instance *instance,
int unique_id,
const URLSpec &url,
const string &post_data) :
Thread(url, "URLGetter"),
_instance(instance),
_unique_id(unique_id),
_url(url),
_post_data(post_data)
{
}
void URLGetterThread::
thread_main() {
HTTPClient *http = HTTPClient::get_global_ptr();
cerr << "Getting URL " << _url << "\n";
PT(HTTPChannel) channel = http->make_channel(false);
if (_post_data.empty()) {
channel->begin_get_document(_url);
} else {
channel->begin_post_form(_url, _post_data);
}
Ramfile rf;
channel->download_to_ram(&rf);
size_t bytes_sent = 0;
while (channel->run()) {
if (rf.get_data_size() != 0) {
// Got some new data.
P3D_instance_feed_url_stream
(_instance, _unique_id, P3D_RC_in_progress,
channel->get_status_code(),
channel->get_file_size(),
(const unsigned char *)rf.get_data().data(), rf.get_data_size());
bytes_sent += rf.get_data_size();
rf.clear();
}
}
// All done.
P3D_result_code status = P3D_RC_done;
if (!channel->is_valid()) {
if (channel->get_status_code() != 0) {
status = P3D_RC_http_error;
} else {
status = P3D_RC_generic_error;
}
}
P3D_instance_feed_url_stream
(_instance, _unique_id, status,
channel->get_status_code(),
bytes_sent, NULL, 0);
cerr << "Done getting URL " << _url << ", got " << bytes_sent << " bytes\n";
}
bool
load_plugin(const string &config_xml_filename,
const string &p3d_plugin_filename) {
load_plugin(const string &p3d_plugin_filename) {
string filename = p3d_plugin_filename;
if (filename.empty()) {
// Look for the plugin along the path.
@ -102,7 +195,7 @@ load_plugin(const string &config_xml_filename,
}
// Successfully loaded.
if (!P3D_initialize(NULL, filename.c_str())) {
if (!P3D_initialize()) {
// Oops, failure to initialize.
return false;
}
@ -116,12 +209,40 @@ handle_request(P3D_request *request) {
switch (request->_request_type) {
case P3D_RT_stop:
cerr << "Got P3D_RT_stop\n";
P3D_instance_finish(request->_instance);
_instances.erase(request->_instance);
#ifdef _WIN32
// Post a silly message to spin the event loop.
PostMessage(NULL, WM_USER, 0, 0);
#endif
handled = true;
break;
case P3D_RT_get_url:
cerr << "Got P3D_RT_get_url\n";
{
PT(URLGetterThread) thread = new URLGetterThread
(request->_instance, request->_request._get_url._unique_id,
URLSpec(request->_request._get_url._url), "");
thread->start(TP_normal, false);
}
break;
case P3D_RT_post_url:
cerr << "Got P3D_RT_post_url\n";
{
PT(URLGetterThread) thread = new URLGetterThread
(request->_instance, request->_request._post_url._unique_id,
URLSpec(request->_request._post_url._url),
string(request->_request._post_url._post_data, request->_request._post_url._post_data_size));
thread->start(TP_normal, false);
}
break;
default:
// Some request types are not handled.
cerr << "Unhandled request: " << request->_request_type << "\n";
break;
};
@ -189,12 +310,6 @@ usage() {
<< "Options:\n\n"
<< " -c config.xml\n"
<< " Specify the name of the config.xml file that informs the Panda\n"
<< " plugin where to download patches and such. This is normally\n"
<< " not necessary to specify, since it is already stored within\n"
<< " the Panda plugin itself.\n\n"
<< " -p p3d_plugin.dll\n"
<< " Specify the full path to the particular Panda plugin DLL to\n"
<< " run. Normally, this will be found by searching in the usual\n"
@ -231,9 +346,8 @@ int
main(int argc, char *argv[]) {
extern char *optarg;
extern int optind;
const char *optstr = "c:p:t:s:o:h";
const char *optstr = "p:t:s:o:h";
string config_xml_filename;
string p3d_plugin_filename;
P3D_window_type window_type = P3D_WT_toplevel;
int win_x = 0, win_y = 0;
@ -243,10 +357,6 @@ main(int argc, char *argv[]) {
while (flag != EOF) {
switch (flag) {
case 'c':
config_xml_filename = optarg;
break;
case 'p':
p3d_plugin_filename = optarg;
break;
@ -297,7 +407,7 @@ main(int argc, char *argv[]) {
return 1;
}
if (!load_plugin(config_xml_filename, p3d_plugin_filename)) {
if (!load_plugin(p3d_plugin_filename)) {
cerr << "Unable to load Panda3D plugin.\n";
return 1;
}
@ -342,50 +452,75 @@ main(int argc, char *argv[]) {
int inst_x = win_x + xi * inst_width;
int inst_y = win_y + yi * inst_height;
P3D_create_instance
P3D_instance *inst = P3D_create_instance
(NULL, argv[i + 1],
P3D_WT_embedded, inst_x, inst_y, inst_width, inst_height, parent_window,
NULL, 0);
_instances.insert(inst);
}
}
} else {
// Not an embedded window. Create each window with the same parameters.
for (int i = 0; i < num_instances; ++i) {
P3D_create_instance
P3D_instance *inst = P3D_create_instance
(NULL, argv[i + 1],
window_type, win_x, win_y, win_width, win_height, parent_window,
NULL, 0);
_instances.insert(inst);
}
}
#ifdef _WIN32
// Wait for new messages from Windows, and new requests from the
// plugin.
MSG msg;
int retval;
retval = GetMessage(&msg, NULL, 0, 0);
while (retval != 0) {
if (retval == -1) {
cerr << "Error processing message queue.\n";
exit(1);
if (window_type == P3D_WT_embedded) {
// Wait for new messages from Windows, and new requests from the
// plugin.
MSG msg;
int retval;
retval = GetMessage(&msg, NULL, 0, 0);
while (retval != 0 && !_instances.empty()) {
if (retval == -1) {
cerr << "Error processing message queue.\n";
exit(1);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
// Check for new requests from the Panda3D plugin.
P3D_instance *inst = P3D_check_request(false);
while (inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) {
handle_request(request);
}
inst = P3D_check_request(false);
}
retval = GetMessage(&msg, NULL, 0, 0);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
cerr << "WM_QUIT\n";
// WM_QUIT has been received. Terminate all instances, and fall
// through.
Instances::iterator ii;
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
P3D_instance_finish(*ii);
}
_instances.clear();
// Check for new requests from the Panda3D plugin.
P3D_instance *inst = P3D_check_request(false);
} else {
// Not an embedded window, so we don't have our own window to
// generate Windows events. Instead, just wait for requests.
P3D_instance *inst = P3D_check_request(true);
while (inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) {
handle_request(request);
}
inst = P3D_check_request(false);
inst = P3D_check_request(true);
}
retval = GetMessage(&msg, NULL, 0, 0);
}
#else
#endif
// Now wait while we process pending requests.
P3D_instance *inst = P3D_check_request(true);
@ -396,7 +531,6 @@ main(int argc, char *argv[]) {
}
inst = P3D_check_request(true);
}
#endif
// All instances have finished; we can exit.

View File

@ -1,76 +0,0 @@
/*
POSIX getopt for Windows
AT&T Public License
Code given out at the 1985 UNIFORUM conference in Dallas.
*/
#ifndef __GNUC__
#include "wingetopt.h"
#include <stdio.h>
#include <string.h>
//#define NULL 0
#define EOF (-1)
#define ERR(s, c) if(opterr){\
char errbuf[2];\
errbuf[0] = c; errbuf[1] = '\n';\
fputs(argv[0], stderr);\
fputs(s, stderr);\
fputc(c, stderr);}
//(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
//(void) write(2, s, (unsigned)strlen(s));\
//(void) write(2, errbuf, 2);}
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int
getopt(int argc, char **argv, const char *opts)
{
static int sp = 1;
register int c;
register char *cp;
if(sp == 1)
if(optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return(EOF);
else if(strcmp(argv[optind], "--") == NULL) {
optind++;
return(EOF);
}
optopt = c = argv[optind][sp];
if(c == ':' || (cp=strchr(opts, c)) == NULL) {
ERR(": illegal option -- ", c);
if(argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return('?');
}
if(*++cp == ':') {
if(argv[optind][sp+1] != '\0')
optarg = &argv[optind++][sp+1];
else if(++optind >= argc) {
ERR(": option requires an argument -- ", c);
sp = 1;
return('?');
} else
optarg = argv[optind++];
sp = 1;
} else {
if(argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return(c);
}
#endif /* __GNUC__ */

View File

@ -1,32 +0,0 @@
/*
POSIX getopt for Windows
AT&T Public License
Code given out at the 1985 UNIFORUM conference in Dallas.
*/
#ifdef __GNUC__
#include <getopt.h>
#endif
#ifndef __GNUC__
#ifndef _WINGETOPT_H_
#define _WINGETOPT_H_
#ifdef __cplusplus
extern "C" {
#endif
extern int opterr;
extern int optind;
extern int optopt;
extern char *optarg;
extern int getopt(int argc, char **argv, const char *opts);
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H_ */
#endif /* __GNUC__ */

View File

@ -230,7 +230,7 @@ class AppPacker:
bamFile = BamFile()
stream = StringStream()
bamFile.openWrite(stream)
bamFile.getWriter().setFileTextureMode(BTMUnchanged)
bamFile.getWriter().setFileTextureMode(bamFile.BTMUnchanged)
bamFile.writeObject(node)
bamFile.close()

View File

@ -44,6 +44,11 @@ def initPackedAppEnvironment():
__packedAppEnvironmentInitialized = True
# We need to make sure sys.stdout maps to sys.stderr instead, so
# if someone makes an unadorned print command within Python code,
# it won't muck up the data stream between parent and child.
sys.stdout = sys.stderr
vfs = VirtualFileSystem.getGlobalPtr()
# Clear *all* the mount points, including "/", so that we no
@ -145,17 +150,6 @@ def setupWindow(windowType, x, y, width, height, parent):
loadPrcFileData("setupWindow", data)
def add_check_comm(func, this):
""" This function is provided just a convenience for
p3dPythonRun.cxx. It adds the indicated function to the task
manager with the appropriate parameters for the check_comm
task. """
return taskMgr.add(func, "check_comm", sort = -50, extraArgs = [this],
appendTask = True)
def exit():
taskMgr.stop()
if __name__ == '__main__':
try:
runPackedApp(sys.argv[1:])