From 2b0a6b995a3eaf3b54e480b8b7bcbe43fd20b5d9 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 26 Dec 2020 16:17:01 +0100 Subject: [PATCH] display: Add a way to query system DPI scaling See #426 --- doc/ReleaseNotes | 1 + panda/src/display/config_display.cxx | 8 ++++++ panda/src/display/config_display.h | 1 + panda/src/display/graphicsPipe.cxx | 32 ++++++++++++++++++++++++ panda/src/display/graphicsPipe.h | 4 +++ panda/src/windisplay/winGraphicsPipe.cxx | 16 ++++++++++++ panda/src/x11display/x11GraphicsPipe.cxx | 24 ++++++++++++++++++ 7 files changed, 86 insertions(+) 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 965d68f4e3..2cb2f40c27 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -478,6 +478,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 21f1acb510..fb4da08b8d 100644 --- a/panda/src/display/config_display.h +++ b/panda/src/display/config_display.h @@ -108,6 +108,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 52ccfa426d..e2e55b5db0 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/panda/src/display/graphicsPipe.cxx @@ -99,6 +99,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; /** @@ -268,6 +271,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/windisplay/winGraphicsPipe.cxx b/panda/src/windisplay/winGraphicsPipe.cxx index 7da40c64f1..b89d022ca8 100644 --- a/panda/src/windisplay/winGraphicsPipe.cxx +++ b/panda/src/windisplay/winGraphicsPipe.cxx @@ -239,6 +239,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 64393a1541..e871cb20a7 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 @@ -300,6 +301,29 @@ x11GraphicsPipe(const std::string &display) : XFree(im_supported_styles); */ + 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);