소스 검색

add p3dpythonw.exe, more robust startup

David Rose 16 년 전
부모
커밋
a308a4a01c

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

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

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

@@ -183,6 +183,52 @@
   #define WIN_SYS_LIBS user32.lib
   #define WIN_SYS_LIBS user32.lib
 #end bin_target
 #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
 #begin static_lib_target
   #define BUILD_TARGET $[and $[HAVE_TINYXML],$[HAVE_OPENSSL]]
   #define BUILD_TARGET $[and $[HAVE_TINYXML],$[HAVE_OPENSSL]]
   #define TARGET plugin_common
   #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, 
             const string &contents_filename, const string &download_url, 
             bool verify_contents, const string &platform,
             bool verify_contents, const string &platform,
             const string &log_directory, const string &log_basename,
             const string &log_directory, const string &log_basename,
-            bool trusted_environment,
+            bool trusted_environment, bool console_environment,
             ostream &logfile) {
             ostream &logfile) {
   string filename = p3d_plugin_filename;
   string filename = p3d_plugin_filename;
   if (filename.empty()) {
   if (filename.empty()) {
@@ -313,7 +313,7 @@ load_plugin(const string &p3d_plugin_filename,
   if (!P3D_initialize(P3D_API_VERSION, contents_filename.c_str(),
   if (!P3D_initialize(P3D_API_VERSION, contents_filename.c_str(),
                       download_url.c_str(), verify_contents, platform.c_str(),
                       download_url.c_str(), verify_contents, platform.c_str(),
                       log_directory.c_str(), log_basename.c_str(),
                       log_directory.c_str(), log_basename.c_str(),
-                      trusted_environment)) {
+                      trusted_environment, console_environment)) {
     // Oops, failure to initialize.
     // Oops, failure to initialize.
     logfile << "Failed to initialize plugin (wrong API version?)\n";
     logfile << "Failed to initialize plugin (wrong API version?)\n";
     unload_plugin();
     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,
             const string &contents_filename, const string &download_url,
             bool verify_contents, const string &platform,
             bool verify_contents, const string &platform,
             const string &log_directory, const string &log_basename,
             const string &log_directory, const string &log_basename,
-            bool trusted_environment,
+            bool trusted_environment, bool console_environment,
             ostream &logfile);
             ostream &logfile);
 void unload_plugin();
 void unload_plugin();
 bool is_plugin_loaded();
 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
 //       Access: Public
 //  Description: Asks the host to shut down this particular instance,
 //  Description: Asks the host to shut down this particular instance,
 //               presumably because the user has indicated it should
 //               presumably because the user has indicated it should
-//               exit.
+//               exit.  This call may be made in any thread.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 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) {
   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;
     _requested_stop = true;
     P3D_request *request = new P3D_request;
     P3D_request *request = new P3D_request;
     request->_request_type = P3D_RT_stop;
     request->_request_type = P3D_RT_stop;
@@ -1533,7 +1572,7 @@ handle_script_request(const string &operation, P3D_object *object,
 
 
   } else if (operation == "set_property") {
   } else if (operation == "set_property") {
     bool result = 
     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");
     TiXmlElement *xvalue = new TiXmlElement("value");
     xvalue->SetAttribute("type", "bool");
     xvalue->SetAttribute("type", "bool");
@@ -1541,7 +1580,7 @@ handle_script_request(const string &operation, P3D_object *object,
     xcommand->LinkEndChild(xvalue);
     xcommand->LinkEndChild(xvalue);
 
 
   } else if (operation == "del_property") {
   } 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");
     TiXmlElement *xvalue = new TiXmlElement("value");
     xvalue->SetAttribute("type", "bool");
     xvalue->SetAttribute("type", "bool");

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

@@ -98,7 +98,8 @@ public:
   inline bool is_trusted() const;
   inline bool is_trusted() const;
   void start_download(P3DDownload *download);
   void start_download(P3DDownload *download);
   inline bool is_started() const;
   inline bool is_started() const;
-  void request_stop();
+  void request_stop_sub_thread();
+  void request_stop_main_thread();
   void request_refresh();
   void request_refresh();
 
 
   TiXmlElement *make_xml();
   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.
 //               file will be run without checking its signature.
 //
 //
 //               This should generally be true only when run by
 //               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::
 inline bool P3DInstanceManager::
 get_trusted_environment() const {
 get_trusted_environment() const {
   return _trusted_environment;
   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
 //     Function: P3DInstanceManager::get_super_mirror
 //       Access: Public
 //       Access: Public

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

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

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

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

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

@@ -143,7 +143,7 @@ get_property(const string &property) {
 //               success, false on failure.
 //               success, false on failure.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool P3DMainObject::
 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.
   // First, we set the property locally.
   if (value != NULL) {
   if (value != NULL) {
     Properties::iterator pi;
     Properties::iterator pi;
@@ -172,7 +172,7 @@ set_property(const string &property, P3D_object *value) {
   }
   }
 
 
   // With a pyobj, we also pass this request down.
   // 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) {
       for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
         const string &property_name = (*pi).first;
         const string &property_name = (*pi).first;
         P3D_object *value = (*pi).second;
         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 void make_string(string &value);
 
 
   virtual P3D_object *get_property(const string &property);
   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 bool has_method(const string &method_name);
   virtual P3D_object *call(const string &method_name, bool needs_response,
   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
 static bool
 object_set_property(P3D_object *object, const char *property,
 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
 static bool
@@ -155,7 +155,7 @@ generic_get_property(P3D_object *object, const char *property) {
 
 
 static bool
 static bool
 generic_set_property(P3D_object *object, const char *property,
 generic_set_property(P3D_object *object, const char *property,
-                     P3D_object *value) {
+                     bool needs_response, P3D_object *value) {
   return false;
   return false;
 }
 }
 
 
@@ -275,7 +275,7 @@ get_property(const string &property) {
 //               success, false on failure.
 //               success, false on failure.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool P3DObject::
 bool P3DObject::
-set_property(const string &property, P3D_object *value) {
+set_property(const string &property, bool needs_response, P3D_object *value) {
   return false;
   return false;
 }
 }
 
 
@@ -398,12 +398,11 @@ get_bool_property(const string &property) {
 //  Description: Changes the value of the named property to the
 //  Description: Changes the value of the named property to the
 //               indicated boolean value.
 //               indicated boolean value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool P3DObject::
+void P3DObject::
 set_bool_property(const string &property, bool value) {
 set_bool_property(const string &property, bool value) {
   P3D_object *bvalue = new P3DBoolObject(value);
   P3D_object *bvalue = new P3DBoolObject(value);
-  bool result = set_property(property, bvalue);
+  set_property(property, false, bvalue);
   P3D_OBJECT_DECREF(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
 //  Description: Changes the value of the named property to the
 //               indicated integer value.
 //               indicated integer value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool P3DObject::
+void P3DObject::
 set_int_property(const string &property, int value) {
 set_int_property(const string &property, int value) {
   P3D_object *ivalue = new P3DIntObject(value);
   P3D_object *ivalue = new P3DIntObject(value);
-  bool result = set_property(property, ivalue);
+  set_property(property, false, ivalue);
   P3D_OBJECT_DECREF(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
 //  Description: Changes the value of the named property to the
 //               indicated floating-point value.
 //               indicated floating-point value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool P3DObject::
+void P3DObject::
 set_float_property(const string &property, double value) {
 set_float_property(const string &property, double value) {
   P3D_object *fvalue = new P3DFloatObject(value);
   P3D_object *fvalue = new P3DFloatObject(value);
-  bool result = set_property(property, fvalue);
+  set_property(property, false, fvalue);
   P3D_OBJECT_DECREF(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
 //  Description: Changes the value of the named property to the
 //               indicated string value.
 //               indicated string value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool P3DObject::
+void P3DObject::
 set_string_property(const string &property, const string &value) {
 set_string_property(const string &property, const string &value) {
   P3D_object *svalue = new P3DStringObject(value);
   P3D_object *svalue = new P3DStringObject(value);
-  bool result = set_property(property, svalue);
+  set_property(property, false, svalue);
   P3D_OBJECT_DECREF(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 void make_string(string &value)=0;
 
 
   virtual P3D_object *get_property(const string &property);
   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 bool has_method(const string &method_name);
   virtual P3D_object *call(const string &method_name, bool needs_response,
   virtual P3D_object *call(const string &method_name, bool needs_response,
@@ -57,16 +58,16 @@ public:
 
 
   // Convenience functions.
   // Convenience functions.
   bool get_bool_property(const string &property);
   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);
   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);
   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);
   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:
 public:
   static P3D_class_definition _object_class;
   static P3D_class_definition _object_class;

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

@@ -16,6 +16,8 @@
 
 
 #include <iostream>
 #include <iostream>
 #include <sstream>
 #include <sstream>
+#include <vector>
+#include <assert.h>
 #include <string.h>  // strrchr
 #include <string.h>  // strrchr
 using namespace std;
 using namespace std;
          
          
@@ -24,6 +26,74 @@ using namespace std;
 extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
 extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
 #endif
 #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
 //     Function: main
 //  Description: This is a trivial main() function that invokes
 //  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.
 //               success, false on failure.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool P3DPythonObject::
 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];
   P3D_object *params[2];
   params[0] = new P3DStringObject(property);
   params[0] = new P3DStringObject(property);
@@ -163,12 +163,12 @@ set_property(const string &property, P3D_object *value) {
 
 
   if (value == NULL) {
   if (value == NULL) {
     // Delete an attribute.
     // Delete an attribute.
-    result = call("__del_property__", true, params, 1);
+    result = call("__del_property__", needs_response, params, 1);
 
 
   } else {
   } else {
     // Set a new attribute.
     // Set a new attribute.
     params[1] = value;
     params[1] = value;
-    result = call("__set_property__", true, params, 2);
+    result = call("__set_property__", needs_response, params, 2);
   }
   }
 
 
   P3D_OBJECT_DECREF(params[0]);
   P3D_OBJECT_DECREF(params[0]);

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

@@ -42,7 +42,7 @@ public:
   virtual void make_string(string &value);
   virtual void make_string(string &value);
 
 
   virtual P3D_object *get_property(const string &property);
   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 bool has_method(const string &method_name);
   virtual P3D_object *call(const string &method_name, bool needs_response,
   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
   // If we're not to be preserving the user's current directory, then
   // we'll need to change to the standard start directory.
   // we'll need to change to the standard start directory.
   _keep_user_env = false;
   _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;
     _keep_user_env = true;
   }
   }
   if (!_keep_user_env) {
   if (!_keep_user_env) {
@@ -776,10 +778,13 @@ start_p3dpython(P3DInstance *inst) {
   _p3dpython_exe = P3D_PLUGIN_P3DPYTHON;
   _p3dpython_exe = P3D_PLUGIN_P3DPYTHON;
   if (_p3dpython_exe.empty()) {
   if (_p3dpython_exe.empty()) {
     _p3dpython_exe = _python_root_dir + "/p3dpython";
     _p3dpython_exe = _python_root_dir + "/p3dpython";
+  }
 #ifdef _WIN32
 #ifdef _WIN32
-    _p3dpython_exe += ".exe";
-#endif
+  if (!inst_mgr->get_console_environment()) {
+    _p3dpython_exe += "w";
   }
   }
+  _p3dpython_exe += ".exe";
+#endif
 
 
   // Populate the new process' environment.
   // Populate the new process' environment.
   _env = string();
   _env = string();
@@ -1191,7 +1196,7 @@ rt_terminate() {
 
 
   for (Instances::iterator ii = icopy.begin(); ii != icopy.end(); ++ii) {
   for (Instances::iterator ii = icopy.begin(); ii != icopy.end(); ++ii) {
     P3DInstance *inst = (*ii).second;
     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.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
   startup_info.dwFlags |= STARTF_USESTDHANDLES;
   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;
   startup_info.dwFlags |= STARTF_USESHOWWINDOW;
 
 
   // If _keep_user_env, meaning not to change the current directory,
   // 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) {
     if (!_thread_running && _thread_continue) {
       // The user must have closed the window.  Let's shut down the
       // The user must have closed the window.  Let's shut down the
       // instance, too.
       // 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) {
     if (!_thread_running && _thread_continue) {
       // The user must have closed the window.  Let's shut down the
       // The user must have closed the window.  Let's shut down the
       // instance, too.
       // 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) {
     if (!_thread_running && _thread_continue) {
       // The user must have closed the window.  Let's shut down the
       // The user must have closed the window.  Let's shut down the
       // instance, too.
       // instance, too.
-      _inst->request_stop();
+      _inst->request_stop_main_thread();
     }
     }
   }
   }
 }
 }
@@ -377,6 +377,9 @@ thread_run() {
 
 
   // Tell our parent thread that we're done.
   // Tell our parent thread that we're done.
   _thread_running = false;
   _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 *download_url, bool verify_contents,
                const char *platform,
                const char *platform,
                const char *log_directory, const char *log_basename,
                const char *log_directory, const char *log_basename,
-               bool trusted_environment) {
+               bool trusted_environment, bool console_environment) {
   if (api_version != P3D_API_VERSION) {
   if (api_version != P3D_API_VERSION) {
     // Can't accept an incompatible version.
     // Can't accept an incompatible version.
     return false;
     return false;
@@ -74,7 +74,7 @@ P3D_initialize(int api_version, const char *contents_filename,
   bool result = inst_mgr->initialize(contents_filename, download_url,
   bool result = inst_mgr->initialize(contents_filename, download_url,
                                      verify_contents, platform,
                                      verify_contents, platform,
                                      log_directory, log_basename,
                                      log_directory, log_basename,
-                                     trusted_environment);
+                                     trusted_environment, console_environment);
   RELEASE_LOCK(_api_lock);
   RELEASE_LOCK(_api_lock);
   return result;
   return result;
 }
 }
@@ -227,10 +227,10 @@ P3D_object_get_property(P3D_object *object, const char *property) {
 
 
 bool
 bool
 P3D_object_set_property(P3D_object *object, const char *property, 
 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());
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
   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);
   RELEASE_LOCK(_api_lock);
   return result;
   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
    (below). This number will be incremented whenever there are changes
    to any of the interface specifications defined in this header
    to any of the interface specifications defined in this header
    file. */
    file. */
-#define P3D_API_VERSION 7
+#define P3D_API_VERSION 8
 
 
 /************************ GLOBAL FUNCTIONS **************************/
 /************************ GLOBAL FUNCTIONS **************************/
 
 
@@ -122,11 +122,18 @@ extern "C" {
    core API.  Note that the individual instances also have their own
    core API.  Note that the individual instances also have their own
    log_basename values.
    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
    This function returns true if the core API is valid and uses a
    compatible API, false otherwise.  If it returns false, the host
    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 *download_url, bool verify_contents,
                     const char *platform,
                     const char *platform,
                     const char *log_directory, const char *log_basename,
                     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
 /* This function should be called to unload the core API.  It will
    release all internally-allocated memory and return the core API to
    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
    correspondingly incremented.  Any existing object previously
    assigned to the corresponding property is replaced, and its
    assigned to the corresponding property is replaced, and its
    reference count decremented.  If the value pointer is NULL, the
    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
 typedef bool
 P3D_object_set_property_method(P3D_object *object, const char *property,
 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,
 /* Returns true if the indicated method name exists on the object,
    false otherwise.  In the Python case, this actually returns true if
    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_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_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_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)))
 #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);
 P3D_object_get_property_func(P3D_object *object, const char *property);
 typedef bool
 typedef bool
 P3D_object_set_property_func(P3D_object *object, const char *property, 
 P3D_object_set_property_func(P3D_object *object, const char *property, 
-                             P3D_object *value);
+                             bool needs_response, P3D_object *value);
 typedef bool
 typedef bool
 P3D_object_has_method_func(P3D_object *object, const char *method_name);
 P3D_object_has_method_func(P3D_object *object, const char *method_name);
 typedef P3D_object *
 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,
 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, 
 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 );
     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 );
     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;
     int get_repr( char* buffer, int buffer_length ) const;
     P3D_object* get_property( const std::string &property ) 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* call( const std::string &method_name, 
         P3D_object* params[], int num_params ) const;
         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
 #endif  // P3D_PLUGIN_P3D_PLUGIN
       
       
       nout << "Attempting to load core API from " << pathname << "\n";
       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";
         nout << "Unable to launch core API in " << pathname << "\n";
         error = 1;
         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 );
     COleVariant vaArg( pdispparams->rgvarg );
     P3D_object* param = variant_to_p3dobj( &vaArg );
     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 );
     P3D_OBJECT_DECREF( param );
 
 
+    if (!result) {
+      return E_FAIL;
+    }
+
     return S_OK;
     return S_OK;
 }
 }
 
 

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

@@ -50,6 +50,7 @@ STDMETHODIMP_(unsigned long) PPandaObject::Release()
     if( m_refs <= 0 )
     if( m_refs <= 0 )
     {
     {
         delete this;
         delete this;
+        return 0;
     }
     }
     return m_refs;
     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
 static bool
 object_set_property(P3D_object *object, const char *property,
 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 *
 static P3D_object *
@@ -158,7 +158,7 @@ get_property(const string &property) const {
 //               success, false on failure.
 //               success, false on failure.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PPBrowserObject::
 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());
   NPIdentifier property_name = browser->getstringidentifier(property.c_str());
   bool result;
   bool result;
   if (value != NULL) {
   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;
   int get_repr(char *buffer, int buffer_length) const;
   P3D_object *get_property(const string &property) 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 *call(const string &method_name, 
                    P3D_object *params[], int num_params) const;
                    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
 #endif  // P3D_PLUGIN_P3D_PLUGIN
 
 
   nout << "Attempting to load core API from " << pathname << "\n";
   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";
     nout << "Unable to launch core API in " << pathname << "\n";
     return;
     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);
   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);
   P3D_OBJECT_DECREF(object);
   return result;
   return result;
 }
 }
@@ -294,7 +295,8 @@ remove_property(NPIdentifier name) {
     return false;
     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;
   return result;
 }
 }
 
 

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

@@ -52,12 +52,6 @@ Panda3D() {
   _root_dir = find_root_dir();
   _root_dir = find_root_dir();
   _reporting_download = false;
   _reporting_download = false;
   _enable_security = 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;
   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(),
   if (!load_plugin(pathname, contents_filename.to_os_specific(),
                    download_url, verify_contents, this_platform, _log_dirname,
                    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;
     cerr << "Unable to launch core API in " << pathname << "\n" << flush;
     return false;
     return false;
   }
   }
@@ -599,7 +600,6 @@ run_getters() {
 void Panda3D::
 void Panda3D::
 handle_request(P3D_request *request) {
 handle_request(P3D_request *request) {
   bool handled = false;
   bool handled = false;
-
   switch (request->_request_type) {
   switch (request->_request_type) {
   case P3D_RT_stop:
   case P3D_RT_stop:
     delete_instance(request->_instance);
     delete_instance(request->_instance);
@@ -1169,7 +1169,7 @@ parse_unquoted_arg(char *&p) {
   return strdup(result.c_str());
   return strdup(result.c_str());
 }
 }
 
 
-WINAPI 
+int WINAPI 
 WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
 WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
   char *command_line = GetCommandLine();
   char *command_line = GetCommandLine();