autorandr
autorandr copied to clipboard
Handle DPI settings
I'd like to (re)store any DPI settings, which I currently set via xrandr --dpi 120
.
This results in these changes in the output from xdpyinfo
(from 96 to 120):
< dimensions: 1366x768 pixels (361x203 millimeters)
< resolution: 96x96 dots per inch
---
> dimensions: 1366x768 pixels (289x162 millimeters)
> resolution: 120x120 dots per inch
This does not appear to be reflected in the output of xrandr -q --verbose
.
I am using xsettings now (instead of
gnome-settings-daemon), and a script to automatically set it there via
xdpyinfo
(source).
However, xdpyinfo
for my laptop display (Lenovo X220t) is not correct, and
therefore I set it manually.
It would be nice if this could be set per display, but apparently it's per X display (screen).
(The real DPI is 125, but I've read that you should stick to certain factors from the default of 96 (a factor of 1.25 in this case))
This does not appear to be reflected in the output of xrandr -q --verbose.
Couldn't we extract this from the first line (it states effective resolution and physical device size in mm) of each output?
I just tried. No, that doesn't work, and that it doesn't makes a lot of sense, too, now that I've come to think about it.. What xrandr displays is per-output DPI only, which can be different from the screen's DPI and also isn't alterable (the physical screen size is hard-coded in the EDID, bytes 21 & 22). What --dpi
alters, on the other hand, is the screen's DPI, which corresponds to the FB resolution (first line in xrandr's output)
I don't think that including a call to xdpyinfo
in autorandr is a good idea. For one, that would be an external dependency. For the other, it currently doesn't fiddle with the FB size at all (but lets xrandr decide how to set it), but once we'd set --dpi
, we'd need to set --fb
as well, and I don't know what sorts of regression that might create.
What we could do, if you need this, is to integrate a plugin structure that would enable you to do this without maintaining your own fork - I'm thinking of something simple like importing all modules from a plugin directory and calling well-named hooks from those plugins at detection and application time, probably with a mechanism to store custom settings?!
A plugin structure would be nice, but a more simple approach is probably just looking at autorandr's output, and then call by xsettings-setup
manually.
I can use just autorandr
and look for "(detected)", right? (It would not change the current setup)
But then again (and for other use cases), it would be useful to have information about if the detected setup is already applied, without calling "autorandr -c", which would apply the changes.
In the end, I think two lines should be added to the output: "detected: X" and "current: X" (or something similar).
Currently I could just use -c
and then grep for the (detected)
line, especially since I will likely move calling autorandr to a custom script anyway. "Config already loaded"
could then be used there to not apply any changes (again).
If you're fine with configuring this manually, then you can also place a script called postswitch
in your profile's directory. It is executed after applying a profile, and only then.
Changing autorandr's default output is a good idea. The current output comes from the legacy bash version (not quite, it exits after it has found the "detected" configuration), and I always thought that it is quite useless in its current form, too. For increased backwards compatibility, we could keep it in its current form, but just replace "(detected)" with "(current)" for the currently loaded configuration?!
Oh yeah, postswitch
is useful in this case - had forgotten about it.
Re backwards compatibility: a change from "(detected)" to "(current)" would then also be not backwards compatible.
I think this issue can be closed for now - there's no need to change anything currently.
Re backwards compatibility: a change from "(detected)" to "(current)" would then also be not backwards compatible.
Right. But it'd require less changes in existing scripts. (Maybe I'll change this.. if anyone complains this could always be reverted.)
I think this issue can be closed for now - there's no need to change anything currently.
Ok
But it'd require less changes in existing scripts. (Maybe I'll change this.. if anyone complains this could always be reverted.)
:+1:
@blueyed Would you please share your final solutions? I have an internal and external display that differ a lot in dpi.
A couple of thoughts on DPI from my experience
First, in X there is no such thing as per-display DPI from practical standpoint. You have to choose some global value that suits you.
Second, xdpyinfo is a sufficiently reliable source of the current DPI. It is directly affected by xrandr's --dpi
parameter and can be used as the base for further manipulations.
Said manipulations would include exporting that value to xrdb and fontconfig. With DPI value correctly set in these three places, majority of applications are affected.
I've ported the example DPI hook from my rerandr3 to autorandr scripts:
postsave: saves current DPI value to "${AUTORANDR_PROFILE_FOLDER}/dpi"
#!/bin/sh
DPI="$(xdpyinfo | grep 'resolution:' | grep -o '[0-9]\+x[0-9]\+' | head -n 1 | cut -d 'x' -f 1)"
[ -n "$DPI" ] && echo "$DPI" > "${AUTORANDR_PROFILE_FOLDER}/dpi"
postswitch: expects DPI value in "${AUTORANDR_PROFILE_FOLDER}/dpi", falls back to calculated DPI of primary monitor, then falls back to default 96.
#!/bin/sh
DEFAULT_DPI=96
## try DPI from profile
printf "%s\n" "Trying to get DPI from \"${AUTORANDR_PROFILE_FOLDER}/dpi\""
DPI="$(cat "${AUTORANDR_PROFILE_FOLDER}/dpi" 2>/dev/null | head -n 1 | grep -o '[0-9]\+')"
## try dpi from primary monitor
if [ -z "$DPI" ]
then
printf "%s\n%s\n" "No DPI value in profile \"$AUTORANDR_CURRENT_PROFILE\"" "Trying to calculate from primary monitor"
DPX="$(xrandr -q | grep ' primary ' | grep -o ' [0-9]\+x' | grep -o '[0-9]\+')"
DMM="$(xrandr -q | grep ' primary ' | grep -o ') [0-9]\+mm' | grep -o '[0-9]\+')"
if [ -n "$DPX" -a -n "$DMM" ]
then
DPI="$(python -c "print( int( $DPX / ( $DMM * 0.039370079 ) ) )" )"
fi
fi
if [ -z "$DPI" ]
then
printf "%s\n%s\n" "Could not calculate DPI of primary monitor" "Using default"
DPI=$DEFAULT_DPI
fi
printf "%s\n" "Resulting DPI: $DPI"
## apply DPI to xrandr
xrandr --dpi "$DPI"
## sync dpi to xrdb
printf "%s\n" "Xft.dpi: $DPI" | xrdb -merge
## sync dpi to fontconfig
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/fontconfig/conf.d"
cat > "${XDG_CONFIG_HOME:-$HOME/.config}/fontconfig/conf.d/90-xrandr-sync-dpi.conf" << EOF
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!-- Generated by autorandr postswitch script, do not edit. -->
<fontconfig>
<match target="pattern">
<edit name="dpi" mode="assign"><double>$DPI</double></edit>
</match>
</fontconfig>
EOF
Turns out that adding --fb
to autorandr is a brilliant idea, I hadn't considered the side effect @Vladimir-csp mentioned in #88. Gives a much smoother user experience on my notebook at least. So let's reconsider adding native DPI support: Anyone willing to implement this?
What would it entail to implement it?
Using Vladimir's script as a template extract the DPI while storing a profile (using xdpyinfo
and the falllback if it's not installed), store it in config
files a dpi xyz
, (probably extend autorandr to be able to handle such non-output related options at all, IIRC it currently matches everything to an output), and finally extend apply_configuration
to set it.
It might actually be a good idea to just store the --fb
value to the configuration in general, and only use the calculation function if the key is not present in the configuration.
I had a look, but I'm not up to the task. :disappointed:
I'm not a Python developer, but I thought I could find a test and adjust it and then just figure out the code as I went. I wasn't aware that all the code is in a single file without no tests, so I'm just too scared to try it. I also cannot tell where in the code the config file is parsed either.
(Not saying it's bad or anything, just that I personally don't want to go in there and muck around without better understanding of Python. :bowing_man:)
I think that if someone could add support for non-output specific options (like dpi
and fb
), then a lot of setups could be supported even if detection cannot happen automatically. Maybe that's a simpler goal for someone to take a look at?
Pushed a work in progress version with an early attempt to toy around with this to the dpi
branch. I don't bother much with obtaining dpi information from the external tool yet, it's mainly an attempt to play around with piggy-backing the options onto the first output. Feedback appreciated.
I've tested dpi branch. It seems to get primary output native dpi correctly, save it and apply on restore to xrandr.
Pushed a work in progress version with an early attempt to toy around with this to the
dpi
branch. I don't bother much with obtaining dpi information from the external tool yet, it's mainly an attempt to play around with piggy-backing the options onto the first output. Feedback appreciated.
Very nice project, thank you. How is DPI handled in the current release (AUR)?
How does all of this relate to multihead (multiple monitors) with different resolutions/DPIs?
I have a laptop (3840x2160) and an ultrawide (3440x1440). I've had to settle with running my laptop at 2560x1440 and ultrawide at 3440x1440, with a DPI of 96. This keeps my laptop at reasonable size, but my ultrawide is actually a bit too big. However, I'd prefer to run both at full resolution, but a DPI of 144 for the laptop and 72 for the ultrawide..
Sadly X11 only supports a single global DPI. You'll need Wayland for Display-specific DPI settings.