diff --git a/direct/src/p3d/panda3d.pdef b/direct/src/p3d/panda3d.pdef index 5ff1d63ef1..18b7c73f84 100755 --- a/direct/src/p3d/panda3d.pdef +++ b/direct/src/p3d/panda3d.pdef @@ -44,12 +44,21 @@ class panda3d(package): # automatically be included as well, and we end up with a pretty # complete list that way. module('direct.directbase.DirectStart', + 'direct.actor.*', + 'direct.controls.*', + 'direct.directdevices.*', + 'direct.directnotify.*', + 'direct.directtools.*', + 'direct.directutil.*', + 'direct.distributed.*', + 'direct.fsm.*', + 'direct.gui.*', + 'direct.interval.*', + 'direct.particles.*', 'direct.showbase.*', - 'direct.actor.Actor', - 'direct.fsm.FSM', - 'direct.interval.IntervalGlobal', - 'direct.particles.ParticleEffect', - 'direct.directutil.Mopath') + 'direct.showutil.*', + 'direct.stdpy.*') + # Exclude these GUI toolkits; they're big, and many applications don't # use them. We define them as separate, optional packages, below. diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 2d92f6d457..75b8d76f1a 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -404,7 +404,8 @@ check_request() { // Function: P3DInstanceManager::wait_request // Access: Public // Description: Does not return until a request is pending on some -// instance, or until no instances remain. Use +// instance, or until no instances remain, or until the +// indicated time in seconds has elapsed. Use // check_request to retrieve the pending request. Due // to the possibility of race conditions, it is possible // for this function to return when there is in fact no @@ -412,9 +413,60 @@ check_request() { // the request first). //////////////////////////////////////////////////////////////////// void P3DInstanceManager:: -wait_request() { +wait_request(double timeout) { +#ifdef _WIN32 + int stop_tick = int(GetTickCount() + timeout * 1000.0); +#else + struct timeval stop_time; + gettimeofday(&stop_time, NULL); + + int seconds = (int)floor(timeout); + stop_time.tv_sec += seconds; + stop_time.tv_usec += (int)((timeout - seconds) * 1000.0); + if (stop_time.tv_usec > 1000) { + stop_time.tv_usec -= 1000; + ++stop_time.tv_sec; + } +#endif + _request_ready.acquire(); + if (check_request() != (P3DInstance *)NULL) { + _request_ready.release(); + return; + } + if (_instances.empty()) { + _request_ready.release(); + return; + } + + // No pending requests; go to sleep. + _request_ready.wait(timeout); + while (true) { +#ifdef _WIN32 + int remaining_ticks = stop_tick - GetTickCount(); + if (remaining_ticks <= 0) { + break; + } + timeout = remaining_ticks * 0.001; +#else + struct timeval now; + gettimeofday(&now, NULL); + + struct timeval remaining; + remaining.tv_sec = stop_time.tv_sec - now.tv_sec; + remaining.tv_usec = stop_time.tv_usec - now.tv_usec; + + if (remaining.tv_usec < 0) { + remaining.tv_usec += 1000; + --remaining.tv_sec; + } + if (remaining.tv_sec < 0) { + break; + } + timeout = remaining.tv_sec + remaining.tv_usec * 0.001; +#endif + if (check_request() != (P3DInstance *)NULL) { _request_ready.release(); return; @@ -425,7 +477,7 @@ wait_request() { } // No pending requests; go to sleep. - _request_ready.wait(); + _request_ready.wait(timeout); } _request_ready.release(); } diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index cd87cadfb6..6fc6972ce5 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/direct/src/plugin/p3dInstanceManager.h @@ -73,7 +73,7 @@ public: P3DInstance *validate_instance(P3D_instance *instance); P3DInstance *check_request(); - void wait_request(); + void wait_request(double timeout); P3DHost *get_host(const string &host_url); diff --git a/direct/src/plugin/p3d_plugin.cxx b/direct/src/plugin/p3d_plugin.cxx index 26c8160935..417cdab080 100644 --- a/direct/src/plugin/p3d_plugin.cxx +++ b/direct/src/plugin/p3d_plugin.cxx @@ -25,6 +25,7 @@ #include "p3dStringObject.h" #include +#include // Use a simple lock to protect the C-style API functions in this // module from parallel access by multiple threads in the host. @@ -405,21 +406,65 @@ P3D_instance_get_request(P3D_instance *instance) { } P3D_instance * -P3D_check_request(bool wait) { +P3D_check_request(double timeout) { assert(P3DInstanceManager::get_global_ptr()->is_initialized()); ACQUIRE_LOCK(_api_lock); P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3D_instance *inst = inst_mgr->check_request(); - if (inst != NULL || !wait) { + if (inst != NULL || timeout <= 0.0) { RELEASE_LOCK(_api_lock); return inst; } - + +#ifdef _WIN32 + int stop_tick = int(GetTickCount() + timeout * 1000.0); +#else + struct timeval stop_time; + gettimeofday(&stop_time, NULL); + + int seconds = (int)floor(timeout); + stop_time.tv_sec += seconds; + stop_time.tv_usec += (int)((timeout - seconds) * 1000.0); + if (stop_time.tv_usec > 1000) { + stop_time.tv_usec -= 1000; + ++stop_time.tv_sec; + } +#endif + // Now we have to block until a request is available. + RELEASE_LOCK(_api_lock); + inst_mgr->wait_request(timeout); + ACQUIRE_LOCK(_api_lock); + inst = inst_mgr->check_request(); + while (inst == NULL && inst_mgr->get_num_instances() != 0) { +#ifdef _WIN32 + int remaining_ticks = stop_tick - GetTickCount(); + if (remaining_ticks <= 0) { + break; + } + timeout = remaining_ticks * 0.001; +#else + struct timeval now; + gettimeofday(&now, NULL); + + struct timeval remaining; + remaining.tv_sec = stop_time.tv_sec - now.tv_sec; + remaining.tv_usec = stop_time.tv_usec - now.tv_usec; + + if (remaining.tv_usec < 0) { + remaining.tv_usec += 1000; + --remaining.tv_sec; + } + if (remaining.tv_sec < 0) { + break; + } + timeout = remaining.tv_sec + remaining.tv_usec * 0.001; +#endif + RELEASE_LOCK(_api_lock); - inst_mgr->wait_request(); + inst_mgr->wait_request(timeout); ACQUIRE_LOCK(_api_lock); inst = inst_mgr->check_request(); } diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index a53fcf9a51..a9eadecd94 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/direct/src/plugin/p3d_plugin.h @@ -738,10 +738,9 @@ P3D_instance_get_request_func(P3D_instance *instance); If any open instance has a pending request, this function will return a pointer to one of them (which you may then pass to P3D_instance_get_request_func). If no instances have a pending - request, this function will return NULL. If wait is true, this - function will never return NULL unless there are no instances open; - instead, it will wait indefinitely until there is a request - available. + request, this function will return NULL. This function will not + return until at least timeout seconds have elapsed, or a request is + available, whichever comes first. Note that, due to race conditions, it is possible for this function to return a P3D_instance that does not in fact have any requests @@ -749,7 +748,7 @@ P3D_instance_get_request_func(P3D_instance *instance); should always verify that the return value of P3D_instance_get_request() is not NULL. */ typedef P3D_instance * -P3D_check_request_func(bool wait); +P3D_check_request_func(double timeout); /* A request retrieved by P3D_instance_get_request() should eventually be passed here, after it has been handled, to deallocate its diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 090ae27d58..4838bc18ca 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -36,6 +36,9 @@ #endif +// The amount of time in seconds to wait for new messages. +static const double wait_cycle = 0.2; + //////////////////////////////////////////////////////////////////// // Function: Panda3D::Constructor // Access: Public @@ -61,7 +64,7 @@ run(int argc, char *argv[]) { // We prefix a "+" sign to tell gnu getopt not to parse options // following the first not-option parameter. (These will be passed // into the sub-process.) - const char *optstr = "+mu:p:ft:s:o:l:h"; + const char *optstr = "+mu:p:fw:t:s:o:l:h"; bool allow_multiple = false; string download_url = PANDA_PACKAGE_HOST_URL; @@ -92,7 +95,7 @@ run(int argc, char *argv[]) { verify_contents = true; break; - case 't': + case 'w': if (strcmp(optarg, "toplevel") == 0) { window_type = P3D_WT_toplevel; } else if (strcmp(optarg, "embedded") == 0) { @@ -102,7 +105,14 @@ run(int argc, char *argv[]) { } else if (strcmp(optarg, "hidden") == 0) { window_type = P3D_WT_hidden; } else { - cerr << "Invalid value for -t: " << optarg << "\n"; + cerr << "Invalid value for -w: " << optarg << "\n"; + return 1; + } + break; + + case 't': + if (!parse_token(optarg)) { + cerr << "Web tokens (-t) must be of the form token=value: " << optarg << "\n"; return 1; } break; @@ -248,13 +258,13 @@ run(int argc, char *argv[]) { DispatchMessage(&msg); // Check for new requests from the Panda3D plugin. - P3D_instance *inst = P3D_check_request(false); + P3D_instance *inst = P3D_check_request(wait_cycle); 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(wait_cycle); } while (!_url_getters.empty() && @@ -276,7 +286,7 @@ run(int argc, char *argv[]) { // Not an embedded window, so we don't have our own window to // generate Windows events. Instead, just wait for requests. while (!_instances.empty()) { - P3D_instance *inst = P3D_check_request(false); + P3D_instance *inst = P3D_check_request(wait_cycle); if (inst != (P3D_instance *)NULL) { P3D_request *request = P3D_instance_get_request(inst); if (request != (P3D_request *)NULL) { @@ -294,7 +304,7 @@ run(int argc, char *argv[]) { EventLoopRef main_loop = GetMainEventLoop(); EventLoopTimerUPP timer_upp = NewEventLoopTimerUPP(st_timer_callback); EventLoopTimerRef timer; - EventTimerInterval interval = 200 * kEventDurationMillisecond; + EventTimerInterval interval = wait_cycle * kEventDurationSecond; InstallEventLoopTimer(main_loop, interval, interval, timer_upp, this, &timer); RunApplicationEventLoop(); @@ -310,7 +320,7 @@ run(int argc, char *argv[]) { // Now wait while we process pending requests. while (!_instances.empty()) { - P3D_instance *inst = P3D_check_request(false); + P3D_instance *inst = P3D_check_request(wait_cycle); if (inst != (P3D_instance *)NULL) { P3D_request *request = P3D_instance_get_request(inst); if (request != (P3D_request *)NULL) { @@ -647,7 +657,7 @@ create_instance(const string &p3d, P3D_window_type window_type, } // Build up the token list. - pvector tokens; + Tokens tokens = _tokens; P3D_token token; string log_basename; @@ -745,7 +755,11 @@ usage() { << " time, but additional arguments may not be passed to any of the\n" << " applictions.\n\n" - << " -t [toplevel|embedded|fullscreen|hidden]\n" + << " -t token=value\n" + << " Defines a web token or parameter to pass to the application(s).\n" + << " This simulates a entry in an tag.\n\n" + + << " -w [toplevel|embedded|fullscreen|hidden]\n" << " Specify the type of graphic window to create. If you specify\n" << " \"embedded\", a new window is created to be the parent.\n\n" @@ -775,6 +789,33 @@ usage() { << DTOOL_PLATFORM << "\" .\n\n"; } +//////////////////////////////////////////////////////////////////// +// Function: Panda3D::parse_token +// Access: Private +// Description: Parses a web token of the form token=value, and +// stores it in _tokens. Returns true on success, false +// on failure. +//////////////////////////////////////////////////////////////////// +bool Panda3D:: +parse_token(char *arg) { + char *equals = strchr(arg, '='); + if (equals == NULL) { + return false; + } + + // Directly munge the C string to truncate it at the equals sign. + // Classic C tricks. + *equals = '\0'; + P3D_token token; + token._keyword = strdup(arg); + token._value = strdup(equals + 1); + *equals = '='; + + _tokens.push_back(token); + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: Panda3D::parse_int_pair // Access: Private @@ -857,13 +898,13 @@ st_timer_callback(EventLoopTimerRef timer, void *user_data) { void Panda3D:: timer_callback(EventLoopTimerRef timer) { // Check for new requests from the Panda3D plugin. - P3D_instance *inst = P3D_check_request(false); + P3D_instance *inst = P3D_check_request(0.0); 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(0.0); } // Check the download tasks. diff --git a/direct/src/plugin_standalone/panda3d.h b/direct/src/plugin_standalone/panda3d.h index 30e6e26349..e113fd1bf2 100755 --- a/direct/src/plugin_standalone/panda3d.h +++ b/direct/src/plugin_standalone/panda3d.h @@ -63,6 +63,7 @@ private: void delete_instance(P3D_instance *instance); void usage(); + bool parse_token(char *arg); bool parse_int_pair(char *arg, int &x, int &y); void report_downloading_package(P3D_instance *instance); @@ -83,6 +84,9 @@ private: typedef pset Instances; Instances _instances; + typedef pvector Tokens; + Tokens _tokens; + // This nested class keeps track of active URL requests. class URLGetter { public: