diff --git a/README.md b/README.md index 92db8aa77c..3e60e633bd 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Installing Panda3D ================== The latest Panda3D SDK can be downloaded from -[this page](https://www.panda3d.org/download/sdk-1-10-7/). +[this page](https://www.panda3d.org/download/sdk-1-10-8/). If you are familiar with installing Python packages, you can use the following command: diff --git a/direct/src/extensions_native/NodePath_extensions.py b/direct/src/extensions_native/NodePath_extensions.py index 6756819f47..ffb55daceb 100644 --- a/direct/src/extensions_native/NodePath_extensions.py +++ b/direct/src/extensions_native/NodePath_extensions.py @@ -789,6 +789,7 @@ def r_subdivideCollisions(self, solids, numSolidsInLeaves): return newSolids def r_constructCollisionTree(self, solidTree, parentNode, colName): + from panda3d.core import CollisionNode for item in solidTree: if type(item[0]) == type([]): newNode = parentNode.attachNewNode('%s-branch' % colName) diff --git a/direct/src/gui/OnscreenText.py b/direct/src/gui/OnscreenText.py index cfdad68475..fbc487b3e6 100644 --- a/direct/src/gui/OnscreenText.py +++ b/direct/src/gui/OnscreenText.py @@ -294,6 +294,9 @@ class OnscreenText(NodePath): text = property(getText, setText) def setTextX(self, x): + """ + .. versionadded:: 1.10.8 + """ self.setTextPos(x, self.__pos[1]) def setX(self, x): @@ -304,6 +307,9 @@ class OnscreenText(NodePath): self.setTextPos(x, self.__pos[1]) def setTextY(self, y): + """ + .. versionadded:: 1.10.8 + """ self.setTextPos(self.__pos[0], y) def setY(self, y): @@ -316,6 +322,8 @@ class OnscreenText(NodePath): def setTextPos(self, x, y=None): """ Position the onscreen text in 2d screen space + + .. versionadded:: 1.10.8 """ if y is None: self.__pos = tuple(x) @@ -324,6 +332,9 @@ class OnscreenText(NodePath): self.updateTransformMat() def getTextPos(self): + """ + .. versionadded:: 1.10.8 + """ return self.__pos text_pos = property(getTextPos, setTextPos) @@ -350,6 +361,8 @@ class OnscreenText(NodePath): def setTextR(self, r): """setTextR(self, float) Rotates the text around the screen's normal. + + .. versionadded:: 1.10.8 """ self.__roll = -r self.updateTransformMat() @@ -382,6 +395,8 @@ class OnscreenText(NodePath): """setTextScale(self, float, float) Scale the text in 2d space. You may specify either a single uniform scale, or two scales, or a tuple of two scales. + + .. versionadded:: 1.10.8 """ if sy is None: @@ -394,6 +409,9 @@ class OnscreenText(NodePath): self.updateTransformMat() def getTextScale(self): + """ + .. versionadded:: 1.10.8 + """ return self.__scale text_scale = property(getTextScale, setTextScale) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index 83fe5b1bd5..392589b07c 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -10,6 +10,7 @@ Recommended maintenance release. * Fix sounds resuming on reactivation if stop() was called while inactive (#559) * Collision traverser now releases GIL during traversal (#1033) * Fix crash caused by some gamepad drivers on Linux (#1066) +* Add GraphicsPipe::get_display_zoom() for querying system DPI scaling * Skinning-enabled shaders can now properly render unskinned models as well * BitMask, SparseArray, BitArray types can now be pickled (#886) * VFSImporter now properly detects source file encodings in Python 3 diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 23bbf44c9c..4ae956d50b 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -485,6 +485,14 @@ ConfigVariableBool sync_video "cheesy estimate of scene complexity. Some drivers may ignore " "this request.")); +ConfigVariableDouble display_zoom +("display-zoom", 0.0, + PRC_DESC("If this is set to a value other than 0.0, it overrides the detected " + "system DPI scaling. GraphicsPipe::get_display_zoom() will instead " + "return whatever was passed in here. You should generally only " + "change this based on a user preference change or to test how the UI " + "will look on monitors with different pixel densities.")); + /** * Initializes the library. This must be called at least once before any of * the functions or classes in this library can be used. Normally it will be diff --git a/panda/src/display/config_display.h b/panda/src/display/config_display.h index c425894389..c06d284674 100644 --- a/panda/src/display/config_display.h +++ b/panda/src/display/config_display.h @@ -109,6 +109,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableDouble pixel_zoom; extern EXPCL_PANDA_DISPLAY ConfigVariableColor background_color; extern EXPCL_PANDA_DISPLAY ConfigVariableBool sync_video; +extern EXPCL_PANDA_DISPLAY ConfigVariableDouble display_zoom; extern EXPCL_PANDA_DISPLAY void init_libdisplay(); diff --git a/panda/src/display/graphicsPipe.cxx b/panda/src/display/graphicsPipe.cxx index 439e450b0a..39c09b76e8 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/panda/src/display/graphicsPipe.cxx @@ -97,6 +97,9 @@ static void update_memory_info(DisplayInformation *info) { } #endif +// Temporarily declared as global float. +static PN_stdfloat detected_display_zoom = 1.0; + TypeHandle GraphicsPipe::_type_handle; /** @@ -266,6 +269,35 @@ make_output(const std::string &name, return nullptr; } +/** + * Returns the display zoom factor configured in the operating system. If the + * operating system automatically scales windows to match the DPI (such as when + * dpi-aware is set to false), this will be 1.0. Otherwise, this will be set to + * a value approximating the density of the monitor divided by the standard + * density of the operating system (usually 96), yielding a value like 1.5 or + * 2.0. + * + * @since 1.10.8 + */ +PN_stdfloat GraphicsPipe:: +get_display_zoom() const { + if (display_zoom.get_num_words() > 0) { + double override = display_zoom.get_value(); + if (override != 0.0) { + return override; + } + } + return detected_display_zoom; +} + +/** + * Called by derived class to set the display zoom factor. + */ +void GraphicsPipe:: +set_detected_display_zoom(PN_stdfloat zoom) { + detected_display_zoom = zoom; +} + /** * Gets the pipe's DisplayInformation. */ diff --git a/panda/src/display/graphicsPipe.h b/panda/src/display/graphicsPipe.h index ef3a3b8496..156467f66a 100644 --- a/panda/src/display/graphicsPipe.h +++ b/panda/src/display/graphicsPipe.h @@ -91,8 +91,10 @@ PUBLISHED: INLINE int get_display_width() const; INLINE int get_display_height() const; + PN_stdfloat get_display_zoom() const; MAKE_PROPERTY(display_width, get_display_width); MAKE_PROPERTY(display_height, get_display_height); + MAKE_PROPERTY(display_zoom, get_display_zoom); DisplayInformation *get_display_information(); MAKE_PROPERTY(display_information, get_display_information); @@ -115,6 +117,8 @@ public: virtual PT(GraphicsStateGuardian) make_callback_gsg(GraphicsEngine *engine); protected: + void set_detected_display_zoom(PN_stdfloat zoom); + virtual void close_gsg(GraphicsStateGuardian *gsg); virtual PT(GraphicsOutput) make_output(const std::string &name, diff --git a/panda/src/ffmpeg/ffmpegAudioCursor.cxx b/panda/src/ffmpeg/ffmpegAudioCursor.cxx index af66ef28d4..455d79d4cc 100644 --- a/panda/src/ffmpeg/ffmpegAudioCursor.cxx +++ b/panda/src/ffmpeg/ffmpegAudioCursor.cxx @@ -224,7 +224,7 @@ cleanup() { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0) avcodec_free_context(&_audio_ctx); #else - delete _audio_ctx; + av_free(_audio_ctx); #endif } _audio_ctx = nullptr; diff --git a/panda/src/ffmpeg/ffmpegVideoCursor.cxx b/panda/src/ffmpeg/ffmpegVideoCursor.cxx index 8b700d2342..3305368a42 100644 --- a/panda/src/ffmpeg/ffmpegVideoCursor.cxx +++ b/panda/src/ffmpeg/ffmpegVideoCursor.cxx @@ -616,7 +616,7 @@ close_stream() { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0) avcodec_free_context(&_video_ctx); #else - delete _video_ctx; + av_free(_video_ctx); #endif } _video_ctx = nullptr; diff --git a/panda/src/windisplay/winGraphicsPipe.cxx b/panda/src/windisplay/winGraphicsPipe.cxx index ece0559426..4815262a77 100644 --- a/panda/src/windisplay/winGraphicsPipe.cxx +++ b/panda/src/windisplay/winGraphicsPipe.cxx @@ -227,6 +227,22 @@ WinGraphicsPipe() { windisplay_cat.debug() << "Calling SetProcessDpiAwareness().\n"; } pfnSetProcessDpiAwareness(Process_Per_Monitor_DPI_Aware); + + HDC dc = GetDC(nullptr); + if (dc) { + int dpi = GetDeviceCaps(dc, LOGPIXELSX); + if (dpi > 0) { + PN_stdfloat zoom = (double)dpi / 96.0; + set_detected_display_zoom(zoom); + + if (windisplay_cat.is_debug()) { + windisplay_cat.debug() + << "Determined display zoom to be " << zoom + << " based on LOGPIXELSX " << dpi << "\n"; + } + } + ReleaseDC(nullptr, dc); + } } } } diff --git a/panda/src/x11display/x11GraphicsPipe.cxx b/panda/src/x11display/x11GraphicsPipe.cxx index 3e095d0833..b181318861 100644 --- a/panda/src/x11display/x11GraphicsPipe.cxx +++ b/panda/src/x11display/x11GraphicsPipe.cxx @@ -16,6 +16,7 @@ #include "config_x11display.h" #include "frameBufferProperties.h" #include "displayInformation.h" +#include "pstrtod.h" #include @@ -350,6 +351,29 @@ x11GraphicsPipe(const std::string &display) : setlocale(LC_ALL, saved_locale.c_str()); } + const char *dpi = XGetDefault(_display, "Xft", "dpi"); + if (dpi != nullptr) { + char *endptr = nullptr; + double result = pstrtod(dpi, &endptr); + if (result != 0 && !cnan(result) && endptr[0] == '\0') { + result /= 96; + set_detected_display_zoom(result); + + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Determined display zoom to be " << result + << " based on specified Xft.dpi " << dpi << "\n"; + } + } else { + x11display_cat.warning() + << "Unable to determine display zoom because Xft.dpi is invalid: " + << dpi << "\n"; + } + } else if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Unable to determine display zoom because Xft.dpi was not set.\n"; + } + // Get some X atom numbers. _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false); _net_wm_pid = XInternAtom(_display, "_NET_WM_PID", false); diff --git a/pandatool/src/deploy-stub/deploy-stub.c b/pandatool/src/deploy-stub/deploy-stub.c index 65a604fa01..2565760d06 100644 --- a/pandatool/src/deploy-stub/deploy-stub.c +++ b/pandatool/src/deploy-stub/deploy-stub.c @@ -321,15 +321,20 @@ static int enable_line_buffering(PyObject *file) { if (method != NULL) { PyObject *result = PyObject_Call(method, args, kwargs); Py_DECREF(method); + Py_DECREF(kwargs); + Py_DECREF(args); if (result != NULL) { Py_DECREF(result); } else { PyErr_Clear(); return 0; } + } else { + Py_DECREF(kwargs); + Py_DECREF(args); + PyErr_Clear(); + return 0; } - Py_DECREF(kwargs); - Py_DECREF(args); #else /* Older versions just don't expose a way to reconfigure(), but it's still safe to override the property; we just have to use a hack to do it,