diff --git a/direct/src/directnotify/Notifier.py b/direct/src/directnotify/Notifier.py index e7586efaff..152f4de77a 100644 --- a/direct/src/directnotify/Notifier.py +++ b/direct/src/directnotify/Notifier.py @@ -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'): diff --git a/direct/src/plugin/Sources.pp b/direct/src/plugin/Sources.pp index 871a783c14..528005e581 100644 --- a/direct/src/plugin/Sources.pp +++ b/direct/src/plugin/Sources.pp @@ -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 diff --git a/direct/src/plugin/handleStreamBuf.cxx b/direct/src/plugin/handleStreamBuf.cxx index 465e39318d..e08d6f658a 100644 --- a/direct/src/plugin/handleStreamBuf.cxx +++ b/direct/src/plugin/handleStreamBuf.cxx @@ -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 diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 09d78f3022..59b7ae948b 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -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); diff --git a/direct/src/plugin/p3dInstanceManager.I b/direct/src/plugin/p3dInstanceManager.I index a4ee3838b4..783c7b98f1 100644 --- a/direct/src/plugin/p3dInstanceManager.I +++ b/direct/src/plugin/p3dInstanceManager.I @@ -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; -} diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 578744ee6e..7f64635087 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -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; } diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index d5c9103a60..00ea869361 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/direct/src/plugin/p3dInstanceManager.h @@ -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 Instances; diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index 883fe6865d..63c027a34d 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -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); diff --git a/direct/src/plugin/p3dPythonRun.h b/direct/src/plugin/p3dPythonRun.h index fe510ee996..74d9863068 100755 --- a/direct/src/plugin/p3dPythonRun.h +++ b/direct/src/plugin/p3dPythonRun.h @@ -90,8 +90,8 @@ private: char **_py_argv; PyObject *_runPackedApp; - PyObject *_exit; PyObject *_setupWindow; + PyObject *_taskMgr; PT(GenericAsyncTask) _check_comm_task; diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index d84b43805f..634accd3ab 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -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 diff --git a/direct/src/plugin/p3dSession.h b/direct/src/plugin/p3dSession.h index fb0758ac8c..24aa3fcc7f 100644 --- a/direct/src/plugin/p3dSession.h +++ b/direct/src/plugin/p3dSession.h @@ -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 Instances; + typedef map 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" diff --git a/direct/src/plugin/p3d_plugin.cxx b/direct/src/plugin/p3d_plugin.cxx index f3d58e809a..cdb1b08ebd 100644 --- a/direct/src/plugin/p3d_plugin.cxx +++ b/direct/src/plugin/p3d_plugin.cxx @@ -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; } diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index d7f6375a8e..373f0450d1 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/direct/src/plugin/p3d_plugin.h @@ -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; diff --git a/direct/src/plugin/panda3d.cxx b/direct/src/plugin/panda3d.cxx index 8ec3128e56..4d2eb18cce 100644 --- a/direct/src/plugin/panda3d.cxx +++ b/direct/src/plugin/panda3d.cxx @@ -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 -#include -#include +#include "pandabase.h" #ifdef _WIN32 -#include "wingetopt.h" #include -#else -#include #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 + #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 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. diff --git a/direct/src/plugin/wingetopt.c b/direct/src/plugin/wingetopt.c deleted file mode 100644 index bf82b6435b..0000000000 --- a/direct/src/plugin/wingetopt.c +++ /dev/null @@ -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 -#include - -//#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__ */ diff --git a/direct/src/plugin/wingetopt.h b/direct/src/plugin/wingetopt.h deleted file mode 100644 index f48590f30a..0000000000 --- a/direct/src/plugin/wingetopt.h +++ /dev/null @@ -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 -#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__ */ diff --git a/direct/src/showbase/MakeAppMF.py b/direct/src/showbase/MakeAppMF.py index d1608152dd..2dfa827e8e 100644 --- a/direct/src/showbase/MakeAppMF.py +++ b/direct/src/showbase/MakeAppMF.py @@ -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() diff --git a/direct/src/showbase/RunAppMF.py b/direct/src/showbase/RunAppMF.py index 9b64a98db6..ff1aea31e7 100644 --- a/direct/src/showbase/RunAppMF.py +++ b/direct/src/showbase/RunAppMF.py @@ -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:])