Browse Source

add p3dpythonw.exe, more robust startup

David Rose 16 years ago
parent
commit
a308a4a01c

+ 2 - 0
direct/src/p3d/Packager.py

@@ -2411,6 +2411,8 @@ class Packager:
         # extensions are automatically replaced with the appropriate
         # platform-specific extensions.
         self.do_file('p3dpython.exe')
+        if PandaSystem.getPlatform().startswith('win'):
+            self.do_file('p3dpythonw.exe')
         self.do_file('libp3dpython.dll')
 
     def do_freeze(self, filename, compileToExe = False):

+ 46 - 0
direct/src/plugin/Sources.pp

@@ -183,6 +183,52 @@
   #define WIN_SYS_LIBS user32.lib
 #end bin_target
 
+#begin bin_target
+  // Windows requires a special executable, p3dpythonw.exe, to launch
+  // a desktop-friendly application.
+  #define BUILD_TARGET $[and $[HAVE_TINYXML],$[HAVE_PYTHON],$[HAVE_OPENSSL],$[WINDOWS_PLATFORM]]
+  #define USE_PACKAGES tinyxml python openssl
+  #define TARGET p3dpythonw
+  #define EXTRA_CDEFS NON_CONSOLE
+
+  #define OTHER_LIBS \
+    dtoolutil:c dtoolbase:c dtool:m \
+    interrogatedb:c dconfig:c dtoolconfig:m \
+    express:c pandaexpress:m \
+    pgraph:c pgraphnodes:c cull:c gsgbase:c gobj:c \
+    mathutil:c lerp:c downloader:c pnmimage:c \
+    prc:c pstatclient:c pandabase:c linmath:c putil:c \
+    pipeline:c event:c nativenet:c net:c display:c panda:m
+
+  #define SOURCES \
+    binaryXml.cxx binaryXml.h \
+    fhandle.h \
+    handleStream.cxx handleStream.h handleStream.I \
+    handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
+    p3d_lock.h p3d_plugin.h \
+    p3d_plugin_config.h \
+    p3dCInstance.cxx \
+    p3dCInstance.h p3dCInstance.I \
+    p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I \
+    run_p3dpython.h run_p3dpython.cxx
+
+  #define SOURCES $[SOURCES] \
+    p3dPythonMain.cxx
+
+  // If you have to link with a static Python library, define it here.
+  #define EXTRA_LIBS $[EXTRA_P3DPYTHON_LIBS]
+  #define OSX_SYS_FRAMEWORKS Carbon
+
+  #if $[OSX_PLATFORM]
+    // Not entirely sure why this option is required for OSX, but we
+    // get objections about ___dso_handle otherwise--but only when
+    // building universal binaries.
+    #define LFLAGS $[LFLAGS] -undefined dynamic_lookup
+  #endif
+
+  #define WIN_SYS_LIBS user32.lib
+#end bin_target
+
 #begin static_lib_target
   #define BUILD_TARGET $[and $[HAVE_TINYXML],$[HAVE_OPENSSL]]
   #define TARGET plugin_common

+ 2 - 2
direct/src/plugin/load_plugin.cxx

@@ -128,7 +128,7 @@ load_plugin(const string &p3d_plugin_filename,
             const string &contents_filename, const string &download_url, 
             bool verify_contents, const string &platform,
             const string &log_directory, const string &log_basename,
-            bool trusted_environment,
+            bool trusted_environment, bool console_environment,
             ostream &logfile) {
   string filename = p3d_plugin_filename;
   if (filename.empty()) {
@@ -313,7 +313,7 @@ load_plugin(const string &p3d_plugin_filename,
   if (!P3D_initialize(P3D_API_VERSION, contents_filename.c_str(),
                       download_url.c_str(), verify_contents, platform.c_str(),
                       log_directory.c_str(), log_basename.c_str(),
-                      trusted_environment)) {
+                      trusted_environment, console_environment)) {
     // Oops, failure to initialize.
     logfile << "Failed to initialize plugin (wrong API version?)\n";
     unload_plugin();

+ 1 - 1
direct/src/plugin/load_plugin.h

@@ -64,7 +64,7 @@ load_plugin(const string &p3d_plugin_filename,
             const string &contents_filename, const string &download_url,
             bool verify_contents, const string &platform,
             const string &log_directory, const string &log_basename,
-            bool trusted_environment,
+            bool trusted_environment, bool console_environment,
             ostream &logfile);
 void unload_plugin();
 bool is_plugin_loaded();

+ 44 - 5
direct/src/plugin/p3dInstance.cxx

@@ -864,15 +864,54 @@ start_download(P3DDownload *download) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DInstance::request_stop
+//     Function: P3DInstance::request_stop_sub_thread
 //       Access: Public
 //  Description: Asks the host to shut down this particular instance,
 //               presumably because the user has indicated it should
-//               exit.
+//               exit.  This call may be made in any thread.
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
-request_stop() {
+request_stop_sub_thread() {
+  // Atomically check _requested_stop.
+  bool add_request = false;
+  ACQUIRE_LOCK(_request_lock);
+  if (!_requested_stop) {
+    _requested_stop = true;
+    add_request = true;
+  }
+  RELEASE_LOCK(_request_lock);
+
+  // If we haven't requested a stop already, do it now.
+  if (add_request) {
+    TiXmlDocument *doc = new TiXmlDocument;
+    TiXmlElement *xrequest = new TiXmlElement("request");
+    xrequest->SetAttribute("rtype", "stop");
+    doc->LinkEndChild(xrequest);
+    
+    add_raw_request(doc);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::request_stop_main_thread
+//       Access: Public
+//  Description: Asks the host to shut down this particular instance,
+//               presumably because the user has indicated it should
+//               exit.  This call may only be made in the main thread.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+request_stop_main_thread() {
+  // Atomically check _requested_stop.
+  bool add_request = false;
+  ACQUIRE_LOCK(_request_lock);
   if (!_requested_stop) {
+    _requested_stop = true;
+    add_request = true;
+  }
+  RELEASE_LOCK(_request_lock);
+
+  // If we haven't requested a stop already, do it now.
+  if (add_request) {
     _requested_stop = true;
     P3D_request *request = new P3D_request;
     request->_request_type = P3D_RT_stop;
@@ -1533,7 +1572,7 @@ handle_script_request(const string &operation, P3D_object *object,
 
   } else if (operation == "set_property") {
     bool result = 
-      P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), value);
+      P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), true, value);
     
     TiXmlElement *xvalue = new TiXmlElement("value");
     xvalue->SetAttribute("type", "bool");
@@ -1541,7 +1580,7 @@ handle_script_request(const string &operation, P3D_object *object,
     xcommand->LinkEndChild(xvalue);
 
   } else if (operation == "del_property") {
-    bool result = P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), NULL);
+    bool result = P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), true, NULL);
     
     TiXmlElement *xvalue = new TiXmlElement("value");
     xvalue->SetAttribute("type", "bool");

+ 2 - 1
direct/src/plugin/p3dInstance.h

@@ -98,7 +98,8 @@ public:
   inline bool is_trusted() const;
   void start_download(P3DDownload *download);
   inline bool is_started() const;
-  void request_stop();
+  void request_stop_sub_thread();
+  void request_stop_main_thread();
   void request_refresh();
 
   TiXmlElement *make_xml();

+ 19 - 1
direct/src/plugin/p3dInstanceManager.I

@@ -127,13 +127,31 @@ get_log_pathname() const {
 //               file will be run without checking its signature.
 //
 //               This should generally be true only when run by
-//               panda3d.exe, and not when run by the web plugin.
+//               panda3d.exe or panda3dw.exe, and not when run by the
+//               web plugin.
 ////////////////////////////////////////////////////////////////////
 inline bool P3DInstanceManager::
 get_trusted_environment() const {
   return _trusted_environment;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::get_console_environment
+//       Access: Public
+//  Description: Returns the value of the console_environment flag
+//               passed to the constructor.  If this is true, it means
+//               we are running from a text-based console window, and
+//               not from a desktop environment.
+//
+//               This should generally be true only when run by
+//               panda3d.exe, and not when run by the web plugin or by
+//               panda3dw.exe.
+////////////////////////////////////////////////////////////////////
+inline bool P3DInstanceManager::
+get_console_environment() const {
+  return _console_environment;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::get_super_mirror
 //       Access: Public

+ 3 - 1
direct/src/plugin/p3dInstanceManager.cxx

@@ -172,8 +172,10 @@ bool P3DInstanceManager::
 initialize(const string &contents_filename, const string &download_url,
            bool verify_contents,
            const string &platform, const string &log_directory,
-           const string &log_basename, bool trusted_environment) {
+           const string &log_basename, bool trusted_environment,
+           bool console_environment) {
   _trusted_environment = trusted_environment;
+  _console_environment = console_environment;
   _verify_contents = verify_contents;
   _platform = platform;
   if (_platform.empty()) {

+ 4 - 1
direct/src/plugin/p3dInstanceManager.h

@@ -55,7 +55,8 @@ public:
                   const string &platform,
                   const string &log_directory,
                   const string &log_basename,
-                  bool trusted_environment);
+                  bool trusted_environment,
+                  bool console_environment);
 
   inline bool is_initialized() const;
   inline bool get_verify_contents() const;
@@ -67,6 +68,7 @@ public:
   inline const string &get_log_directory() const;
   inline const string &get_log_pathname() const;
   inline bool get_trusted_environment() const;
+  inline bool get_console_environment() const;
 
   void set_super_mirror(const string &super_mirror_url);
   inline const string &get_super_mirror() const;
@@ -133,6 +135,7 @@ private:
   string _log_pathname;
   string _temp_directory;
   bool _trusted_environment;
+  bool _console_environment;
   string _super_mirror_url;
 
   P3D_object *_undefined_object;

+ 3 - 3
direct/src/plugin/p3dMainObject.cxx

@@ -143,7 +143,7 @@ get_property(const string &property) {
 //               success, false on failure.
 ////////////////////////////////////////////////////////////////////
 bool P3DMainObject::
-set_property(const string &property, P3D_object *value) {
+set_property(const string &property, bool needs_response, P3D_object *value) {
   // First, we set the property locally.
   if (value != NULL) {
     Properties::iterator pi;
@@ -172,7 +172,7 @@ set_property(const string &property, P3D_object *value) {
   }
 
   // With a pyobj, we also pass this request down.
-  return P3D_OBJECT_SET_PROPERTY(_pyobj, property.c_str(), value);
+  return P3D_OBJECT_SET_PROPERTY(_pyobj, property.c_str(), needs_response, value);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -269,7 +269,7 @@ set_pyobj(P3D_object *pyobj) {
       for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
         const string &property_name = (*pi).first;
         P3D_object *value = (*pi).second;
-        P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), value);
+        P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), false, value);
       }
     }
   }

+ 2 - 1
direct/src/plugin/p3dMainObject.h

@@ -53,7 +53,8 @@ public:
   virtual void make_string(string &value);
 
   virtual P3D_object *get_property(const string &property);
-  virtual bool set_property(const string &property, P3D_object *value);
+  virtual bool set_property(const string &property, bool needs_response,
+                            P3D_object *value);
 
   virtual bool has_method(const string &method_name);
   virtual P3D_object *call(const string &method_name, bool needs_response,

+ 12 - 16
direct/src/plugin/p3dObject.cxx

@@ -65,8 +65,8 @@ object_get_property(P3D_object *object, const char *property) {
 
 static bool
 object_set_property(P3D_object *object, const char *property,
-                    P3D_object *value) {
-  return ((P3DObject *)object)->set_property(property, value);
+                    bool needs_response, P3D_object *value) {
+  return ((P3DObject *)object)->set_property(property, needs_response, value);
 }
 
 static bool
@@ -155,7 +155,7 @@ generic_get_property(P3D_object *object, const char *property) {
 
 static bool
 generic_set_property(P3D_object *object, const char *property,
-                     P3D_object *value) {
+                     bool needs_response, P3D_object *value) {
   return false;
 }
 
@@ -275,7 +275,7 @@ get_property(const string &property) {
 //               success, false on failure.
 ////////////////////////////////////////////////////////////////////
 bool P3DObject::
-set_property(const string &property, P3D_object *value) {
+set_property(const string &property, bool needs_response, P3D_object *value) {
   return false;
 }
 
@@ -398,12 +398,11 @@ get_bool_property(const string &property) {
 //  Description: Changes the value of the named property to the
 //               indicated boolean value.
 ////////////////////////////////////////////////////////////////////
-bool P3DObject::
+void P3DObject::
 set_bool_property(const string &property, bool value) {
   P3D_object *bvalue = new P3DBoolObject(value);
-  bool result = set_property(property, bvalue);
+  set_property(property, false, bvalue);
   P3D_OBJECT_DECREF(bvalue);
-  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -429,12 +428,11 @@ get_int_property(const string &property) {
 //  Description: Changes the value of the named property to the
 //               indicated integer value.
 ////////////////////////////////////////////////////////////////////
-bool P3DObject::
+void P3DObject::
 set_int_property(const string &property, int value) {
   P3D_object *ivalue = new P3DIntObject(value);
-  bool result = set_property(property, ivalue);
+  set_property(property, false, ivalue);
   P3D_OBJECT_DECREF(ivalue);
-  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -461,12 +459,11 @@ get_float_property(const string &property) {
 //  Description: Changes the value of the named property to the
 //               indicated floating-point value.
 ////////////////////////////////////////////////////////////////////
-bool P3DObject::
+void P3DObject::
 set_float_property(const string &property, double value) {
   P3D_object *fvalue = new P3DFloatObject(value);
-  bool result = set_property(property, fvalue);
+  set_property(property, false, fvalue);
   P3D_OBJECT_DECREF(fvalue);
-  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -499,10 +496,9 @@ get_string_property(const string &property) {
 //  Description: Changes the value of the named property to the
 //               indicated string value.
 ////////////////////////////////////////////////////////////////////
-bool P3DObject::
+void P3DObject::
 set_string_property(const string &property, const string &value) {
   P3D_object *svalue = new P3DStringObject(value);
-  bool result = set_property(property, svalue);
+  set_property(property, false, svalue);
   P3D_OBJECT_DECREF(svalue);
-  return result;
 }

+ 6 - 5
direct/src/plugin/p3dObject.h

@@ -43,7 +43,8 @@ public:
   virtual void make_string(string &value)=0;
 
   virtual P3D_object *get_property(const string &property);
-  virtual bool set_property(const string &property, P3D_object *value);
+  virtual bool set_property(const string &property, bool needs_response,
+                            P3D_object *value);
 
   virtual bool has_method(const string &method_name);
   virtual P3D_object *call(const string &method_name, bool needs_response,
@@ -57,16 +58,16 @@ public:
 
   // Convenience functions.
   bool get_bool_property(const string &property);
-  bool set_bool_property(const string &property, bool value);
+  void set_bool_property(const string &property, bool value);
 
   int get_int_property(const string &property);
-  bool set_int_property(const string &property, int value);
+  void set_int_property(const string &property, int value);
 
   double get_float_property(const string &property);
-  bool set_float_property(const string &property, double value);
+  void set_float_property(const string &property, double value);
 
   string get_string_property(const string &property);
-  bool set_string_property(const string &property, const string &value);
+  void set_string_property(const string &property, const string &value);
 
 public:
   static P3D_class_definition _object_class;

+ 70 - 0
direct/src/plugin/p3dPythonMain.cxx

@@ -16,6 +16,8 @@
 
 #include <iostream>
 #include <sstream>
+#include <vector>
+#include <assert.h>
 #include <string.h>  // strrchr
 using namespace std;
          
@@ -24,6 +26,74 @@ using namespace std;
 extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
 #endif
 
+#if defined(_WIN32) && defined(NON_CONSOLE)
+// On Windows, we may need to build p3dpythonw.exe, a non-console
+// version of this program.
+
+// We'll wrap the main() function with our own startup WinMain().
+#define main local_main
+int main(int argc, char *argv[]);
+
+// Returns a newly-allocated string representing the quoted argument
+// beginning at p.  Advances p to the first character following the
+// close quote.
+static char *
+parse_quoted_arg(char *&p) {
+  char quote = *p;
+  ++p;
+  string result;
+
+  while (*p != '\0' && *p != quote) {
+    // TODO: handle escape characters?  Not sure if we need to.
+    result += *p;
+    ++p;
+  }
+  if (*p == quote) {
+    ++p;
+  }
+  return strdup(result.c_str());
+}
+
+// Returns a newly-allocated string representing the unquoted argument
+// beginning at p.  Advances p to the first whitespace following the
+// argument.
+static char *
+parse_unquoted_arg(char *&p) {
+  string result;
+  while (*p != '\0' && !isspace(*p)) {
+    result += *p;
+    ++p;
+  }
+  return strdup(result.c_str());
+}
+
+int WINAPI 
+WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
+  char *command_line = GetCommandLine();
+
+  vector<char *> argv;
+  
+  char *p = command_line;
+  while (*p != '\0') {
+    if (*p == '"') {
+      char *arg = parse_quoted_arg(p);
+      argv.push_back(arg);
+    } else {
+      char *arg = parse_unquoted_arg(p);
+      argv.push_back(arg);
+    }
+
+    // Skip whitespace.
+    while (*p != '\0' && isspace(*p)) {
+      ++p;
+    }
+  }
+
+  assert(!argv.empty());
+  return main(argv.size(), &argv[0]);
+}
+#endif  // NON_CONSOLE
+
 ////////////////////////////////////////////////////////////////////
 //     Function: main
 //  Description: This is a trivial main() function that invokes

+ 4 - 4
direct/src/plugin/p3dPythonObject.cxx

@@ -153,8 +153,8 @@ get_property(const string &property) {
 //               success, false on failure.
 ////////////////////////////////////////////////////////////////////
 bool P3DPythonObject::
-set_property(const string &property, P3D_object *value) {
-  bool bresult = false;
+set_property(const string &property, bool needs_response, P3D_object *value) {
+  bool bresult = !needs_response;
 
   P3D_object *params[2];
   params[0] = new P3DStringObject(property);
@@ -163,12 +163,12 @@ set_property(const string &property, P3D_object *value) {
 
   if (value == NULL) {
     // Delete an attribute.
-    result = call("__del_property__", true, params, 1);
+    result = call("__del_property__", needs_response, params, 1);
 
   } else {
     // Set a new attribute.
     params[1] = value;
-    result = call("__set_property__", true, params, 2);
+    result = call("__set_property__", needs_response, params, 2);
   }
 
   P3D_OBJECT_DECREF(params[0]);

+ 1 - 1
direct/src/plugin/p3dPythonObject.h

@@ -42,7 +42,7 @@ public:
   virtual void make_string(string &value);
 
   virtual P3D_object *get_property(const string &property);
-  virtual bool set_property(const string &property, P3D_object *value);
+  virtual bool set_property(const string &property, bool needs_response, P3D_object *value);
 
   virtual bool has_method(const string &method_name);
   virtual P3D_object *call(const string &method_name, bool needs_response,

+ 11 - 6
direct/src/plugin/p3dSession.cxx

@@ -688,7 +688,9 @@ start_p3dpython(P3DInstance *inst) {
   // If we're not to be preserving the user's current directory, then
   // we'll need to change to the standard start directory.
   _keep_user_env = false;
-  if (inst_mgr->get_trusted_environment() && inst->_keep_user_env) {
+  if (inst_mgr->get_trusted_environment() && 
+      inst_mgr->get_console_environment() && 
+      inst->_keep_user_env) {
     _keep_user_env = true;
   }
   if (!_keep_user_env) {
@@ -776,10 +778,13 @@ start_p3dpython(P3DInstance *inst) {
   _p3dpython_exe = P3D_PLUGIN_P3DPYTHON;
   if (_p3dpython_exe.empty()) {
     _p3dpython_exe = _python_root_dir + "/p3dpython";
+  }
 #ifdef _WIN32
-    _p3dpython_exe += ".exe";
-#endif
+  if (!inst_mgr->get_console_environment()) {
+    _p3dpython_exe += "w";
   }
+  _p3dpython_exe += ".exe";
+#endif
 
   // Populate the new process' environment.
   _env = string();
@@ -1191,7 +1196,7 @@ rt_terminate() {
 
   for (Instances::iterator ii = icopy.begin(); ii != icopy.end(); ++ii) {
     P3DInstance *inst = (*ii).second;
-    inst->request_stop();
+    inst->request_stop_main_thread();
   }
 }
 
@@ -1246,8 +1251,8 @@ win_create_process() {
   startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
   startup_info.dwFlags |= STARTF_USESTDHANDLES;
 
-  // Make sure the "python" console window is hidden.
-  startup_info.wShowWindow = SW_HIDE;
+  // We want to show the output window these days.
+  startup_info.wShowWindow = SW_SHOW;
   startup_info.dwFlags |= STARTF_USESHOWWINDOW;
 
   // If _keep_user_env, meaning not to change the current directory,

+ 6 - 3
direct/src/plugin/p3dWinSplashWindow.cxx

@@ -137,7 +137,7 @@ set_image_filename(const string &image_filename, ImagePlacement image_placement)
     if (!_thread_running && _thread_continue) {
       // The user must have closed the window.  Let's shut down the
       // instance, too.
-      _inst->request_stop();
+      _inst->request_stop_main_thread();
     }
   }
 }
@@ -163,7 +163,7 @@ set_install_label(const string &install_label) {
     if (!_thread_running && _thread_continue) {
       // The user must have closed the window.  Let's shut down the
       // instance, too.
-      _inst->request_stop();
+      _inst->request_stop_main_thread();
     }
   }
 }
@@ -186,7 +186,7 @@ set_install_progress(double install_progress) {
     if (!_thread_running && _thread_continue) {
       // The user must have closed the window.  Let's shut down the
       // instance, too.
-      _inst->request_stop();
+      _inst->request_stop_main_thread();
     }
   }
 }
@@ -377,6 +377,9 @@ thread_run() {
 
   // Tell our parent thread that we're done.
   _thread_running = false;
+
+  // Close the instance.
+  _inst->request_stop_sub_thread();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 4
direct/src/plugin/p3d_plugin.cxx

@@ -38,7 +38,7 @@ P3D_initialize(int api_version, const char *contents_filename,
                const char *download_url, bool verify_contents,
                const char *platform,
                const char *log_directory, const char *log_basename,
-               bool trusted_environment) {
+               bool trusted_environment, bool console_environment) {
   if (api_version != P3D_API_VERSION) {
     // Can't accept an incompatible version.
     return false;
@@ -74,7 +74,7 @@ P3D_initialize(int api_version, const char *contents_filename,
   bool result = inst_mgr->initialize(contents_filename, download_url,
                                      verify_contents, platform,
                                      log_directory, log_basename,
-                                     trusted_environment);
+                                     trusted_environment, console_environment);
   RELEASE_LOCK(_api_lock);
   return result;
 }
@@ -227,10 +227,10 @@ P3D_object_get_property(P3D_object *object, const char *property) {
 
 bool
 P3D_object_set_property(P3D_object *object, const char *property, 
-                        P3D_object *value) {
+                        bool needs_response, P3D_object *value) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
-  bool result = P3D_OBJECT_SET_PROPERTY(object, property, value);
+  bool result = P3D_OBJECT_SET_PROPERTY(object, property, needs_response, value);
   RELEASE_LOCK(_api_lock);
   return result;
 }

+ 21 - 12
direct/src/plugin/p3d_plugin.h

@@ -79,7 +79,7 @@ extern "C" {
    (below). This number will be incremented whenever there are changes
    to any of the interface specifications defined in this header
    file. */
-#define P3D_API_VERSION 7
+#define P3D_API_VERSION 8
 
 /************************ GLOBAL FUNCTIONS **************************/
 
@@ -122,11 +122,18 @@ extern "C" {
    core API.  Note that the individual instances also have their own
    log_basename values.
 
-   Finally, trusted_environment should be set true to indicate that
-   the environment and p3d file are already trusted.  If this is set,
-   the current working directory will remain unchanged, and the p3d
-   file will be run without checking its signature.  Normally, a
-   browser plugin should set this false.
+   Next, trusted_environment should be set true to indicate that the
+   environment and p3d file are already trusted.  If this is set, the
+   current working directory will remain unchanged, and the p3d file
+   will be run without checking its signature.  Normally, a browser
+   plugin should set this false.
+
+   Finally, console_environment should be set true to indicate that we
+   are running within a text-based console, and expect to preserve the
+   current working directory, and also see standard output, or false
+   to indicate that we are running within a GUI environment, and
+   expect none of these.  Normally, a browser plugin should set this
+   false.
 
    This function returns true if the core API is valid and uses a
    compatible API, false otherwise.  If it returns false, the host
@@ -137,7 +144,7 @@ P3D_initialize_func(int api_version, const char *contents_filename,
                     const char *download_url, bool verify_contents,
                     const char *platform,
                     const char *log_directory, const char *log_basename,
-                    bool trusted_environment);
+                    bool trusted_environment, bool console_environment);
 
 /* This function should be called to unload the core API.  It will
    release all internally-allocated memory and return the core API to
@@ -439,11 +446,13 @@ P3D_object_get_property_method(P3D_object *object, const char *property);
    correspondingly incremented.  Any existing object previously
    assigned to the corresponding property is replaced, and its
    reference count decremented.  If the value pointer is NULL, the
-   property is removed altogether.  Returns true on success, false on
-   failure.  */
+   property is removed altogether.  If needs_response is true, this
+   method returns true on success, false on failure.  If
+   needs_response is false, the return value is always true regardless
+   of success or failure.*/
 typedef bool
 P3D_object_set_property_method(P3D_object *object, const char *property,
-                               P3D_object *value);
+                               bool needs_response, P3D_object *value);
 
 /* Returns true if the indicated method name exists on the object,
    false otherwise.  In the Python case, this actually returns true if
@@ -521,7 +530,7 @@ struct _P3D_object {
 #define P3D_OBJECT_GET_REPR(object, buffer, buffer_size) ((object)->_class->_get_repr((object), (buffer), (buffer_size)))
 
 #define P3D_OBJECT_GET_PROPERTY(object, property) ((object)->_class->_get_property((object), (property)))
-#define P3D_OBJECT_SET_PROPERTY(object, property, value) ((object)->_class->_set_property((object), (property), (value)))
+#define P3D_OBJECT_SET_PROPERTY(object, property, needs_response, value) ((object)->_class->_set_property((object), (property), (needs_response), (value)))
 
 #define P3D_OBJECT_HAS_METHOD(object, method_name) ((object)->_class->_has_method((object), (method_name)))
 #define P3D_OBJECT_CALL(object, method_name, needs_response, params, num_params) ((object)->_class->_call((object), (method_name), (needs_response), (params), (num_params)))
@@ -561,7 +570,7 @@ typedef P3D_object *
 P3D_object_get_property_func(P3D_object *object, const char *property);
 typedef bool
 P3D_object_set_property_func(P3D_object *object, const char *property, 
-                             P3D_object *value);
+                             bool needs_response, P3D_object *value);
 typedef bool
 P3D_object_has_method_func(P3D_object *object, const char *method_name);
 typedef P3D_object *

+ 4 - 3
direct/src/plugin_activex/PPBrowserObject.cpp

@@ -40,9 +40,9 @@ static P3D_object* object_get_property(P3D_object *object, const char *property)
 }
 
 static bool object_set_property(P3D_object* object, const char* property,
-                                P3D_object *value) 
+                                bool needs_response, P3D_object *value) 
 {
-    return ((PPBrowserObject *)object)->set_property(property, value);
+    return ((PPBrowserObject *)object)->set_property(property, needs_response, value);
 }
 
 static P3D_object* object_call(P3D_object* object, const char* method_name, 
@@ -111,7 +111,8 @@ P3D_object* PPBrowserObject::get_property( const std::string &property ) const
     return m_interface->variant_to_p3dobj( &varResult );
 }
 
-bool PPBrowserObject::set_property( const std::string& property, P3D_object* value )
+bool PPBrowserObject::set_property( const std::string& property, bool needs_response,
+                                    P3D_object* value )
 {   
     assert( m_interface );
 

+ 2 - 1
direct/src/plugin_activex/PPBrowserObject.h

@@ -28,7 +28,8 @@ public:
 
     int get_repr( char* buffer, int buffer_length ) const;
     P3D_object* get_property( const std::string &property ) const;
-    bool set_property( const std::string& property, P3D_object* value );
+    bool set_property( const std::string& property, bool needs_response,
+                       P3D_object* value );
 
     P3D_object* call( const std::string &method_name, 
         P3D_object* params[], int num_params ) const;

+ 1 - 1
direct/src/plugin_activex/PPInstance.cpp

@@ -428,7 +428,7 @@ int PPInstance::LoadPlugin( const std::string& dllFilename )
 #endif  // P3D_PLUGIN_P3D_PLUGIN
       
       nout << "Attempting to load core API from " << pathname << "\n";
-      if (!load_plugin(pathname, "", "", true, "", "", "", false, nout)) {
+      if (!load_plugin(pathname, "", "", true, "", "", "", false, false, nout)) {
         nout << "Unable to launch core API in " << pathname << "\n";
         error = 1;
       }

+ 5 - 1
direct/src/plugin_activex/PPInterface.cpp

@@ -309,9 +309,13 @@ HRESULT PPInterface::P3DSetProperty( P3D_object* p3dObject, CString& name, DISPP
     }
     COleVariant vaArg( pdispparams->rgvarg );
     P3D_object* param = variant_to_p3dobj( &vaArg );
-    result = P3D_OBJECT_SET_PROPERTY( p3dObject, name, param );
+    result = P3D_OBJECT_SET_PROPERTY( p3dObject, name, true, param );
     P3D_OBJECT_DECREF( param );
 
+    if (!result) {
+      return E_FAIL;
+    }
+
     return S_OK;
 }
 

+ 1 - 0
direct/src/plugin_activex/PPPandaObject.cpp

@@ -50,6 +50,7 @@ STDMETHODIMP_(unsigned long) PPandaObject::Release()
     if( m_refs <= 0 )
     {
         delete this;
+        return 0;
     }
     return m_refs;
 }

+ 3 - 3
direct/src/plugin_npapi/ppBrowserObject.cxx

@@ -38,8 +38,8 @@ object_get_property(P3D_object *object, const char *property) {
 
 static bool
 object_set_property(P3D_object *object, const char *property,
-                    P3D_object *value) {
-  return ((PPBrowserObject *)object)->set_property(property, value);
+                    bool needs_response, P3D_object *value) {
+  return ((PPBrowserObject *)object)->set_property(property, needs_response, value);
 }
 
 static P3D_object *
@@ -158,7 +158,7 @@ get_property(const string &property) const {
 //               success, false on failure.
 ////////////////////////////////////////////////////////////////////
 bool PPBrowserObject::
-set_property(const string &property, P3D_object *value) {
+set_property(const string &property, bool needs_response, P3D_object *value) {
   NPIdentifier property_name = browser->getstringidentifier(property.c_str());
   bool result;
   if (value != NULL) {

+ 2 - 1
direct/src/plugin_npapi/ppBrowserObject.h

@@ -37,7 +37,8 @@ public:
 
   int get_repr(char *buffer, int buffer_length) const;
   P3D_object *get_property(const string &property) const;
-  bool set_property(const string &property, P3D_object *value);
+  bool set_property(const string &property, bool needs_response,
+                    P3D_object *value);
 
   P3D_object *call(const string &method_name, 
                    P3D_object *params[], int num_params) const;

+ 1 - 1
direct/src/plugin_npapi/ppInstance.cxx

@@ -1113,7 +1113,7 @@ do_load_plugin() {
 #endif  // P3D_PLUGIN_P3D_PLUGIN
 
   nout << "Attempting to load core API from " << pathname << "\n";
-  if (!load_plugin(pathname, "", "", true, "", "", "", false, nout)) {
+  if (!load_plugin(pathname, "", "", true, "", "", "", false, false, nout)) {
     nout << "Unable to launch core API in " << pathname << "\n";
     return;
   }

+ 4 - 2
direct/src/plugin_npapi/ppPandaObject.cxx

@@ -274,7 +274,8 @@ set_property(NPIdentifier name, const NPVariant *value) {
   }
 
   P3D_object *object = _instance->variant_to_p3dobj(value);
-  bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), object);
+  bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), 
+                                        true, object);
   P3D_OBJECT_DECREF(object);
   return result;
 }
@@ -294,7 +295,8 @@ remove_property(NPIdentifier name) {
     return false;
   }
 
-  bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), NULL);
+  bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), 
+                                        true, NULL);
   return result;
 }
 

+ 9 - 9
direct/src/plugin_standalone/panda3d.cxx

@@ -52,12 +52,6 @@ Panda3D() {
   _root_dir = find_root_dir();
   _reporting_download = false;
   _enable_security = false;
-
-#ifdef NON_CONSOLE
-  // For the desktop version of this program, let's always assume -S
-  // is in effect.
-  _enable_security = true;
-#endif
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -555,9 +549,16 @@ get_core_api(const Filename &contents_filename, const string &download_url,
 
   bool trusted_environment = !_enable_security;
 
+#ifdef NON_CONSOLE
+  static const bool console_environment = false;
+#else
+  static const bool console_environment = true;
+#endif
+
   if (!load_plugin(pathname, contents_filename.to_os_specific(),
                    download_url, verify_contents, this_platform, _log_dirname,
-                   _log_basename, trusted_environment, cerr)) {
+                   _log_basename, trusted_environment, console_environment,
+                   cerr)) {
     cerr << "Unable to launch core API in " << pathname << "\n" << flush;
     return false;
   }
@@ -599,7 +600,6 @@ run_getters() {
 void Panda3D::
 handle_request(P3D_request *request) {
   bool handled = false;
-
   switch (request->_request_type) {
   case P3D_RT_stop:
     delete_instance(request->_instance);
@@ -1169,7 +1169,7 @@ parse_unquoted_arg(char *&p) {
   return strdup(result.c_str());
 }
 
-WINAPI 
+int WINAPI 
 WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
   char *command_line = GetCommandLine();