Browse Source

Merge branch 'master' into deploy-ng

rdb 8 years ago
parent
commit
5cf2f92597

+ 1 - 0
.travis.yml

@@ -35,6 +35,7 @@ addons:
     - python-dev
     - python-dev
     - python3-dev
     - python3-dev
     - zlib1g-dev
     - zlib1g-dev
+    - fakeroot
 script: $PYTHONV makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT $FLAGS --threads 4 && LD_LIBRARY_PATH=built/lib PYTHONPATH=built $PYTHONV makepanda/test_imports.py
 script: $PYTHONV makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT $FLAGS --threads 4 && LD_LIBRARY_PATH=built/lib PYTHONPATH=built $PYTHONV makepanda/test_imports.py
 notifications:
 notifications:
   irc:
   irc:

+ 1 - 1
direct/src/actor/Actor.py

@@ -897,7 +897,7 @@ class Actor(DirectObject, NodePath):
         return ((toFrame+1)-fromFrame) / animControl.getFrameRate()
         return ((toFrame+1)-fromFrame) / animControl.getFrameRate()
 
 
     def getNumFrames(self, animName=None, partName=None):
     def getNumFrames(self, animName=None, partName=None):
-        lodName = next(iter(self.__animControlDict))
+        #lodName = next(iter(self.__animControlDict))
         controls = self.getAnimControls(animName, partName)
         controls = self.getAnimControls(animName, partName)
         if len(controls) == 0:
         if len(controls) == 0:
             return None
             return None

+ 8 - 10
dtool/src/interrogate/functionRemap.cxx

@@ -772,16 +772,14 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     first_param = 1;
     first_param = 1;
   }
   }
 
 
-  if (_has_this || _type == T_constructor) {
-    if (_parameters.size() > (size_t)first_param && _parameters[first_param]._name == "self" &&
-        TypeManager::is_pointer_to_PyObject(_parameters[first_param]._remap->get_orig_type())) {
-      // Here's a special case.  If the first parameter of a nonstatic method
-      // is a PyObject * called "self", then we will automatically fill it in
-      // from the this pointer, and remove it from the generated parameter
-      // list.
-      _parameters.erase(_parameters.begin() + first_param);
-      _flags |= F_explicit_self;
-    }
+  if (_parameters.size() > (size_t)first_param && _parameters[first_param]._name == "self" &&
+      TypeManager::is_pointer_to_PyObject(_parameters[first_param]._remap->get_orig_type())) {
+    // Here's a special case.  If the first parameter of a nonstatic method
+    // is a PyObject * called "self", then we will automatically fill it in
+    // from the this pointer, and remove it from the generated parameter
+    // list.
+    _parameters.erase(_parameters.begin() + first_param);
+    _flags |= F_explicit_self;
   }
   }
 
 
   if ((int)_parameters.size() == first_param) {
   if ((int)_parameters.size() == first_param) {

+ 1 - 1
dtool/src/interrogate/interfaceMaker.cxx

@@ -616,7 +616,7 @@ record_function(const InterrogateType &itype, FunctionIndex func_index) {
 
 
           // If *any* of the variants of this function has a "this" pointer,
           // If *any* of the variants of this function has a "this" pointer,
           // the entire set of functions is deemed to have a "this" pointer.
           // the entire set of functions is deemed to have a "this" pointer.
-          if (remap->_has_this) {
+          if (remap->_has_this || (remap->_flags & FunctionRemap::F_explicit_self) != 0) {
             func->_has_this = true;
             func->_has_this = true;
           }
           }
 
 

+ 40 - 24
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -478,6 +478,11 @@ get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap,
       def._wrapper_type = WT_mapping_setitem;
       def._wrapper_type = WT_mapping_setitem;
       return true;
       return true;
     }
     }
+    if (remap->_flags & FunctionRemap::F_size) {
+      def._answer_location = "mp_length";
+      def._wrapper_type = WT_sequence_size;
+      return true;
+    }
   }
   }
 
 
   if (obj->_protocol_types & Object::PT_iter) {
   if (obj->_protocol_types & Object::PT_iter) {
@@ -707,7 +712,10 @@ write_python_instance(ostream &out, int indent_level, const string &return_expr,
 
 
   string class_name = itype.get_scoped_name();
   string class_name = itype.get_scoped_name();
 
 
-  if (IsPandaTypedObject(itype._cpptype->as_struct_type())) {
+  // We don't handle final classes via DTool_CreatePyInstanceTyped since we
+  // know it can't be of a subclass type, so we don't need to do the downcast.
+  CPPStructType *struct_type = itype._cpptype->as_struct_type();
+  if (IsPandaTypedObject(struct_type) && !struct_type->is_final()) {
     // We can't let DTool_CreatePyInstanceTyped do the NULL check since we
     // We can't let DTool_CreatePyInstanceTyped do the NULL check since we
     // will be grabbing the type index (which would obviously crash when
     // will be grabbing the type index (which would obviously crash when
     // called on a NULL pointer), so we do it here.
     // called on a NULL pointer), so we do it here.
@@ -2100,10 +2108,10 @@ write_module_class(ostream &out, Object *obj) {
           for (ri = def._remaps.begin(); ri != def._remaps.end(); ++ri) {
           for (ri = def._remaps.begin(); ri != def._remaps.end(); ++ri) {
             FunctionRemap *remap = (*ri);
             FunctionRemap *remap = (*ri);
 
 
-            if (remap->_flags & FunctionRemap::F_setitem_int) {
+            if (remap->_flags & FunctionRemap::F_setitem) {
               setitem_remaps.insert(remap);
               setitem_remaps.insert(remap);
 
 
-            } else if (remap->_flags & FunctionRemap::F_delitem_int) {
+            } else if (remap->_flags & FunctionRemap::F_delitem) {
               delitem_remaps.insert(remap);
               delitem_remaps.insert(remap);
             }
             }
           }
           }
@@ -2137,14 +2145,21 @@ write_module_class(ostream &out, Object *obj) {
           out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "//////////////////\n";
           out << "static int " << def._wrapper_name << "(PyObject *self) {\n";
           out << "static int " << def._wrapper_name << "(PyObject *self) {\n";
-          out << "  " << cClassName  << " *local_this = NULL;\n";
-          out << "  if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n";
-          out << "    return -1;\n";
-          out << "  }\n\n";
 
 
+          // Find the remap.  There should be only one.
           FunctionRemap *remap = *def._remaps.begin();
           FunctionRemap *remap = *def._remaps.begin();
+          const char *container = "";
+
+          if (remap->_has_this) {
+            out << "  " << cClassName  << " *local_this = NULL;\n";
+            out << "  if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n";
+            out << "    return -1;\n";
+            out << "  }\n\n";
+            container = "local_this";
+          }
+
           vector_string params;
           vector_string params;
-          out << "  return (int) " << remap->call_function(out, 4, false, "local_this", params) << ";\n";
+          out << "  return (int) " << remap->call_function(out, 4, false, container, params) << ";\n";
           out << "}\n\n";
           out << "}\n\n";
         }
         }
         break;
         break;
@@ -2374,23 +2389,25 @@ write_module_class(ostream &out, Object *obj) {
           out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "//////////////////\n";
           out << "static int " << def._wrapper_name << "(PyObject *self, visitproc visit, void *arg) {\n";
           out << "static int " << def._wrapper_name << "(PyObject *self, visitproc visit, void *arg) {\n";
-          out << "  " << cClassName << " *local_this = NULL;\n";
-          out << "  DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **) &local_this);\n";
-          out << "  if (local_this == NULL) {\n";
-          out << "    return 0;\n";
-          out << "  }\n\n";
 
 
           // Find the remap.  There should be only one.
           // Find the remap.  There should be only one.
           FunctionRemap *remap = *def._remaps.begin();
           FunctionRemap *remap = *def._remaps.begin();
+          const char *container = "";
 
 
-          vector_string params(1);
-          if (remap->_flags & FunctionRemap::F_explicit_self) {
-            params.push_back("self");
+          if (remap->_has_this) {
+            out << "  " << cClassName << " *local_this = NULL;\n";
+            out << "  DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **) &local_this);\n";
+            out << "  if (local_this == NULL) {\n";
+            out << "    return 0;\n";
+            out << "  }\n\n";
+            container = "local_this";
           }
           }
+
+          vector_string params((int)remap->_has_this);
           params.push_back("visit");
           params.push_back("visit");
           params.push_back("arg");
           params.push_back("arg");
 
 
-          out << "  return " << remap->call_function(out, 2, false, "local_this", params) << ";\n";
+          out << "  return " << remap->call_function(out, 2, false, container, params) << ";\n";
           out << "}\n\n";
           out << "}\n\n";
         }
         }
         break;
         break;
@@ -2857,11 +2874,9 @@ write_module_class(ostream &out, Object *obj) {
   }
   }
 
 
   // getattrofunc tp_getattro;
   // getattrofunc tp_getattro;
-  write_function_slot(out, 4, slots, "tp_getattro",
-                      "PyObject_GenericGetAttr");
+  write_function_slot(out, 4, slots, "tp_getattro");
   // setattrofunc tp_setattro;
   // setattrofunc tp_setattro;
-  write_function_slot(out, 4, slots, "tp_setattro",
-                      "PyObject_GenericSetAttr");
+  write_function_slot(out, 4, slots, "tp_setattro");
 
 
   // PyBufferProcs *tp_as_buffer;
   // PyBufferProcs *tp_as_buffer;
   if (has_parent_class || has_local_getbuffer) {
   if (has_parent_class || has_local_getbuffer) {
@@ -4180,7 +4195,7 @@ int get_type_sort(CPPType *type) {
     return 7;
     return 7;
   } else if (TypeManager::is_longlong(type)) {
   } else if (TypeManager::is_longlong(type)) {
     return 6;
     return 6;
-  } else if (TypeManager::is_integer(type)) {
+  } else if (TypeManager::is_integer(type) && !TypeManager::is_bool(type)) {
     return 5;
     return 5;
   } else if (TypeManager::is_double(type)) {
   } else if (TypeManager::is_double(type)) {
     return 4;
     return 4;
@@ -4973,7 +4988,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
         format_specifiers += "O";
         format_specifiers += "O";
         parameter_list += ", &" + param_name;
         parameter_list += ", &" + param_name;
       }
       }
-      pexpr_string = "NULL";
+      pexpr_string = "nullptr";
       expected_params += "NoneType";
       expected_params += "NoneType";
 
 
     } else if (TypeManager::is_char(type)) {
     } else if (TypeManager::is_char(type)) {
@@ -5800,7 +5815,8 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     indent_level += 2;
     indent_level += 2;
   }
   }
 
 
-  if (!remap->_has_this && (remap->_flags & FunctionRemap::F_explicit_self) != 0) {
+  if (is_constructor && !remap->_has_this &&
+      (remap->_flags & FunctionRemap::F_explicit_self) != 0) {
     // If we'll be passing "self" to the constructor, we need to pre-
     // If we'll be passing "self" to the constructor, we need to pre-
     // initialize it here.  Unfortunately, we can't pre-load the "this"
     // initialize it here.  Unfortunately, we can't pre-load the "this"
     // pointer, but the constructor itself can do this.
     // pointer, but the constructor itself can do this.

+ 20 - 4
dtool/src/interrogate/interrogateBuilder.cxx

@@ -1850,12 +1850,24 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
         continue;
         continue;
       }
       }
 
 
+      const CPPParameterList::Parameters &params = ftype->_parameters->_parameters;
+
+      size_t expected_num_args = (size_t)is_seq;
+      size_t index_arg = 0;
+
+      if (!params.empty() && params[0]->get_simple_name() == "self" &&
+          TypeManager::is_pointer_to_PyObject(params[0]->_type)) {
+        // Taking a PyObject *self argument.
+        expected_num_args += 1;
+        index_arg += 1;
+      }
+
       // The getter must either take no arguments, or all defaults.
       // The getter must either take no arguments, or all defaults.
-      if (ftype->_parameters->_parameters.size() == (size_t)is_seq ||
-          (ftype->_parameters->_parameters.size() > (size_t)is_seq &&
-           ftype->_parameters->_parameters[(size_t)is_seq]->_initializer != NULL)) {
+      if (params.size() == expected_num_args ||
+          (params.size() > expected_num_args &&
+           params[expected_num_args]->_initializer != NULL)) {
         // If this is a sequence getter, it must take an index argument.
         // If this is a sequence getter, it must take an index argument.
-        if (is_seq && !TypeManager::is_integer(ftype->_parameters->_parameters[0]->_type)) {
+        if (is_seq && !TypeManager::is_integer(params[index_arg]->_type)) {
           continue;
           continue;
         }
         }
 
 
@@ -2428,6 +2440,10 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
     break;
     break;
   }
   }
 
 
+  if (cpptype->is_final()) {
+    itype._flags |= InterrogateType::F_final;
+  }
+
   if (cpptype->_file.is_c_file()) {
   if (cpptype->_file.is_c_file()) {
     // This type declaration appears in a .C file.  We can only export types
     // This type declaration appears in a .C file.  We can only export types
     // defined in a .h file.
     // defined in a .h file.

+ 8 - 0
dtool/src/interrogatedb/interrogateType.I

@@ -289,6 +289,14 @@ is_union() const {
   return (_flags & F_union) != 0;
   return (_flags & F_union) != 0;
 }
 }
 
 
+/**
+ *
+ */
+INLINE bool InterrogateType::
+is_final() const {
+  return (_flags & F_final) != 0;
+}
+
 /**
 /**
  *
  *
  */
  */

+ 2 - 0
dtool/src/interrogatedb/interrogateType.h

@@ -75,6 +75,7 @@ public:
   INLINE bool is_struct() const;
   INLINE bool is_struct() const;
   INLINE bool is_class() const;
   INLINE bool is_class() const;
   INLINE bool is_union() const;
   INLINE bool is_union() const;
+  INLINE bool is_final() const;
 
 
   INLINE bool is_fully_defined() const;
   INLINE bool is_fully_defined() const;
   INLINE bool is_unpublished() const;
   INLINE bool is_unpublished() const;
@@ -139,6 +140,7 @@ private:
     F_typedef              = 0x200000,
     F_typedef              = 0x200000,
     F_array                = 0x400000,
     F_array                = 0x400000,
     F_scoped_enum          = 0x800000,
     F_scoped_enum          = 0x800000,
+    F_final                =0x1000000,
   };
   };
 
 
 public:
 public:

+ 5 - 9
dtool/src/interrogatedb/py_panda.cxx

@@ -17,6 +17,8 @@
 
 
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
 
 
+PyTupleObject Dtool_EmptyTuple;
+
 PyMemberDef standard_type_members[] = {
 PyMemberDef standard_type_members[] = {
   {(char *)"this", (sizeof(void*) == sizeof(int)) ? T_UINT : T_ULONGLONG, offsetof(Dtool_PyInstDef, _ptr_to_object), READONLY, (char *)"C++ 'this' pointer, if any"},
   {(char *)"this", (sizeof(void*) == sizeof(int)) ? T_UINT : T_ULONGLONG, offsetof(Dtool_PyInstDef, _ptr_to_object), READONLY, (char *)"C++ 'this' pointer, if any"},
   {(char *)"this_ownership", T_BOOL, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"},
   {(char *)"this_ownership", T_BOOL, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"},
@@ -65,15 +67,6 @@ size_t PyLongOrInt_AsSize_t(PyObject *vv) {
 }
 }
 #endif
 #endif
 
 
-#if PY_VERSION_HEX < 0x03060000
-INLINE static PyObject *_PyObject_CallNoArg(PyObject *func) {
-  PyObject *args = PyTuple_New(0);
-  PyObject *result = PyObject_Call(func, args, NULL);
-  Py_DECREF(args);
-  return result;
-}
-#endif
-
 /**
 /**
  * Given a valid (non-NULL) PyObject, does a simple check to see if it might
  * Given a valid (non-NULL) PyObject, does a simple check to see if it might
  * be an instance of a Panda type.  It does this using a signature that is
  * be an instance of a Panda type.  It does this using a signature that is
@@ -625,6 +618,9 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
       return Dtool_Raise_TypeError("PyType_Ready(Dtool_StaticProperty_Type)");
       return Dtool_Raise_TypeError("PyType_Ready(Dtool_StaticProperty_Type)");
     }
     }
 
 
+    // Initialize the "empty tuple".
+    (void)PyObject_INIT_VAR((PyObject *)&Dtool_EmptyTuple, &PyTuple_Type, 0);
+
     // Initialize the base class of everything.
     // Initialize the base class of everything.
     Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(NULL);
     Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(NULL);
   }
   }

+ 6 - 0
dtool/src/interrogatedb/py_panda.h

@@ -138,6 +138,12 @@ typedef long Py_hash_t;
 #define FMTCHAR_BYTES "s"
 #define FMTCHAR_BYTES "s"
 #endif
 #endif
 
 
+extern EXPCL_INTERROGATEDB PyTupleObject Dtool_EmptyTuple;
+
+#ifndef _PyObject_CallNoArg
+#define _PyObject_CallNoArg(func) PyObject_Call((func), (PyObject *)&Dtool_EmptyTuple, NULL)
+#endif
+
 using namespace std;
 using namespace std;
 
 
 // this is tempory .. untill this is glued better into the panda build system
 // this is tempory .. untill this is glued better into the panda build system

+ 2 - 2
dtool/src/pystub/pystub.cxx

@@ -142,7 +142,6 @@ extern "C" {
   EXPCL_PYSTUB int PyTuple_New(...);
   EXPCL_PYSTUB int PyTuple_New(...);
   EXPCL_PYSTUB int PyTuple_Pack(...);
   EXPCL_PYSTUB int PyTuple_Pack(...);
   EXPCL_PYSTUB int PyTuple_Size(...);
   EXPCL_PYSTUB int PyTuple_Size(...);
-  EXPCL_PYSTUB int PyTuple_Type(...);
   EXPCL_PYSTUB int PyType_GenericAlloc(...);
   EXPCL_PYSTUB int PyType_GenericAlloc(...);
   EXPCL_PYSTUB int PyType_IsSubtype(...);
   EXPCL_PYSTUB int PyType_IsSubtype(...);
   EXPCL_PYSTUB int PyType_Ready(...);
   EXPCL_PYSTUB int PyType_Ready(...);
@@ -224,6 +223,7 @@ extern "C" {
   EXPCL_PYSTUB extern void *PyExc_SystemExit;
   EXPCL_PYSTUB extern void *PyExc_SystemExit;
   EXPCL_PYSTUB extern void *PyExc_TypeError;
   EXPCL_PYSTUB extern void *PyExc_TypeError;
   EXPCL_PYSTUB extern void *PyExc_ValueError;
   EXPCL_PYSTUB extern void *PyExc_ValueError;
+  EXPCL_PYSTUB extern void *PyTuple_Type;
   EXPCL_PYSTUB extern void *PyType_Type;
   EXPCL_PYSTUB extern void *PyType_Type;
   EXPCL_PYSTUB extern void *_PyThreadState_Current;
   EXPCL_PYSTUB extern void *_PyThreadState_Current;
   EXPCL_PYSTUB extern void *_Py_FalseStruct;
   EXPCL_PYSTUB extern void *_Py_FalseStruct;
@@ -363,7 +363,6 @@ int PyTuple_GetItem(...) { return 0; }
 int PyTuple_New(...) { return 0; }
 int PyTuple_New(...) { return 0; }
 int PyTuple_Pack(...) { return 0; }
 int PyTuple_Pack(...) { return 0; }
 int PyTuple_Size(...) { return 0; };
 int PyTuple_Size(...) { return 0; };
-int PyTuple_Type(...) { return 0; };
 int PyType_GenericAlloc(...) { return 0; };
 int PyType_GenericAlloc(...) { return 0; };
 int PyType_IsSubtype(...) { return 0; }
 int PyType_IsSubtype(...) { return 0; }
 int PyType_Ready(...) { return 0; };
 int PyType_Ready(...) { return 0; };
@@ -451,6 +450,7 @@ void *PyExc_StopIteration = (void *)NULL;
 void *PyExc_SystemExit = (void *)NULL;
 void *PyExc_SystemExit = (void *)NULL;
 void *PyExc_TypeError = (void *)NULL;
 void *PyExc_TypeError = (void *)NULL;
 void *PyExc_ValueError = (void *)NULL;
 void *PyExc_ValueError = (void *)NULL;
+void *PyTuple_Type = (void *)NULL;
 void *PyType_Type = (void *)NULL;
 void *PyType_Type = (void *)NULL;
 void *_PyThreadState_Current = (void *)NULL;
 void *_PyThreadState_Current = (void *)NULL;
 void *_Py_FalseStruct = (void *)NULL;
 void *_Py_FalseStruct = (void *)NULL;

+ 8 - 2
makepanda/test_imports.py

@@ -7,13 +7,19 @@ import os, importlib
 import direct.showbase.VerboseImport
 import direct.showbase.VerboseImport
 
 
 
 
+import imp
 import panda3d
 import panda3d
 dir = os.path.dirname(panda3d.__file__)
 dir = os.path.dirname(panda3d.__file__)
 
 
+extensions = set()
+for suffix in imp.get_suffixes():
+    extensions.add(suffix[0])
+
 for basename in os.listdir(dir):
 for basename in os.listdir(dir):
-    module, ext = os.path.splitext(basename)
+    module = basename.split('.', 1)[0]
+    ext = basename[len(module):]
 
 
-    if ext in ('.pyd', '.so'):
+    if ext in extensions:
         importlib.import_module('panda3d.%s' % (module))
         importlib.import_module('panda3d.%s' % (module))
 
 
 
 

+ 4 - 0
panda/src/express/datagramSink.h

@@ -40,6 +40,10 @@ PUBLISHED:
   virtual const Filename &get_filename();
   virtual const Filename &get_filename();
   virtual const FileReference *get_file();
   virtual const FileReference *get_file();
   virtual streampos get_file_pos();
   virtual streampos get_file_pos();
+
+  MAKE_PROPERTY(filename, get_filename);
+  MAKE_PROPERTY(file, get_file);
+  MAKE_PROPERTY(file_pos, get_file_pos);
 };
 };
 
 
 #include "datagramSink.I"
 #include "datagramSink.I"

+ 7 - 2
panda/src/putil/datagramOutputFile.h

@@ -28,14 +28,13 @@
  * header followed by a number of datagrams.
  * header followed by a number of datagrams.
  */
  */
 class EXPCL_PANDA_PUTIL DatagramOutputFile : public DatagramSink {
 class EXPCL_PANDA_PUTIL DatagramOutputFile : public DatagramSink {
-public:
+PUBLISHED:
   INLINE DatagramOutputFile();
   INLINE DatagramOutputFile();
   INLINE ~DatagramOutputFile();
   INLINE ~DatagramOutputFile();
 
 
   bool open(const FileReference *file);
   bool open(const FileReference *file);
   INLINE bool open(const Filename &filename);
   INLINE bool open(const Filename &filename);
   bool open(ostream &out, const Filename &filename = Filename());
   bool open(ostream &out, const Filename &filename = Filename());
-  INLINE ostream &get_stream();
 
 
   void close();
   void close();
 
 
@@ -46,10 +45,16 @@ public:
   virtual bool is_error();
   virtual bool is_error();
   virtual void flush();
   virtual void flush();
 
 
+public:
   virtual const Filename &get_filename();
   virtual const Filename &get_filename();
   virtual const FileReference *get_file();
   virtual const FileReference *get_file();
   virtual streampos get_file_pos();
   virtual streampos get_file_pos();
 
 
+  INLINE ostream &get_stream();
+
+PUBLISHED:
+  MAKE_PROPERTY(stream, get_stream);
+
 private:
 private:
   bool _wrote_first_datagram;
   bool _wrote_first_datagram;
   bool _error;
   bool _error;

+ 10 - 6
panda/src/windisplay/winGraphicsWindow.cxx

@@ -1440,15 +1440,12 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
     break;
     break;
 
 
   case WM_SIZE:
   case WM_SIZE:
+    // Actually, since we don't return in WM_WINDOWPOSCHANGED, WM_SIZE won't
+    // end up being called at all.  This is more efficient according to MSDN.
     if (windisplay_cat.is_debug()) {
     if (windisplay_cat.is_debug()) {
       windisplay_cat.debug()
       windisplay_cat.debug()
         << "WM_SIZE: " << hwnd << ", " << wparam << "\n";
         << "WM_SIZE: " << hwnd << ", " << wparam << "\n";
     }
     }
-
-    // Resist calling handle_reshape before the window has opened.
-    if (_hWnd != NULL) {
-      handle_reshape();
-    }
     break;
     break;
 
 
   case WM_EXITSIZEMOVE:
   case WM_EXITSIZEMOVE:
@@ -1456,8 +1453,15 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
     break;
     break;
 
 
   case WM_WINDOWPOSCHANGED:
   case WM_WINDOWPOSCHANGED:
+    if (windisplay_cat.is_debug()) {
+      windisplay_cat.debug()
+        << "WM_WINDOWPOSCHANGED: " << hwnd << ", " << wparam << "\n";
+    }
+    if (_hWnd != NULL) {
+      handle_reshape();
+    }
     adjust_z_order();
     adjust_z_order();
-    break;
+    return 0;
 
 
   case WM_PAINT:
   case WM_PAINT:
     // In response to WM_PAINT, we check to see if there are any update
     // In response to WM_PAINT, we check to see if there are any update