Browse Source

Merge branch 'master' into ios

Donny Lawrence 5 years ago
parent
commit
7db1b5b574
55 changed files with 1186 additions and 509 deletions
  1. 1 1
      .editorconfig
  2. 1 1
      .github/codecov.yml
  3. 2 0
      direct/src/dcparser/dcClass.cxx
  4. 3 2
      direct/src/dcparser/dcClass.h
  5. 3 0
      direct/src/dcparser/dcLexer.cxx.prebuilt
  6. 3 1
      direct/src/dcparser/dcLexer.lxx
  7. 2 0
      direct/src/dcparser/dcbase.h
  8. 134 15
      direct/src/dist/FreezeTool.py
  9. 0 7
      direct/src/dist/commands.py
  10. 5 5
      direct/src/showbase/DirectObject.py
  11. 0 1
      direct/src/showbase/ProfileSession.py
  12. 1 1
      dtool/Package.cmake
  13. 432 353
      dtool/src/cppparser/cppBison.cxx.prebuilt
  14. 6 2
      dtool/src/cppparser/cppBison.h.prebuilt
  15. 13 37
      dtool/src/cppparser/cppBison.yxx
  16. 47 9
      dtool/src/cppparser/cppExpression.cxx
  17. 3 1
      dtool/src/cppparser/cppExpression.h
  18. 11 1
      dtool/src/cppparser/cppInstance.cxx
  19. 1 1
      dtool/src/cppparser/cppInstanceIdentifier.cxx
  20. 2 2
      dtool/src/cppparser/cppInstanceIdentifier.h
  21. 15 11
      dtool/src/parser-inc/map
  22. 2 0
      dtool/src/parser-inc/ostream
  23. 9 8
      dtool/src/parser-inc/string
  24. 10 6
      dtool/src/parser-inc/vector
  25. 1 1
      makepanda/makepanda.py
  26. 1 0
      panda/src/cocoadisplay/cocoaGraphicsWindow.h
  27. 52 2
      panda/src/cocoadisplay/cocoaGraphicsWindow.mm
  28. 2 1
      panda/src/collide/collisionPolygon.h
  29. 7 0
      panda/src/display/config_display.cxx
  30. 1 0
      panda/src/display/config_display.h
  31. 1 0
      panda/src/display/graphicsWindow.cxx
  32. 39 0
      panda/src/display/windowProperties.I
  33. 7 0
      panda/src/display/windowProperties.cxx
  34. 9 0
      panda/src/display/windowProperties.h
  35. 3 3
      panda/src/downloader/httpClient.I
  36. 4 4
      panda/src/grutil/meshDrawer2D.I
  37. 2 2
      panda/src/grutil/meshDrawer2D.h
  38. 12 4
      panda/src/nativenet/buffered_datagramconnection.h
  39. 7 5
      panda/src/pgraph/geomNode.cxx
  40. 6 0
      panda/src/pgraph/pandaNode_ext.cxx
  41. 9 0
      panda/src/pgui/pgItem.h
  42. 5 5
      panda/src/putil/bitArray.cxx
  43. 60 14
      panda/src/windisplay/winGraphicsWindow.cxx
  44. 2 0
      panda/src/x11display/x11GraphicsPipe.cxx
  45. 2 0
      panda/src/x11display/x11GraphicsPipe.h
  46. 75 1
      panda/src/x11display/x11GraphicsWindow.cxx
  47. 3 0
      pandatool/src/deploy-stub/deploy-stub.c
  48. 0 1
      samples/fireflies/light.sha
  49. 20 0
      tests/display/test_winprops.py
  50. 18 0
      tests/pgraph/test_cullfaceattrib.py
  51. 34 0
      tests/pgraph/test_lightattrib.py
  52. 29 0
      tests/pgraph/test_nodepath.py
  53. 5 1
      tests/pgraph/test_shaderattrib.py
  54. 47 0
      tests/pgraph/test_textureattrib.py
  55. 17 0
      tests/putil/test_bitarray.py

+ 1 - 1
.editorconfig

@@ -10,7 +10,7 @@ insert_final_newline = true
 indent_style = space
 indent_style = space
 indent_size = 4
 indent_size = 4
 
 
-[*.{h,c,cxx,cpp,I}]
+[*.{h,c,cxx,cpp,I,T}]
 indent_style = space
 indent_style = space
 indent_size = 2
 indent_size = 2
 
 

+ 1 - 1
.github/codecov.yml

@@ -5,7 +5,7 @@ coverage:
         threshold: 0.1
         threshold: 0.1
     patch:
     patch:
       default:
       default:
-        threshold: 0.1
+        target: 0%
 codecov:
 codecov:
   require_ci_to_pass: true
   require_ci_to_pass: true
   notify:
   notify:

+ 2 - 0
direct/src/dcparser/dcClass.cxx

@@ -77,7 +77,9 @@ DCClass(DCFile *dc_file, const string &name, bool is_struct, bool bogus_class) :
   _number = -1;
   _number = -1;
   _constructor = nullptr;
   _constructor = nullptr;
 
 
+#ifdef WITHIN_PANDA
   _python_class_defs = nullptr;
   _python_class_defs = nullptr;
+#endif
 }
 }
 
 
 /**
 /**

+ 3 - 2
direct/src/dcparser/dcClass.h

@@ -172,6 +172,9 @@ private:
   typedef pmap<int, DCField *> FieldsByIndex;
   typedef pmap<int, DCField *> FieldsByIndex;
   FieldsByIndex _fields_by_index;
   FieldsByIndex _fields_by_index;
 
 
+  friend class DCField;
+
+#ifdef WITHIN_PANDA
   // See pandaNode.h for an explanation of this trick
   // See pandaNode.h for an explanation of this trick
   class PythonClassDefs : public ReferenceCount {
   class PythonClassDefs : public ReferenceCount {
   public:
   public:
@@ -179,8 +182,6 @@ private:
   };
   };
   PT(PythonClassDefs) _python_class_defs;
   PT(PythonClassDefs) _python_class_defs;
 
 
-  friend class DCField;
-#ifdef WITHIN_PANDA
   friend class Extension<DCClass>;
   friend class Extension<DCClass>;
 #endif
 #endif
 };
 };

+ 3 - 0
direct/src/dcparser/dcLexer.cxx.prebuilt

@@ -599,7 +599,10 @@ char *dcyytext;
 #include "dcParser.h"
 #include "dcParser.h"
 #include "dcFile.h"
 #include "dcFile.h"
 #include "dcindent.h"
 #include "dcindent.h"
+
+#ifdef WITHIN_PANDA
 #include "pstrtod.h"
 #include "pstrtod.h"
+#endif
 
 
 
 
 static int yyinput(void);        // declared by flex.
 static int yyinput(void);        // declared by flex.

+ 3 - 1
direct/src/dcparser/dcLexer.lxx

@@ -11,8 +11,10 @@
 #include "dcParser.h"
 #include "dcParser.h"
 #include "dcFile.h"
 #include "dcFile.h"
 #include "dcindent.h"
 #include "dcindent.h"
-#include "pstrtod.h"
 
 
+#ifdef WITHIN_PANDA
+#include "pstrtod.h"
+#endif
 
 
 static int yyinput(void);        // declared by flex.
 static int yyinput(void);        // declared by flex.
 extern "C" int dcyywrap();
 extern "C" int dcyywrap();

+ 2 - 0
direct/src/dcparser/dcbase.h

@@ -70,6 +70,7 @@
 #define BEGIN_PUBLISH
 #define BEGIN_PUBLISH
 #define END_PUBLISH
 #define END_PUBLISH
 #define BLOCKING
 #define BLOCKING
+#define EXTENSION(x)
 
 
 // These control the declspec(dllexport/dllimport) on Windows.  When compiling
 // These control the declspec(dllexport/dllimport) on Windows.  When compiling
 // outside of Panda, we assume we aren't part of a DLL.
 // outside of Panda, we assume we aren't part of a DLL.
@@ -100,6 +101,7 @@ typedef std::string Filename;
 #define pmap std::map
 #define pmap std::map
 #define pset std::set
 #define pset std::set
 #define vector_uchar std::vector<unsigned char>
 #define vector_uchar std::vector<unsigned char>
+#define patof(x) atof(x)
 
 
 #include <stdint.h>
 #include <stdint.h>
 #include <string.h>
 #include <string.h>

+ 134 - 15
direct/src/dist/FreezeTool.py

@@ -639,6 +639,51 @@ okMissing = [
     'direct.extensions_native.extensions_darwin',
     'direct.extensions_native.extensions_darwin',
     ]
     ]
 
 
+# Since around macOS 10.15, Apple's codesigning process has become more strict.
+# Appending data to the end of a Mach-O binary is now explicitly forbidden. The
+# solution is to embed our own segment into the binary so it can be properly
+# signed.
+mach_header_64_layout = '<IIIIIIII'
+
+# Each load command is guaranteed to start with the command identifier and
+# command size. We'll call this the "lc header".
+lc_header_layout = '<II'
+
+# Each Mach-O segment is made up of sections. We need to change both the segment
+# and section information, so we'll need to know the layout of a section as
+# well.
+section64_header_layout = '<16s16sQQIIIIIIII'
+
+# These are all of the load commands we'll need to modify parts of.
+LC_SEGMENT_64 = 0x19
+LC_DYLD_INFO_ONLY = 0x80000022
+LC_SYMTAB = 0x02
+LC_DYSYMTAB = 0x0B
+LC_FUNCTION_STARTS = 0x26
+LC_DATA_IN_CODE = 0x29
+
+lc_layouts = {
+    LC_SEGMENT_64: '<II16sQQQQIIII',
+    LC_DYLD_INFO_ONLY: '<IIIIIIIIIIII',
+    LC_SYMTAB: '<IIIIII',
+    LC_DYSYMTAB: '<IIIIIIIIIIIIIIIIIIII',
+    LC_FUNCTION_STARTS: '<IIII',
+    LC_DATA_IN_CODE: '<IIII',
+}
+
+# All of our modifications involve sliding some offsets, since we need to insert
+# our data in the middle of the binary (we can't just put the data at the end
+# since __LINKEDIT must be the last segment).
+lc_indices_to_slide = {
+    b'__PANDA': [4, 6],
+    b'__LINKEDIT': [3, 5],
+    LC_DYLD_INFO_ONLY: [2, 4, 8, 10],
+    LC_SYMTAB: [2, 4],
+    LC_DYSYMTAB: [14],
+    LC_FUNCTION_STARTS: [2],
+    LC_DATA_IN_CODE: [2],
+}
+
 class Freezer:
 class Freezer:
     class ModuleDef:
     class ModuleDef:
         def __init__(self, moduleName, filename = None,
         def __init__(self, moduleName, filename = None,
@@ -1799,21 +1844,36 @@ class Freezer:
             # Align to page size, so that it can be mmapped.
             # Align to page size, so that it can be mmapped.
             blob_align = 4096
             blob_align = 4096
 
 
-        # Add padding before the blob if necessary.
-        blob_offset = len(stub_data)
-        if (blob_offset & (blob_align - 1)) != 0:
-            pad = (blob_align - (blob_offset & (blob_align - 1)))
-            stub_data += (b'\0' * pad)
-            blob_offset += pad
-        assert (blob_offset % blob_align) == 0
-        assert blob_offset == len(stub_data)
-
         # Also determine the total blob size now.  Add padding to the end.
         # Also determine the total blob size now.  Add padding to the end.
         blob_size = pool_offset + len(pool)
         blob_size = pool_offset + len(pool)
-        if blob_size & 31 != 0:
-            pad = (32 - (blob_size & 31))
+        if blob_size & (blob_align - 1) != 0:
+            pad = (blob_align - (blob_size & (blob_align - 1)))
             blob_size += pad
             blob_size += pad
 
 
+        # TODO: Support creating custom sections in universal binaries.
+        append_blob = True
+        if self.platform.startswith('macosx') and len(bitnesses) == 1:
+            # If our deploy-stub has a __PANDA segment, we know we're meant to
+            # put our blob there rather than attach it to the end.
+            load_commands = self._parse_macho_load_commands(stub_data)
+            if b'__PANDA' in load_commands.keys():
+                append_blob = False
+
+        if self.platform.startswith("macosx") and not append_blob:
+            # Take this time to shift any Mach-O structures around to fit our
+            # blob. We don't need to worry about aligning the offset since the
+            # compiler already took care of that when creating the segment.
+            blob_offset = self._shift_macho_structures(stub_data, load_commands, blob_size)
+        else:
+            # Add padding before the blob if necessary.
+            blob_offset = len(stub_data)
+            if (blob_offset & (blob_align - 1)) != 0:
+                pad = (blob_align - (blob_offset & (blob_align - 1)))
+                stub_data += (b'\0' * pad)
+                blob_offset += pad
+            assert (blob_offset % blob_align) == 0
+            assert blob_offset == len(stub_data)
+
         # Calculate the offsets for the variables.  These are pointers,
         # Calculate the offsets for the variables.  These are pointers,
         # relative to the beginning of the blob.
         # relative to the beginning of the blob.
         field_offsets = {}
         field_offsets = {}
@@ -1893,9 +1953,13 @@ class Freezer:
             blob += struct.pack('<Q', blob_offset)
             blob += struct.pack('<Q', blob_offset)
 
 
         with open(target, 'wb') as f:
         with open(target, 'wb') as f:
-            f.write(stub_data)
-            assert f.tell() == blob_offset
-            f.write(blob)
+            if append_blob:
+                f.write(stub_data)
+                assert f.tell() == blob_offset
+                f.write(blob)
+            else:
+                stub_data[blob_offset:blob_offset + blob_size] = blob
+                f.write(stub_data)
 
 
         os.chmod(target, 0o755)
         os.chmod(target, 0o755)
         return target
         return target
@@ -2153,7 +2217,9 @@ class Freezer:
                     symoff += nlist_size
                     symoff += nlist_size
                     name = strings[strx : strings.find(b'\0', strx)]
                     name = strings[strx : strings.find(b'\0', strx)]
 
 
-                    if name == b'_' + symbol_name:
+                    # If the entry's type has any bits at 0xe0 set, it's a debug
+                    # symbol, and will point us to the wrong place.
+                    if name == b'_' + symbol_name and type & 0xe0 == 0:
                         # Find out in which segment this is.
                         # Find out in which segment this is.
                         for vmaddr, vmsize, fileoff in segments:
                         for vmaddr, vmsize, fileoff in segments:
                             # Is it defined in this segment?
                             # Is it defined in this segment?
@@ -2163,6 +2229,59 @@ class Freezer:
                                 return fileoff + rel
                                 return fileoff + rel
                         print("Could not find memory address for symbol %s" % (symbol_name))
                         print("Could not find memory address for symbol %s" % (symbol_name))
 
 
+    def _parse_macho_load_commands(self, macho_data):
+        """Returns the list of load commands from macho_data."""
+        mach_header_64 = list(
+            struct.unpack_from(mach_header_64_layout, macho_data, 0))
+
+        num_load_commands = mach_header_64[4]
+
+        load_commands = {}
+
+        curr_lc_offset = struct.calcsize(mach_header_64_layout)
+        for i in range(num_load_commands):
+            lc = struct.unpack_from(lc_header_layout, macho_data, curr_lc_offset)
+            layout = lc_layouts.get(lc[0])
+            if layout:
+                # Make it a list since we want to mutate it.
+                lc = list(struct.unpack_from(layout, macho_data, curr_lc_offset))
+
+                if lc[0] == LC_SEGMENT_64:
+                    stripped_name = lc[2].rstrip(b'\0')
+                    if stripped_name in [b'__PANDA', b'__LINKEDIT']:
+                        load_commands[stripped_name] = (curr_lc_offset, lc)
+                else:
+                    load_commands[lc[0]] = (curr_lc_offset, lc)
+
+            curr_lc_offset += lc[1]
+
+        return load_commands
+
+    def _shift_macho_structures(self, macho_data, load_commands, blob_size):
+        """Given the stub and the size of our blob, make room for it and edit
+        all of the necessary structures to keep the binary valid. Returns the
+        offset where the blob should be placed."""
+
+        for lc_key in load_commands.keys():
+            for index in lc_indices_to_slide[lc_key]:
+                load_commands[lc_key][1][index] += blob_size
+
+            if lc_key == b'__PANDA':
+                section_header_offset = load_commands[lc_key][0] + struct.calcsize(lc_layouts[LC_SEGMENT_64])
+                section_header = list(struct.unpack_from(section64_header_layout, macho_data, section_header_offset))
+                section_header[3] = blob_size
+                struct.pack_into(section64_header_layout, macho_data, section_header_offset, *section_header)
+
+            layout = LC_SEGMENT_64 if lc_key in [b'__PANDA', b'__LINKEDIT'] else lc_key
+            struct.pack_into(lc_layouts[layout], macho_data, load_commands[lc_key][0], *load_commands[lc_key][1])
+
+        blob_offset = load_commands[b'__PANDA'][1][5]
+
+        # Write in some null bytes until we write in the actual blob.
+        macho_data[blob_offset:blob_offset] = b'\0' * blob_size
+
+        return blob_offset
+
     def makeModuleDef(self, mangledName, code):
     def makeModuleDef(self, mangledName, code):
         result = ''
         result = ''
         result += 'static unsigned char %s[] = {' % (mangledName)
         result += 'static unsigned char %s[] = {' % (mangledName)

+ 0 - 7
direct/src/dist/commands.py

@@ -4,10 +4,6 @@ See the :ref:`distribution` section of the programming manual for information
 on how to use these commands.
 on how to use these commands.
 """
 """
 
 
-from __future__ import print_function
-
-from pathlib import Path
-from modulefinder import ModuleFinder
 import collections
 import collections
 import os
 import os
 import plistlib
 import plistlib
@@ -35,9 +31,6 @@ import panda3d.core as p3d
 
 
 
 
 if sys.version_info < (3, 0):
 if sys.version_info < (3, 0):
-    # Python 3 defines these subtypes of IOError, but Python 2 doesn't.
-    FileNotFoundError = IOError
-
     # Warn the user.  They might be using Python 2 by accident.
     # Warn the user.  They might be using Python 2 by accident.
     print("=================================================================")
     print("=================================================================")
     print("WARNING: You are using Python 2, which has reached the end of its")
     print("WARNING: You are using Python 2, which has reached the end of its")

+ 5 - 5
direct/src/showbase/DirectObject.py

@@ -94,12 +94,12 @@ class DirectObject:
         if hasattr(self, '_taskList'):
         if hasattr(self, '_taskList'):
             tasks = [task.name for task in self._taskList.values()]
             tasks = [task.name for task in self._taskList.values()]
         if len(events) or len(tasks):
         if len(events) or len(tasks):
-            estr = choice(len(events), 'listening to events: %s' % events, '')
-            andStr = choice(len(events) and len(tasks), ' and ', '')
-            tstr = choice(len(tasks), '%srunning tasks: %s' % (andStr, tasks), '')
+            estr = ('listening to events: %s' % events if len(events) else '')
+            andStr = (' and ' if len(events) and len(tasks) else '')
+            tstr = ('%srunning tasks: %s' % (andStr, tasks) if len(tasks) else '')
             notify = directNotify.newCategory('LeakDetect')
             notify = directNotify.newCategory('LeakDetect')
-            func = choice(getRepository()._crashOnProactiveLeakDetect,
-                          self.notify.error, self.notify.warning)
+            crash = getattr(getRepository(), '_crashOnProactiveLeakDetect', False)
+            func = (self.notify.error if crash else self.notify.warning)
             func('destroyed %s instance is still %s%s' % (self.__class__.__name__, estr, tstr))
             func('destroyed %s instance is still %s%s' % (self.__class__.__name__, estr, tstr))
 
 
     #snake_case alias:
     #snake_case alias:

+ 0 - 1
direct/src/showbase/ProfileSession.py

@@ -1,4 +1,3 @@
-from __future__ import print_function
 from panda3d.core import TrueClock
 from panda3d.core import TrueClock
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.showbase.PythonUtil import (
 from direct.showbase.PythonUtil import (

+ 1 - 1
dtool/Package.cmake

@@ -408,7 +408,7 @@ package_status(SQUISH "libsquish")
 #
 #
 
 
 # Assimp
 # Assimp
-find_package(Assimp QUIET)
+find_package(Assimp QUIET MODULE)
 
 
 package_option(Assimp
 package_option(Assimp
   "Build pandatool with support for loading 3D assets supported by Assimp.")
   "Build pandatool with support for loading 3D assets supported by Assimp.")

File diff suppressed because it is too large
+ 432 - 353
dtool/src/cppparser/cppBison.cxx.prebuilt


+ 6 - 2
dtool/src/cppparser/cppBison.h.prebuilt

@@ -1,8 +1,9 @@
-/* A Bison parser, made by GNU Bison 3.0.5.  */
+/* A Bison parser, made by GNU Bison 3.5.3.  */
 
 
 /* Bison interface for Yacc-like parsers in C
 /* Bison interface for Yacc-like parsers in C
 
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+   Inc.
 
 
    This program is free software: you can redistribute it and/or modify
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
@@ -30,6 +31,9 @@
    This special exception was added by the Free Software Foundation in
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
    version 2.2 of Bison.  */
 
 
+/* Undocumented macros, especially those whose name start with YY_,
+   are private implementation details.  Do not rely on them.  */
+
 #ifndef YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED
 #ifndef YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED
 # define YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED
 # define YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED
 /* Debug traces.  */
 /* Debug traces.  */

+ 13 - 37
dtool/src/cppparser/cppBison.yxx

@@ -1891,7 +1891,7 @@ instance_identifier_and_maybe_trailing_return_type:
   }
   }
   $$ = $1;
   $$ = $1;
 }
 }
-        | instance_identifier ':' INTEGER
+        | instance_identifier ':' const_expr
 {
 {
   // Bitfield definition.
   // Bitfield definition.
   $1->_bit_width = $3;
   $1->_bit_width = $3;
@@ -3278,17 +3278,9 @@ no_angle_bracket_const_expr:
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
 }
 }
-        | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY
+        | KW_SIZEOF no_angle_bracket_const_expr %prec UNARY
 {
 {
-  CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer);
-  if (arg == nullptr) {
-    yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3);
-  } else if (arg->get_subtype() == CPPDeclaration::ST_instance) {
-    CPPInstance *inst = arg->as_instance();
-    $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type));
-  } else {
-    $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type()));
-  }
+  $$ = new CPPExpression(CPPExpression::sizeof_func($2));
 }
 }
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
 {
 {
@@ -3402,9 +3394,9 @@ no_angle_bracket_const_expr:
 {
 {
   $$ = new CPPExpression('f', $1);
   $$ = new CPPExpression('f', $1);
 }
 }
-        | no_angle_bracket_const_expr '.' no_angle_bracket_const_expr
+        | no_angle_bracket_const_expr '.' name
 {
 {
-  $$ = new CPPExpression('.', $1, $3);
+  $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer));
 }
 }
         | no_angle_bracket_const_expr POINTSAT no_angle_bracket_const_expr
         | no_angle_bracket_const_expr POINTSAT no_angle_bracket_const_expr
 {
 {
@@ -3542,17 +3534,9 @@ const_expr:
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
 }
 }
-        | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY
+        | KW_SIZEOF const_expr %prec UNARY
 {
 {
-  CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer);
-  if (arg == nullptr) {
-    yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3);
-  } else if (arg->get_subtype() == CPPDeclaration::ST_instance) {
-    CPPInstance *inst = arg->as_instance();
-    $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type));
-  } else {
-    $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type()));
-  }
+  $$ = new CPPExpression(CPPExpression::sizeof_func($2));
 }
 }
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
 {
 {
@@ -3704,9 +3688,9 @@ const_expr:
 {
 {
   $$ = new CPPExpression('f', $1);
   $$ = new CPPExpression('f', $1);
 }
 }
-        | const_expr '.' const_expr
+        | const_expr '.' name
 {
 {
-  $$ = new CPPExpression('.', $1, $3);
+  $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer));
 }
 }
         | const_expr POINTSAT const_expr
         | const_expr POINTSAT const_expr
 {
 {
@@ -3886,17 +3870,9 @@ formal_const_expr:
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
 }
 }
-        | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY
+        | KW_SIZEOF formal_const_expr %prec UNARY
 {
 {
-  CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer);
-  if (arg == nullptr) {
-    yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3);
-  } else if (arg->get_subtype() == CPPDeclaration::ST_instance) {
-    CPPInstance *inst = arg->as_instance();
-    $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type));
-  } else {
-    $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type()));
-  }
+  $$ = new CPPExpression(CPPExpression::sizeof_func($2));
 }
 }
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
 {
 {
@@ -4044,9 +4020,9 @@ formal_const_expr:
 {
 {
   $$ = new CPPExpression('f', $1);
   $$ = new CPPExpression('f', $1);
 }
 }
-        | formal_const_expr '.' const_expr
+        | formal_const_expr '.' name
 {
 {
-  $$ = new CPPExpression('.', $1, $3);
+  $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer));
 }
 }
         | formal_const_expr POINTSAT const_expr
         | formal_const_expr POINTSAT const_expr
 {
 {

+ 47 - 9
dtool/src/cppparser/cppExpression.cxx

@@ -429,12 +429,24 @@ type_trait(int trait, CPPType *type, CPPType *arg) {
 CPPExpression CPPExpression::
 CPPExpression CPPExpression::
 sizeof_func(CPPType *type) {
 sizeof_func(CPPType *type) {
   CPPExpression expr(0);
   CPPExpression expr(0);
-  expr._type = T_sizeof;
+  expr._type = T_sizeof_type;
   expr._u._typecast._to = type;
   expr._u._typecast._to = type;
   expr._u._typecast._op1 = nullptr;
   expr._u._typecast._op1 = nullptr;
   return expr;
   return expr;
 }
 }
 
 
+/**
+ *
+ */
+CPPExpression CPPExpression::
+sizeof_func(CPPExpression *op1) {
+  CPPExpression expr(0);
+  expr._type = T_sizeof_expr;
+  expr._u._typecast._to = nullptr;
+  expr._u._typecast._op1 = op1;
+  return expr;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -629,7 +641,8 @@ evaluate() const {
   case T_empty_aggregate_init:
   case T_empty_aggregate_init:
   case T_new:
   case T_new:
   case T_default_new:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
+  case T_sizeof_expr:
   case T_sizeof_ellipsis:
   case T_sizeof_ellipsis:
     return Result();
     return Result();
 
 
@@ -1058,7 +1071,8 @@ determine_type() const {
   case T_default_new:
   case T_default_new:
     return CPPType::new_type(new CPPPointerType(_u._typecast._to));
     return CPPType::new_type(new CPPPointerType(_u._typecast._to));
 
 
-  case T_sizeof:
+  case T_sizeof_type:
+  case T_sizeof_expr:
   case T_sizeof_ellipsis:
   case T_sizeof_ellipsis:
   case T_alignof:
   case T_alignof:
     // Note: this should actually be size_t, but that is defined as a typedef
     // Note: this should actually be size_t, but that is defined as a typedef
@@ -1334,10 +1348,13 @@ is_fully_specified() const {
   case T_default_construct:
   case T_default_construct:
   case T_empty_aggregate_init:
   case T_empty_aggregate_init:
   case T_default_new:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
   case T_alignof:
     return _u._typecast._to->is_fully_specified();
     return _u._typecast._to->is_fully_specified();
 
 
+  case T_sizeof_expr:
+    return _u._typecast._op1->is_fully_specified();
+
   case T_sizeof_ellipsis:
   case T_sizeof_ellipsis:
     return _u._ident->is_fully_specified();
     return _u._ident->is_fully_specified();
 
 
@@ -1469,7 +1486,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   case T_default_construct:
   case T_default_construct:
   case T_empty_aggregate_init:
   case T_empty_aggregate_init:
   case T_default_new:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
   case T_alignof:
     rep->_u._typecast._to =
     rep->_u._typecast._to =
       _u._typecast._to->substitute_decl(subst, current_scope, global_scope)
       _u._typecast._to->substitute_decl(subst, current_scope, global_scope)
@@ -1477,6 +1494,13 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     any_changed = any_changed || (rep->_u._typecast._to != _u._typecast._to);
     any_changed = any_changed || (rep->_u._typecast._to != _u._typecast._to);
     break;
     break;
 
 
+  case T_sizeof_expr:
+    rep->_u._typecast._op1 =
+      _u._typecast._op1->substitute_decl(subst, current_scope, global_scope)
+      ->as_expression();
+    any_changed = any_changed || (rep->_u._typecast._op1 != _u._typecast._op1);
+    break;
+
   case T_trinary_operation:
   case T_trinary_operation:
     rep->_u._op._op3 =
     rep->_u._op._op3 =
       _u._op._op3->substitute_decl(subst, current_scope, global_scope)
       _u._op._op3->substitute_decl(subst, current_scope, global_scope)
@@ -1567,10 +1591,13 @@ is_tbd() const {
   case T_new:
   case T_new:
   case T_default_construct:
   case T_default_construct:
   case T_default_new:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
   case T_alignof:
     return _u._typecast._to->is_tbd();
     return _u._typecast._to->is_tbd();
 
 
+  case T_sizeof_expr:
+    return _u._typecast._op1->is_tbd();
+
   case T_trinary_operation:
   case T_trinary_operation:
     if (_u._op._op3->is_tbd()) {
     if (_u._op._op3->is_tbd()) {
       return true;
       return true;
@@ -1807,12 +1834,17 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool) const {
     out << "())";
     out << "())";
     break;
     break;
 
 
-  case T_sizeof:
+  case T_sizeof_type:
     out << "sizeof(";
     out << "sizeof(";
     _u._typecast._to->output(out, indent_level, scope, false);
     _u._typecast._to->output(out, indent_level, scope, false);
     out << ")";
     out << ")";
     break;
     break;
 
 
+  case T_sizeof_expr:
+    out << "sizeof ";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    break;
+
   case T_sizeof_ellipsis:
   case T_sizeof_ellipsis:
     out << "sizeof...(";
     out << "sizeof...(";
     _u._ident->output(out, scope);
     _u._ident->output(out, scope);
@@ -2222,10 +2254,13 @@ is_equal(const CPPDeclaration *other) const {
   case T_default_construct:
   case T_default_construct:
   case T_empty_aggregate_init:
   case T_empty_aggregate_init:
   case T_default_new:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
   case T_alignof:
     return _u._typecast._to == ot->_u._typecast._to;
     return _u._typecast._to == ot->_u._typecast._to;
 
 
+  case T_sizeof_expr:
+    return _u._typecast._op1 == ot->_u._typecast._op1;
+
   case T_unary_operation:
   case T_unary_operation:
     return *_u._op._op1 == *ot->_u._op._op1;
     return *_u._op._op1 == *ot->_u._op._op1;
 
 
@@ -2324,10 +2359,13 @@ is_less(const CPPDeclaration *other) const {
   case T_default_construct:
   case T_default_construct:
   case T_empty_aggregate_init:
   case T_empty_aggregate_init:
   case T_default_new:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
   case T_alignof:
     return _u._typecast._to < ot->_u._typecast._to;
     return _u._typecast._to < ot->_u._typecast._to;
 
 
+  case T_sizeof_expr:
+    return _u._typecast._op1 < ot->_u._typecast._op1;
+
   case T_trinary_operation:
   case T_trinary_operation:
     if (*_u._op._op3 != *ot->_u._op._op3) {
     if (*_u._op._op3 != *ot->_u._op._op3) {
       return *_u._op._op3 < *ot->_u._op._op3;
       return *_u._op._op3 < *ot->_u._op._op3;

+ 3 - 1
dtool/src/cppparser/cppExpression.h

@@ -52,7 +52,8 @@ public:
     T_empty_aggregate_init,
     T_empty_aggregate_init,
     T_new,
     T_new,
     T_default_new,
     T_default_new,
-    T_sizeof,
+    T_sizeof_type,
+    T_sizeof_expr,
     T_sizeof_ellipsis,
     T_sizeof_ellipsis,
     T_alignof,
     T_alignof,
     T_unary_operation,
     T_unary_operation,
@@ -89,6 +90,7 @@ public:
   static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info);
   static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info);
   static CPPExpression type_trait(int trait, CPPType *type, CPPType *arg = nullptr);
   static CPPExpression type_trait(int trait, CPPType *type, CPPType *arg = nullptr);
   static CPPExpression sizeof_func(CPPType *type);
   static CPPExpression sizeof_func(CPPType *type);
+  static CPPExpression sizeof_func(CPPExpression *op1);
   static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident);
   static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident);
   static CPPExpression alignof_func(CPPType *type);
   static CPPExpression alignof_func(CPPType *type);
   static CPPExpression lambda(CPPClosureType *type);
   static CPPExpression lambda(CPPClosureType *type);

+ 11 - 1
dtool/src/cppparser/cppInstance.cxx

@@ -74,7 +74,17 @@ CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
   ii->_ident = nullptr;
   ii->_ident = nullptr;
   _storage_class = storage_class;
   _storage_class = storage_class;
   _initializer = nullptr;
   _initializer = nullptr;
-  _bit_width = ii->_bit_width;
+
+  if (ii->_bit_width != nullptr) {
+    CPPExpression::Result result = ii->_bit_width->evaluate();
+    if (result._type != CPPExpression::RT_error) {
+      _bit_width = ii->_bit_width->evaluate().as_integer();
+    } else {
+      _bit_width = -1;
+    }
+  } else {
+    _bit_width = -1;
+  }
 
 
   CPPParameterList *params = ii->get_initializer();
   CPPParameterList *params = ii->get_initializer();
   if (params != nullptr) {
   if (params != nullptr) {

+ 1 - 1
dtool/src/cppparser/cppInstanceIdentifier.cxx

@@ -82,7 +82,7 @@ initializer_type(CPPParameterList *params) {
 CPPInstanceIdentifier::
 CPPInstanceIdentifier::
 CPPInstanceIdentifier(CPPIdentifier *ident) :
 CPPInstanceIdentifier(CPPIdentifier *ident) :
   _ident(ident),
   _ident(ident),
-  _bit_width(-1),
+  _bit_width(nullptr),
   _packed(false) {
   _packed(false) {
 }
 }
 
 

+ 2 - 2
dtool/src/cppparser/cppInstanceIdentifier.h

@@ -86,8 +86,8 @@ public:
   typedef std::vector<Modifier> Modifiers;
   typedef std::vector<Modifier> Modifiers;
   Modifiers _modifiers;
   Modifiers _modifiers;
 
 
-  // If not -1, indicates a bitfield
-  int _bit_width;
+  // If not null, indicates a bitfield
+  CPPExpression *_bit_width;
 
 
   // Indicates a parameter pack
   // Indicates a parameter pack
   bool _packed;
   bool _packed;

+ 15 - 11
dtool/src/parser-inc/map

@@ -24,19 +24,23 @@
 #include <stdcompare.h>
 #include <stdcompare.h>
 #include <pair>
 #include <pair>
 
 
-template<class key, class element, class compare = less<key> >
+namespace std {
+  template<class T> class allocator;
+}
+
+template<class Key, class T, class Compare = less<Key>, class Allocator = std::allocator<pair<const Key, T> > >
 class map {
 class map {
 public:
 public:
-  typedef key key_type;
-  typedef element data_type;
-  typedef element mapped_type;
-  typedef pair<const key, element> value_type;
-  typedef compare key_compare;
-
-  typedef element *pointer;
-  typedef const element *const_pointer;
-  typedef element &reference;
-  typedef const element &const_reference;
+  typedef Key key_type;
+  typedef T data_type;
+  typedef T mapped_type;
+  typedef pair<const Key, T> value_type;
+  typedef Compare key_compare;
+
+  typedef T *pointer;
+  typedef const T *const_pointer;
+  typedef T &reference;
+  typedef const T &const_reference;
 
 
   class iterator;
   class iterator;
   class const_iterator;
   class const_iterator;

+ 2 - 0
dtool/src/parser-inc/ostream

@@ -1,5 +1,7 @@
 #pragma once
 #pragma once
 
 
+#include <iosfwd>
+
 namespace std {
 namespace std {
   template<class CharT, class Traits>
   template<class CharT, class Traits>
   std::basic_ostream<CharT, Traits> &ends(std::basic_ostream<CharT, Traits> &os);
   std::basic_ostream<CharT, Traits> &ends(std::basic_ostream<CharT, Traits> &os);

+ 9 - 8
dtool/src/parser-inc/string

@@ -26,6 +26,7 @@
 
 
 namespace std {
 namespace std {
   template<class charT> struct char_traits;
   template<class charT> struct char_traits;
+  template<class T> class allocator;
 
 
   template<> struct char_traits<char> {
   template<> struct char_traits<char> {
     using char_type = char;
     using char_type = char;
@@ -51,7 +52,7 @@ namespace std {
     using state_type = mbstate_t;
     using state_type = mbstate_t;
   };
   };
 
 
-  template<class ctype>
+  template<class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT> >
   class basic_string {
   class basic_string {
   public:
   public:
     struct iterator;
     struct iterator;
@@ -63,17 +64,17 @@ namespace std {
     static const size_t npos = -1;
     static const size_t npos = -1;
 
 
     basic_string();
     basic_string();
-    basic_string(const basic_string<ctype> &copy);
-    void operator = (const basic_string<ctype> &copy);
-    basic_string(const ctype *string);
+    basic_string(const basic_string<CharT> &copy);
+    void operator = (const basic_string<CharT> &copy);
+    basic_string(const CharT *string);
     ~basic_string();
     ~basic_string();
 
 
-    const ctype *c_str() const;
+    const CharT *c_str() const;
     size_t length() const;
     size_t length() const;
 
 
-    ctype at(size_t pos) const;
-    ctype operator[](size_t pos) const;
-    ctype &operator[](size_t pos);
+    CharT at(size_t pos) const;
+    CharT operator[](size_t pos) const;
+    CharT &operator[](size_t pos);
   };
   };
 
 
   typedef basic_string<char> string;
   typedef basic_string<char> string;

+ 10 - 6
dtool/src/parser-inc/vector

@@ -22,17 +22,21 @@
 
 
 #include <stdtypedefs.h>
 #include <stdtypedefs.h>
 
 
+namespace std {
+  template<class T> class allocator;
+}
+
 inline namespace std {
 inline namespace std {
 
 
-template<class element>
+template<class T, class Allocator = std::allocator<T> >
 class vector {
 class vector {
 public:
 public:
-  typedef element value_type;
+  typedef T value_type;
 
 
-  typedef element *pointer;
-  typedef const element *const_pointer;
-  typedef element &reference;
-  typedef const element &const_reference;
+  typedef T *pointer;
+  typedef const T *const_pointer;
+  typedef T &reference;
+  typedef const T &const_reference;
 
 
   typedef pointer iterator;
   typedef pointer iterator;
   typedef const_pointer const_iterator;
   typedef const_pointer const_iterator;

+ 1 - 1
makepanda/makepanda.py

@@ -168,7 +168,7 @@ def parseopts(args):
     # Options for which to display a deprecation warning.
     # Options for which to display a deprecation warning.
     removedopts = [
     removedopts = [
         "use-touchinput", "no-touchinput", "no-awesomium", "no-directscripts",
         "use-touchinput", "no-touchinput", "no-awesomium", "no-directscripts",
-        "no-carbon", "universal", "no-physx", "no-rocket"
+        "no-carbon", "universal", "no-physx", "no-rocket", "host"
         ]
         ]
 
 
     # All recognized options.
     # All recognized options.

+ 1 - 0
panda/src/cocoadisplay/cocoaGraphicsWindow.h

@@ -51,6 +51,7 @@ public:
   void handle_move_event();
   void handle_move_event();
   void handle_resize_event();
   void handle_resize_event();
   void handle_minimize_event(bool minimized);
   void handle_minimize_event(bool minimized);
+  void handle_maximize_event(bool maximized);
   void handle_foreground_event(bool foreground);
   void handle_foreground_event(bool foreground);
   bool handle_close_request();
   bool handle_close_request();
   void handle_close_event();
   void handle_close_event();

+ 52 - 2
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -405,6 +405,9 @@ open_window() {
   if (!_properties.has_minimized()) {
   if (!_properties.has_minimized()) {
     _properties.set_minimized(false);
     _properties.set_minimized(false);
   }
   }
+  if (!_properties.has_maximized()) {
+    _properties.set_maximized(false);
+  }
   if (!_properties.has_z_order()) {
   if (!_properties.has_z_order()) {
     _properties.set_z_order(WindowProperties::Z_normal);
     _properties.set_z_order(WindowProperties::Z_normal);
   }
   }
@@ -713,7 +716,7 @@ close_window() {
 
 
   if (_window != nil) {
   if (_window != nil) {
     [_window close];
     [_window close];
-    
+
     // Process events once more so any pending NSEvents are cleared. Not doing
     // Process events once more so any pending NSEvents are cleared. Not doing
     // this causes the window to stick around after calling [_window close].
     // this causes the window to stick around after calling [_window close].
     process_events();
     process_events();
@@ -925,6 +928,14 @@ set_properties_now(WindowProperties &properties) {
     properties.clear_origin();
     properties.clear_origin();
   }
   }
 
 
+  if (properties.has_maximized() && _window != nil) {
+    _properties.set_maximized(properties.get_maximized());
+    if (properties.get_maximized() != !![_window isZoomed]) {
+      [_window zoom:nil];
+    }
+    properties.clear_maximized();
+  }
+
   if (properties.has_title() && _window != nil) {
   if (properties.has_title() && _window != nil) {
     _properties.set_title(properties.get_title());
     _properties.set_title(properties.get_title());
     [_window setTitle:[NSString stringWithUTF8String:properties.get_title().c_str()]];
     [_window setTitle:[NSString stringWithUTF8String:properties.get_title().c_str()]];
@@ -1404,10 +1415,12 @@ handle_resize_event() {
 
 
   NSRect frame = [_view convertRect:[_view bounds] toView:nil];
   NSRect frame = [_view convertRect:[_view bounds] toView:nil];
 
 
+  WindowProperties properties;
+  bool changed = false;
+
   if (frame.size.width != _properties.get_x_size() ||
   if (frame.size.width != _properties.get_x_size() ||
       frame.size.height != _properties.get_y_size()) {
       frame.size.height != _properties.get_y_size()) {
 
 
-    WindowProperties properties;
     properties.set_size(frame.size.width, frame.size.height);
     properties.set_size(frame.size.width, frame.size.height);
 
 
     if (cocoadisplay_cat.is_spam()) {
     if (cocoadisplay_cat.is_spam()) {
@@ -1415,6 +1428,18 @@ handle_resize_event() {
         << "Window changed size to (" << frame.size.width
         << "Window changed size to (" << frame.size.width
        << ", " << frame.size.height << ")\n";
        << ", " << frame.size.height << ")\n";
     }
     }
+    changed = true;
+  }
+
+  if (_window != nil) {
+    bool is_maximized = [_window isZoomed];
+    if (is_maximized != _properties.get_maximized()) {
+      properties.set_maximized(is_maximized);
+      changed = true;
+    }
+  }
+
+  if (changed) {
     system_changed_properties(properties);
     system_changed_properties(properties);
   }
   }
 
 
@@ -1444,6 +1469,31 @@ handle_minimize_event(bool minimized) {
   system_changed_properties(properties);
   system_changed_properties(properties);
 }
 }
 
 
+/**
+ * Called by the window delegate when the window is maximized or
+ * demaximized.
+ */
+void CocoaGraphicsWindow::
+handle_maximize_event(bool maximized) {
+  if (maximized == _properties.get_maximized()) {
+    return;
+  }
+
+  if (cocoadisplay_cat.is_debug()) {
+    if (maximized) {
+      cocoadisplay_cat.debug() << "Window was maximized\n";
+    } else {
+      cocoadisplay_cat.debug() << "Window was demaximized\n";
+    }
+  }
+
+  WindowProperties properties;
+  properties.set_maximized(maximized);
+  system_changed_properties(properties);
+}
+
+
+
 /**
 /**
  * Called by the window delegate when the window has become the key window or
  * Called by the window delegate when the window has become the key window or
  * resigned that status.
  * resigned that status.

+ 2 - 1
panda/src/collide/collisionPolygon.h

@@ -42,6 +42,8 @@ public:
 
 
   virtual CollisionSolid *make_copy();
   virtual CollisionSolid *make_copy();
 
 
+  static bool verify_points(const LPoint3 *begin, const LPoint3 *end);
+
 PUBLISHED:
 PUBLISHED:
   virtual LPoint3 get_collision_origin() const;
   virtual LPoint3 get_collision_origin() const;
 
 
@@ -53,7 +55,6 @@ PUBLISHED:
   INLINE static bool verify_points(const LPoint3 &a, const LPoint3 &b,
   INLINE static bool verify_points(const LPoint3 &a, const LPoint3 &b,
                                    const LPoint3 &c, const LPoint3 &d);
                                    const LPoint3 &c, const LPoint3 &d);
   static bool verify_points(const LPoint3 &a, const LPoint3 &b, const LPoint3 &c);
   static bool verify_points(const LPoint3 &a, const LPoint3 &b, const LPoint3 &c);
-  static bool verify_points(const LPoint3 *begin, const LPoint3 *end);
 
 
   bool is_valid() const;
   bool is_valid() const;
   bool is_concave() const;
   bool is_concave() const;

+ 7 - 0
panda/src/display/config_display.cxx

@@ -328,6 +328,13 @@ ConfigVariableInt win_origin
 ConfigVariableBool fullscreen
 ConfigVariableBool fullscreen
 ("fullscreen", false);
 ("fullscreen", false);
 
 
+ConfigVariableBool maximized
+("maximized", false,
+ PRC_DESC("Start the window in a maximized state as handled by the window"
+          "manager.  In comparison to the fullscreen setting, this will"
+          "usually not remove the window decoration and not occupy the"
+          "whole screen space."));
+
 ConfigVariableBool undecorated
 ConfigVariableBool undecorated
 ("undecorated", false,
 ("undecorated", false,
  PRC_DESC("This specifies the default value of the 'undecorated' window "
  PRC_DESC("This specifies the default value of the 'undecorated' window "

+ 1 - 0
panda/src/display/config_display.h

@@ -73,6 +73,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableBool old_alpha_blend;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt win_size;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt win_size;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt win_origin;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt win_origin;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool fullscreen;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool fullscreen;
+extern EXPCL_PANDA_DISPLAY ConfigVariableBool maximized;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool undecorated;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool undecorated;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool win_fixed_size;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool win_fixed_size;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool cursor_hidden;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool cursor_hidden;

+ 1 - 0
panda/src/display/graphicsWindow.cxx

@@ -54,6 +54,7 @@ GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
   _properties.set_undecorated(false);
   _properties.set_undecorated(false);
   _properties.set_fullscreen(false);
   _properties.set_fullscreen(false);
   _properties.set_minimized(false);
   _properties.set_minimized(false);
+  _properties.set_maximized(false);
   _properties.set_cursor_hidden(false);
   _properties.set_cursor_hidden(false);
 
 
   request_properties(WindowProperties::get_default());
   request_properties(WindowProperties::get_default());

+ 39 - 0
panda/src/display/windowProperties.I

@@ -407,6 +407,45 @@ clear_minimized() {
   _flags &= ~F_minimized;
   _flags &= ~F_minimized;
 }
 }
 
 
+/**
+ * Specifies whether the window should be created maximized (true), or normal
+ * (false).
+ */
+INLINE void WindowProperties::
+set_maximized(bool maximized) {
+  if (maximized) {
+    _flags |= F_maximized;
+  } else {
+    _flags &= ~F_maximized;
+  }
+  _specified |= S_maximized;
+}
+
+/**
+ * Returns true if the window is maximized.
+ */
+INLINE bool WindowProperties::
+get_maximized() const {
+  return (_flags & F_maximized) != 0;
+}
+
+/**
+ * Returns true if set_maximized() has been specified.
+ */
+INLINE bool WindowProperties::
+has_maximized() const {
+  return ((_specified & S_maximized) != 0);
+}
+
+/**
+ * Removes the maximized specification from the properties.
+ */
+INLINE void WindowProperties::
+clear_maximized() {
+  _specified &= ~S_maximized;
+  _flags &= ~F_maximized;
+}
+
 /**
 /**
  * Specifies whether the window should read the raw mouse devices.
  * Specifies whether the window should read the raw mouse devices.
  */
  */

+ 7 - 0
panda/src/display/windowProperties.cxx

@@ -69,6 +69,7 @@ get_config_properties() {
   props.set_fullscreen(fullscreen);
   props.set_fullscreen(fullscreen);
   props.set_undecorated(undecorated);
   props.set_undecorated(undecorated);
   props.set_fixed_size(win_fixed_size);
   props.set_fixed_size(win_fixed_size);
+  props.set_maximized(maximized);
   props.set_cursor_hidden(cursor_hidden);
   props.set_cursor_hidden(cursor_hidden);
   if (!icon_filename.empty()) {
   if (!icon_filename.empty()) {
     props.set_icon_filename(icon_filename);
     props.set_icon_filename(icon_filename);
@@ -240,6 +241,9 @@ add_properties(const WindowProperties &other) {
   if (other.has_minimized()) {
   if (other.has_minimized()) {
     set_minimized(other.get_minimized());
     set_minimized(other.get_minimized());
   }
   }
+  if (other.has_maximized()) {
+    set_maximized(other.get_maximized());
+  }
   if (other.has_raw_mice()) {
   if (other.has_raw_mice()) {
     set_raw_mice(other.get_raw_mice());
     set_raw_mice(other.get_raw_mice());
   }
   }
@@ -296,6 +300,9 @@ output(ostream &out) const {
   if (has_minimized()) {
   if (has_minimized()) {
     out << (get_minimized() ? "minimized " : "!minimized ");
     out << (get_minimized() ? "minimized " : "!minimized ");
   }
   }
+  if (has_maximized()) {
+    out << (get_maximized() ? "maximized " : "!maximized ");
+  }
   if (has_raw_mice()) {
   if (has_raw_mice()) {
     out << (get_raw_mice() ? "raw_mice " : "!raw_mice ");
     out << (get_raw_mice() ? "raw_mice " : "!raw_mice ");
   }
   }

+ 9 - 0
panda/src/display/windowProperties.h

@@ -132,6 +132,13 @@ PUBLISHED:
   MAKE_PROPERTY2(minimized, has_minimized, get_minimized,
   MAKE_PROPERTY2(minimized, has_minimized, get_minimized,
                             set_minimized, clear_minimized);
                             set_minimized, clear_minimized);
 
 
+  INLINE void set_maximized(bool maximized);
+  INLINE bool get_maximized() const;
+  INLINE bool has_maximized() const;
+  INLINE void clear_maximized();
+  MAKE_PROPERTY2(maximized, has_maximized, get_maximized,
+                            set_maximized, clear_maximized);
+
   INLINE void set_raw_mice(bool raw_mice);
   INLINE void set_raw_mice(bool raw_mice);
   INLINE bool get_raw_mice() const;
   INLINE bool get_raw_mice() const;
   INLINE bool has_raw_mice() const;
   INLINE bool has_raw_mice() const;
@@ -202,6 +209,7 @@ private:
     S_mouse_mode           = 0x02000,
     S_mouse_mode           = 0x02000,
     S_parent_window        = 0x04000,
     S_parent_window        = 0x04000,
     S_raw_mice             = 0x08000,
     S_raw_mice             = 0x08000,
+    S_maximized            = 0x10000,
   };
   };
 
 
   // This bitmask represents the truefalse settings for various boolean flags
   // This bitmask represents the truefalse settings for various boolean flags
@@ -211,6 +219,7 @@ private:
     F_fullscreen     = S_fullscreen,
     F_fullscreen     = S_fullscreen,
     F_foreground     = S_foreground,
     F_foreground     = S_foreground,
     F_minimized      = S_minimized,
     F_minimized      = S_minimized,
+    F_maximized      = S_maximized,
     F_open           = S_open,
     F_open           = S_open,
     F_cursor_hidden  = S_cursor_hidden,
     F_cursor_hidden  = S_cursor_hidden,
     F_fixed_size     = S_fixed_size,
     F_fixed_size     = S_fixed_size,

+ 3 - 3
panda/src/downloader/httpClient.I

@@ -111,9 +111,9 @@ get_verify_ssl() const {
  * Specifies the set of ciphers that are to be made available for SSL
  * Specifies the set of ciphers that are to be made available for SSL
  * connections.  This is a string as described in the ciphers(1) man page of
  * connections.  This is a string as described in the ciphers(1) man page of
  * the OpenSSL documentation (or see
  * the OpenSSL documentation (or see
- * https://www.openssl.org/docs/apps/ciphers.html ).  If this isn't specified,
- * the default is provided by the Config file.  You may also specify "DEFAULT"
- * to use the built-in OpenSSL default value.
+ * https://www.openssl.org/docs/man1.1.1/man1/ciphers.html ).  If this isn't
+ * specified, the default is provided by the Config file.  You may also specify
+ * "DEFAULT" to use the built-in OpenSSL default value.
  */
  */
 INLINE void HTTPClient::
 INLINE void HTTPClient::
 set_cipher_list(const std::string &cipher_list) {
 set_cipher_list(const std::string &cipher_list) {

+ 4 - 4
panda/src/grutil/meshDrawer2D.I

@@ -60,7 +60,7 @@ set_budget(int total_budget) {
 }
 }
 
 
 /**
 /**
- * Gets the total triangle budget of the drawer
+ * Gets the total triangle budget of the drawer.
  */
  */
 INLINE int MeshDrawer2D::
 INLINE int MeshDrawer2D::
 get_budget() {
 get_budget() {
@@ -68,7 +68,7 @@ get_budget() {
 }
 }
 
 
 /**
 /**
- * Sets clipping rectangle
+ * Sets the clipping rectangle.
  */
  */
 INLINE void MeshDrawer2D::
 INLINE void MeshDrawer2D::
 set_clip(PN_stdfloat x, PN_stdfloat y, PN_stdfloat w, PN_stdfloat h) {
 set_clip(PN_stdfloat x, PN_stdfloat y, PN_stdfloat w, PN_stdfloat h) {
@@ -79,7 +79,7 @@ set_clip(PN_stdfloat x, PN_stdfloat y, PN_stdfloat w, PN_stdfloat h) {
 }
 }
 
 
 /**
 /**
- * Draws a 2d rectangle.  Ignores the cliping rectangle
+ * Draws a 2D rectangle.  Ignores the clipping rectangle.
  */
  */
 INLINE void MeshDrawer2D::
 INLINE void MeshDrawer2D::
 quad_raw(const LVector3 &v1, const LVector4 &c1, const LVector2 &uv1,
 quad_raw(const LVector3 &v1, const LVector4 &c1, const LVector2 &uv1,
@@ -125,7 +125,7 @@ rectangle_raw(PN_stdfloat x, PN_stdfloat y, PN_stdfloat w, PN_stdfloat h,
 }
 }
 
 
 /**
 /**
- * Draws a 2d rectangle, that can be cliped
+ * Draws a 2D rectangle which can be clipped.
  */
  */
 INLINE void MeshDrawer2D::
 INLINE void MeshDrawer2D::
 rectangle(PN_stdfloat x, PN_stdfloat y, PN_stdfloat w, PN_stdfloat h,
 rectangle(PN_stdfloat x, PN_stdfloat y, PN_stdfloat w, PN_stdfloat h,

+ 2 - 2
panda/src/grutil/meshDrawer2D.h

@@ -39,8 +39,8 @@
 #include "nodePath.h"
 #include "nodePath.h"
 
 
 /**
 /**
- * This class allows the drawing of 2d objects - mainly based on quads and
- * rectangles.  Allows clipping and serverl high level UI theme functions.
+ * This class allows the drawing of 2D objects - mainly based on quads and
+ * rectangles.  It allows clipping and several high level UI theme functions.
  */
  */
 class EXPCL_PANDA_GRUTIL MeshDrawer2D : public TypedObject {
 class EXPCL_PANDA_GRUTIL MeshDrawer2D : public TypedObject {
 PUBLISHED:
 PUBLISHED:

+ 12 - 4
panda/src/nativenet/buffered_datagramconnection.h

@@ -136,7 +136,10 @@ private:
  * used to do a full reset of buffers
  * used to do a full reset of buffers
  */
  */
 inline void Buffered_DatagramConnection::ClearAll(void) {
 inline void Buffered_DatagramConnection::ClearAll(void) {
-  nativenet_cat.error() << "Buffered_DatagramConnection::ClearAll Starting Auto Reset\n";
+  if (nativenet_cat.is_debug()) {
+    nativenet_cat.debug()
+      << "Buffered_DatagramConnection::ClearAll Starting Auto Reset\n";
+  }
   Close();
   Close();
   _Writer.ReSet();
   _Writer.ReSet();
   _Reader.ReSet();
   _Reader.ReSet();
@@ -215,8 +218,11 @@ inline Buffered_DatagramConnection::~Buffered_DatagramConnection(void)
 inline Buffered_DatagramConnection::Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point)
 inline Buffered_DatagramConnection::Buffered_DatagramConnection(int rbufsize, int wbufsize, int write_flush_point)
     :  _Writer(wbufsize,write_flush_point) , _Reader(rbufsize)
     :  _Writer(wbufsize,write_flush_point) , _Reader(rbufsize)
 {
 {
-  nativenet_cat.error() << "Buffered_DatagramConnection Constructor rbufsize = " << rbufsize
-                        << " wbufsize = " << wbufsize << " write_flush_point = " << write_flush_point << "\n";
+  if (nativenet_cat.is_debug()) {
+    nativenet_cat.debug()
+      << "Buffered_DatagramConnection Constructor rbufsize = " << rbufsize
+      << " wbufsize = " << wbufsize << " write_flush_point = " << write_flush_point << "\n";
+  }
 }
 }
 
 
 inline bool  Buffered_DatagramConnection::SendMessageBufferOnly(Datagram &msg)
 inline bool  Buffered_DatagramConnection::SendMessageBufferOnly(Datagram &msg)
@@ -289,7 +295,9 @@ bool Buffered_DatagramConnection::Flush(void)
  * Reset
  * Reset
  */
  */
 inline void Buffered_DatagramConnection::Reset() {
 inline void Buffered_DatagramConnection::Reset() {
-  nativenet_cat.error() << "Buffered_DatagramConnection::Reset()\n";
+  if (nativenet_cat.is_debug()) {
+    nativenet_cat.debug() << "Buffered_DatagramConnection::Reset()\n";
+  }
   ClearAll();
   ClearAll();
 }
 }
 
 

+ 7 - 5
panda/src/pgraph/geomNode.cxx

@@ -507,8 +507,10 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
       << " draw_mask = " << data._draw_mask << "\n";
       << " draw_mask = " << data._draw_mask << "\n";
   }
   }
 
 
+  Thread *current_thread = trav->get_current_thread();
+
   // Get all the Geoms, with no decalling.
   // Get all the Geoms, with no decalling.
-  Geoms geoms = get_geoms(trav->get_current_thread());
+  Geoms geoms = get_geoms(current_thread);
   int num_geoms = geoms.get_num_geoms();
   int num_geoms = geoms.get_num_geoms();
   trav->_geoms_pcollector.add_level(num_geoms);
   trav->_geoms_pcollector.add_level(num_geoms);
   CPT(TransformState) internal_transform = data.get_internal_transform(trav);
   CPT(TransformState) internal_transform = data.get_internal_transform(trav);
@@ -532,9 +534,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
     if (num_geoms > 1) {
     if (num_geoms > 1) {
       if (data._view_frustum != nullptr) {
       if (data._view_frustum != nullptr) {
         // Cull the individual Geom against the view frustum.
         // Cull the individual Geom against the view frustum.
-        CPT(BoundingVolume) geom_volume = geom->get_bounds();
+        CPT(BoundingVolume) geom_volume = geom->get_bounds(current_thread);
         const GeometricBoundingVolume *geom_gbv =
         const GeometricBoundingVolume *geom_gbv =
-          DCAST(GeometricBoundingVolume, geom_volume);
+          geom_volume->as_geometric_bounding_volume();
 
 
         int result = data._view_frustum->contains(geom_gbv);
         int result = data._view_frustum->contains(geom_gbv);
         if (result == BoundingVolume::IF_no_intersection) {
         if (result == BoundingVolume::IF_no_intersection) {
@@ -544,9 +546,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
       }
       }
       if (!data._cull_planes->is_empty()) {
       if (!data._cull_planes->is_empty()) {
         // Also cull the Geom against the cull planes.
         // Also cull the Geom against the cull planes.
-        CPT(BoundingVolume) geom_volume = geom->get_bounds();
+        CPT(BoundingVolume) geom_volume = geom->get_bounds(current_thread);
         const GeometricBoundingVolume *geom_gbv =
         const GeometricBoundingVolume *geom_gbv =
-          DCAST(GeometricBoundingVolume, geom_volume);
+          geom_volume->as_geometric_bounding_volume();
         int result;
         int result;
         data._cull_planes->do_cull(result, state, geom_gbv);
         data._cull_planes->do_cull(result, state, geom_gbv);
         if (result == BoundingVolume::IF_no_intersection) {
         if (result == BoundingVolume::IF_no_intersection) {

+ 6 - 0
panda/src/pgraph/pandaNode_ext.cxx

@@ -165,6 +165,12 @@ clear_python_tag(PyObject *key) {
   if (PyDict_GetItem(dict, key) != nullptr) {
   if (PyDict_GetItem(dict, key) != nullptr) {
     PyDict_DelItem(dict, key);
     PyDict_DelItem(dict, key);
   }
   }
+
+  if (PyDict_Size(dict) == 0 && Py_REFCNT(dict) == 1) {
+    // This was the last tag, and do_get_python_tags() made sure we have a
+    // unique reference to the tags, so clear the tag object.
+    _this->_python_tag_data.clear();
+  }
 }
 }
 
 
 /**
 /**

+ 9 - 0
panda/src/pgui/pgItem.h

@@ -141,6 +141,15 @@ PUBLISHED:
   INLINE const std::string &get_id() const;
   INLINE const std::string &get_id() const;
   INLINE void set_id(const std::string &id);
   INLINE void set_id(const std::string &id);
 
 
+  MAKE_PROPERTY(name, get_name, set_name);
+  MAKE_PROPERTY2(frame, has_frame, get_frame, set_frame, clear_frame);
+  MAKE_PROPERTY(state, get_state, set_state);
+  MAKE_PROPERTY(active, get_active, set_active);
+  MAKE_PROPERTY(focus, get_focus, set_focus);
+  MAKE_PROPERTY(background_focus, get_background_focus, set_background_focus);
+  MAKE_PROPERTY(suppress_flags, get_suppress_flags, set_suppress_flags);
+  MAKE_PROPERTY(id, get_id, set_id);
+
   INLINE static std::string get_enter_prefix();
   INLINE static std::string get_enter_prefix();
   INLINE static std::string get_exit_prefix();
   INLINE static std::string get_exit_prefix();
   INLINE static std::string get_within_prefix();
   INLINE static std::string get_within_prefix();

+ 5 - 5
panda/src/putil/bitArray.cxx

@@ -114,6 +114,11 @@ has_any_of(int low_bit, int size) const {
   ++w;
   ++w;
 
 
   while (size > 0) {
   while (size > 0) {
+    if ((size_t)w >= get_num_words()) {
+      // Now we're up to the highest bits.
+      return (_highest_bits != 0);
+    }
+
     if (size <= num_bits_per_word) {
     if (size <= num_bits_per_word) {
       // The remainder fits within one word of the array.
       // The remainder fits within one word of the array.
       return _array[w].has_any_of(0, size);
       return _array[w].has_any_of(0, size);
@@ -125,11 +130,6 @@ has_any_of(int low_bit, int size) const {
     }
     }
     size -= num_bits_per_word;
     size -= num_bits_per_word;
     ++w;
     ++w;
-
-    if (w >= (int)get_num_words()) {
-      // Now we're up to the highest bits.
-      return (_highest_bits != 0);
-    }
   }
   }
 
 
   return false;
   return false;

+ 60 - 14
panda/src/windisplay/winGraphicsWindow.cxx

@@ -306,22 +306,29 @@ set_properties_now(WindowProperties &properties) {
     LPoint2i bottom_right = top_left + _properties.get_size();
     LPoint2i bottom_right = top_left + _properties.get_size();
 
 
     DWORD window_style = make_style(_properties);
     DWORD window_style = make_style(_properties);
+    DWORD current_style = GetWindowLong(_hWnd, GWL_STYLE);
     SetWindowLong(_hWnd, GWL_STYLE, window_style);
     SetWindowLong(_hWnd, GWL_STYLE, window_style);
 
 
-    // Now calculate the proper size and origin with the new window style.
-    RECT view_rect;
-    SetRect(&view_rect, top_left[0], top_left[1],
-            bottom_right[0], bottom_right[1]);
-    WINDOWINFO wi;
-    GetWindowInfo(_hWnd, &wi);
-    AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
-
-    // We need to call this to ensure that the style change takes effect.
-    SetWindowPos(_hWnd, HWND_NOTOPMOST, view_rect.left, view_rect.top,
-                 view_rect.right - view_rect.left,
-                 view_rect.bottom - view_rect.top,
-                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED |
-                 SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+    // If we switched to/from undecorated, calculate the new size.
+    if (((window_style ^ current_style) & WS_CAPTION) != 0) {
+      RECT view_rect;
+      SetRect(&view_rect, top_left[0], top_left[1],
+              bottom_right[0], bottom_right[1]);
+      WINDOWINFO wi;
+      GetWindowInfo(_hWnd, &wi);
+      AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
+
+      SetWindowPos(_hWnd, HWND_NOTOPMOST, view_rect.left, view_rect.top,
+                   view_rect.right - view_rect.left,
+                   view_rect.bottom - view_rect.top,
+                   SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED |
+                   SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+    } else {
+      // We need to call this to ensure that the style change takes effect.
+      SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+                   SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
+                   SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+    }
   }
   }
 
 
   if (properties.has_title()) {
   if (properties.has_title()) {
@@ -402,6 +409,23 @@ set_properties_now(WindowProperties &properties) {
     properties.clear_minimized();
     properties.clear_minimized();
   }
   }
 
 
+  if (properties.has_maximized()) {
+    if (_properties.get_maximized() != properties.get_maximized()) {
+      if (properties.get_maximized()) {
+        ShowWindow(_hWnd, SW_MAXIMIZE);
+      } else {
+        ShowWindow(_hWnd, SW_RESTORE);
+      }
+      _properties.set_maximized(properties.get_maximized());
+
+      if (_properties.get_minimized()) {
+        // Immediately minimize it again
+        ShowWindow(_hWnd, SW_MINIMIZE);
+      }
+    }
+    properties.clear_maximized();
+  }
+
   if (properties.has_fullscreen()) {
   if (properties.has_fullscreen()) {
     if (properties.get_fullscreen() && !is_fullscreen()) {
     if (properties.get_fullscreen() && !is_fullscreen()) {
       if (do_fullscreen_switch()){
       if (do_fullscreen_switch()){
@@ -507,6 +531,7 @@ open_window() {
   }
   }
   bool want_foreground = (!_properties.has_foreground() || _properties.get_foreground());
   bool want_foreground = (!_properties.has_foreground() || _properties.get_foreground());
   bool want_minimized = (_properties.has_minimized() && _properties.get_minimized()) && !want_foreground;
   bool want_minimized = (_properties.has_minimized() && _properties.get_minimized()) && !want_foreground;
+  bool want_maximized = (_properties.has_maximized() && _properties.get_maximized()) && want_foreground;
 
 
   HWND old_foreground_window = GetForegroundWindow();
   HWND old_foreground_window = GetForegroundWindow();
 
 
@@ -533,6 +558,9 @@ open_window() {
   if (want_minimized) {
   if (want_minimized) {
     ShowWindow(_hWnd, SW_MINIMIZE);
     ShowWindow(_hWnd, SW_MINIMIZE);
     ShowWindow(_hWnd, SW_MINIMIZE);
     ShowWindow(_hWnd, SW_MINIMIZE);
+  } else if (want_maximized) {
+    ShowWindow(_hWnd, SW_MAXIMIZE);
+    ShowWindow(_hWnd, SW_MAXIMIZE);
   } else {
   } else {
     ShowWindow(_hWnd, SW_SHOWNORMAL);
     ShowWindow(_hWnd, SW_SHOWNORMAL);
     ShowWindow(_hWnd, SW_SHOWNORMAL);
     ShowWindow(_hWnd, SW_SHOWNORMAL);
@@ -854,6 +882,21 @@ handle_reshape() {
       << "," << properties.get_y_size() << ")\n";
       << "," << properties.get_y_size() << ")\n";
   }
   }
 
 
+  // Check whether the window has been maximized or unmaximized.
+  WINDOWPLACEMENT pl;
+  pl.length = sizeof(WINDOWPLACEMENT);
+  if (GetWindowPlacement(_hWnd, &pl)) {
+    if (pl.showCmd == SW_SHOWMAXIMIZED || (pl.flags & WPF_RESTORETOMAXIMIZED) != 0) {
+      properties.set_maximized(true);
+    } else {
+      properties.set_maximized(false);
+    }
+  }
+  else if (windisplay_cat.is_debug()) {
+    windisplay_cat.debug()
+      << "GetWindowPlacement() failed in handle_reshape.  Ignoring.\n";
+  }
+
   adjust_z_order();
   adjust_z_order();
   system_changed_properties(properties);
   system_changed_properties(properties);
 }
 }
@@ -1083,6 +1126,9 @@ calculate_metrics(bool fullscreen, DWORD window_style, WINDOW_METRICS &metrics,
 bool WinGraphicsWindow::
 bool WinGraphicsWindow::
 open_graphic_window() {
 open_graphic_window() {
   DWORD window_style = make_style(_properties);
   DWORD window_style = make_style(_properties);
+  if (_properties.get_maximized()) {
+    window_style |= WS_MAXIMIZE;
+  }
 
 
   wstring title;
   wstring title;
   if (_properties.has_title()) {
   if (_properties.has_title()) {

+ 2 - 0
panda/src/x11display/x11GraphicsPipe.cxx

@@ -363,6 +363,8 @@ x11GraphicsPipe(const std::string &display) :
   _net_wm_state_add = XInternAtom(_display, "_NET_WM_STATE_ADD", false);
   _net_wm_state_add = XInternAtom(_display, "_NET_WM_STATE_ADD", false);
   _net_wm_state_remove = XInternAtom(_display, "_NET_WM_STATE_REMOVE", false);
   _net_wm_state_remove = XInternAtom(_display, "_NET_WM_STATE_REMOVE", false);
   _net_wm_bypass_compositor = XInternAtom(_display, "_NET_WM_BYPASS_COMPOSITOR", false);
   _net_wm_bypass_compositor = XInternAtom(_display, "_NET_WM_BYPASS_COMPOSITOR", false);
+  _net_wm_state_maximized_vert = XInternAtom(_display, "_NET_WM_STATE_MAXIMIZED_VERT", false);
+  _net_wm_state_maximized_horz = XInternAtom(_display, "_NET_WM_STATE_MAXIMIZED_HORZ", false);
 }
 }
 
 
 /**
 /**

+ 2 - 0
panda/src/x11display/x11GraphicsPipe.h

@@ -177,6 +177,8 @@ public:
   Atom _net_wm_state_add;
   Atom _net_wm_state_add;
   Atom _net_wm_state_remove;
   Atom _net_wm_state_remove;
   Atom _net_wm_bypass_compositor;
   Atom _net_wm_bypass_compositor;
+  Atom _net_wm_state_maximized_vert;
+  Atom _net_wm_state_maximized_horz;
 
 
   // Extension functions.
   // Extension functions.
   typedef int (*pfn_XcursorGetDefaultSize)(X11_Display *);
   typedef int (*pfn_XcursorGetDefaultSize)(X11_Display *);

+ 75 - 1
panda/src/x11display/x11GraphicsWindow.cxx

@@ -309,6 +309,9 @@ process_events() {
   WindowProperties properties;
   WindowProperties properties;
   bool changed_properties = false;
   bool changed_properties = false;
 
 
+  XPropertyEvent property_event;
+  bool got_net_wm_state_change = false;
+
   while (XCheckIfEvent(_display, &event, check_event, (char *)this)) {
   while (XCheckIfEvent(_display, &event, check_event, (char *)this)) {
     if (got_keyrelease_event) {
     if (got_keyrelease_event) {
       // If a keyrelease event is immediately followed by a matching keypress
       // If a keyrelease event is immediately followed by a matching keypress
@@ -362,6 +365,19 @@ process_events() {
     case ReparentNotify:
     case ReparentNotify:
       break;
       break;
 
 
+    case PropertyNotify:
+      //std::cout << "PropertyNotify event: atom = " << event.xproperty.atom << std::endl;
+      x11GraphicsPipe *x11_pipe;
+      DCAST_INTO_V(x11_pipe, _pipe);
+      if (event.xproperty.atom == x11_pipe->_net_wm_state) {
+        // currently we're only interested in the net_wm_state type of
+        // changes and only need to gather property informations once at
+        // the end after the while loop
+        property_event = event.xproperty;
+        got_net_wm_state_change = true;
+      }
+      break;
+
     case ConfigureNotify:
     case ConfigureNotify:
       // When resizing or moving the window, multiple ConfigureNotify events
       // When resizing or moving the window, multiple ConfigureNotify events
       // may be sent in rapid succession.  We only respond to the last one.
       // may be sent in rapid succession.  We only respond to the last one.
@@ -585,6 +601,45 @@ process_events() {
       }
       }
   }
   }
 
 
+  if (got_net_wm_state_change) {
+    // some wm state properties have been changed, check their values
+    // once in this part instead of multiple times in the while loop
+
+    // Check if this window is maximized or not
+    bool is_maximized = false;
+    Atom wmState = property_event.atom;
+    Atom type;
+    int format;
+    unsigned long nItem, bytesAfter;
+    unsigned char *new_window_properties = NULL;
+    // gather all properties from the active dispplay and window
+    XGetWindowProperty(_display, _xwindow, wmState, 0, LONG_MAX, false, AnyPropertyType, &type, &format, &nItem, &bytesAfter, &new_window_properties);
+    if (nItem > 0) {
+      x11GraphicsPipe *x11_pipe;
+      DCAST_INTO_V(x11_pipe, _pipe);
+      // run through all found items
+      for (unsigned long iItem = 0; iItem < nItem; ++iItem) {
+        unsigned long item = reinterpret_cast<unsigned long *>(new_window_properties)[iItem];
+        // check if the item is one of the maximized states
+        if (item == x11_pipe->_net_wm_state_maximized_horz ||
+            item == x11_pipe->_net_wm_state_maximized_vert) {
+          // The window was maximized
+          is_maximized = true;
+        }
+      }
+    }
+
+    // Debug entry
+    if (x11display_cat.is_debug()) {
+      x11display_cat.debug()
+        << "set maximized to: " << is_maximized << "\n";
+    }
+
+    // Now make sure the property will get stored correctly
+    properties.set_maximized(is_maximized);
+    changed_properties = true;
+  }
+
   if (changed_properties) {
   if (changed_properties) {
     system_changed_properties(properties);
     system_changed_properties(properties);
   }
   }
@@ -791,6 +846,12 @@ set_properties_now(WindowProperties &properties) {
     properties.clear_fullscreen();
     properties.clear_fullscreen();
   }
   }
 
 
+  // Same for maximized.
+  if (properties.has_maximized()) {
+    _properties.set_maximized(properties.get_maximized());
+    properties.clear_maximized();
+  }
+
   // The size and position of an already-open window are changed via explicit
   // The size and position of an already-open window are changed via explicit
   // X calls.  These may still get intercepted by the window manager.  Rather
   // X calls.  These may still get intercepted by the window manager.  Rather
   // than changing _properties immediately, we'll wait for the ConfigureNotify
   // than changing _properties immediately, we'll wait for the ConfigureNotify
@@ -1101,7 +1162,8 @@ open_window() {
     KeyPressMask | KeyReleaseMask |
     KeyPressMask | KeyReleaseMask |
     EnterWindowMask | LeaveWindowMask |
     EnterWindowMask | LeaveWindowMask |
     PointerMotionMask |
     PointerMotionMask |
-    FocusChangeMask | StructureNotifyMask;
+    FocusChangeMask | StructureNotifyMask |
+    PropertyChangeMask;
 
 
   // Initialize window attributes
   // Initialize window attributes
   XSetWindowAttributes wa;
   XSetWindowAttributes wa;
@@ -1269,6 +1331,18 @@ set_wm_properties(const WindowProperties &properties, bool already_mapped) {
   SetAction set_data[max_set_data];
   SetAction set_data[max_set_data];
   int next_set_data = 0;
   int next_set_data = 0;
 
 
+  if (properties.has_maximized()) {
+    if (properties.get_maximized()) {
+      state_data[next_state_data++] = x11_pipe->_net_wm_state_maximized_vert;
+      set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_maximized_vert, 1);
+      state_data[next_state_data++] = x11_pipe->_net_wm_state_maximized_horz;
+      set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_maximized_horz, 1);
+    } else {
+      set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_maximized_vert, 0);
+      set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_maximized_horz, 0);
+    }
+  }
+
   if (properties.has_fullscreen()) {
   if (properties.has_fullscreen()) {
     if (properties.get_fullscreen()) {
     if (properties.get_fullscreen()) {
       // For a "fullscreen" request, we pass this through, hoping the window
       // For a "fullscreen" request, we pass this through, hoping the window

+ 3 - 0
pandatool/src/deploy-stub/deploy-stub.c

@@ -655,6 +655,9 @@ int main(int argc, char *argv[]) {
   PyImport_FrozenModules = blobinfo.pointers[0];
   PyImport_FrozenModules = blobinfo.pointers[0];
   retval = Py_FrozenMain(argc, argv);
   retval = Py_FrozenMain(argc, argv);
 
 
+  fflush(stdout);
+  fflush(stderr);
+
   unmap_blob(blob);
   unmap_blob(blob);
   return retval;
   return retval;
 }
 }

+ 0 - 1
samples/fireflies/light.sha

@@ -14,7 +14,6 @@ void vshader(float4 vtx_position : POSITION,
 }
 }
 
 
 void fshader(float4 l_pos: TEXCOORD0,
 void fshader(float4 l_pos: TEXCOORD0,
-             float4 l_scale: TEXCOORD1,
              uniform sampler2D k_texnormal : TEXUNIT0,
              uniform sampler2D k_texnormal : TEXUNIT0,
              uniform sampler2D k_texalbedo : TEXUNIT1,
              uniform sampler2D k_texalbedo : TEXUNIT1,
              uniform sampler2D k_texdepth  : TEXUNIT2,
              uniform sampler2D k_texdepth  : TEXUNIT2,

+ 20 - 0
tests/display/test_winprops.py

@@ -66,3 +66,23 @@ def test_winprops_size_property():
     # Test clear
     # Test clear
     props.size = None
     props.size = None
     assert not props.has_size()
     assert not props.has_size()
+
+
+def test_winprops_maximized_property():
+    props = WindowProperties()
+
+    # Test get
+    props.set_maximized(True)
+    assert props.maximized == True
+
+    # Test has
+    props.clear_maximized()
+    assert props.maximized is None
+
+    # Test set
+    props.maximized = True
+    assert props.get_maximized() == True
+
+    # Test clear
+    props.maximized = None
+    assert not props.has_maximized()

+ 18 - 0
tests/pgraph/test_cullfaceattrib.py

@@ -0,0 +1,18 @@
+from panda3d.core import CullFaceAttrib
+
+
+def test_cullfaceattrib_compare():
+    clockwise1 = CullFaceAttrib.make()
+    clockwise2 = CullFaceAttrib.make()
+    reverse1 = CullFaceAttrib.make_reverse()
+    reverse2 = CullFaceAttrib.make_reverse()
+
+    assert clockwise1.compare_to(clockwise2) == 0
+    assert clockwise2.compare_to(clockwise1) == 0
+
+    assert reverse1.compare_to(reverse2) == 0
+    assert reverse2.compare_to(reverse1) == 0
+
+    assert reverse1.compare_to(clockwise1) != 0
+    assert clockwise1.compare_to(reverse1) != 0
+    assert reverse1.compare_to(clockwise1) == -clockwise1.compare_to(reverse1)

+ 34 - 0
tests/pgraph/test_lightattrib.py

@@ -107,3 +107,37 @@ def test_lightattrib_compare():
     assert lattr1.compare_to(lattr2) != 0
     assert lattr1.compare_to(lattr2) != 0
     assert lattr2.compare_to(lattr1) != 0
     assert lattr2.compare_to(lattr1) != 0
     assert lattr2.compare_to(lattr1) == -lattr1.compare_to(lattr2)
     assert lattr2.compare_to(lattr1) == -lattr1.compare_to(lattr2)
+
+    # An on light is not the same as an off light
+    lattr1 = core.LightAttrib.make().add_on_light(spot)
+    lattr2 = core.LightAttrib.make().add_off_light(spot)
+    assert lattr1.compare_to(lattr2) != 0
+    assert lattr2.compare_to(lattr1) != 0
+    assert lattr2.compare_to(lattr1) == -lattr1.compare_to(lattr2)
+
+    # If both have the same off light, they are equal
+    lattr1 = core.LightAttrib.make().add_off_light(spot)
+    lattr2 = core.LightAttrib.make().add_off_light(spot)
+    assert lattr1.compare_to(lattr2) == 0
+    assert lattr2.compare_to(lattr1) == 0
+
+    # Off light should not be equal to empty
+    lattr1 = core.LightAttrib.make().add_off_light(spot)
+    lattr2 = core.LightAttrib.make_all_off()
+    assert lattr1.compare_to(lattr2) != 0
+    assert lattr2.compare_to(lattr1) != 0
+    assert lattr2.compare_to(lattr1) == -lattr1.compare_to(lattr2)
+
+    # Off light should not be equal to all-off
+    lattr1 = core.LightAttrib.make().add_off_light(spot)
+    lattr2 = core.LightAttrib.make_all_off()
+    assert lattr1.compare_to(lattr2) != 0
+    assert lattr2.compare_to(lattr1) != 0
+    assert lattr2.compare_to(lattr1) == -lattr1.compare_to(lattr2)
+
+    # Different off lights shouldn't be equal either, of course
+    lattr1 = core.LightAttrib.make().add_off_light(spot)
+    lattr2 = core.LightAttrib.make().add_off_light(point)
+    assert lattr1.compare_to(lattr2) != 0
+    assert lattr2.compare_to(lattr1) != 0
+    assert lattr2.compare_to(lattr1) == -lattr1.compare_to(lattr2)

+ 29 - 0
tests/pgraph/test_nodepath.py

@@ -194,6 +194,35 @@ def test_nodepath_python_tags():
     assert rc1 == rc2
     assert rc1 == rc2
 
 
 
 
+def test_nodepath_clear_python_tag():
+    from panda3d.core import NodePath
+
+    path = NodePath("node")
+    assert not path.has_python_tag("a")
+    assert not path.has_python_tag("b")
+    assert not path.node().has_tags()
+
+    path.set_python_tag("a", "value")
+    assert path.has_python_tag("a")
+    assert not path.has_python_tag("b")
+    assert path.node().has_tags()
+
+    path.set_python_tag("b", "value")
+    assert path.has_python_tag("a")
+    assert path.has_python_tag("b")
+    assert path.node().has_tags()
+
+    path.clear_python_tag("a")
+    assert not path.has_python_tag("a")
+    assert path.has_python_tag("b")
+    assert path.node().has_tags()
+
+    path.clear_python_tag("b")
+    assert not path.has_python_tag("a")
+    assert not path.has_python_tag("b")
+    assert not path.node().has_tags()
+
+
 def test_nodepath_replace_texture():
 def test_nodepath_replace_texture():
     from panda3d.core import NodePath, Texture
     from panda3d.core import NodePath, Texture
 
 

+ 5 - 1
tests/pgraph/test_shaderattrib.py

@@ -48,10 +48,14 @@ def test_shaderattrib_compare():
     assert shattr1.compare_to(shattr2) == 0
     assert shattr1.compare_to(shattr2) == 0
     assert shattr2.compare_to(shattr1) == 0
     assert shattr2.compare_to(shattr1) == 0
 
 
-    shattr2 = core.ShaderAttrib.make().set_flag(core.ShaderAttrib.F_subsume_alpha_test, True)
+    shattr2 = core.ShaderAttrib.make().set_flag(core.ShaderAttrib.F_subsume_alpha_test, False)
     assert shattr1.compare_to(shattr2) != 0
     assert shattr1.compare_to(shattr2) != 0
     assert shattr2.compare_to(shattr1) != 0
     assert shattr2.compare_to(shattr1) != 0
 
 
     shattr1 = core.ShaderAttrib.make().set_flag(core.ShaderAttrib.F_subsume_alpha_test, False)
     shattr1 = core.ShaderAttrib.make().set_flag(core.ShaderAttrib.F_subsume_alpha_test, False)
+    assert shattr1.compare_to(shattr2) == 0
+    assert shattr2.compare_to(shattr1) == 0
+
+    shattr2 = core.ShaderAttrib.make().set_flag(core.ShaderAttrib.F_subsume_alpha_test, True)
     assert shattr1.compare_to(shattr2) != 0
     assert shattr1.compare_to(shattr2) != 0
     assert shattr2.compare_to(shattr1) != 0
     assert shattr2.compare_to(shattr1) != 0

+ 47 - 0
tests/pgraph/test_textureattrib.py

@@ -9,6 +9,19 @@ tex2 = core.Texture("tex2")
 tex3 = core.Texture("tex3")
 tex3 = core.Texture("tex3")
 
 
 
 
+def test_textureattrib_compose_empty():
+    # Tests a case in which a child node does not alter the original.
+    tattr1 = core.TextureAttrib.make()
+    tattr1 = tattr1.add_on_stage(stage1, tex1)
+
+    tattr2 = core.TextureAttrib.make()
+
+    tattr3 = tattr1.compose(tattr2)
+    assert tattr3.get_num_on_stages() == 1
+
+    assert stage1 in tattr3.on_stages
+
+
 def test_textureattrib_compose_add():
 def test_textureattrib_compose_add():
     # Tests a case in which a child node adds another texture.
     # Tests a case in which a child node adds another texture.
     tattr1 = core.TextureAttrib.make()
     tattr1 = core.TextureAttrib.make()
@@ -24,6 +37,21 @@ def test_textureattrib_compose_add():
     assert stage2 in tattr3.on_stages
     assert stage2 in tattr3.on_stages
 
 
 
 
+def test_textureattrib_compose_override():
+    # Tests a case in which a child node overrides a texture.
+    tattr1 = core.TextureAttrib.make()
+    tattr1 = tattr1.add_on_stage(stage1, tex1)
+
+    tattr2 = core.TextureAttrib.make()
+    tattr2 = tattr2.add_on_stage(stage1, tex2)
+
+    tattr3 = tattr1.compose(tattr2)
+    assert tattr3.get_num_on_stages() == 1
+
+    assert stage1 in tattr3.on_stages
+    assert tattr3.get_on_texture(stage1) == tex2
+
+
 def test_textureattrib_compose_subtract():
 def test_textureattrib_compose_subtract():
     # Tests a case in which a child node disables a texture.
     # Tests a case in which a child node disables a texture.
     tattr1 = core.TextureAttrib.make()
     tattr1 = core.TextureAttrib.make()
@@ -61,6 +89,25 @@ def test_textureattrib_compose_both():
     assert stage3 in tattr3.on_stages
     assert stage3 in tattr3.on_stages
 
 
 
 
+def test_textureattrib_implicit_sort():
+    # Tests that two TextureStages with same sort retain insertion order.
+    tattr1 = core.TextureAttrib.make()
+    tattr1 = tattr1.add_on_stage(stage1, tex1)
+    tattr1 = tattr1.add_on_stage(stage2, tex2)
+
+    assert tattr1.get_on_stage(0) == stage1
+    assert tattr1.get_on_stage(1) == stage2
+
+    tattr2 = core.TextureAttrib.make()
+    tattr2 = tattr1.add_on_stage(stage2, tex2)
+    tattr2 = tattr1.add_on_stage(stage1, tex1)
+
+    assert tattr2.get_on_stage(0) == stage2
+    assert tattr2.get_on_stage(1) == stage1
+
+    assert tattr1.compare_to(tattr2) == -tattr2.compare_to(tattr1)
+
+
 def test_textureattrib_compose_alloff():
 def test_textureattrib_compose_alloff():
     # Tests a case in which a child node disables all textures.
     # Tests a case in which a child node disables all textures.
     tattr1 = core.TextureAttrib.make()
     tattr1 = core.TextureAttrib.make()

+ 17 - 0
tests/putil/test_bitarray.py

@@ -123,3 +123,20 @@ def test_bitarray_pickle():
 
 
     ba = ~BitArray(94187049178237918273981729127381723)
     ba = ~BitArray(94187049178237918273981729127381723)
     assert ba == pickle.loads(pickle.dumps(ba, -1))
     assert ba == pickle.loads(pickle.dumps(ba, -1))
+
+
+def test_bitarray_has_any_of():
+    ba = BitArray()
+    assert not ba.has_any_of(100, 200)
+
+    ba = BitArray()
+    ba.set_range(0, 53)
+    assert ba.has_any_of(52, 1)
+    assert ba.has_any_of(52, 100)
+    assert not ba.has_any_of(53, 45)
+
+    ba = BitArray()
+    ba.invert_in_place()
+    assert ba.has_any_of(0, 1)
+    assert ba.has_any_of(53, 45)
+    assert ba.has_any_of(0, 100)

Some files were not shown because too many files changed in this diff