dpi_scaling_round2: a bit of research on Qt6's hiDPI support #49

Open
goodboy wants to merge 4 commits from dpi_scaling_round2 into dpi-font-auto-calc

hey @momo here’s a couple tweaks i made while testing your #48 B)

Namely,

  • tweaked the .ui.style.DpiAwareFont.configure_to_dpi()’s log msg to use .info() level (again) and dump more, and better formatted, screen info by default.
  • added some updates to our snippets/ dumper script based on a bit of research i did on Qt6’s hiDPI docs:
    • https://doc.qt.io/qt-6/highdpi.html
    • NOTE, i also added a buncha embedded links in comments for further investigation as to what stuff we might want to include in something that would go into piker.ui somewhere

lmk wutchu think!

hey @momo here's a couple tweaks i made while testing your #48 B) Namely, - tweaked the `.ui.style.DpiAwareFont.configure_to_dpi()`'s log msg to use `.info()` level (again) and dump more, and better formatted, screen info by default. - added some updates to our `snippets/` dumper script based on a bit of research i did on `Qt6`'s hiDPI docs: - https://doc.qt.io/qt-6/highdpi.html - NOTE, i also added a buncha embedded links in comments for further investigation as to what stuff we might want to include in something that would go into `piker.ui` somewhere lmk wutchu think!
goodboy added 3 commits 2025-12-18 23:31:14 +00:00
35744f666f Add some Qt DPI extras to `qt_screen_info.py`
- set `QT_USE_PHYSICAL_DPI='1'` env var for Qt6 high-DPI
  * we likely want to do this in `piker.ui` as well!
- move `pxr` calc from widget to per-screen in loop.
- add `unscaled_size` calc using `pxr * size`.
- switch from `.availableGeometry()` to `.geometry()` for full
  bounds.
- shorten output labels, add `!r` repr formatting
- add Qt6 DPI rounding policy TODO with doc links

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
49bedb4912 Reorder imports in `qt_screen_info.py` ??
For wtv reason on nixos importing `pyqtgraph` first is causing `numpy`
to fail import?? No idea, but likely something to do with recent
`flake.nix`'s ld-lib-linking with `<nixpkgs>` marlarky?
goodboy reviewed 2025-12-18 23:36:18 +00:00
@ -46,0 +47,4 @@
# https://doc.qt.io/qt-6/highdpi.html#environment-variable-reference
os.environ['QT_USE_PHYSICAL_DPI'] = '1'
Poster
Owner

FWIW, i think we might want to add this setting by default since it seems (at least on sway/wayland) the “logical DPI” has very little value and is often plain deceiving since almost all compositor’s are going to pre-scale yet always report a 96..

at least this way (and try it urself via the updated script to verify) the “logical DPI” will be a rounded version, at least it seems, of the physical value; this at least discards ever using the “always 96 and not correct” default XD

FWIW, i think we might want to add this setting by default since it seems (at least on sway/wayland) the "logical DPI" has very little value and is often plain deceiving since almost all compositor's are going to pre-scale yet always report a 96.. at least this way (and try it urself via the updated script to verify) the "logical DPI" will be a rounded version, at least it seems, of the physical value; this at least discards ever using the "always 96 and not correct" default XD
goodboy reviewed 2025-12-18 23:37:04 +00:00
@ -61,1 +69,4 @@
app = QtWidgets.QApplication([])
#
# ^TODO? various global DPI settings?
# [ ] DPI rounding policy,
Poster
Owner

Not sure if this helps us more as well but figured i’d include it for further investigation.

Not sure if this helps us more as well but figured i'd include it for further investigation.
goodboy reviewed 2025-12-19 00:36:36 +00:00
@ -81,0 +97,4 @@
# https://doc.qt.io/qt-6/highdpi.html
pxr: float = screen.devicePixelRatio()
unscaled_size: QSize = pxr * size
Poster
Owner

Note this should actually be per-screen and the correct abs resolution dimensions (in pxs obvi).

A further gotcha here on wayland is that only int values of pxr are able to be read.. which means anyone doing fancy float reso-scaling (like i was in my sway config) will get a wrong calculation for this..

I’m not exactly sure how to guard against this yet but at the least we can document that it’s unsupported for now, possibly a warning in the .configure_to_dpi() message; it would be best if we can actually detect that case but i found no immediately obvious cross-platform way other then something gemini recommended,

from screeninfo import get_monitors

print("Monitor Information:")
for i, m in enumerate(get_monitors()):
    print(f"Monitor {i}:")
    print(f"  Name: {m.name}")
    print(f"  Resolution (pixels): {m.width}x{m.height}")
    # Physical dimensions are provided in millimeters (mm)
    print(f"  Physical Size (mm): {m.width_mm}mm x {m.height_mm}mm")
    print(f"  Is Primary: {m.is_primary}")

main issue is that the screeninfo lib doesn’t natively support wayland except through xwayland.. so we need another wayland nodding approach as well.

a couple options on this front might be pywayland and pywlroots and i also was already sniffing at python-wayland for use in modden as an eventual gesture daemon approach (for mobile / touch screens that is). Anyway, this is more of a me only problem i’d imagine since i seem be one of the few using piker on wayland Bp


OH RIGHT XD

i forgot gemini also reco-ed tnkinter which is in the stdlib,

import tkinter as tk

def get_screen_resolution_tkinter():
    """
    Gets the primary screen resolution using Tkinter.
    Works on Windows, macOS, and Linux (including Wayland/X11).
    """
    root = tk.Tk()
    # Hide the main window
    root.withdraw()
    
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    
    # Destroy the Tkinter instance after getting the information
    root.destroy()
    
    return screen_width, screen_height

if __name__ == "__main__":
    width, height = get_screen_resolution_tkinter()
    print(f"Screen resolution: {width}x{height}")

but i don’t think we can get the “physical dimensions” (like in cm/inches) from this? needs some tinkering if you feel up for it @momo ;)

Note this should actually be per-screen and the correct abs resolution dimensions (in pxs obvi). A further gotcha here on `wayland` is that only `int` values of `pxr` are able to be read.. which means anyone doing fancy `float` reso-scaling (like i was in my `sway` config) will get a wrong calculation for this.. I'm not exactly sure how to guard against this yet but at the least we can document that it's unsupported for now, possibly a warning in the `.configure_to_dpi()` message; it would be best if we can actually detect that case but i found no immediately obvious cross-platform way other then something `gemini` recommended, ```python from screeninfo import get_monitors print("Monitor Information:") for i, m in enumerate(get_monitors()): print(f"Monitor {i}:") print(f" Name: {m.name}") print(f" Resolution (pixels): {m.width}x{m.height}") # Physical dimensions are provided in millimeters (mm) print(f" Physical Size (mm): {m.width_mm}mm x {m.height_mm}mm") print(f" Is Primary: {m.is_primary}") ``` main issue is that the `screeninfo` lib doesn't natively support `wayland` except through `xwayland`.. so we need another wayland nodding approach as well. a couple options on this front might be `pywayland` and `pywlroots` and i also was already sniffing at [python-wayland](https://python-wayland.org/) for use in `modden` as an eventual gesture daemon approach (for mobile / touch screens that is). Anyway, this is more of a *me only* problem i'd imagine since i seem be one of the few using `piker` on `wayland` Bp --- OH RIGHT XD i forgot `gemini` also reco-ed `tnkinter` which is in the stdlib, ```python import tkinter as tk def get_screen_resolution_tkinter(): """ Gets the primary screen resolution using Tkinter. Works on Windows, macOS, and Linux (including Wayland/X11). """ root = tk.Tk() # Hide the main window root.withdraw() screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() # Destroy the Tkinter instance after getting the information root.destroy() return screen_width, screen_height if __name__ == "__main__": width, height = get_screen_resolution_tkinter() print(f"Screen resolution: {width}x{height}") ``` but i don't think we can get the "physical dimensions" (like in cm/inches) from this? needs some tinkering if you feel up for it @momo ;)
Poster
Owner

created #50 to track all my recent research on this and help drive the longer term desired feature.

created #50 to track all my recent research on this and help drive the longer term desired feature.
goodboy added 1 commit 2025-12-20 00:29:40 +00:00
e63cffaf53 Add `.xsh` script mentioned in gitea #50
Note since it's actually `xonsh` code run with either,
- most pedantically: `xonsh ./snippets/calc_ppi.xsh`
- or relying on how shebang: `./snippets/calc_ppi.xsh`
  * an sheboom.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
You can also view command line instructions.

Step 1:

From your project repository, check out a new branch and test the changes.
git checkout -b dpi_scaling_round2 dpi-font-auto-calc
git pull origin dpi_scaling_round2

Step 2:

Merge the changes and update on Gitea.
git checkout dpi-font-auto-calc
git merge --no-ff dpi_scaling_round2
git push origin dpi-font-auto-calc
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: pikers/piker#49
There is no content yet.