From 08c686ba188160f90b2e331710ff236c2bc03fbe Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 8 Mar 2019 11:14:56 +0100 Subject: [PATCH 1/6] windisplay: fix issues with runtime fullscreen switching --- panda/src/windisplay/winGraphicsWindow.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index 195189ac9e..d3e444cac9 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -979,12 +979,12 @@ make_style(const WindowProperties &properties) { DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - if (_properties.get_fullscreen()) { + if (properties.get_fullscreen()) { window_style |= WS_SYSMENU; - } else if (!_properties.get_undecorated()) { + } else if (!properties.get_undecorated()) { window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); - if (!_properties.get_fixed_size()) { + if (!properties.get_fixed_size()) { window_style |= (WS_SIZEBOX | WS_MAXIMIZEBOX); } else { window_style |= WS_BORDER; From a634e729c83a44db91c40991686930454309f1fd Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 8 Mar 2019 11:45:47 +0100 Subject: [PATCH 2/6] interrogate: fix uninitialized var, fixes sporadic nb_true_divide This was a regression introduced by fa6c066b2f21856036cb24d482a7152406c6c2e2 (which in turn fixed #529) --- dtool/src/interrogate/interfaceMakerPythonNative.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.h b/dtool/src/interrogate/interfaceMakerPythonNative.h index 8b18ef1957..c667ab22fa 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.h +++ b/dtool/src/interrogate/interfaceMakerPythonNative.h @@ -121,7 +121,7 @@ private: public: std::string _answer_location; WrapperType _wrapper_type; - int _min_version; + int _min_version = 0; std::string _wrapper_name; std::set _remaps; bool _keep_method; From 0e70997fbf627c9a7a7057df66497b53e8249869 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 19:30:13 +0100 Subject: [PATCH 3/6] x11display: fixes for multi-monitor and fullscreen support - DisplayInformation now gives the list of display modes returned by XRRGetScreenResources if RandR 1.2 is supported, which is apparently more reliable than the previous XRRSizes/XRRRates approach. - Switching fullscreen on X11 to the current resolution on the CRTC that the monitor is on will make the window cover the CRTC properly, rather than forcing the window to have an origin of (0, 0). - Passing in the pipe's display width/height is commonly done to go fullscreen at native res, but this may not correspond to a real display resolution. It now detects when this is done, and interprets this as "go fullscreen at the native resolution on the current CRTC". Fixes #575 --- panda/src/x11display/x11GraphicsPipe.cxx | 175 ++++++++++++++++++--- panda/src/x11display/x11GraphicsPipe.h | 64 ++++++++ panda/src/x11display/x11GraphicsWindow.cxx | 91 ++++++++--- 3 files changed, 283 insertions(+), 47 deletions(-) diff --git a/panda/src/x11display/x11GraphicsPipe.cxx b/panda/src/x11display/x11GraphicsPipe.cxx index e5e8da18c8..6050911fb4 100644 --- a/panda/src/x11display/x11GraphicsPipe.cxx +++ b/panda/src/x11display/x11GraphicsPipe.cxx @@ -156,21 +156,55 @@ x11GraphicsPipe(const std::string &display) : void *xrandr = dlopen("libXrandr.so.2", RTLD_NOW | RTLD_LOCAL); if (xrandr != nullptr) { pfn_XRRQueryExtension _XRRQueryExtension = (pfn_XRRQueryExtension)dlsym(xrandr, "XRRQueryExtension"); + pfn_XRRQueryVersion _XRRQueryVersion = (pfn_XRRQueryVersion)dlsym(xrandr, "XRRQueryVersion"); + _XRRSizes = (pfn_XRRSizes)dlsym(xrandr, "XRRSizes"); _XRRRates = (pfn_XRRRates)dlsym(xrandr, "XRRRates"); _XRRGetScreenInfo = (pfn_XRRGetScreenInfo)dlsym(xrandr, "XRRGetScreenInfo"); _XRRConfigCurrentConfiguration = (pfn_XRRConfigCurrentConfiguration)dlsym(xrandr, "XRRConfigCurrentConfiguration"); _XRRSetScreenConfig = (pfn_XRRSetScreenConfig)dlsym(xrandr, "XRRSetScreenConfig"); + int event, error, major, minor; if (_XRRQueryExtension == nullptr || _XRRSizes == nullptr || _XRRRates == nullptr || _XRRGetScreenInfo == nullptr || _XRRConfigCurrentConfiguration == nullptr || - _XRRSetScreenConfig == nullptr) { + _XRRSetScreenConfig == nullptr || _XRRQueryVersion == nullptr) { _have_xrandr = false; x11display_cat.warning() << "libXrandr.so.2 does not provide required functions; resolution setting will not work.\n"; + } + else if (_XRRQueryExtension(_display, &event, &error) && + _XRRQueryVersion(_display, &major, &minor)) { + _have_xrandr = true; + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Found RandR extension " << major << "." << minor << "\n"; + } + + if (major > 1 || (major == 1 && minor >= 2)) { + if (major > 1 || (major == 1 && minor >= 3)) { + _XRRGetScreenResourcesCurrent = (pfn_XRRGetScreenResources) + dlsym(xrandr, "XRRGetScreenResourcesCurrent"); + } else { + // Fall back to this slower version. + _XRRGetScreenResourcesCurrent = (pfn_XRRGetScreenResources) + dlsym(xrandr, "XRRGetScreenResources"); + } + + _XRRFreeScreenResources = (pfn_XRRFreeScreenResources)dlsym(xrandr, "XRRFreeScreenResources"); + _XRRGetCrtcInfo = (pfn_XRRGetCrtcInfo)dlsym(xrandr, "XRRGetCrtcInfo"); + _XRRFreeCrtcInfo = (pfn_XRRFreeCrtcInfo)dlsym(xrandr, "XRRFreeCrtcInfo"); + } else { + _XRRGetScreenResourcesCurrent = nullptr; + _XRRFreeScreenResources = nullptr; + _XRRGetCrtcInfo = nullptr; + _XRRFreeCrtcInfo = nullptr; + } } else { - int event, error; - _have_xrandr = _XRRQueryExtension(_display, &event, &error); + _have_xrandr = false; + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "RandR extension not supported; resolution setting will not work.\n"; + } } } else { _have_xrandr = false; @@ -182,29 +216,61 @@ x11GraphicsPipe(const std::string &display) : // Use Xrandr to fill in the supported resolution list. if (_have_xrandr) { - int num_sizes, num_rates; - XRRScreenSize *xrrs; - xrrs = _XRRSizes(_display, 0, &num_sizes); - _display_information->_total_display_modes = 0; - for (int i = 0; i < num_sizes; ++i) { - _XRRRates(_display, 0, i, &num_rates); - _display_information->_total_display_modes += num_rates; - } + // If we have XRRGetScreenResources, we prefer that. It seems to be more + // reliable than XRRSizes in multi-monitor set-ups. + if (auto res = get_screen_resources()) { + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Using XRRScreenResources to obtain display modes\n"; + } + _display_information->_total_display_modes = res->nmode; + _display_information->_display_mode_array = new DisplayMode[res->nmode]; + for (int i = 0; i < res->nmode; ++i) { + XRRModeInfo &mode = res->modes[i]; - short *rates; - short counter = 0; - _display_information->_display_mode_array = new DisplayMode[_display_information->_total_display_modes]; - for (int i = 0; i < num_sizes; ++i) { - int num_rates; - rates = _XRRRates(_display, 0, i, &num_rates); - for (int j = 0; j < num_rates; ++j) { - DisplayMode* dm = _display_information->_display_mode_array + counter; - dm->width = xrrs[i].width; - dm->height = xrrs[i].height; - dm->refresh_rate = rates[j]; + DisplayMode *dm = _display_information->_display_mode_array + i; + dm->width = mode.width; + dm->height = mode.height; dm->bits_per_pixel = -1; dm->fullscreen_only = false; - ++counter; + + if (mode.hTotal && mode.vTotal) { + dm->refresh_rate = (double)mode.dotClock / + ((double)mode.hTotal * (double)mode.vTotal); + } else { + dm->refresh_rate = 0; + } + } + } else { + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Using XRRSizes and XRRRates to obtain display modes\n"; + } + + int num_sizes, num_rates; + XRRScreenSize *xrrs; + xrrs = _XRRSizes(_display, 0, &num_sizes); + _display_information->_total_display_modes = 0; + for (int i = 0; i < num_sizes; ++i) { + _XRRRates(_display, 0, i, &num_rates); + _display_information->_total_display_modes += num_rates; + } + + short *rates; + short counter = 0; + _display_information->_display_mode_array = new DisplayMode[_display_information->_total_display_modes]; + for (int i = 0; i < num_sizes; ++i) { + int num_rates; + rates = _XRRRates(_display, 0, i, &num_rates); + for (int j = 0; j < num_rates; ++j) { + DisplayMode* dm = _display_information->_display_mode_array + counter; + dm->width = xrrs[i].width; + dm->height = xrrs[i].height; + dm->refresh_rate = rates[j]; + dm->bits_per_pixel = -1; + dm->fullscreen_only = false; + ++counter; + } } } } @@ -258,6 +324,69 @@ x11GraphicsPipe:: } } +/** + * Returns an XRRScreenResources object, or null if RandR 1.2 is not supported. + */ +std::unique_ptr x11GraphicsPipe:: +get_screen_resources() const { + XRRScreenResources *res = nullptr; + + if (_have_xrandr && _XRRGetScreenResourcesCurrent != nullptr) { + res = _XRRGetScreenResourcesCurrent(_display, _root); + } + + return std::unique_ptr(res, _XRRFreeScreenResources); +} + +/** + * Returns an XRRCrtcInfo object, or null if RandR 1.2 is not supported. + */ +std::unique_ptr x11GraphicsPipe:: +get_crtc_info(XRRScreenResources *res, RRCrtc crtc) const { + XRRCrtcInfo *info = nullptr; + + if (_have_xrandr && _XRRGetCrtcInfo != nullptr) { + info = _XRRGetCrtcInfo(_display, res, crtc); + } + + return std::unique_ptr(info, _XRRFreeCrtcInfo); +} + +/** + * Finds a CRTC for going fullscreen to, at the given origin. The new CRTC + * is returned, along with its x, y, width and height. + * + * If the required RandR extension is not supported, a value of None will be + * returned, but x, y, width and height will still be populated. + */ +RRCrtc x11GraphicsPipe:: +find_fullscreen_crtc(const LPoint2i &point, + int &x, int &y, int &width, int &height) { + x = 0; + y = 0; + width = DisplayWidth(_display, _screen); + height = DisplayHeight(_display, _screen); + + if (auto res = get_screen_resources()) { + for (int i = 0; i < res->ncrtc; ++i) { + RRCrtc crtc = res->crtcs[i]; + if (auto info = get_crtc_info(res.get(), crtc)) { + if (point[0] >= info->x && point[0] < info->x + info->width && + point[1] >= info->y && point[1] < info->y + info->height) { + + x = info->x; + y = info->y; + width = info->width; + height = info->height; + return crtc; + } + } + } + } + + return None; +} + /** * Returns an indication of the thread in which this GraphicsPipe requires its * window processing to be performed: typically either the app thread (e.g. diff --git a/panda/src/x11display/x11GraphicsPipe.h b/panda/src/x11display/x11GraphicsPipe.h index 3b8802e6e2..e1abf80b00 100644 --- a/panda/src/x11display/x11GraphicsPipe.h +++ b/panda/src/x11display/x11GraphicsPipe.h @@ -32,12 +32,61 @@ typedef struct _XcursorImages XcursorImages; typedef unsigned short Rotation; typedef unsigned short SizeID; +typedef unsigned long XRRModeFlags; +typedef XID RROutput; +typedef XID RRCrtc; +typedef XID RRMode; + typedef struct _XRRScreenConfiguration XRRScreenConfiguration; typedef struct { int width, height; int mwidth, mheight; } XRRScreenSize; +typedef struct _XRRModeInfo { + RRMode id; + unsigned int width; + unsigned int height; + unsigned long dotClock; + unsigned int hSyncStart; + unsigned int hSyncEnd; + unsigned int hTotal; + unsigned int hSkew; + unsigned int vSyncStart; + unsigned int vSyncEnd; + unsigned int vTotal; + char *name; + unsigned int nameLength; + XRRModeFlags modeFlags; +} XRRModeInfo; + +typedef struct _XRRScreenResources { + Time timestamp; + Time configTimestamp; + int ncrtc; + RRCrtc *crtcs; + int noutput; + RROutput *outputs; + int nmode; + XRRModeInfo *modes; +} XRRScreenResources; + +typedef struct _XRRCrtcInfo { + Time timestamp; + int x, y; + unsigned int width, height; + RRMode mode; + Rotation rotation; + int noutput; + RROutput *outputs; + Rotation rotations; + int npossible; + RROutput *possible; +} XRRCrtcInfo; + +typedef void (*pfn_XRRFreeScreenResources)(XRRScreenResources *resources); +typedef void (*pfn_XRRFreeCrtcInfo)(XRRCrtcInfo *crtcInfo); + class FrameBufferProperties; /** @@ -64,6 +113,12 @@ public: static INLINE int enable_x_error_messages(); static INLINE int get_x_error_count(); + std::unique_ptr get_screen_resources() const; + std::unique_ptr get_crtc_info(XRRScreenResources *res, RRCrtc crtc) const; + + RRCrtc find_fullscreen_crtc(const LPoint2i &point, + int &x, int &y, int &width, int &height); + public: virtual PreferredWindowThread get_preferred_window_thread() const; @@ -100,6 +155,7 @@ public: pfn_XcursorImageDestroy _XcursorImageDestroy; typedef Bool (*pfn_XRRQueryExtension)(X11_Display *, int*, int*); + typedef Status (*pfn_XRRQueryVersion)(X11_Display *, int*, int*); typedef XRRScreenSize *(*pfn_XRRSizes)(X11_Display*, int, int*); typedef short *(*pfn_XRRRates)(X11_Display*, int, int, int*); typedef XRRScreenConfiguration *(*pfn_XRRGetScreenInfo)(X11_Display*, X11_Window); @@ -126,6 +182,14 @@ protected: typedef Status (*pfn_XF86DGADirectVideo)(X11_Display *, int, int); pfn_XF86DGADirectVideo _XF86DGADirectVideo; + typedef XRRScreenResources *(*pfn_XRRGetScreenResources)(X11_Display*, X11_Window); + typedef XRRCrtcInfo *(*pfn_XRRGetCrtcInfo)(X11_Display *dpy, XRRScreenResources *resources, RRCrtc crtc); + + pfn_XRRGetScreenResources _XRRGetScreenResourcesCurrent; + pfn_XRRFreeScreenResources _XRRFreeScreenResources; + pfn_XRRGetCrtcInfo _XRRGetCrtcInfo; + pfn_XRRFreeCrtcInfo _XRRFreeCrtcInfo; + private: void make_hidden_cursor(); void release_hidden_cursor(); diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 0aa4e0bf64..5599959cdb 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -579,20 +579,60 @@ set_properties_now(WindowProperties &properties) { bool is_fullscreen = _properties.has_fullscreen() && _properties.get_fullscreen(); bool want_fullscreen = properties.has_fullscreen() ? properties.get_fullscreen() : is_fullscreen; + if (want_fullscreen && properties.has_origin()) { + // If we're fullscreen, reject changes to the origin. + properties.clear_origin(); + } + if (is_fullscreen != want_fullscreen || (is_fullscreen && properties.has_size())) { if (want_fullscreen) { - if (x11_pipe->_have_xrandr) { - XRRScreenConfiguration* conf = _XRRGetScreenInfo(_display, x11_pipe->get_root()); + // OK, first figure out which CRTC the window is on. It may be on more + // than one, actually, so grab a point in the center in order to figure + // out which one it's more-or-less mostly on. + LPoint2i center = _properties.get_origin() + _properties.get_size() / 2; + int x, y, width, height; + x11_pipe->find_fullscreen_crtc(center, x, y, width, height); + + // Which size should we go fullscreen in? + int reqsizex, reqsizey; + if (properties.has_size()) { + reqsizex = properties.get_x_size(); + reqsizey = properties.get_y_size(); + } else if (_properties.has_size()) { + reqsizex = _properties.get_x_size(); + reqsizey = _properties.get_y_size(); + } else { + reqsizex = width; + reqsizey = height; + } + + // Are we passing in pipe.display_width/height? This is actually the + // size of the virtual desktop, which may not be a real resolution, so + // if that is passed in, we have to assume that the user means to just + // fullscreen without changing the screen resolution. + if ((reqsizex == x11_pipe->get_display_width() && + reqsizey == x11_pipe->get_display_height()) + || (width == reqsizex && height == reqsizey) + || !x11_pipe->_have_xrandr) { + + // Cover the current CRTC. + properties.set_origin(x, y); + properties.set_size(width, height); + + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Setting window to fullscreen on CRTC " + << width << "x" << height << "+" << x << "+" << y << "\n"; + } + } else { + // We may need to change the screen resolution. The code below is + // suboptimal; in the future, we probably want to only touch the CRTC + // that the window is on. + XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, _xwindow); SizeID old_size_id = x11_pipe->_XRRConfigCurrentConfiguration(conf, &_orig_rotation); SizeID new_size_id = (SizeID) -1; - int num_sizes = 0, reqsizex, reqsizey; - if (properties.has_size()) { - reqsizex = properties.get_x_size(); - reqsizey = properties.get_y_size(); - } else { - reqsizex = _properties.get_x_size(); - reqsizey = _properties.get_y_size(); - } + int num_sizes = 0; + XRRScreenSize *xrrs; xrrs = x11_pipe->_XRRSizes(_display, 0, &num_sizes); for (int i = 0; i < num_sizes; ++i) { @@ -605,21 +645,29 @@ set_properties_now(WindowProperties &properties) { x11display_cat.error() << "Videocard has no supported display resolutions at specified res (" << reqsizex << " x " << reqsizey << ")\n"; - } else { - if (new_size_id != old_size_id) { + // Just go fullscreen at native resolution, then. + properties.set_origin(x, y); + properties.set_size(width, height); + } else { + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Switching to fullscreen with resolution " + << reqsizex << "x" << reqsizey << "\n"; + } + + if (new_size_id != old_size_id) { _XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime); if (_orig_size_id == (SizeID) -1) { // Remember the original resolution so we can switch back to it. _orig_size_id = old_size_id; } + + // Since the above changes the entire screen configuration, we + // have to set the origin to 0, 0. + properties.set_origin(0, 0); } } - } else { - // If we don't have Xrandr support, we fake the fullscreen support by - // setting the window size to the desktop size. - properties.set_size(x11_pipe->get_display_width(), - x11_pipe->get_display_height()); } } else { // Change the resolution back to what it was. Don't remove the SizeID @@ -1130,13 +1178,8 @@ set_wm_properties(const WindowProperties &properties, bool already_mapped) { size_hints_p = XAllocSizeHints(); if (size_hints_p != nullptr) { if (properties.has_origin()) { - if (_properties.get_fullscreen()) { - size_hints_p->x = 0; - size_hints_p->y = 0; - } else { - size_hints_p->x = properties.get_x_origin(); - size_hints_p->y = properties.get_y_origin(); - } + size_hints_p->x = properties.get_x_origin(); + size_hints_p->y = properties.get_y_origin(); size_hints_p->flags |= USPosition; } LVecBase2i size = _properties.get_size(); From 088b90e887d2646ffcaf9a1670472388e173cbf4 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 20:20:56 +0100 Subject: [PATCH 4/6] TexMemWatcher: fix compatibility issues with Python 3 Closes #578 --- direct/src/showutil/TexMemWatcher.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/direct/src/showutil/TexMemWatcher.py b/direct/src/showutil/TexMemWatcher.py index 843395d58d..eb9a5b84cf 100644 --- a/direct/src/showutil/TexMemWatcher.py +++ b/direct/src/showutil/TexMemWatcher.py @@ -786,8 +786,9 @@ class TexMemWatcher(DirectObject): # Look for a single rectangular hole to hold this piece. tp = self.findHole(tr.area, tr.w, tr.h) if tp: - texCmp = cmp(tr.w, tr.h) - holeCmp = cmp(tp.p[1] - tp.p[0], tp.p[3] - tp.p[2]) + texCmp = (tr.w > tr.h) - (tr.w < tr.h) + holeCmp = ((tp.p[1] - tp.p[0]) > (tp.p[3] - tp.p[2])) \ + - ((tp.p[1] - tp.p[0]) < (tp.p[3] - tp.p[2])) if texCmp != 0 and holeCmp != 0 and texCmp != holeCmp: tp.rotated = True tr.placements = [tp] @@ -803,10 +804,11 @@ class TexMemWatcher(DirectObject): # in. tpList = self.findHolePieces(tr.area) if tpList: - texCmp = cmp(tr.w, tr.h) + texCmp = (tr.w > tr.h) - (tr.w < tr.h) tr.placements = tpList for tp in tpList: - holeCmp = cmp(tp.p[1] - tp.p[0], tp.p[3] - tp.p[2]) + holeCmp = ((tp.p[1] - tp.p[0]) > (tp.p[3] - tp.p[2])) \ + - ((tp.p[1] - tp.p[0]) < (tp.p[3] - tp.p[2])) if texCmp != 0 and holeCmp != 0 and texCmp != holeCmp: tp.rotated = True tp.setBitmasks(self.bitmasks) @@ -858,11 +860,11 @@ class TexMemWatcher(DirectObject): # we have to squish it? if tw < w: # We'd have to make it taller. - nh = min(area / tw, th) + nh = min(area // tw, th) th = nh elif th < h: # We'd have to make it narrower. - nw = min(area / th, tw) + nw = min(area // th, tw) tw = nw else: # Hey, we don't have to squish it after all! Just @@ -912,7 +914,7 @@ class TexMemWatcher(DirectObject): tpArea = (r - l) * (t - b) if tpArea >= area: # we're done. - shorten = (tpArea - area) / (r - l) + shorten = (tpArea - area) // (r - l) t -= shorten tp.p = (l, r, b, t) tp.area = (r - l) * (t - b) From 0dd33265ee008878ef36b9352235bea539da3575 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 20:44:02 +0100 Subject: [PATCH 5/6] doc: add release notes for 1.10.2 --- doc/ReleaseNotes | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index ba67ff8dc8..b9a1150731 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,3 +1,28 @@ +------------------------ RELEASE 1.10.2 ----------------------- + +This release fixes several more bugs, including a few regressions +in 1.10.2. Upgrading is highly recommended. + +* Fix regression on Windows causing freezes and instability +* Fix a memory leak issue in Python applications +* Fix crash reading unaligned float4 column in GeomVertexReader +* Fixes for switching to fullscreen at runtime on Windows and Linux +* Fix incorrect display mode listing in some Linux distributions +* Fix threading crash on Linux when using get_keyboard_map() +* Support "from __future__ import division" for Panda types +* Support building with Visual Studio 2019 in makepanda +* Work around Assimp crash when loading multiple .ply models +* On Windows, a Python 3-compatible version of Pmw is included +* Fix ParticlePanel spam when hovering over File menu items +* TexMemWatcher has been fixed for Python 3 +* Prevent macOS window getting stuck after base.destroy() +* Fix assertion setting mass before shape with Bullet debug build +* Don't error if DirectScrolledFrame is destroyed twice +* Fix reference count corruption accessing task.__dict__ +* Fix writing to SequenceNode frame_rate property +* Fix collider sort not copied when copying CollisionNode +* Add OpenCollective backer file + ------------------------ RELEASE 1.10.1 ----------------------- This is a bugfix release intended to fix several issues in 1.10.0. From 3f97c3534e5eb4e490f97c4c00d0ab58a27fd239 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 20:46:13 +0100 Subject: [PATCH 6/6] doc: fix typo in release notes [skip ci] --- doc/ReleaseNotes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index b9a1150731..41d69d7f99 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,7 +1,7 @@ ------------------------ RELEASE 1.10.2 ----------------------- This release fixes several more bugs, including a few regressions -in 1.10.2. Upgrading is highly recommended. +in 1.10.1. Upgrading is highly recommended. * Fix regression on Windows causing freezes and instability * Fix a memory leak issue in Python applications